// Copyright (2019-2023) Paul Scherrer Institute #include #include "NetworkAddressConvert.h" #include "JFJochCompressor.h" // For ZSTD_USE_JFJOCH_RLE #include "GitInfo.h" #include "DiffractionExperiment.h" #include "JFJochException.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) DiffractionExperiment::DiffractionExperiment() : DiffractionExperiment(DetectorGeometry(8, 2)) {} DiffractionExperiment::DiffractionExperiment(const DetectorSetup& det_setup) : detector(det_setup) { default_omega_axis = {1, 0, 0}; dataset.photon_energy_keV = WVL_1A_IN_KEV; dataset.detector_distance_mm = 100; dataset.data_file_count = 1; dataset.file_prefix = "test"; dataset.ntrigger = 1; dataset.images_per_trigger = 1; dataset.summation = 1; dataset.fpga_pixel_output = FPGAPixelOutput::Auto; dataset.space_group_number = 0; // not set dataset.compression = CompressionAlgorithm::BSHUF_LZ4; dataset.rad_int_polarization_corr = false; dataset.rad_int_solid_angle_corr = true; dataset.save_calibration = false; dataset.omega_rotation_axis = default_omega_axis; internal_fpga_packet_generator = false; debug_pixel_mask = false; ndatastreams = 1; frame_time = std::chrono::microseconds(MIN_FRAME_TIME_HALF_SPEED_IN_US); count_time = std::chrono::microseconds(MIN_FRAME_TIME_HALF_SPEED_IN_US - READOUT_TIME_IN_US); frame_time_pedestalG1G2 = std::chrono::microseconds(FRAME_TIME_PEDE_G1G2_IN_US); mask_chip_edges = false; mask_module_edges = false; preview_period = std::chrono::microseconds(1000*1000); // 1s / 1 Hz low_q = 0.1; high_q = 5.0; q_spacing = 0.05; ipv4_base_addr = 0x0132010a; git_sha1 = jfjoch_git_sha1(); git_date = jfjoch_git_date(); storage_cells = 1; storage_cell_start = 15; storage_cell_delay = std::chrono::nanoseconds(10*1000); detector_delay = std::chrono::nanoseconds(0); pedestal_g0_frames = 0; pedestal_g1_frames = 0; pedestal_g2_frames = 0; fix_gain_g1 = false; use_gain_hg0 = false; series_id = 0; conversion_on_fpga = true; Mode(DetectorMode::Conversion); } // setter functions DiffractionExperiment &DiffractionExperiment::Detector(const DetectorSetup &input) { detector = input; return *this; } DiffractionExperiment &DiffractionExperiment::Mode(DetectorMode input) { mode = input; return *this; } DiffractionExperiment &DiffractionExperiment::DataStreams(int64_t input) { check_max("Number of data streams", input, 16); check_min("Number of data streams", input, 1); ndatastreams = input; return *this; } DiffractionExperiment &DiffractionExperiment::ImagesPerTrigger(int64_t input) { check_max("Total number of images", input, 10*1000*1000); check_min("Total number of images", input, 0); dataset.images_per_trigger = input; return *this; } DiffractionExperiment &DiffractionExperiment::NumTriggers(int64_t input) { check_max("Total number of triggers", input, 10*1000*1000); check_min("Total number of triggers", input, 1); dataset.ntrigger = input; return *this; } DiffractionExperiment &DiffractionExperiment::FrameTime(std::chrono::microseconds in_frame_time, std::chrono::microseconds in_count_time) { check_min("Frame time (us)", in_frame_time.count(), MIN_FRAME_TIME_FULL_SPEED_IN_US); check_max("Frame time (us)", in_frame_time.count(), MAX_FRAME_TIME); check_max("Count time (us)", in_count_time.count(), in_frame_time.count() - READOUT_TIME_IN_US); if (in_count_time.count() != 0) { check_min("Count time (us)", in_count_time.count(), MIN_COUNT_TIME_IN_US); } frame_time = in_frame_time; if (in_count_time.count() == 0) count_time = in_frame_time - std::chrono::microseconds(READOUT_TIME_IN_US); else count_time = in_count_time; return *this; } DiffractionExperiment &DiffractionExperiment::PedestalG1G2FrameTime(std::chrono::microseconds input) { check_min("Pedestal G1G2 frame time (us) ", input.count(), MIN_FRAME_TIME_FULL_SPEED_IN_US); frame_time_pedestalG1G2 = input; return *this; } DiffractionExperiment &DiffractionExperiment::PedestalG0Frames(int64_t input) { check_min("Pedestal G0 frames", input, 0); pedestal_g0_frames = input; return *this; } DiffractionExperiment &DiffractionExperiment::PedestalG1Frames(int64_t input) { check_min("Pedestal G1 frames", input, 0); pedestal_g1_frames = input; return *this; } DiffractionExperiment &DiffractionExperiment::PedestalG2Frames(int64_t input) { check_min("Pedestal G2 frames", input, 0); pedestal_g2_frames = input; return *this; } DiffractionExperiment &DiffractionExperiment::PhotonEnergy_keV(float input) { check_min("Energy (keV)", input, MIN_ENERGY); check_max("Energy (keV)", input, MAX_ENERGY); dataset.photon_energy_keV = input; return *this; } DiffractionExperiment &DiffractionExperiment::BeamX_pxl(float input) { dataset.beam_x_pxl = input; return *this; } DiffractionExperiment &DiffractionExperiment::BeamY_pxl(float input) { dataset.beam_y_pxl = input; return *this; } DiffractionExperiment &DiffractionExperiment::DetectorDistance_mm(float input) { check_min("Detector distance (mm)", input, 1); dataset.detector_distance_mm = input; return *this; } DiffractionExperiment &DiffractionExperiment::FilePrefix(std::string input) { // File prefix with front slash is not allowed for security reasons if (input.front() == '/') throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Path cannot start with slash"); if (input.substr(0,3) == "../") throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Path cannot start with ../"); if (input.find("/../") != std::string::npos) throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Path cannot contain /../"); if ((input.find("_master.h5") == input.length() - 10) && (input.length() > 10)) dataset.file_prefix = input.substr(0, input.length() - 10); else dataset.file_prefix = input; return *this; } DiffractionExperiment &DiffractionExperiment::DataFileCount(int64_t input) { check_min("File count", input, 1); check_max("File count", input, 1000); dataset.data_file_count = input; return *this; } DiffractionExperiment &DiffractionExperiment::UseInternalPacketGenerator(bool input) { internal_fpga_packet_generator = input; return *this; } DiffractionExperiment &DiffractionExperiment::IPv4BaseAddr(std::string input) { ipv4_base_addr = IPv4AddressFromStr(input); return *this; } DiffractionExperiment &DiffractionExperiment::MaskModuleEdges(bool input) { mask_module_edges = input; return *this; } DiffractionExperiment &DiffractionExperiment::Compression(CompressionAlgorithm input) { switch (input) { case CompressionAlgorithm::NO_COMPRESSION: case CompressionAlgorithm::BSHUF_LZ4: case CompressionAlgorithm::BSHUF_ZSTD: case CompressionAlgorithm::BSHUF_ZSTD_RLE: dataset.compression = input; break; default: throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Invalid value for enum parameter"); } return *this; } DiffractionExperiment &DiffractionExperiment::MaskChipEdges(bool input) { mask_chip_edges = input; return *this; } DiffractionExperiment& DiffractionExperiment::LowResForAzimInt_A(float input) { check_min("Low Resolution for azimuthal integration", input, 0.1); check_max("Low Resolution for azimuthal integration", input, 500.0); low_q = 2 * static_cast(M_PI) / input; return *this; } DiffractionExperiment& DiffractionExperiment::HighResForAzimInt_A(float input) { check_min("High Resolution for azimuthal integration", input, 0.1); check_max("High Resolution for azimuthal integration", input, 500.0); high_q = 2 * static_cast(M_PI) / input; return *this; } DiffractionExperiment& DiffractionExperiment::LowQForAzimInt_recipA(float input) { check_min("Low Q for azimuthal integration", input, 0.001); check_max("Low Q for azimuthal integration", input, 10.0); low_q = input; return *this; } DiffractionExperiment& DiffractionExperiment::HighQForAzimInt_recipA(float input) { check_min("High Q for azimuthal integration", input, 0.001); check_max("High Q for azimuthal integration", input, 10.0); high_q = input; return *this; } DiffractionExperiment& DiffractionExperiment::QSpacingForAzimInt_recipA(float input) { check_min("Q spacing for azimuthal integration", input, 0.01); q_spacing = input; return *this; } DiffractionExperiment &DiffractionExperiment::SetUnitCell(const std::optional &cell) { dataset.unit_cell = cell; return *this; } DiffractionExperiment &DiffractionExperiment::PreviewPeriod(std::chrono::microseconds input) { check_min("Preview image generation period", input.count(), 0); preview_period = input; return *this; } DiffractionExperiment &DiffractionExperiment::SpaceGroupNumber(int64_t input) { check_min("Space group number", input, 0); check_max("Space group number", input, 230); dataset.space_group_number = input; return *this; } DiffractionExperiment &DiffractionExperiment::StorageCells(int64_t input) { check_min("Storage cell number", input, 1); check_max("Storage cell number", input, 16); //if ((input != 1) && (input != 2) && (input != 4) && (input != 8) && (input != 16)) // throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, // "Storage cell count invalid, must be power of 2"); storage_cells = input; return *this; } DiffractionExperiment &DiffractionExperiment::StorageCellStart(int64_t input) { check_min("Start storage cell", input, 0); check_max("Start storage cell", input, 15); storage_cell_start = input; return *this; } DiffractionExperiment &DiffractionExperiment::SampleName(std::string input) { dataset.sample_name = input; return *this; } // getter functions int64_t DiffractionExperiment::GetNumTriggers() const { switch (GetDetectorMode()) { case DetectorMode::Conversion: case DetectorMode::Raw: return dataset.ntrigger; case DetectorMode::PedestalG0: if (GetPedestalWithExternalTrigger()) return pedestal_g0_frames; else return 1; case DetectorMode::PedestalG1: if (GetPedestalWithExternalTrigger()) return pedestal_g1_frames; else return 1; case DetectorMode::PedestalG2: if (GetPedestalWithExternalTrigger()) return pedestal_g2_frames; else return 1; default: return 1; } } DetectorMode DiffractionExperiment::GetDetectorMode() const { return mode; } std::chrono::microseconds DiffractionExperiment::GetFrameTime() const { switch (GetDetectorMode()) { case DetectorMode::PedestalG1: case DetectorMode::PedestalG2: return frame_time_pedestalG1G2; case DetectorMode::Conversion: case DetectorMode::Raw: case DetectorMode::PedestalG0: default: return frame_time; } } std::chrono::microseconds DiffractionExperiment::GetImageTime() const { switch (GetDetectorMode()) { case DetectorMode::PedestalG1: case DetectorMode::PedestalG2: return frame_time_pedestalG1G2; case DetectorMode::Conversion: case DetectorMode::Raw: return GetFrameTime() * GetSummation(); case DetectorMode::PedestalG0: default: return GetFrameTime(); } } int64_t DiffractionExperiment::GetImageNum() const { switch (GetDetectorMode()) { case DetectorMode::Conversion: case DetectorMode::Raw: return GetImageNumPerTrigger() * GetNumTriggers(); case DetectorMode::PedestalG0: case DetectorMode::PedestalG1: case DetectorMode::PedestalG2: default: return 0; } } int64_t DiffractionExperiment::GetImageNumPerTrigger() const { switch (GetDetectorMode()) { case DetectorMode::Conversion: case DetectorMode::Raw: if (GetStorageCellNumber() > 1) return GetStorageCellNumber(); return GetFrameNumPerTrigger() / GetSummation(); case DetectorMode::PedestalG0: case DetectorMode::PedestalG1: case DetectorMode::PedestalG2: default: return 0; } } int64_t DiffractionExperiment::GetFrameNum() const { return GetFrameNumPerTrigger() * GetNumTriggers(); } int64_t DiffractionExperiment::GetFrameNumPerTrigger() const { switch (GetDetectorMode()) { case DetectorMode::Conversion: case DetectorMode::Raw: if (GetStorageCellNumber() > 1) return GetStorageCellNumber(); else return dataset.images_per_trigger * GetSummation(); case DetectorMode::PedestalG0: if (GetPedestalWithExternalTrigger()) return GetStorageCellNumber(); return pedestal_g0_frames * GetStorageCellNumber(); case DetectorMode::PedestalG1: if (GetPedestalWithExternalTrigger()) return GetStorageCellNumber(); return pedestal_g1_frames * GetStorageCellNumber(); case DetectorMode::PedestalG2: if (GetPedestalWithExternalTrigger()) return GetStorageCellNumber(); return pedestal_g2_frames * GetStorageCellNumber(); default: return 0; } } std::chrono::microseconds DiffractionExperiment::GetFrameCountTime() const { return count_time; } std::chrono::microseconds DiffractionExperiment::GetImageCountTime() const { return GetFrameCountTime() * GetSummation(); } int64_t DiffractionExperiment::GetPedestalG0Frames() const { return pedestal_g0_frames; } int64_t DiffractionExperiment::GetPedestalG1Frames() const { return pedestal_g1_frames; } int64_t DiffractionExperiment::GetPedestalG2Frames() const { return pedestal_g2_frames; } float DiffractionExperiment::GetPhotonEnergy_keV() const { return dataset.photon_energy_keV; } float DiffractionExperiment::GetWavelength_A() const { return WVL_1A_IN_KEV / dataset.photon_energy_keV; } float DiffractionExperiment::GetBeamX_pxl() const { return dataset.beam_x_pxl; } float DiffractionExperiment::GetBeamY_pxl() const { return dataset.beam_y_pxl; } float DiffractionExperiment::GetDetectorDistance_mm() const { return dataset.detector_distance_mm; } Coord DiffractionExperiment::GetScatteringVector() const { return {0,0,dataset.photon_energy_keV / WVL_1A_IN_KEV}; } std::string DiffractionExperiment::GetFilePrefix() const { return dataset.file_prefix; } int64_t DiffractionExperiment::GetDataFileCount() const { if (GetStorageCellNumber() > 1) return GetStorageCellNumber(); else return dataset.data_file_count; } CompressionAlgorithm DiffractionExperiment::GetCompressionAlgorithm() const { if (GetDetectorMode() != DetectorMode::Conversion) // Compression not supported for raw data and pedestal return CompressionAlgorithm::NO_COMPRESSION; return dataset.compression; } int64_t DiffractionExperiment::GetPixelDepth() const { switch (GetFPGAOutputMode()) { case FPGAPixelOutput::Int16: case FPGAPixelOutput::Uint16: return 2; default: case FPGAPixelOutput::Auto: if (GetSummation() > 2) return 4; else return 2; case FPGAPixelOutput::Int32: case FPGAPixelOutput::Uint32: return 4; } } bool DiffractionExperiment::IsPixelSigned() const { switch (GetFPGAOutputMode()) { case FPGAPixelOutput::Int16: case FPGAPixelOutput::Int32: return true; case FPGAPixelOutput::Uint16: case FPGAPixelOutput::Uint32: return false; default: case FPGAPixelOutput::Auto: if (GetDetectorMode() == DetectorMode::Conversion) return true; else return false; } } int64_t DiffractionExperiment::GetDataStreamsNum() const { return std::min(ndatastreams, detector.GetModulesNum()); } int64_t DiffractionExperiment::GetModulesNum(uint16_t data_stream) const { if (data_stream >= GetDataStreamsNum()) throw JFJochException(JFJochExceptionCategory::ArrayOutOfBounds, "Non existing data stream"); return (detector.GetModulesNum() + (GetDataStreamsNum() - 1) - data_stream) / GetDataStreamsNum(); } int64_t DiffractionExperiment::GetModulesNum() const { return detector.GetModulesNum(); } int64_t DiffractionExperiment::GetFirstModuleOfDataStream(uint16_t data_stream) const { if (data_stream >= GetDataStreamsNum()) throw JFJochException(JFJochExceptionCategory::ArrayOutOfBounds, "Non exisiting data stream"); int64_t val = 0; for (int i = 0; i < data_stream; i++) val += GetModulesNum(i); return val; } int64_t DiffractionExperiment::GetMaxCompressedSize() const { return MaxCompressedSize(GetCompressionAlgorithm(), GetPixelsNum(), GetPixelDepth()); } int64_t DiffractionExperiment::GetPixelsNum() const { return GetXPixelsNum() * GetYPixelsNum(); } int64_t DiffractionExperiment::GetXPixelsNum() const { if (GetDetectorMode() != DetectorMode::Conversion) return RAW_MODULE_COLS; else return detector.GetGeometry().GetWidth(); } int64_t DiffractionExperiment::GetYPixelsNum() const { if (GetDetectorMode() != DetectorMode::Conversion) return RAW_MODULE_LINES * GetModulesNum(); else return detector.GetGeometry().GetHeight(); } int64_t DiffractionExperiment::GetPixel0OfModule(uint16_t module_number) const { if (module_number >= GetModulesNum()) throw JFJochException(JFJochExceptionCategory::ArrayOutOfBounds, "Module number out of bounds"); if (GetDetectorMode() != DetectorMode::Conversion) return RAW_MODULE_SIZE * module_number; else return detector.GetGeometry().GetPixel0(module_number); } int64_t DiffractionExperiment::GetOverflow() const { if (GetPixelDepth() == 2) return INT16_MAX; else return INT32_MAX; } int64_t DiffractionExperiment::GetUnderflow() const { if (GetPixelDepth() == 2) return INT16_MIN; else return INT32_MIN; } std::chrono::microseconds DiffractionExperiment::GetPreviewPeriod() const { return preview_period; } int64_t DiffractionExperiment::GetPreviewStride() const { return GetPreviewStride(GetPreviewPeriod()); } int64_t DiffractionExperiment::GetSpotFindingBin() const { if (GetImageTime().count() >= 200*1000) return 1; else return 200*1000 / GetImageTime().count(); // 1 bin = 1 second } int64_t DiffractionExperiment::GetPreviewStride(std::chrono::microseconds period) const { switch (GetDetectorMode()) { case DetectorMode::Conversion: return CalculateStride(GetImageTime(), period); default: return 0; } } bool DiffractionExperiment::IsUsingInternalPacketGen() const { return internal_fpga_packet_generator; } uint32_t DiffractionExperiment::GetSrcIPv4Address(uint32_t data_stream, uint32_t half_module) const { if (data_stream >= GetDataStreamsNum()) throw JFJochException(JFJochExceptionCategory::ArrayOutOfBounds, "Non existing data stream"); if (half_module >= 2 * GetModulesNum(data_stream)) throw JFJochException(JFJochExceptionCategory::ArrayOutOfBounds, "Non existing module"); uint32_t host = half_module + 2 * GetFirstModuleOfDataStream(data_stream); return ipv4_base_addr + (host << 24); } bool DiffractionExperiment::CheckGitSha1Consistent() const { return (git_sha1 == jfjoch_git_sha1()); } std::string DiffractionExperiment::CheckGitSha1Msg() const { if (git_sha1 == jfjoch_git_sha1()) return ""; else { return "Local component git repo is rev. " + jfjoch_git_sha1().substr(0,6) + " (" + jfjoch_git_date() +") remote component repo is rev. " + git_sha1.substr(0,6) + " (" + git_date + ")"; } } bool DiffractionExperiment::GetMaskModuleEdges() const { return mask_module_edges; } bool DiffractionExperiment::GetMaskChipEdges() const { return mask_chip_edges; } std::optional DiffractionExperiment::GetUnitCell() const { return dataset.unit_cell; } Coord DiffractionExperiment::LabCoord(float detector_x, float detector_y) const { // Assumes planar detector, 90 deg towards beam return {(detector_x - GetBeamX_pxl()) * GetPixelSize_mm() , (detector_y - GetBeamY_pxl()) * GetPixelSize_mm() , GetDetectorDistance_mm()}; } int64_t DiffractionExperiment::GetSpaceGroupNumber() const { return dataset.space_group_number; } int64_t DiffractionExperiment::GetStorageCellNumber() const { switch (GetDetectorMode()) { case DetectorMode::PedestalG1: case DetectorMode::PedestalG2: if (storage_cells > 1) return 2; else return 1; default: return storage_cells; } } int64_t DiffractionExperiment::GetStorageCellStart() const { return storage_cell_start; } float DiffractionExperiment::GetLowQForAzimInt_recipA() const { return low_q; } float DiffractionExperiment::GetHighQForAzimInt_recipA() const { return high_q; } float DiffractionExperiment::GetQSpacingForAzimInt_recipA() const { return q_spacing; } int64_t DiffractionExperiment::GetMaxSpotCount() const { return max_spot_count; } std::string DiffractionExperiment::GetSampleName() const { return dataset.sample_name; } void DiffractionExperiment::CheckDataProcessingSettings(const SpotFindingSettings &settings) { check_min("Signal to noise threshold", settings.signal_to_noise_threshold, 1); check_min("Photon count threshold", settings.photon_count_threshold, 0); check_min("Minimum pixels per spot", settings.min_pix_per_spot, 1); check_min("Maximum pixels per spot", settings.max_pix_per_spot, settings.min_pix_per_spot + 1); if (settings.high_resolution_limit > 0) { check_min("Spot finding high resolution limit", settings.high_resolution_limit, 0.5); check_max("Spot finding high resolution limit", settings.high_resolution_limit, 50.0); if (settings.low_resolution_limit > 0) { check_min("Spot finding low resolution limit", settings.low_resolution_limit, settings.high_resolution_limit); } } else if (settings.low_resolution_limit > 0) { check_min("Spot finding low resolution limit", settings.low_resolution_limit, 1.0); check_max("Spot finding low resolution limit", settings.low_resolution_limit, 50.0); } } SpotFindingSettings DiffractionExperiment::DefaultDataProcessingSettings() { SpotFindingSettings ret{}; ret.signal_to_noise_threshold = 3; ret.photon_count_threshold = 16; ret.min_pix_per_spot = 2; ret.max_pix_per_spot = 50; ret.low_resolution_limit = 20.0; ret.high_resolution_limit = 2.5; return ret; } void DiffractionExperiment::FillMessage(StartMessage &message) const { message.data_file_count = GetDataFileCount(); message.beam_center_x = GetBeamX_pxl(); message.beam_center_y = GetBeamY_pxl(); message.detector_distance = GetDetectorDistance_mm() * 1e-3f; message.incident_wavelength = GetWavelength_A(); message.incident_energy = GetPhotonEnergy_keV() * 1e3f; message.image_size_x = GetXPixelsNum(); message.image_size_y = GetYPixelsNum(); message.saturation_value = GetOverflow() - 1; message.error_value = GetUnderflow(); message.frame_time = GetImageTime().count() * 1e-6f; message.count_time = GetImageCountTime().count() * 1e-6f; message.number_of_images = GetImageNum(); message.pixel_size_x = GetPixelSize_mm() * 1e-3f; message.pixel_size_y = GetPixelSize_mm() * 1e-3f; message.sensor_material = detector.GetSensorMaterial(); message.sensor_thickness = detector.GetSensorThickness_um() * 1e-6f; message.compression_algorithm = GetCompressionAlgorithm(); message.compression_block_size = JFJochBitShuffleCompressor::DefaultBlockSize; message.pixel_bit_depth = GetPixelDepth() * 8; message.storage_cell_number = GetStorageCellNumber(); message.storage_cell_delay_ns = GetStorageCellDelay().count(); message.file_prefix = GetFilePrefix(); message.pixel_signed = IsPixelSigned(); message.sample_name = GetSampleName(); message.max_spot_count = GetMaxSpotCount(); message.pixel_mask_enabled = GetApplyPixelMaskInFPGA(); message.detector_description = GetDetectorDescription(); message.space_group_number = GetSpaceGroupNumber(); message.unit_cell = GetUnitCell(); message.total_flux = GetTotalFlux(); message.attenuator_transmission = GetAttenuatorTransmission(); message.detector_translation[0] = 0.0f; message.detector_translation[1] = 0.0f; message.detector_translation[2] = GetDetectorDistance_mm() * 1e-3f; message.source_name = GetSourceName(); message.source_name_short = GetSourceNameShort(); message.instrument_name = GetInstrumentName(); message.instrument_name_short = GetInstrumentNameShort(); message.summation = GetSummation(); message.user_data = GetHeaderAppendix(); message.roi_summation_area = GetROISummation(); if (GetOmegaStep()) message.goniometer["omega"] = GoniometerAxis{.increment = GetOmegaStep().value(), .start = GetOmegaStart(), .axis = {GetOmegaAxis().x, GetOmegaAxis().y, GetOmegaAxis().z}}; message.series_id = GetSeriesID(); message.series_unique_id = GetSeriesIDString(); } DiffractionExperiment &DiffractionExperiment::ApplyPixelMaskInFPGA(bool input) { debug_pixel_mask = !input; return *this; } bool DiffractionExperiment::GetApplyPixelMaskInFPGA() const { if (GetDetectorMode() == DetectorMode::Conversion) return !debug_pixel_mask; else return false; } float DiffractionExperiment::GetPixelSize_mm() const { return detector.GetPixelSize_mm(); } DiffractionExperiment &DiffractionExperiment::SourceName(std::string input) { source_name = input; return *this; } DiffractionExperiment &DiffractionExperiment::SourceNameShort(std::string input) { source_name_short = input; return *this; } DiffractionExperiment &DiffractionExperiment::InstrumentName(std::string input) { instrument_name = input; return *this; } DiffractionExperiment &DiffractionExperiment::InstrumentNameShort(std::string input) { instrument_name_short = input; return *this; } std::string DiffractionExperiment::GetSourceName() const { return source_name; } std::string DiffractionExperiment::GetSourceNameShort() const { return source_name_short; } std::string DiffractionExperiment::GetInstrumentName() const { return instrument_name; } std::string DiffractionExperiment::GetInstrumentNameShort() const { return instrument_name_short; } int64_t DiffractionExperiment::GetModuleFastDirectionStep(uint16_t module_number) const { if (module_number >= GetModulesNum()) throw JFJochException(JFJochExceptionCategory::ArrayOutOfBounds, "Module number out of bounds"); return detector.GetGeometry().GetFastDirectionStep(module_number); } int64_t DiffractionExperiment::GetModuleSlowDirectionStep(uint16_t module_number) const { if (module_number >= GetModulesNum()) throw JFJochException(JFJochExceptionCategory::ArrayOutOfBounds, "Module number out of bounds"); return detector.GetGeometry().GetSlowDirectionStep(module_number); } std::vector DiffractionExperiment::GetDetectorModuleHostname() const { return detector.GetDetectorModuleHostname(); } std::string DiffractionExperiment::GetDetectorDescription() const { return detector.GetDescription(); } bool DiffractionExperiment::GetPedestalWithExternalTrigger() const { return (GetStorageCellNumber() > 1); } DiffractionExperiment &DiffractionExperiment::ApplySolidAngleCorr(bool input) { dataset.rad_int_solid_angle_corr = input; return *this; } DiffractionExperiment &DiffractionExperiment::ApplyPolarizationCorr(bool input) { dataset.rad_int_polarization_corr = input; return *this; } DiffractionExperiment &DiffractionExperiment::PolarizationFactor(float input) { dataset.rad_int_polarization_factor = input; return *this; } bool DiffractionExperiment::GetApplySolidAngleCorr() const { return dataset.rad_int_solid_angle_corr; } bool DiffractionExperiment::GetApplyPolarizationCorr() const { return dataset.rad_int_polarization_corr; } float DiffractionExperiment::GetPolarizationFactor() const { return dataset.rad_int_polarization_factor; } DiffractionExperiment &DiffractionExperiment::SaveCalibration(bool input) { dataset.save_calibration = input; return *this; } bool DiffractionExperiment::GetSaveCalibration() const { return dataset.save_calibration; } DiffractionExperiment &DiffractionExperiment::StorageCellDelay(std::chrono::nanoseconds input) { check_min("Storage cell delay [ns]", input.count(), MIN_STORAGE_CELL_DELAY_IN_NS); storage_cell_delay = input; return *this; } std::chrono::nanoseconds DiffractionExperiment::GetStorageCellDelay() const { return storage_cell_delay; } DiffractionExperiment &DiffractionExperiment::Summation(int64_t input) { check_min("Summation", input, 1); check_max("Summation", input, MAX_FPGA_SUMMATION); dataset.summation = input; return *this; } int64_t DiffractionExperiment::GetSummation() const { switch (GetDetectorMode()) { case DetectorMode::PedestalG0: case DetectorMode::PedestalG1: case DetectorMode::PedestalG2: return 1; default: case DetectorMode::Conversion: case DetectorMode::Raw: // FPGA summation for raw data makes zero sense - but it is still available as a means for debug, etc. return dataset.summation; } } DiffractionExperiment &DiffractionExperiment::FPGAOutputMode(FPGAPixelOutput input) { switch (input) { case FPGAPixelOutput::Auto: case FPGAPixelOutput::Int16: case FPGAPixelOutput::Uint16: case FPGAPixelOutput::Int32: case FPGAPixelOutput::Uint32: dataset.fpga_pixel_output = input; break; default: throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Invalid value for enum parameter"); } return *this; } FPGAPixelOutput DiffractionExperiment::GetFPGAOutputMode() const { return dataset.fpga_pixel_output; } int64_t DiffractionExperiment::GetUDPInterfaceCount() const { return detector.GetUDPInterfaceCount(); } std::vector DiffractionExperiment::GetDetectorModuleConfig(const std::vector &net_config) const{ std::vector ret; for (int d = 0; d < GetDataStreamsNum(); d++) { for (int m = 0; m < GetModulesNum(d); m++) { DetectorModuleConfig mod_cfg; mod_cfg.udp_dest_port_1 = net_config[d].udp_port; mod_cfg.udp_dest_port_2 = net_config[d].udp_port; mod_cfg.ipv4_src_addr_1 = IPv4AddressToStr(GetSrcIPv4Address(d, 2 * m)); mod_cfg.ipv4_src_addr_2 = IPv4AddressToStr(GetSrcIPv4Address(d, 2 * m + 1)); mod_cfg.ipv4_dest_addr_1 = net_config[d].ipv4_addr; mod_cfg.ipv4_dest_addr_2 = net_config[d].ipv4_addr; mod_cfg.mac_addr_dest_1 = net_config[d].mac_addr; mod_cfg.mac_addr_dest_2 = net_config[d].mac_addr; mod_cfg.module_id_in_data_stream = m; ret.emplace_back(std::move(mod_cfg)); } } return ret; } float DiffractionExperiment::GetLowQForBkgEstimate_recipA() const { return 2 * static_cast(M_PI) / 5.0; } float DiffractionExperiment::GetHighQForBkgEstimate_recipA() const { return 2 * static_cast(M_PI) / 3.0; } DiffractionExperiment &DiffractionExperiment::AttenuatorTransmission(const std::optional &input) { dataset.attenuator_transmission = input; return *this; } DiffractionExperiment &DiffractionExperiment::TotalFlux(const std::optional &input) { dataset.total_flux = input; return *this; } std::optional DiffractionExperiment::GetAttenuatorTransmission() const { return dataset.attenuator_transmission; } std::optional DiffractionExperiment::GetTotalFlux() const { return dataset.total_flux; } DiffractionExperiment &DiffractionExperiment::OmegaStep(const std::optional &input) { if (input && (input == 0.0f)) dataset.omega_step.reset(); else dataset.omega_step = input; return *this; } DiffractionExperiment &DiffractionExperiment::OmegaStart(const float input) { dataset.omega_start = input; return *this; } std::optional DiffractionExperiment::GetOmegaStep() const { return dataset.omega_step; } float DiffractionExperiment::GetOmegaStart() const { return dataset.omega_start; } DiffractionExperiment &DiffractionExperiment::UsingGainHG0(bool input) { use_gain_hg0 = input; return *this; } DiffractionExperiment &DiffractionExperiment::FixedGainG1(bool input) { fix_gain_g1 = input; return *this; } bool DiffractionExperiment::IsFixedGainG1() const { return fix_gain_g1; } bool DiffractionExperiment::IsUsingGainHG0() const { return use_gain_hg0; } DiffractionExperiment &DiffractionExperiment::HeaderAppendix(const std::string &input) { dataset.header_appendix = input; return *this; } DiffractionExperiment &DiffractionExperiment::ImageAppendix(const std::string &input) { dataset.image_appendix = input; return *this; } std::string DiffractionExperiment::GetHeaderAppendix() const { return dataset.header_appendix; } std::string DiffractionExperiment::GetImageAppendix() const { return dataset.image_appendix; } DiffractionExperiment &DiffractionExperiment::OmegaAxis(const Coord &c) { if (c.Length() == 0.0) throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Cannot use empty vector for omega"); dataset.omega_rotation_axis = c.Normalize(); return *this; } DiffractionExperiment &DiffractionExperiment::OmegaAxis() { dataset.omega_rotation_axis = default_omega_axis; return *this; } Coord DiffractionExperiment::GetOmegaAxis() const { return dataset.omega_rotation_axis; } DiffractionExperiment &DiffractionExperiment::DefaultOmegaAxis(const Coord &c) { if (c.Length() == 0.0) throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Cannot use empty vector for omega axis"); default_omega_axis = c.Normalize(); return *this; } Coord DiffractionExperiment::GetDefaultOmegaAxis() const { return default_omega_axis; } uint64_t DiffractionExperiment::GetSeriesID() const { return series_id; } std::string DiffractionExperiment::GetSeriesIDString() const { return std::to_string(series_id) + ": " + dataset.file_prefix; } DiffractionExperiment &DiffractionExperiment::IncrementSeriesID() { series_id++; return *this; } Coord DiffractionExperiment::GetModuleFastDirection(uint16_t module_number) const { return detector.GetGeometry().GetFastDirection(module_number); } Coord DiffractionExperiment::GetModuleSlowDirection(uint16_t module_number) const { return detector.GetGeometry().GetSlowDirection(module_number); } DiffractionExperiment &DiffractionExperiment::ROISummation(const std::optional &input) { if (input) { check_max("Max X for ROI summation", input->x_max, GetXPixelsNum() - 1); check_max("Max Y for ROI summation", input->y_max, GetYPixelsNum() - 1); check_max("Min X for ROI summation", input->x_min, input->x_max); check_max("Min Y for ROI summation", input->y_min, input->y_max); } dataset.roi_sum = input; return *this; } std::optional DiffractionExperiment::GetROISummation() const { return dataset.roi_sum; } DiffractionExperiment &DiffractionExperiment::ConversionOnFPGA(bool input) { conversion_on_fpga = input; return *this; } bool DiffractionExperiment::IsConversionOnFPGA() const { if (GetDetectorMode() == DetectorMode::Conversion) return conversion_on_fpga; else return false; } DiffractionExperiment &DiffractionExperiment::DetectorDelay(std::chrono::nanoseconds input) { detector_delay = input; return *this; } std::chrono::nanoseconds DiffractionExperiment::GetDetectorDelay() const { return detector_delay; } const DetectorSetup &DiffractionExperiment::GetDetectorSetup() const { return detector; }