// Copyright (2019-2023) Paul Scherrer Institute #include #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) #define check_finite(param, val) if (!std::isfinite(val)) throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, param) DiffractionExperiment::DiffractionExperiment() : DiffractionExperiment(DetectorGeometry(8, 2)) {} DiffractionExperiment::DiffractionExperiment(const DetectorSetup& det_setup) : detector(det_setup) { default_omega_axis = {1, 0, 0}; rad_int_polarization_corr = false; rad_int_solid_angle_corr = true; internal_fpga_packet_generator = false; internal_fpga_packet_generator_images = 1; 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; pulsed_source = false; 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) { dataset.ImagesPerTrigger(input); return *this; } DiffractionExperiment &DiffractionExperiment::NumTriggers(int64_t input) { dataset.NumTriggers(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) { dataset.PhotonEnergy_keV(input); return *this; } DiffractionExperiment &DiffractionExperiment::BeamX_pxl(float input) { dataset.BeamX_pxl(input); return *this; } DiffractionExperiment &DiffractionExperiment::BeamY_pxl(float input) { dataset.BeamY_pxl(input); return *this; } DiffractionExperiment &DiffractionExperiment::DetectorDistance_mm(float input) { dataset.DetectorDistance_mm(input); return *this; } DiffractionExperiment &DiffractionExperiment::FilePrefix(std::string input) { dataset.FilePrefix(std::move(input)); return *this; } DiffractionExperiment &DiffractionExperiment::DataFileCount(int64_t input) { dataset.DataFileCount(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) { dataset.Compression(input); return *this; } DiffractionExperiment &DiffractionExperiment::MaskChipEdges(bool input) { mask_chip_edges = input; return *this; } DiffractionExperiment& DiffractionExperiment::LowResForAzimInt_A(float input) { check_finite("Low Resolution for azimuthal integration", 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_finite("High Resolution for azimuthal integration", 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_finite("Low Q for azimuthal integration", 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_finite("High Q for azimuthal integration", 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_finite("Q spacing for azimuthal integration", input); check_min("Q spacing for azimuthal integration", input, 0.01); q_spacing = input; return *this; } DiffractionExperiment &DiffractionExperiment::SetUnitCell(const std::optional &cell) { dataset.SetUnitCell(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) { dataset.SpaceGroupNumber(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.SampleName(input); return *this; } // getter functions int64_t DiffractionExperiment::GetNumTriggers() const { switch (GetDetectorMode()) { case DetectorMode::Conversion: case DetectorMode::Raw: return dataset.GetNumTriggers(); case DetectorMode::PedestalG0: if (IsPulsedSource()) return pedestal_g0_frames; else return 1; case DetectorMode::PedestalG1: if (IsPulsedSource()) return pedestal_g1_frames; else return 1; case DetectorMode::PedestalG2: if (IsPulsedSource()) 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: 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 { if (IsPulsedSource()) return GetStorageCellNumber() * GetSummation(); switch (GetDetectorMode()) { case DetectorMode::Conversion: case DetectorMode::Raw: return dataset.GetImageNumPerTrigger() * GetSummation(); case DetectorMode::PedestalG0: return pedestal_g0_frames * GetStorageCellNumber(); case DetectorMode::PedestalG1: return pedestal_g1_frames * GetStorageCellNumber(); case DetectorMode::PedestalG2: 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 { if (detector.GetDetectorType() == DetectorType::EIGER) return 0; return pedestal_g0_frames; } int64_t DiffractionExperiment::GetPedestalG1Frames() const { if (detector.GetDetectorType() == DetectorType::EIGER) return 0; return pedestal_g1_frames; } int64_t DiffractionExperiment::GetPedestalG2Frames() const { if (detector.GetDetectorType() == DetectorType::EIGER) return 0; return pedestal_g2_frames; } float DiffractionExperiment::GetPhotonEnergy_keV() const { return dataset.GetPhotonEnergy_keV(); } float DiffractionExperiment::GetWavelength_A() const { return WVL_1A_IN_KEV / dataset.GetPhotonEnergy_keV(); } float DiffractionExperiment::GetBeamX_pxl() const { return dataset.GetBeamX_pxl(); } float DiffractionExperiment::GetBeamY_pxl() const { return dataset.GetBeamY_pxl(); } float DiffractionExperiment::GetDetectorDistance_mm() const { return dataset.GetDetectorDistance_mm(); } Coord DiffractionExperiment::GetScatteringVector() const { return dataset.GetScatteringVector(); } std::string DiffractionExperiment::GetFilePrefix() const { return dataset.GetFilePrefix(); } int64_t DiffractionExperiment::GetDataFileCount() const { if (GetStorageCellNumber() > 1) return GetStorageCellNumber(); else return dataset.GetDataFileCount(); } CompressionAlgorithm DiffractionExperiment::GetCompressionAlgorithm() const { if (GetDetectorMode() != DetectorMode::Conversion) // Compression not supported for raw data and pedestal return CompressionAlgorithm::NO_COMPRESSION; return dataset.GetCompressionAlgorithm(); } 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) && (detector.GetDetectorType() == DetectorType::JUNGFRAU)) 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 IsPixelSigned() ? INT16_MAX : UINT16_MAX; else return IsPixelSigned() ? INT32_MAX : UINT32_MAX; } int64_t DiffractionExperiment::GetUnderflow() const { if (!IsPixelSigned()) return -1; if (GetPixelDepth() == 2) return INT16_MIN; else return INT32_MIN; } std::chrono::microseconds DiffractionExperiment::GetPreviewPeriod() const { if (GetDetectorMode() == DetectorMode::Conversion) return preview_period; else return std::chrono::microseconds(0); } int64_t DiffractionExperiment::GetSpotFindingBin() const { if (GetImageTime().count() >= 200*1000) return 1; else return 200*1000 / GetImageTime().count(); // 1 bin = 1 second } 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 >= detector.GetUDPInterfaceCount() * GetModulesNum(data_stream)) throw JFJochException(JFJochExceptionCategory::ArrayOutOfBounds, "Non existing module"); uint32_t host = half_module + detector.GetUDPInterfaceCount() * 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.GetUnitCell(); } 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.GetSpaceGroupNumber(); } 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.GetSampleName(); } 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.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(); message.countrate_correction_enabled = false; message.flatfield_enabled = false; if (GetOmegaStep()) message.omega = GoniometerAxis{.increment = GetOmegaStep().value(), .start = GetOmegaStart(), .axis = {GetOmegaAxis().x, GetOmegaAxis().y, GetOmegaAxis().z}}; else message.omega = GoniometerAxis{.increment = 0.0f}; message.series_id = GetSeriesID(); message.series_unique_id = GetSeriesIDString(); message.gain_file_names = detector.GetGainFileNames(); } 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(); } DiffractionExperiment &DiffractionExperiment::ApplySolidAngleCorr(bool input) { rad_int_solid_angle_corr = input; return *this; } DiffractionExperiment &DiffractionExperiment::ApplyPolarizationCorr(bool input) { rad_int_polarization_corr = input; return *this; } DiffractionExperiment &DiffractionExperiment::PolarizationFactor(float input) { check_finite("Polarization factor", input); check_min("Polarization factor", input, -1.0); check_max("Polarization factor", input, 1.0); rad_int_polarization_factor = input; return *this; } bool DiffractionExperiment::GetApplySolidAngleCorr() const { return rad_int_solid_angle_corr; } bool DiffractionExperiment::GetApplyPolarizationCorr() const { return rad_int_polarization_corr; } float DiffractionExperiment::GetPolarizationFactor() const { return rad_int_polarization_factor; } DiffractionExperiment &DiffractionExperiment::SaveCalibration(bool input) { dataset.SaveCalibration(input); return *this; } bool DiffractionExperiment::GetSaveCalibration() const { return dataset.GetSaveCalibration(); } 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) { 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.GetSummation(); } } DiffractionExperiment &DiffractionExperiment::FPGAOutputMode(FPGAPixelOutput input) { dataset.FPGAOutputMode(input); return *this; } FPGAPixelOutput DiffractionExperiment::GetFPGAOutputMode() const { return dataset.GetFPGAOutputMode(); } 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; if (detector.GetUDPInterfaceCount() == 2) { mod_cfg.ipv4_src_addr_1 = IPv4AddressToStr(GetSrcIPv4Address(d, 2 * m)); mod_cfg.ipv4_src_addr_2 = IPv4AddressToStr(GetSrcIPv4Address(d, 2 * m + 1)); } else { mod_cfg.ipv4_src_addr_1 = IPv4AddressToStr(GetSrcIPv4Address(d, m)); mod_cfg.ipv4_src_addr_2 = IPv4AddressToStr(GetSrcIPv4Address(d, m)); // not used, settings just in case } 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.AttenuatorTransmission(input); return *this; } DiffractionExperiment &DiffractionExperiment::TotalFlux(const std::optional &input) { dataset.TotalFlux(input); return *this; } std::optional DiffractionExperiment::GetAttenuatorTransmission() const { return dataset.GetAttenuatorTransmission(); } std::optional DiffractionExperiment::GetTotalFlux() const { return dataset.GetTotalFlux(); } DiffractionExperiment &DiffractionExperiment::OmegaStep(const std::optional &input) { dataset.OmegaStep(input); return *this; } DiffractionExperiment &DiffractionExperiment::OmegaStart(float input) { dataset.OmegaStart(input); return *this; } std::optional DiffractionExperiment::GetOmegaStep() const { return dataset.GetOmegaStep(); } float DiffractionExperiment::GetOmegaStart() const { return dataset.GetOmegaStart(); } 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.HeaderAppendix(input); return *this; } DiffractionExperiment &DiffractionExperiment::ImageAppendix(const std::string &input) { dataset.ImageAppendix(input); return *this; } std::string DiffractionExperiment::GetHeaderAppendix() const { return dataset.GetHeaderAppendix(); } std::string DiffractionExperiment::GetImageAppendix() const { return dataset.GetImageAppendix(); } DiffractionExperiment &DiffractionExperiment::OmegaAxis(const Coord &c) { dataset.OmegaAxis(c); return *this; } DiffractionExperiment &DiffractionExperiment::OmegaAxis() { dataset.OmegaAxis({}); return *this; } Coord DiffractionExperiment::GetOmegaAxis() const { auto tmp = dataset.GetOmegaAxis(); if (tmp) return tmp.value(); else return default_omega_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.GetFilePrefix(); } 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) { dataset.ROISummation(input); return *this; } std::optional DiffractionExperiment::GetROISummation() const { return dataset.GetROISummation(); } DiffractionExperiment &DiffractionExperiment::ConversionOnFPGA(bool input) { conversion_on_fpga = input; return *this; } bool DiffractionExperiment::IsConversionOnFPGA() const { if ((GetDetectorMode() == DetectorMode::Conversion) && (detector.GetDetectorType() == DetectorType::JUNGFRAU)) 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; } DiffractionExperiment &DiffractionExperiment::NeuralNetModelPath(const std::string &input) { neural_net_model_path = input; return *this; } std::string DiffractionExperiment::GetNeuralNetModelPath() const { return neural_net_model_path; } DiffractionExperiment &DiffractionExperiment::PulsedSource(bool input) { pulsed_source = input; return *this; } bool DiffractionExperiment::IsPulsedSource() const { if (GetStorageCellNumber() > 1) return true; else return pulsed_source; } bool DiffractionExperiment::IsSpotFindingEnabled() const { if (GetDetectorMode() == DetectorMode::Conversion) return true; else return false; } DiffractionExperiment &DiffractionExperiment::PhotonEnergyMultiplayer(float input) { dataset.PhotonEnergyMultiplayer(input); return *this; } float DiffractionExperiment::GetPhotonEnergyForConversion_keV() const { return GetPhotonEnergyMultiplier() * GetPhotonEnergy_keV(); } float DiffractionExperiment::GetPhotonEnergyMultiplier() const { if ((GetDetectorSetup().GetDetectorType() == DetectorType::JUNGFRAU) && (GetDetectorMode() == DetectorMode::Conversion)) return dataset.GetPhotonEnergyMultiplier(); else return 1.0f; } DiffractionExperiment &DiffractionExperiment::InternalPacketGeneratorImages(int64_t input) { check_min("Internal packet generator images", input, 1); check_max("Internal packet generator images", input, 128); internal_fpga_packet_generator_images = input; return *this; } int64_t DiffractionExperiment::GetInternalPacketGeneratorImages() const { return internal_fpga_packet_generator_images; } DiffractionExperiment &DiffractionExperiment::ImportDatasetSettings(const DatasetSettings &input) { dataset = input; return *this; } DatasetSettings DiffractionExperiment::GetDatasetSettings() const { return dataset; }