// Copyright (2019-2022) Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-or-later #include #include "NetworkAddressConvert.h" #include "JFJochCompressor.h" // For ZSTD_USE_JFJOCH_RLE #include "GitInfo.h" #include "DiffractionExperiment.h" #include "JFJochException.h" #include "../compression/MaxCompressedSize.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(const JFJochProtoBuf::JungfraujochSettings &settings) : DiffractionExperiment() { Import(settings); } DiffractionExperiment& DiffractionExperiment::Import(const JFJochProtoBuf::JungfraujochSettings &settings) { internal = settings.internal(); dataset = settings.dataset(); return *this; } DiffractionExperiment::operator JFJochProtoBuf::JungfraujochSettings() const { JFJochProtoBuf::JungfraujochSettings settings; *settings.mutable_dataset() = dataset; *settings.mutable_internal() = internal; return settings; } DiffractionExperiment::DiffractionExperiment() : DiffractionExperiment(DetectorGeometry(8, 2)) {} DiffractionExperiment::DiffractionExperiment(const DetectorSetup& det_setup) { dataset.set_photon_energy_kev(WVL_1A_IN_KEV); dataset.set_detector_distance_mm(100); dataset.mutable_scattering_vector()->set_x(0); dataset.mutable_scattering_vector()->set_y(0); dataset.mutable_scattering_vector()->set_z(1); dataset.set_data_file_count(1); dataset.set_file_prefix("test"); dataset.set_ntrigger(1); dataset.set_images_per_trigger(1); dataset.set_summation(1); dataset.set_space_group_number(0); // not set dataset.set_compression(JFJochProtoBuf::BSHUF_LZ4); dataset.set_rad_int_polarization_corr(false); dataset.set_rad_int_solid_angle_corr(false); dataset.set_save_calibration(false); internal.set_debug_pixel_mask(false); internal.set_ndatastreams(1); internal.set_frame_time_us(MIN_FRAME_TIME_HALF_SPEED_IN_US); internal.set_count_time_us(MIN_FRAME_TIME_HALF_SPEED_IN_US - READOUT_TIME_IN_US); internal.set_frame_time_pedestalg1g2_us(FRAME_TIME_PEDE_G1G2_IN_US); internal.set_mask_chip_edges(false); internal.set_mask_module_edges(false); internal.set_preview_period_us(1000*1000); // 1s / 1 Hz internal.set_spot_finding_period_us(5*1000); // 5 ms / 200 Hz internal.set_low_q(0.1); internal.set_high_q(5.0); internal.set_q_spacing(0.05); internal.set_ipv4_base_addr(0x0132010a); internal.set_git_sha1(jfjoch_git_sha1()); internal.set_git_date(jfjoch_git_date()); internal.set_storage_cells(1); internal.set_storage_cell_start(15); Detector(det_setup); Mode(DetectorMode::Conversion); } // setter functions DiffractionExperiment &DiffractionExperiment::Detector(const DetectorSetup &input) { *internal.mutable_detector() = input; return *this; } DiffractionExperiment &DiffractionExperiment::Mode(DetectorMode input) { switch (input) { case DetectorMode::Conversion: internal.set_mode(JFJochProtoBuf::CONVERSION); break; case DetectorMode::Raw: internal.set_mode(JFJochProtoBuf::RAW); break; case DetectorMode::PedestalG0: internal.set_mode(JFJochProtoBuf::PEDESTAL_G0); break; case DetectorMode::PedestalG1: internal.set_mode(JFJochProtoBuf::PEDESTAL_G1); break; case DetectorMode::PedestalG2: internal.set_mode(JFJochProtoBuf::PEDESTAL_G2); break; } return *this; } DiffractionExperiment &DiffractionExperiment::DataStreams(int64_t input) { check_max("Number of data streams", input, 7); check_min("Number of data streams", input, 1); internal.set_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.set_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.set_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); } internal.set_frame_time_us(in_frame_time.count()); if (in_count_time.count() == 0) internal.set_count_time_us(in_frame_time.count() - READOUT_TIME_IN_US); else internal.set_count_time_us(in_count_time.count()); return *this; } DiffractionExperiment &DiffractionExperiment::Summation(int64_t input) { check_min("Summation", input, 1); check_max("Summation", input, MAX_SUMMATION); dataset.set_summation(input); return *this; } DiffractionExperiment & DiffractionExperiment::ImageTimeUs(std::chrono::microseconds image_time) { check_min("Image time (us)", image_time.count(), MIN_FRAME_TIME_FULL_SPEED_IN_US); // Exclude negative numbers and zero if ( image_time.count() % GetFrameTime().count() != 0) throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Image time must be multiple of frame time"); Summation(image_time.count() / GetFrameTime().count()); 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); internal.set_frame_time_pedestalg1g2_us(input.count()); return *this; } DiffractionExperiment &DiffractionExperiment::PedestalG0Frames(int64_t input) { check_min("Pedestal G0 frames", input, 0); // Max? internal.set_pedestal_g0_frames(input); return *this; } DiffractionExperiment &DiffractionExperiment::PedestalG1Frames(int64_t input) { check_min("Pedestal G1 frames", input, 0); internal.set_pedestal_g1_frames(input); return *this; } DiffractionExperiment &DiffractionExperiment::PedestalG2Frames(int64_t input) { check_min("Pedestal G2 frames", input, 0); internal.set_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.set_photon_energy_kev(input); return *this; } DiffractionExperiment &DiffractionExperiment::BeamX_pxl(float input) { dataset.set_beam_x_pxl(input); return *this; } DiffractionExperiment &DiffractionExperiment::BeamY_pxl(float input) { dataset.set_beam_y_pxl(input); return *this; } DiffractionExperiment &DiffractionExperiment::DetectorDistance_mm(float input) { check_min("Detector distance (mm)", input, 1); dataset.set_detector_distance_mm(input); return *this; } DiffractionExperiment &DiffractionExperiment::ScatteringVector(Coord input) { auto c = input.Normalize(); dataset.mutable_scattering_vector()->set_x(c.x); dataset.mutable_scattering_vector()->set_y(c.y); dataset.mutable_scattering_vector()->set_z(c.z); return *this; } DiffractionExperiment &DiffractionExperiment::ScatteringVector() { dataset.clear_scattering_vector(); 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.set_file_prefix(input.substr(0, input.length() - 10)); else dataset.set_file_prefix(input); return *this; } DiffractionExperiment &DiffractionExperiment::DataFileCount(int64_t input) { check_min("File count", input, 1); check_max("File count", input, 1000); dataset.set_data_file_count(input); return *this; } DiffractionExperiment &DiffractionExperiment::UseInternalPacketGenerator(bool input) { internal.set_internal_fpga_packet_generator(input); return *this; } DiffractionExperiment &DiffractionExperiment::IPv4BaseAddr(std::string input) { internal.set_ipv4_base_addr(IPv4AddressFromStr(input)); return *this; } DiffractionExperiment &DiffractionExperiment::MaskModuleEdges(bool input) { internal.set_mask_module_edges(input); return *this; } DiffractionExperiment &DiffractionExperiment::Compression(JFJochProtoBuf::Compression input) { dataset.set_compression(input); return *this; } DiffractionExperiment &DiffractionExperiment::MaskChipEdges(bool input) { internal.set_mask_chip_edges(input); return *this; } DiffractionExperiment& DiffractionExperiment::LowResForRadialInt_A(float input) { check_min("Low Resolution for radial integration", input, 0.1); check_max("Low Resolution for radial integration", input, 500.0); internal.set_low_q(2 * static_cast(M_PI) / input); return *this; } DiffractionExperiment& DiffractionExperiment::HighResForRadialInt_A(float input) { check_min("High Resolution for radial integration", input, 0.1); check_max("High Resolution for radial integration", input, 500.0); internal.set_high_q(2 * static_cast(M_PI) / input); return *this; } DiffractionExperiment& DiffractionExperiment::LowQForRadialInt_recipA(float input) { check_min("Low Q for radial integration", input, 0.001); check_max("Low Q for radial integration", input, 10.0); internal.set_low_q(input); return *this; } DiffractionExperiment& DiffractionExperiment::HighQForRadialInt_recipA(float input) { check_min("High Q for radial integration", input, 0.001); check_max("High Q for radial integration", input, 10.0); internal.set_high_q(input); return *this; } DiffractionExperiment& DiffractionExperiment::QSpacingForRadialInt_recipA(float input) { check_min("Q spacing for radial integration", input, 0.01); internal.set_q_spacing(input); return *this; } DiffractionExperiment &DiffractionExperiment::SetUnitCell(const JFJochProtoBuf::UnitCell &cell) { *dataset.mutable_unit_cell() = cell; return *this; } DiffractionExperiment &DiffractionExperiment::SetUnitCell(const UnitCell &cell) { JFJochProtoBuf::UnitCell tmp; tmp.set_a(cell.a); tmp.set_b(cell.b); tmp.set_c(cell.c); tmp.set_alpha(cell.alpha); tmp.set_beta(cell.beta); tmp.set_gamma(cell.gamma); return SetUnitCell(tmp); } DiffractionExperiment &DiffractionExperiment::SetUnitCell() { dataset.clear_unit_cell(); return *this; } DiffractionExperiment &DiffractionExperiment::PreviewPeriod(std::chrono::microseconds input) { check_min("Preview image generation period", input.count(), 0); internal.set_preview_period_us(input.count()); return *this; } DiffractionExperiment &DiffractionExperiment::SpotFindingPeriod(std::chrono::microseconds input) { check_min("Spot finding analysis period", input.count(), 0); internal.set_spot_finding_period_us(input.count()); return *this; } DiffractionExperiment &DiffractionExperiment::SpaceGroupNumber(int64_t input) { check_min("Space group number", input, 0); check_max("Space group number", input, 230); dataset.set_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"); internal.set_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); internal.set_storage_cell_start(input); return *this; } DiffractionExperiment &DiffractionExperiment::SampleName(std::string input) { dataset.set_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 internal.pedestal_g0_frames(); else return 1; case DetectorMode::PedestalG1: if (GetPedestalWithExternalTrigger()) return internal.pedestal_g1_frames(); else return 1; case DetectorMode::PedestalG2: if (GetPedestalWithExternalTrigger()) return internal.pedestal_g2_frames(); else return 1; default: return 1; } } DetectorMode DiffractionExperiment::GetDetectorMode() const { switch (internal.mode()) { case JFJochProtoBuf::RAW: return DetectorMode::Raw; case JFJochProtoBuf::PEDESTAL_G0: return DetectorMode::PedestalG0; case JFJochProtoBuf::PEDESTAL_G1: return DetectorMode::PedestalG1; case JFJochProtoBuf::PEDESTAL_G2: return DetectorMode::PedestalG2; default: case JFJochProtoBuf::CONVERSION: return DetectorMode::Conversion; } } int64_t DiffractionExperiment::GetSummation() const { if (GetDetectorMode() == DetectorMode::Conversion) { if (dataset.has_image_time_us()) throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Internally DiffractionExperiment shouldn't use image_time_us"); return dataset.summation(); } else return 1; } std::chrono::microseconds DiffractionExperiment::GetFrameTime() const { switch (GetDetectorMode()) { case DetectorMode::PedestalG1: case DetectorMode::PedestalG2: return std::chrono::microseconds(internal.frame_time_pedestalg1g2_us()); case DetectorMode::Conversion: case DetectorMode::Raw: case DetectorMode::PedestalG0: default: return std::chrono::microseconds(internal.frame_time_us()); } } std::chrono::microseconds DiffractionExperiment::GetImageTime() const { switch (GetDetectorMode()) { case DetectorMode::PedestalG1: case DetectorMode::PedestalG2: return std::chrono::microseconds(internal.frame_time_pedestalg1g2_us()); case DetectorMode::Conversion: return GetFrameTime() * GetSummation(); case DetectorMode::Raw: 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 internal.pedestal_g0_frames() * GetStorageCellNumber(); case DetectorMode::PedestalG1: if (GetPedestalWithExternalTrigger()) return GetStorageCellNumber(); return internal.pedestal_g1_frames() * GetStorageCellNumber(); case DetectorMode::PedestalG2: if (GetPedestalWithExternalTrigger()) return GetStorageCellNumber(); return internal.pedestal_g2_frames() * GetStorageCellNumber(); default: return 0; } } std::chrono::microseconds DiffractionExperiment::GetFrameCountTime() const { return std::chrono::microseconds(internal.count_time_us()); } std::chrono::microseconds DiffractionExperiment::GetImageCountTime() const { return GetFrameCountTime() * GetSummation(); } int64_t DiffractionExperiment::GetPedestalG0Frames() const { return internal.pedestal_g0_frames(); } int64_t DiffractionExperiment::GetPedestalG1Frames() const { return internal.pedestal_g1_frames(); } int64_t DiffractionExperiment::GetPedestalG2Frames() const { return internal.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 { if (GetBinning2x2()) return dataset.beam_x_pxl() / 2.0f; else return dataset.beam_x_pxl(); } float DiffractionExperiment::GetBeamY_pxl() const { if (GetBinning2x2()) return dataset.beam_y_pxl() / 2.0f; else return dataset.beam_y_pxl(); } float DiffractionExperiment::GetDetectorDistance_mm() const { return dataset.detector_distance_mm(); } Coord DiffractionExperiment::GetScatteringVector() const { if (dataset.has_scattering_vector()) return Coord(dataset.scattering_vector().x(), dataset.scattering_vector().y(), dataset.scattering_vector().z()) * (dataset.photon_energy_kev() / WVL_1A_IN_KEV); else 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 { return dataset.data_file_count(); } JFJochProtoBuf::Compression DiffractionExperiment::GetCompressionAlgorithm() const { switch (GetDetectorMode()) { case DetectorMode::Conversion: return dataset.compression(); default: // Compression not supported for raw data and pedestal return JFJochProtoBuf::NO_COMPRESSION; } } CompressionAlgorithm DiffractionExperiment::GetCompressionAlgorithmEnum() const { switch (GetCompressionAlgorithm()) { case JFJochProtoBuf::BSHUF_LZ4: return CompressionAlgorithm::BSHUF_LZ4; case JFJochProtoBuf::BSHUF_ZSTD: return CompressionAlgorithm::BSHUF_ZSTD; case JFJochProtoBuf::BSHUF_ZSTD_RLE: return CompressionAlgorithm::BSHUF_ZSTD_RLE; default: return CompressionAlgorithm::NO_COMPRESSION; } } int64_t DiffractionExperiment::GetPixelDepth() const { if (GetSummation() == 1) return 2; else return 4; } bool DiffractionExperiment::IsPixelSigned() const { return (GetDetectorMode() == DetectorMode::Conversion) && (GetDetectorType() == JFJochProtoBuf::JUNGFRAU); } int64_t DiffractionExperiment::GetDataStreamsNum() const { return std::min(internal.ndatastreams(), internal.detector().nmodules()); } int64_t DiffractionExperiment::GetModulesNum(uint16_t data_stream) const { if (data_stream == TASK_NO_DATA_STREAM) return internal.detector().nmodules(); if (data_stream >= GetDataStreamsNum()) throw JFJochException(JFJochExceptionCategory::ArrayOutOfBounds, "Non existing data stream"); return (internal.detector().nmodules() + (GetDataStreamsNum() - 1) - data_stream) / GetDataStreamsNum(); } 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(GetCompressionAlgorithmEnum(),GetPixelsNum(), GetPixelDepth()); } int64_t DiffractionExperiment::GetPixelsNum() const { return GetXPixelsNum() * GetYPixelsNum(); } int64_t DiffractionExperiment::GetPixelsNumFullImage() const { return GetXPixelsNumFullImage() * GetYPixelsNumFullImage(); } int64_t DiffractionExperiment::GetXPixelsNumFullImage() const { if (GetDetectorMode() != DetectorMode::Conversion) return RAW_MODULE_COLS; else return internal.detector().geometry().width_pxl(); } int64_t DiffractionExperiment::GetXPixelsNum() const { if (GetBinning2x2()) return GetXPixelsNumFullImage() / 2; else return GetXPixelsNumFullImage(); } int64_t DiffractionExperiment::GetYPixelsNum() const { if (GetBinning2x2()) return GetYPixelsNumFullImage() / 2; else return GetYPixelsNumFullImage(); } int64_t DiffractionExperiment::GetYPixelsNumFullImage() const { if (GetDetectorMode() != DetectorMode::Conversion) return RAW_MODULE_LINES * GetModulesNum(); else return internal.detector().geometry().height_pxl(); } 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 internal.detector().geometry().module_geometry(module_number).pixel0(); } 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 std::chrono::microseconds(internal.preview_period_us()); } std::chrono::microseconds DiffractionExperiment::GetSpotFindingPeriod() const { return std::chrono::microseconds(internal.spot_finding_period_us()); } int64_t DiffractionExperiment::GetPreviewStride() const { return GetPreviewStride(GetPreviewPeriod()); } int64_t DiffractionExperiment::GetSpotFindingStride() const { switch (GetDetectorMode()) { case DetectorMode::Conversion: return CalculateStride(GetImageTime(), GetSpotFindingPeriod()); default: return 0; } } 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.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 internal.ipv4_base_addr() + (host << 24); } bool DiffractionExperiment::CheckGitSha1Consistent() const { return (internal.git_sha1() == jfjoch_git_sha1()); } std::string DiffractionExperiment::CheckGitSha1Msg() const { if (internal.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. " + internal.git_sha1().substr(0,6) + " (" + internal.git_date() + ")"; } } bool DiffractionExperiment::GetMaskModuleEdges() const { return internal.mask_module_edges(); } bool DiffractionExperiment::GetMaskChipEdges() const { return internal.mask_chip_edges(); } UnitCell DiffractionExperiment::GetUnitCell() const { return { .a = dataset.unit_cell().a(), .b = dataset.unit_cell().b(), .c = dataset.unit_cell().c(), .alpha = dataset.unit_cell().alpha(), .beta = dataset.unit_cell().beta(), .gamma = dataset.unit_cell().gamma() }; } bool DiffractionExperiment::HasUnitCell() const { return dataset.has_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 (internal.storage_cells() > 1) return 2; else return 1; default: return internal.storage_cells(); } } int64_t DiffractionExperiment::GetStorageCellStart() const { return internal.storage_cell_start(); } float DiffractionExperiment::GetLowQForRadialInt_recipA() const { return internal.low_q(); } float DiffractionExperiment::GetHighQForRadialInt_recipA() const { return internal.high_q(); } float DiffractionExperiment::GetQSpacingForRadialInt_recipA() const { return internal.q_spacing(); } JFJochProtoBuf::DetectorType DiffractionExperiment::GetDetectorType() const { return internal.detector().type(); } int64_t DiffractionExperiment::GetMaxSpotCount() const { return max_spot_count; } std::string DiffractionExperiment::GetSampleName() const { return dataset.sample_name(); } // Create ProtoBuf structures DiffractionExperiment::operator JFJochProtoBuf::DetectorInput() const { JFJochProtoBuf::DetectorInput ret; ret.set_modules_num(GetModulesNum()); ret.set_mode(internal.mode()); if (GetNumTriggers() == 1) { ret.set_num_frames(GetFrameNumPerTrigger() + DELAY_FRAMES_STOP_AND_QUIT); ret.set_num_triggers(1); } else { // More than 1 trigger - detector needs one trigger or few more trigger if (GetStorageCellNumber() > 1) ret.set_num_frames(1); else ret.set_num_frames(GetFrameNumPerTrigger()); if (GetFrameNumPerTrigger() < DELAY_FRAMES_STOP_AND_QUIT) ret.set_num_triggers(GetNumTriggers() + DELAY_FRAMES_STOP_AND_QUIT); else ret.set_num_triggers(GetNumTriggers() + 1); } ret.set_storage_cell_start(GetStorageCellStart()); ret.set_storage_cell_number(GetStorageCellNumber()); ret.set_storage_cell_delay(7.5); if (GetStorageCellNumber() > 1) { ret.set_period_us((GetFrameTime().count() +10) * GetStorageCellNumber()); } else ret.set_period_us(GetFrameTime().count()); ret.set_count_time_us(GetFrameCountTime().count()); return ret; } JFJochProtoBuf::DetectorConfig DiffractionExperiment::DetectorConfig(const JFJochProtoBuf::ReceiverNetworkConfig &net_config) const { JFJochProtoBuf::DetectorConfig ret; if (net_config.device_size() < GetDataStreamsNum()) throw JFJochException(JFJochExceptionCategory::ArrayOutOfBounds, "Number of FPGA boards in the receiver is less then necessary"); if (!internal.detector().module_hostname().empty() && (internal.detector().module_hostname_size() != GetModulesNum())) throw JFJochException(JFJochExceptionCategory::ArrayOutOfBounds, "Inconsistent number of modules and detector module host names"); if (!internal.detector().module_hostname().empty()) *ret.mutable_module_hostname() = internal.detector().module_hostname(); for (int d = 0; d < GetDataStreamsNum(); d++) { for (int m = 0; m < GetModulesNum(d); m++) { auto mod_cfg = ret.add_modules(); mod_cfg->set_udp_dest_port_1(net_config.device(d).udp_port()); mod_cfg->set_udp_dest_port_2(net_config.device(d).udp_port()); mod_cfg->set_ipv4_src_addr_1(IPv4AddressToStr(GetSrcIPv4Address(d, 2 * m))); mod_cfg->set_ipv4_src_addr_2(IPv4AddressToStr(GetSrcIPv4Address(d, 2 * m + 1))); mod_cfg->set_ipv4_dest_addr_1(net_config.device(d).ipv4_addr()); mod_cfg->set_ipv4_dest_addr_2(net_config.device(d).ipv4_addr()); mod_cfg->set_mac_addr_dest_1(net_config.device(d).mac_addr()); mod_cfg->set_mac_addr_dest_2(net_config.device(d).mac_addr()); mod_cfg->set_module_id_in_data_stream(m); } } return ret; } void DiffractionExperiment::LoadDatasetSettings(const JFJochProtoBuf::DatasetSettings &settings) { // Save DatasetSettings - if something goes wrong, restore old settings auto tmp = dataset; try { dataset = JFJochProtoBuf::DatasetSettings(); ImagesPerTrigger(settings.images_per_trigger()); NumTriggers(settings.ntrigger()); if (settings.has_image_time_us()) ImageTimeUs(std::chrono::microseconds(settings.image_time_us())); else Summation(settings.summation()); BeamX_pxl(settings.beam_x_pxl()); BeamY_pxl(settings.beam_y_pxl()); DetectorDistance_mm(settings.detector_distance_mm()); PhotonEnergy_keV(settings.photon_energy_kev()); FilePrefix(settings.file_prefix()); DataFileCount(settings.data_file_count()); if (settings.has_unit_cell()) SetUnitCell(settings.unit_cell()); else SetUnitCell(); SpaceGroupNumber(settings.space_group_number()); SampleName(settings.sample_name()); if (settings.has_scattering_vector()) ScatteringVector({0,0,1}); Compression(settings.compression()); Binning2x2(settings.binning2x2()); } catch (...) { dataset = tmp; throw; } } void DiffractionExperiment::LoadDetectorSettings(const JFJochProtoBuf::DetectorSettings &settings) { auto tmp = internal; try { if (settings.has_count_time_us()) FrameTime(std::chrono::microseconds(settings.frame_time_us()), std::chrono::microseconds(settings.count_time_us())); else FrameTime(std::chrono::microseconds(settings.frame_time_us())); StorageCells(settings.storage_cell_count()); UseInternalPacketGenerator(settings.use_internal_packet_generator()); if (settings.collect_raw_data()) Mode(DetectorMode::Raw); else Mode(DetectorMode::Conversion); if (settings.has_pedestal_g0_frames()) PedestalG0Frames(settings.pedestal_g0_frames()); if (settings.has_pedestal_g1_frames()) PedestalG1Frames(settings.pedestal_g1_frames()); if (settings.has_pedestal_g2_frames()) PedestalG2Frames(settings.pedestal_g2_frames()); ConversionOnCPU(settings.conversion_on_cpu()); } catch (...) { internal = tmp; throw; } } JFJochProtoBuf::DetectorSettings DiffractionExperiment::GetDetectorSettings() const { JFJochProtoBuf::DetectorSettings ret; ret.set_frame_time_us(GetFrameTime().count()); ret.set_count_time_us(GetFrameCountTime().count()); ret.set_collect_raw_data(GetDetectorMode() != DetectorMode::Conversion); ret.set_use_internal_packet_generator(IsUsingInternalPacketGen()); ret.set_storage_cell_count(GetStorageCellNumber()); ret.set_pedestal_g0_frames(GetPedestalG0Frames()); ret.set_pedestal_g1_frames(GetPedestalG1Frames()); ret.set_pedestal_g2_frames(GetPedestalG2Frames()); return ret; } void DiffractionExperiment::CheckDataProcessingSettings(const JFJochProtoBuf::DataProcessingSettings &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); check_min("Local background size", settings.local_bkg_size(), 2); check_max("Local background size", settings.local_bkg_size(), 7); if (settings.has_high_resolution_limit()) { 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.has_low_resolution_limit()) { check_min("Spot finding low resolution limit", settings.low_resolution_limit(), settings.high_resolution_limit()); } } else if (settings.has_low_resolution_limit()) { 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); } check_min("Background estimate lowQ", settings.bkg_estimate_low_q(), 0.0); check_min("Background estimate highQ", settings.bkg_estimate_high_q(), settings.bkg_estimate_low_q()); } JFJochProtoBuf::DataProcessingSettings DiffractionExperiment::DefaultDataProcessingSettings() { JFJochProtoBuf::DataProcessingSettings ret; ret.set_local_bkg_size(5); ret.set_signal_to_noise_threshold(3); ret.set_photon_count_threshold(16); ret.set_min_pix_per_spot(1); ret.set_max_pix_per_spot(50); ret.set_bkg_estimate_low_q(2 * M_PI / 5.0); ret.set_bkg_estimate_high_q(2 * M_PI / 3.0); return ret; } DiffractionExperiment &DiffractionExperiment::ConversionOnCPU(bool input) { internal.set_conversion_on_cpu(input); return *this; } bool DiffractionExperiment::GetConversionOnCPU() const { if (GetDetectorType() == JFJochProtoBuf::JUNGFRAU) return internal.conversion_on_cpu(); else return false; } bool DiffractionExperiment::GetConversionOnFPGA() const { if (GetDetectorType() == JFJochProtoBuf::JUNGFRAU) return !internal.conversion_on_cpu(); else return false; } 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.min_value = GetUnderflow(); message.saturation_value = GetOverflow(); 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 = SENSOR_MATERIAL; message.sensor_thickness = SENSOR_THICKNESS_IN_UM * 1e-6f; message.compression_algorithm = GetCompressionAlgorithmEnum(); message.compression_block_size = JFJochBitShuffleCompressor::DefaultBlockSize; message.pixel_bit_depth = GetPixelDepth() * 8; message.storage_cell_number = GetStorageCellNumber(); 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(); if (HasUnitCell()) { auto uc = GetUnitCell(); message.unit_cell[0] = uc.a; message.unit_cell[1] = uc.b; message.unit_cell[2] = uc.c; message.unit_cell[3] = uc.alpha; message.unit_cell[4] = uc.beta; message.unit_cell[5] = uc.gamma; } else { message.unit_cell[0] = 0.0; } 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(); } DiffractionExperiment &DiffractionExperiment::ApplyPixelMaskInFPGA(bool input) { internal.set_debug_pixel_mask(!input); return *this; } bool DiffractionExperiment::GetApplyPixelMaskInFPGA() const { if (GetDetectorMode() == DetectorMode::Conversion) return !internal.debug_pixel_mask(); else return false; } float DiffractionExperiment::GetPixelSize_mm() const { if (GetBinning2x2()) return internal.detector().pixel_size_mm() * 2; else return internal.detector().pixel_size_mm(); } DiffractionExperiment &DiffractionExperiment::Binning2x2(bool input) { dataset.set_binning2x2(input); return *this; } bool DiffractionExperiment::GetBinning2x2() const { if (GetDetectorMode() == DetectorMode::Conversion) return dataset.binning2x2(); else return false; } DiffractionExperiment &DiffractionExperiment::SourceName(std::string input) { internal.set_source_name(input); return *this; } DiffractionExperiment &DiffractionExperiment::SourceNameShort(std::string input) { internal.set_source_name_short(input); return *this; } DiffractionExperiment &DiffractionExperiment::InstrumentName(std::string input) { internal.set_instrument_name(input); return *this; } DiffractionExperiment &DiffractionExperiment::InstrumentNameShort(std::string input) { internal.set_instrument_name_short(input); return *this; } std::string DiffractionExperiment::GetSourceName() const { return internal.source_name(); } std::string DiffractionExperiment::GetSourceNameShort() const { return internal.source_name_short(); } std::string DiffractionExperiment::GetInstrumentName() const { return internal.instrument_name(); } std::string DiffractionExperiment::GetInstrumentNameShort() const { return internal.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 internal.detector().geometry().module_geometry(module_number).fast_direction_step(); } int64_t DiffractionExperiment::GetModuleSlowDirectionStep(uint16_t module_number) const { if (module_number >= GetModulesNum()) throw JFJochException(JFJochExceptionCategory::ArrayOutOfBounds, "Module number out of bounds"); return internal.detector().geometry().module_geometry(module_number).slow_direction_step(); } void DiffractionExperiment::GetDetectorModuleHostname(std::vector &output) const { for (const auto &iter: internal.detector().module_hostname()) output.push_back(iter); } std::string DiffractionExperiment::GetDetectorDescription() const { return internal.detector().description(); } bool DiffractionExperiment::GetPedestalWithExternalTrigger() const { return (GetStorageCellNumber() > 1); } DiffractionExperiment &DiffractionExperiment::ApplySolidAngleCorr(bool input) { dataset.set_rad_int_solid_angle_corr(input); return *this; } DiffractionExperiment &DiffractionExperiment::ApplyPolarizationCorr(bool input) { dataset.set_rad_int_polarization_corr(input); return *this; } DiffractionExperiment &DiffractionExperiment::PolarizationFactor(float input) { dataset.set_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::ApplyROI(bool input) { internal.set_roi_apply(input); return *this; } DiffractionExperiment &DiffractionExperiment::AddROIRectangle(int32_t x, int32_t y, int32_t width, int32_t height) { auto *tmp = internal.add_roi_rectangle(); tmp->set_x0(x); tmp->set_y0(y); tmp->set_width(width); tmp->set_height(height); return *this; } DiffractionExperiment &DiffractionExperiment::ClearROI() { internal.clear_roi_rectangle(); return *this; } bool DiffractionExperiment::GetApplyROI() const { return internal.roi_apply(); } void DiffractionExperiment::SetupROIFilter(ROIFilter &filter) { for (const auto& i: internal.roi_rectangle()) filter.SetRectangle(i.x0(), i.y0(), i.width(), i.height()); } DiffractionExperiment &DiffractionExperiment::SaveCalibration(bool input) { dataset.set_save_calibration(input); return *this; } bool DiffractionExperiment::GetSaveCalibration() const { return dataset.save_calibration(); }