// SPDX-FileCopyrightText: 2024 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only #include #include "DatasetSettings.h" #include "Definitions.h" #include "JFJochException.h" #include "CheckPath.h" #define check_max(param, val, max) if ((val) > (max)) throw JFJochException(JFJochExceptionCategory::InputParameterAboveMax, param) #define check_min(param, val, min) if ((val) < (min)) throw JFJochException(JFJochExceptionCategory::InputParameterBelowMin, param) #define check_finite(param, val) if (!std::isfinite(val)) throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, param) DatasetSettings::DatasetSettings() { photon_energy_keV = WVL_1A_IN_KEV; detector_distance_mm = 100; beam_x_pxl = 0.0; beam_y_pxl = 0.0; file_prefix = "test"; ntrigger = 1; images_per_trigger = 1; space_group_number = 0; // not set compression = CompressionAlgorithm::BSHUF_LZ4; images_per_file = 1000; data_reduction_factor_serialmx = 1.0; rotation_axis = {1, 0, 0}; write_nxmx_hdf5_master = true; overwrite_existing_files = false; } DatasetSettings &DatasetSettings::ImagesPerTrigger(int64_t input) { check_max("Total number of images", input, 10*1000*1000); check_min("Total number of images", input, 0); images_per_trigger = input; return *this; } DatasetSettings &DatasetSettings::NumTriggers(int64_t input) { check_max("Total number of triggers", input, 10*1000*1000); check_min("Total number of triggers", input, 1); ntrigger = input; return *this; } DatasetSettings &DatasetSettings::PhotonEnergy_keV(float input) { check_finite("Energy (keV)", input); check_min("Energy (keV)", input, MIN_ENERGY); check_max("Energy (keV)", input, MAX_ENERGY); photon_energy_keV = input; return *this; } DatasetSettings &DatasetSettings::BeamX_pxl(float input) { check_finite("Beam center x", input); beam_x_pxl = input; return *this; } DatasetSettings &DatasetSettings::BeamY_pxl(float input) { check_finite("Beam center y", input); beam_y_pxl = input; return *this; } DatasetSettings &DatasetSettings::DetectorDistance_mm(float input) { check_finite("Detector distance (mm)", input); check_min("Detector distance (mm)", input, 1); detector_distance_mm = input; return *this; } DatasetSettings &DatasetSettings::FilePrefix(std::string input) { CheckPath(input); if ((input.find("_master.h5") == input.length() - 10) && (input.length() > 10)) file_prefix = input.substr(0, input.length() - 10); else file_prefix = input; return *this; } DatasetSettings &DatasetSettings::Compression(CompressionAlgorithm input) { switch (input) { case CompressionAlgorithm::NO_COMPRESSION: case CompressionAlgorithm::BSHUF_LZ4: case CompressionAlgorithm::BSHUF_ZSTD: case CompressionAlgorithm::BSHUF_ZSTD_RLE: compression = input; break; default: throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Invalid value for enum parameter"); } return *this; } DatasetSettings &DatasetSettings::SetUnitCell(const std::optional &cell) { if (cell && (cell->a * cell->b * cell->c * cell->alpha * cell->beta * cell->gamma != 0.0)) { check_min("Angle alpha", cell->alpha, 0); check_min("Angle beta", cell->beta, 0); check_min("Angle gamma", cell->gamma, 0); check_max("Angle alpha", cell->alpha, 360); check_max("Angle beta", cell->beta, 360); check_max("Angle gamma", cell->gamma, 360); unit_cell = cell; } else unit_cell.reset(); return *this; } DatasetSettings &DatasetSettings::SpaceGroupNumber(int64_t input) { check_min("Space group number", input, 0); check_max("Space group number", input, 230); space_group_number = input; return *this; } DatasetSettings &DatasetSettings::SampleName(std::string input) { sample_name = input; return *this; } DatasetSettings &DatasetSettings::AttenuatorTransmission(const std::optional &input) { if (input) { check_finite("Attenuator transmission", input.value()); check_max("Attenuator transmission", input.value(), 1.0); check_min("Attenuator transmission", input.value(), 0.0); } attenuator_transmission = input; return *this; } DatasetSettings &DatasetSettings::TotalFlux(const std::optional &input) { if (input) { check_finite("Total flux", input.value()); check_max("Total flux", input.value(), 1.0); check_min("Total flux", input.value(), 0.0); } total_flux = input; return *this; } DatasetSettings &DatasetSettings::Goniometer(const std::optional &input) { if (input) { check_finite("Rotation angle increment", input->increment); if (input->increment == 0.0f) throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Angle increment cannot be zero"); check_finite("Rotation angle start", input->start); goniometer = input; } return *this; } DatasetSettings &DatasetSettings::RotationAxis(const Coord &c) { if (c.Length() == 0.0) throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Cannot use empty vector for omega"); rotation_axis = c.Normalize(); return *this; } DatasetSettings &DatasetSettings::HeaderAppendix(const nlohmann::json &input) { header_appendix = input; return *this; } DatasetSettings &DatasetSettings::ImageAppendix(const nlohmann::json &input) { image_appendix = input; return *this; } std::optional DatasetSettings::GetAttenuatorTransmission() const { return attenuator_transmission; } std::optional DatasetSettings::GetTotalFlux() const { return total_flux; } std::optional DatasetSettings::GetGoniometer() const { return goniometer; } Coord DatasetSettings::GetRotationAxis() const { return rotation_axis; } const nlohmann::json& DatasetSettings::GetHeaderAppendix() const { return header_appendix; } const nlohmann::json& DatasetSettings::GetImageAppendix() const { return image_appendix; } std::optional DatasetSettings::GetUnitCell() const { return unit_cell; } int64_t DatasetSettings::GetSpaceGroupNumber() const { return space_group_number; } std::string DatasetSettings::GetSampleName() const { return sample_name; } float DatasetSettings::GetPhotonEnergy_keV() const { return photon_energy_keV; } float DatasetSettings::GetBeamX_pxl() const { return beam_x_pxl; } float DatasetSettings::GetBeamY_pxl() const { return beam_y_pxl; } float DatasetSettings::GetDetectorDistance_mm() const { return detector_distance_mm; } Coord DatasetSettings::GetScatteringVector() const { return {0, 0, photon_energy_keV / WVL_1A_IN_KEV}; } std::string DatasetSettings::GetFilePrefix() const { return file_prefix; } CompressionAlgorithm DatasetSettings::GetCompressionAlgorithm() const { return compression; } int64_t DatasetSettings::GetNumTriggers() const { return ntrigger; } int64_t DatasetSettings::GetImageNumPerTrigger() const { return images_per_trigger; } DatasetSettings &DatasetSettings::ImagesPerFile(int64_t input) { check_min("Images per file", input, 0); images_per_file = input; return *this; } int64_t DatasetSettings::GetImagesPerFile() const { return images_per_file; } DatasetSettings &DatasetSettings::LossyCompressionSerialMX(float input) { check_min("Data reduction factor for serial MX", input, 0.0); check_max("Data reduction factor for serial MX", input, 1.0); data_reduction_factor_serialmx = input; return *this; } float DatasetSettings::GetLossyCompressionSerialMX() const { return data_reduction_factor_serialmx; } DatasetSettings &DatasetSettings::RunNumber(const std::optional &input) { if (input) { check_min("Run number", input, 0); check_max("Run number", input, INT64_MAX); } run_number = input; return *this; } DatasetSettings & DatasetSettings::RunName(const std::optional &input) { if (input && input.value().empty()) run_name = {}; else run_name = input; return *this; } DatasetSettings &DatasetSettings::ExperimentGroup(const std::string &input) { group = input; return *this; } std::optional DatasetSettings::GetRunNumber() const { return run_number; } std::optional DatasetSettings::GetRunName() const { return run_name; } std::string DatasetSettings::GetExperimentGroup() const { return group; } std::optional DatasetSettings::GetImageTime() const { return image_time; } DatasetSettings &DatasetSettings::ImageTime(const std::optional &input) { if (input && (input.value().count() == 0)) image_time = {}; else image_time = input; return *this; } DatasetSettings &DatasetSettings::LossyCompressionPoisson(std::optional input) { if (!input || (input == 0)) compression_poisson_factor = {}; else { check_min("Poisson compression factor", input.value(), 1); check_max("Poisson compression factor", input.value(), 16); compression_poisson_factor = input; } return *this; } std::optional DatasetSettings::GetLossyCompressionPoisson() const { return compression_poisson_factor; } DatasetSettings &DatasetSettings::PixelValueLowThreshold(const std::optional &input) { if (!input || (input == 0)) pixel_value_low_threshold = {}; else { check_min("Pixel value low threshold", input.value(), 1); check_max("Pixel value low threshold", input.value(), INT24_MAX - 1); pixel_value_low_threshold = input; } return *this; } std::optional DatasetSettings::GetPixelValueLowThreshold() const { return pixel_value_low_threshold; } bool DatasetSettings::IsWriteNXmxHDF5Master() const { return write_nxmx_hdf5_master; } DatasetSettings &DatasetSettings::WriteNXmxHDF5Master(bool input) { write_nxmx_hdf5_master = input; return *this; } std::optional DatasetSettings::IsSaveCalibration() const { return save_calibration; } DatasetSettings &DatasetSettings::SaveCalibration(std::optional input) { save_calibration = input; return *this; }