// 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; compression = CompressionAlgorithm::BSHUF_LZ4; images_per_file = 1000; data_reduction_factor_serialmx = 1.0; write_nxmx_hdf5_master = true; spot_finding_enable = true; poni_rot_1_rad = 0.0f; poni_rot_2_rad = 0.0f; poni_rot_3_rad = 0.0f; max_spot_count = std::min(MAX_SPOT_COUNT, 250); detect_ice_rings = 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 compression 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(std::optional input) { if (input) { check_min("Space group number", input, 1); 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_min("Total flux", input.value(), 0.0); } total_flux = input; return *this; } DatasetSettings &DatasetSettings::Goniometer(const std::optional &input) { goniometer = input; 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; } const std::optional &DatasetSettings::GetGoniometer() const { return goniometer; } std::optional &DatasetSettings::Goniometer() { return goniometer; } 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; } std::optional 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(), 0); check_max("Pixel value low threshold", input.value(), INT24_MAX - 1); pixel_value_low_threshold = input; } return *this; } DatasetSettings &DatasetSettings::PixelValueHighThreshold(const std::optional &input) { if (!input || (input == 0)) pixel_value_high_threshold = {}; else { check_min("Pixel value high threshold", input.value(), 1); check_max("Pixel value high threshold", input.value(), INT32_MAX); pixel_value_high_threshold = input; } return *this; } std::optional DatasetSettings::GetPixelValueLowThreshold() const { return pixel_value_low_threshold; } std::optional DatasetSettings::GetPixelValueHighThreshold() const { return pixel_value_high_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; } DatasetSettings &DatasetSettings::GridScan(const std::optional &input) { grid_scan = input; return *this; } std::optional &DatasetSettings::GridScan() { return grid_scan; } const std::optional &DatasetSettings::GetGridScan() const { return grid_scan; } std::optional DatasetSettings::GetPolarizationFactor() const { return polarization_factor; } float DatasetSettings::GetPoniRot3_rad() const { return poni_rot_3_rad; } float DatasetSettings::GetPoniRot2_rad() const { return poni_rot_2_rad; } float DatasetSettings::GetPoniRot1_rad() const { return poni_rot_1_rad; } DatasetSettings &DatasetSettings::PoniRot1_rad(float input) { check_finite("PONI rotation 1 (radians)", input); poni_rot_1_rad = input; return *this; } DatasetSettings &DatasetSettings::PoniRot2_rad(float input) { check_finite("PONI rotation 2 (radians)", input); poni_rot_2_rad = input; return *this; } DatasetSettings &DatasetSettings::PoniRot3_rad(float input) { check_finite("PONI rotation 3 (radians)", input); poni_rot_3_rad = input; return *this; } DatasetSettings &DatasetSettings::PolarizationFactor(const std::optional &input) { if (input.has_value()) { check_finite("Polarization factor", input.value()); check_min("Polarization factor", input.value(), -1.0); check_max("Polarization factor", input.value(), 1.0); } polarization_factor = input.value(); return *this; } std::optional DatasetSettings::GetRingCurrent_mA() const { return ring_current_mA; } DatasetSettings &DatasetSettings::RingCurrent_mA(const std::optional &input) { if (input.has_value()) { check_min("Ring current (mA)", input, 0.0); } ring_current_mA = input; return *this; } std::optional DatasetSettings::GetSampleTemperature_K() const { return sample_temperature_K; } DatasetSettings &DatasetSettings::SampleTemperature_K(const std::optional &input) { if (input.has_value()) { check_min("Sample temperature (K)", input, 0.0); check_max("Sample temperature (K)", input, 1000.0); } sample_temperature_K = input; return *this; } DatasetSettings &DatasetSettings::SpotFindingEnable(bool input) { spot_finding_enable = input; return *this; } bool DatasetSettings::IsSpotFindingEnabled() const { return spot_finding_enable; } DatasetSettings &DatasetSettings::MaxSpotCount(int64_t input) { check_min("Max spot count", input, 10); check_max("Max spot count", input, MAX_SPOT_COUNT); max_spot_count = input; return *this; } DatasetSettings & DatasetSettings::DetectIceRings(bool input) { detect_ice_rings = input; return *this; } bool DatasetSettings::IsDetectIceRings() const { return detect_ice_rings; } DatasetSettings &DatasetSettings::FluorescenceSpectrum(const XrayFluorescenceSpectrum &input) { fluorescence_spectrum = input; return *this; } const XrayFluorescenceSpectrum & DatasetSettings::GetFluorescenceSpectrum() const { return fluorescence_spectrum; } int64_t DatasetSettings::GetMaxSpotCount() const { return max_spot_count; }