Files
Jungfraujoch/common/DiffractionExperiment.cpp
2025-08-16 19:59:27 +02:00

1477 lines
48 KiB
C++

// SPDX-FileCopyrightText: 2024 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
// SPDX-License-Identifier: GPL-3.0-only
#include <cmath>
#include <utility>
#include "NetworkAddressConvert.h"
#include "JFJochCompressor.h" // For ZSTD_USE_JFJOCH_RLE
#include "DiffractionExperiment.h"
#include "JFJochException.h"
#include "RawToConvertedGeometry.h"
#include "../include/spdlog/fmt/fmt.h"
#include "GitInfo.h"
using namespace std::literals::chrono_literals;
#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(DetJF4M()) {}
DiffractionExperiment::DiffractionExperiment(const DetectorSetup& det_setup)
: detector(det_setup) {
ndatastreams = 1;
series_id = 0;
mode = DetectorMode::Conversion;
image_format_settings.Conv();
summation = 1;
cpu_summation = false;
}
// setter functions
DiffractionExperiment &DiffractionExperiment::Detector(const DetectorSetup &input) {
detector = input;
auto settings = detector.GetDefaultSettings();
if (settings)
detector_settings = *settings;
return *this;
}
DiffractionExperiment &DiffractionExperiment::Mode(DetectorMode input) {
mode = input;
if (input == DetectorMode::Conversion)
Conversion();
if (input == DetectorMode::Raw)
Raw();
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) {
DetectorSettings tmp = detector_settings;
if (in_count_time.count() == 0)
tmp.FrameTime(in_frame_time);
else
tmp.FrameTime(in_frame_time, in_count_time);
ImportDetectorSettings(tmp);
return *this;
}
DiffractionExperiment &DiffractionExperiment::PedestalG0Frames(int64_t input) {
detector_settings.PedestalG0Frames(input);
return *this;
}
DiffractionExperiment &DiffractionExperiment::PedestalG1Frames(int64_t input) {
detector_settings.PedestalG1Frames(input);
return *this;
}
DiffractionExperiment &DiffractionExperiment::PedestalG2Frames(int64_t input) {
detector_settings.PedestalG2Frames(input);
return *this;
}
DiffractionExperiment &DiffractionExperiment::IncidentEnergy_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::UseInternalPacketGenerator(bool input) {
detector_settings.InternalGeneratorEnable(input);
return *this;
}
DiffractionExperiment &DiffractionExperiment::MaskModuleEdges(bool input) {
image_format_settings.MaskModuleEdges(input);
return *this;
}
DiffractionExperiment &DiffractionExperiment::Compression(CompressionAlgorithm input) {
dataset.Compression(input);
return *this;
}
DiffractionExperiment &DiffractionExperiment::MaskChipEdges(bool input) {
image_format_settings.MaskChipEdges(input);
return *this;
}
DiffractionExperiment &DiffractionExperiment::QRangeForAzimInt_recipA(float low, float high) {
az_integration_settings.QRange_recipA(low, high);
return *this;
}
DiffractionExperiment& DiffractionExperiment::BkgEstimateQRange_recipA(float low, float high) {
az_integration_settings.BkgEstimateQRange_recipA(low, high);
return *this;
}
DiffractionExperiment& DiffractionExperiment::QSpacingForAzimInt_recipA(float input) {
az_integration_settings.QSpacing_recipA(input);
return *this;
}
DiffractionExperiment &DiffractionExperiment::SetUnitCell(const std::optional<UnitCell> &cell) {
dataset.SetUnitCell(cell);
return *this;
}
DiffractionExperiment &DiffractionExperiment::ZMQPreviewPeriod(const std::optional<std::chrono::microseconds> &input) {
if (input.has_value()) {
check_min("Preview image generation period", input.value().count(), 0);
}
zmq_preview_period = input;
return *this;
}
DiffractionExperiment &DiffractionExperiment::SpaceGroupNumber(int64_t input) {
dataset.SpaceGroupNumber(input);
return *this;
}
DiffractionExperiment &DiffractionExperiment::StorageCells(int64_t input) {
detector_settings.StorageCells(input);
return *this;
}
DiffractionExperiment &DiffractionExperiment::StorageCellStart(int64_t input) {
detector_settings.StorageCellStart(input);
return *this;
}
DiffractionExperiment &DiffractionExperiment::SampleName(const std::string &input) {
dataset.SampleName(input);
return *this;
}
DiffractionExperiment &DiffractionExperiment::OverwriteExistingFiles(bool input) {
file_writer.OverwriteExistingFiles(input);
return *this;
}
// getter functions
int64_t DiffractionExperiment::GetNumTriggers() const {
if (IsPedestalRun())
return 1;
else if (IsPulsedSource())
// For pulsed source summation happens over multiple triggers
return dataset.GetNumTriggers() * GetSummation();
else
return dataset.GetNumTriggers();
}
DetectorMode DiffractionExperiment::GetDetectorMode() const {
return mode;
}
std::chrono::microseconds DiffractionExperiment::GetFrameTime() const {
if ((GetDetectorType() != DetectorType::JUNGFRAU) && dataset.GetImageTime().has_value())
return dataset.GetImageTime().value();
switch (GetDetectorMode()) {
case DetectorMode::PedestalG1:
case DetectorMode::PedestalG2:
return detector_settings.GetFrameTimePedestalG1G2();
default:
return detector_settings.GetFrameTime();
}
}
std::chrono::microseconds DiffractionExperiment::GetDetectorPeriod() const {
// Without storage cells - this is just frame time
if (GetStorageCellNumber() == 1)
return GetFrameTime();
// With storage cells
// Do 100 Hz repetition for pedestal G1/G2
// Do 2 kHz repetition for conversion/raw/pedestal G0
switch (GetDetectorMode()) {
case DetectorMode::PedestalG1:
case DetectorMode::PedestalG2:
return detector_settings.GetFrameTimePedestalG1G2();
default:
return std::chrono::microseconds(MIN_FRAME_TIME_JUNGFRAU_FULL_SPEED_IN_US) * GetStorageCellNumber();
}
}
std::chrono::microseconds DiffractionExperiment::GetImageTime() const {
switch (GetDetectorMode()) {
case DetectorMode::PedestalG1:
case DetectorMode::PedestalG2:
return detector_settings.GetFrameTimePedestalG1G2();
default:
return GetFrameTime() * GetSummation();
}
}
int64_t DiffractionExperiment::GetImageNum() const {
return IsPedestalRun() ? 0 : (GetFrameNum() / GetSummation());
}
int64_t DiffractionExperiment::GetFrameNum() const {
return GetFrameNumPerTrigger() * GetNumTriggers();
}
int64_t DiffractionExperiment::GetFrameNumPerTrigger() const {
switch (GetDetectorMode()) {
case DetectorMode::PedestalG0:
return GetPedestalG0Frames() * GetStorageCellNumber();
case DetectorMode::PedestalG1:
return GetPedestalG1Frames() * GetStorageCellNumber();
case DetectorMode::PedestalG2:
return GetPedestalG2Frames()* GetStorageCellNumber();
default:
if (GetStorageCellNumber() > 1)
return GetStorageCellNumber();
else if (IsPulsedSource())
return 1;
else
return dataset.GetImageNumPerTrigger() * GetSummation();
}
}
std::chrono::microseconds DiffractionExperiment::GetFrameCountTime() const {
if ((GetDetectorType() != DetectorType::JUNGFRAU)
&& dataset.GetImageTime().has_value()
&& !detector_settings.GetCountTime().has_value())
return dataset.GetImageTime().value() - detector.GetReadOutTime();
return detector_settings.GetCountTime()
.value_or(detector_settings.GetFrameTime() - detector.GetReadOutTime());
}
bool DiffractionExperiment::GetFrameCountTimeAuto() const {
return detector_settings.GetCountTime().has_value();
}
std::chrono::microseconds DiffractionExperiment::GetImageCountTime() const {
return GetFrameCountTime() * GetSummation();
}
int64_t DiffractionExperiment::GetPedestalG0Frames() const {
if (GetDetectorType() != DetectorType::JUNGFRAU)
return 0;
return detector_settings.GetPedestalG0Frames();
}
int64_t DiffractionExperiment::GetPedestalG1Frames() const {
if (GetDetectorType() != DetectorType::JUNGFRAU)
return 0;
return detector_settings.GetPedestalG1Frames();
}
int64_t DiffractionExperiment::GetPedestalG2Frames() const {
if (GetDetectorType() != DetectorType::JUNGFRAU)
return 0;
return detector_settings.GetPedestalG2Frames();
}
float DiffractionExperiment::GetIncidentEnergy_keV() const {
return dataset.GetPhotonEnergy_keV();
}
float DiffractionExperiment::GetWavelength_A() const {
if (instrument.IsElectronSource()) {
const double hc = WVL_1A_IN_KEV;
const double me_c2 = 511; // in keV
return static_cast<float>(hc / sqrt(dataset.GetPhotonEnergy_keV() * (dataset.GetPhotonEnergy_keV() + 2 * me_c2)));
}
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();
}
CompressionAlgorithm DiffractionExperiment::GetCompressionAlgorithm() const {
return dataset.GetCompressionAlgorithm();
}
int64_t DiffractionExperiment::GetByteDepthImage() const {
if (detector.GetBitDepthImage())
return detector.GetBitDepthImage().value() / 8;
if (IsCPUSummation())
return 4;
auto bit_depth_image = image_format_settings.GetBitDepthImage();
if (!bit_depth_image.has_value()) {
if (GetBitDepthReadout() == 32)
return 4;
if (GetBitDepthReadout() == 8)
return 1;
return (GetSummation() > 2) ? 4 : 2;
}
return bit_depth_image.value() / 8;
}
bool DiffractionExperiment::IsPixelSigned() const {
auto pixel_signed = image_format_settings.IsPixelSigned();
if (!pixel_signed.has_value())
return IsJungfrauConvPhotonCnt() && (GetDetectorType() == DetectorType::JUNGFRAU);
else
return pixel_signed.value();
}
int64_t DiffractionExperiment::GetDataStreamsNum() const {
return std::min<int64_t>(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(), GetByteDepthImage());
}
int64_t DiffractionExperiment::GetPixelsNum() const {
return GetXPixelsNum() * GetYPixelsNum();
}
int64_t DiffractionExperiment::GetXPixelsNum() const {
return detector.GetGeometry().GetWidth(IsGeometryTransformed());
}
int64_t DiffractionExperiment::GetYPixelsNum() const {
return detector.GetGeometry().GetHeight(IsGeometryTransformed());
}
int64_t DiffractionExperiment::GetPixelsNumConv() const {
return GetXPixelsNumConv() * GetYPixelsNumConv();
}
int64_t DiffractionExperiment::GetXPixelsNumConv() const {
return detector.GetGeometry().GetWidth(true);
}
int64_t DiffractionExperiment::GetYPixelsNumConv() const {
return detector.GetGeometry().GetHeight(true);
}
int64_t DiffractionExperiment::GetPixel0OfModuleConv(uint16_t module_number) const {
return detector.GetGeometry().GetPixel0(module_number, true);
}
int64_t DiffractionExperiment::GetOverflow() const {
switch (GetByteDepthImage()) {
case 4:
return IsPixelSigned() ? static_cast<int64_t>(INT32_MAX) : static_cast<int64_t>(UINT32_MAX);
case 2:
return IsPixelSigned() ? INT16_MAX : UINT16_MAX;
case 1:
return IsPixelSigned() ? INT8_MAX : UINT8_MAX;
default:
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Pixel depth unsupported");
}
}
int64_t DiffractionExperiment::GetSaturationLimit() const {
auto sat = detector.GetSaturationLimit();
auto overflow = GetOverflow();
if (!sat)
return overflow;
return std::min(sat.value(), overflow);
}
int64_t DiffractionExperiment::GetUnderflow() const {
if (!IsPixelSigned())
return -1;
switch (GetByteDepthImage()) {
case 1:
return INT8_MIN;
case 2:
return INT16_MIN;
case 4:
return INT32_MIN;
default:
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Pixel depth unsupported");
}
}
std::optional<std::chrono::microseconds> DiffractionExperiment::GetZMQPreviewPeriod() const {
if (IsPedestalRun())
return {};
else
return zmq_preview_period;
}
int64_t DiffractionExperiment::GetDefaultPlotBinning() const {
// If images are equal longer than 100 ms, don't bin images
// If data collection is shorter than 5s, don't bin
if ((GetImageTime() >= 100ms) || (GetImageNum() * GetImageTime() < 5s))
return 1;
return 500ms / GetImageTime(); // 1 bin == 500 ms
}
bool DiffractionExperiment::IsUsingInternalPacketGen() const {
return detector_settings.IsInternalGeneratorEnable();
}
uint32_t DiffractionExperiment::GetSrcIPv4Address(uint32_t data_stream, uint32_t half_module) const {
uint32_t host = half_module + detector.GetUDPInterfaceCount() * GetFirstModuleOfDataStream(data_stream);
return detector.GetSrcIPv4Addr(host);
}
bool DiffractionExperiment::GetMaskModuleEdges() const {
return image_format_settings.IsMaskModuleEdges();
}
bool DiffractionExperiment::GetMaskChipEdges() const {
return image_format_settings.IsMaskChipEdges();
}
std::optional<UnitCell> DiffractionExperiment::GetUnitCell() const {
return dataset.GetUnitCell();
}
std::string DiffractionExperiment::GetUnitCellString() const {
auto uc = dataset.GetUnitCell();
if (uc.has_value()) {
return fmt::format("{:.1f}, {:.1f}, {:.1f}, {:.1f}, {:.1f} {:.1f}",
uc.value().a,
uc.value().b,
uc.value().c,
uc.value().alpha,
uc.value().beta,
uc.value().gamma);
} else
return "-";
}
int64_t DiffractionExperiment::GetSpaceGroupNumber() const {
return dataset.GetSpaceGroupNumber();
}
int64_t DiffractionExperiment::GetStorageCellNumber() const {
auto storage_cells = detector_settings.GetStorageCells();
switch (GetDetectorMode()) {
case DetectorMode::PedestalG1:
if (IsFixedGainG1())
return storage_cells;
case DetectorMode::PedestalG2:
if (storage_cells > 1)
return 2;
else
return 1;
default:
return storage_cells;
}
}
int64_t DiffractionExperiment::GetStorageCellStart() const {
return detector_settings.GetStorageCellStart();
}
float DiffractionExperiment::GetLowQForAzimInt_recipA() const {
return az_integration_settings.GetLowQ_recipA();
}
float DiffractionExperiment::GetHighQForAzimInt_recipA() const {
return az_integration_settings.GetHighQ_recipA();
}
float DiffractionExperiment::GetQSpacingForAzimInt_recipA() const {
return az_integration_settings.GetQSpacing_recipA();
}
DiffractionExperiment &DiffractionExperiment::MaxSpotCount(int64_t input) {
dataset.MaxSpotCount(input);
return *this;
}
int64_t DiffractionExperiment::GetMaxSpotCount() const {
if (!IsSpotFindingEnabled())
return 0;
return dataset.GetMaxSpotCount();
}
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);
}
check_min("min spot count for powder ring detection", settings.min_spot_count_powder_ring, 5);
}
SpotFindingSettings DiffractionExperiment::DefaultDataProcessingSettings() {
return {};
}
void DiffractionExperiment::FillMessage(StartMessage &message) const {
message.images_per_file = GetImagesPerFile();
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 = GetIncidentEnergy_keV() * 1e3f;
message.image_size_x = GetXPixelsNum();
message.image_size_y = GetYPixelsNum();
message.saturation_value = GetSaturationLimit() - 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.bit_depth_image = GetByteDepthImage() * 8;
message.bit_depth_readout = GetBitDepthReadout();
if (GetDetectorType() == DetectorType::JUNGFRAU) {
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 = IsApplyPixelMask();
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_type = GetSourceType();
message.instrument_name = GetInstrumentName();
message.summation = GetSummation();
message.user_data = GetHeaderAppendix();
message.countrate_correction_enabled = false;
message.flatfield_enabled = false;
message.goniometer = dataset.GetGoniometer();
message.grid_scan = dataset.GetGridScan();
message.run_number = GetRunNumber();
message.run_name = GetRunName();
message.gain_file_names = detector.GetGainFileNames();
message.rois = roi_mask.ExportMetadata();
message.data_reduction_factor_serialmx = GetLossyCompressionSerialMX();
message.experiment_group = dataset.GetExperimentGroup();
message.jfjoch_release = jfjoch_version();
message.detector_serial_number = detector.GetSerialNumber();
message.write_master_file = dataset.IsWriteNXmxHDF5Master();
message.overwrite = file_writer.IsOverwriteExistingFiles();
message.file_format = file_writer.GetHDF5MasterFormatVersion();
message.ring_current_mA = dataset.GetRingCurrent_mA();
message.sample_temperature_K = dataset.GetSampleTemperature_K();
message.channels = {"default"};
switch (GetDetectorType()) {
case DetectorType::JUNGFRAU:
message.jungfrau_conversion_enabled = IsJungfrauConvPhotonCnt();
if (IsJungfrauConvPhotonCnt())
message.jungfrau_conversion_factor = GetPhotonEnergyForConversion_keV() * 1000;
break;
case DetectorType::EIGER:
case DetectorType::DECTRIS:
message.threshold_energy["default"] = GetEigerThreshold_keV() * 1000.0f; // threshold in CBOR is in eV
break;
}
message.geometry_transformation_enabled = IsGeometryTransformed();
if (GetSummation() == 1)
message.summation_mode = "none";
else {
if (IsCPUSummation())
message.summation_mode = "cpu";
else
message.summation_mode = "fpga";
}
}
float DiffractionExperiment::GetPixelSize_mm() const {
return detector.GetPixelSize_mm();
}
std::string DiffractionExperiment::GetSourceName() const {
return instrument.GetSourceName();
}
std::string DiffractionExperiment::GetSourceType() const {
return instrument.GetSourceType();
}
std::string DiffractionExperiment::GetInstrumentName() const {
return instrument.GetInstrumentName();
}
int64_t DiffractionExperiment::GetModuleFastDirectionStep(uint16_t module_number) const {
return detector.GetGeometry().GetFastDirectionStep(module_number);
}
int64_t DiffractionExperiment::GetModuleSlowDirectionStep(uint16_t module_number) const {
return detector.GetGeometry().GetSlowDirectionStep(module_number);
}
std::vector<std::string> DiffractionExperiment::GetDetectorModuleHostname() const {
return detector.GetDetectorModuleHostname();
}
std::string DiffractionExperiment::GetDetectorDescription() const {
return detector.GetDescription();
}
DiffractionExperiment &DiffractionExperiment::ApplySolidAngleCorr(bool input) {
az_integration_settings.SolidAngleCorrection(input);
return *this;
}
bool DiffractionExperiment::GetApplySolidAngleCorr() const {
return az_integration_settings.IsSolidAngleCorrection();
}
bool DiffractionExperiment::GetSaveCalibration() const {
auto val = dataset.IsSaveCalibration();
if (val.has_value())
return val.value();
// By default calibration is saved if more than 4 images
// to limit cases were size of the file is determined by the calibration
return (GetImageNum() > 4) && (GetDetectorType() == DetectorType::JUNGFRAU);
}
DiffractionExperiment &DiffractionExperiment::StorageCellDelay(std::chrono::nanoseconds input) {
detector_settings.StorageCellDelay(input);
return *this;
}
std::chrono::nanoseconds DiffractionExperiment::GetStorageCellDelay() const {
return detector_settings.GetStorageCellDelay();
}
DiffractionExperiment &DiffractionExperiment::Summation(int64_t input) {
check_min("Summation factor", input, 1);
summation = input;
return *this;
}
int64_t DiffractionExperiment::GetSummation() const {
if (GetAutoSummation())
return summation;
return 1;
}
int64_t DiffractionExperiment::GetFPGASummation() const {
if (IsCPUSummation())
return 1;
return GetSummation();
}
int64_t DiffractionExperiment::GetByteDepthFPGA() const {
if (IsCPUSummation())
return 2;
return GetByteDepthImage();
}
int64_t DiffractionExperiment::GetUDPInterfaceCount() const {
return detector.GetUDPInterfaceCount();
}
std::vector<DetectorModuleConfig>
DiffractionExperiment::GetDetectorModuleConfig(const std::vector<AcquisitionDeviceNetConfig> &net_config) const{
std::vector<DetectorModuleConfig> 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 az_integration_settings.GetBkgEstimateLowQ_recipA();
}
float DiffractionExperiment::GetHighQForBkgEstimate_recipA() const {
return az_integration_settings.GetBkgEstimateHighQ_recipA();
}
DiffractionExperiment &DiffractionExperiment::AttenuatorTransmission(const std::optional<float> &input) {
dataset.AttenuatorTransmission(input);
return *this;
}
DiffractionExperiment &DiffractionExperiment::TotalFlux(const std::optional<float> &input) {
dataset.TotalFlux(input);
return *this;
}
std::optional<float> DiffractionExperiment::GetAttenuatorTransmission() const {
return dataset.GetAttenuatorTransmission();
}
std::optional<float> DiffractionExperiment::GetTotalFlux() const {
return dataset.GetTotalFlux();
}
DiffractionExperiment &DiffractionExperiment::Goniometer(const std::optional<GoniometerAxis> &input) {
dataset.Goniometer(input);
return *this;
}
std::optional<GoniometerAxis> DiffractionExperiment::GetGoniometer() const {
return dataset.GetGoniometer();
}
std::optional<GridScanSettings> DiffractionExperiment::GetGridScan() const {
return dataset.GetGridScan();
}
DiffractionExperiment &DiffractionExperiment::UsingGainHG0(bool input) {
detector_settings.UseGainHG0(input);
return *this;
}
DiffractionExperiment &DiffractionExperiment::FixedGainG1(bool input) {
detector_settings.FixGainG1(input);
return *this;
}
bool DiffractionExperiment::IsFixedGainG1() const {
return detector_settings.IsFixGainG1();
}
bool DiffractionExperiment::IsUsingGainHG0() const {
return detector_settings.IsUseGainHG0();
}
DiffractionExperiment &DiffractionExperiment::HeaderAppendix(const nlohmann::json &input) {
dataset.HeaderAppendix(input);
return *this;
}
DiffractionExperiment &DiffractionExperiment::ImageAppendix(const nlohmann::json &input) {
dataset.ImageAppendix(input);
return *this;
}
const nlohmann::json& DiffractionExperiment::GetHeaderAppendix() const {
return dataset.GetHeaderAppendix();
}
const nlohmann::json& DiffractionExperiment::GetImageAppendix() const {
return dataset.GetImageAppendix();
}
uint64_t DiffractionExperiment::GetRunNumber() const {
if (dataset.GetRunNumber())
return dataset.GetRunNumber().value();
return series_id;
}
std::string DiffractionExperiment::GetRunName() const {
auto run_name = dataset.GetRunName();
if (run_name)
return run_name.value();
else
return std::to_string(series_id) + ":" + dataset.GetFilePrefix();
}
DiffractionExperiment &DiffractionExperiment::IncrementRunNumber() {
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::JungfrauConvPhotonCnt(bool input) {
image_format_settings.JungfrauConversion(input);
return *this;
}
bool DiffractionExperiment::IsJungfrauConvPhotonCnt() const {
if (!IsPedestalRun() && (GetDetectorType() == DetectorType::JUNGFRAU))
return image_format_settings.IsJungfrauConversion();
else
return false;
}
DiffractionExperiment &DiffractionExperiment::DetectorDelay(std::chrono::nanoseconds input) {
detector_settings.DetectorDelay(input);
return *this;
}
std::chrono::nanoseconds DiffractionExperiment::GetDetectorDelay() const {
return detector_settings.GetDetectorDelay();
}
const DetectorSetup &DiffractionExperiment::GetDetectorSetup() const {
return detector;
}
DetectorSetup &DiffractionExperiment::Detector() {
return detector;
}
DiffractionExperiment &DiffractionExperiment::InferenceServerAddr(const std::vector<std::string> &input) {
inference_server_addr = input;
return *this;
}
const std::vector<std::string> &DiffractionExperiment::GetInferenceServerAddress() const {
return inference_server_addr;
}
DiffractionExperiment &DiffractionExperiment::PulsedSource(bool input) {
instrument.PulsedSource(input);
return *this;
}
bool DiffractionExperiment::IsPulsedSource() const {
return instrument.IsPulsedSource();
}
bool DiffractionExperiment::IsSpotFindingEnabled() const {
return dataset.IsSpotFindingEnabled() && !IsPedestalRun();
}
float DiffractionExperiment::GetPhotonEnergyForConversion_keV() const {
auto val = GetJungfrauConversionFactor_keV();
if (val.has_value())
return val.value();
else
return GetIncidentEnergy_keV();
}
DiffractionExperiment &DiffractionExperiment::InternalPacketGeneratorImages(int64_t input) {
detector_settings.InternalGeneratorImages(input);
return *this;
}
int64_t DiffractionExperiment::GetInternalPacketGeneratorImages() const {
return detector_settings.GetInternalGeneratorImages();
}
DiffractionExperiment &DiffractionExperiment::ImportDatasetSettings(const DatasetSettings &input) {
auto tmp = dataset;
dataset = input;
auto image_time = input.GetImageTime();
if (image_time) {
switch (GetDetectorType()) {
case DetectorType::EIGER:
case DetectorType::DECTRIS:
check_min("Image time [us]", image_time.value().count(), detector.GetMinFrameTime().count());
summation = 1;
break;
case DetectorType::JUNGFRAU:
if (image_time->count() % GetFrameTime().count() != 0) {
dataset = tmp;
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"Image time must be multiple of frame time");
}
if (GetFrameTime().count() == 0) {
dataset = tmp;
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"Frame time cannot be zero");
}
if (image_time < GetFrameTime()) {
dataset = tmp;
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"Image time cannot be less than base frame time");
}
this->Summation(image_time.value() / GetFrameTime());
break;
}
} else
summation = 1;
if (dataset.GridScan())
dataset.GridScan()->ImageNum(GetImageNum());
if (GetFrameNum() >= MAX_FRAMES) {
dataset = tmp;
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"Frame number (summation * images_per_trigger * ntrigger) cannot exceed "
+ std::to_string(MAX_FRAMES));
}
return *this;
}
DatasetSettings DiffractionExperiment::GetDatasetSettings() const {
return dataset;
}
ROIMap &DiffractionExperiment::ROI() {
return roi_mask;
}
const ROIMap &DiffractionExperiment::ROI() const {
return roi_mask;
}
std::vector<uint16_t> DiffractionExperiment::ExportROIMap() const {
return roi_mask.GetROIMap(GetDiffractionGeometry(), GetXPixelsNumConv(), GetYPixelsNumConv());
}
DiffractionExperiment &DiffractionExperiment::ImagesPerFile(int64_t input) {
dataset.ImagesPerFile(input);
return *this;
}
int64_t DiffractionExperiment::GetImagesPerFile() const {
auto tmp = dataset.GetImagesPerFile();
if (tmp == 0)
return GetImageNum();
else
return tmp;
}
int64_t DiffractionExperiment::GetImageBufferLocationSize() const {
return GetMaxCompressedSize() + 1024 * 1024;
}
float DiffractionExperiment::GetLossyCompressionSerialMX() const {
return dataset.GetLossyCompressionSerialMX();
}
DiffractionExperiment &DiffractionExperiment::LossyCompressionSerialMX(float input) {
dataset.LossyCompressionSerialMX(input);
return *this;
}
std::optional<int64_t> DiffractionExperiment::GetLossyCompressionPoisson() const {
return dataset.GetLossyCompressionPoisson();
}
DiffractionExperiment &DiffractionExperiment::LossyCompressionPoisson(const std::optional<int64_t> &input) {
dataset.LossyCompressionPoisson(input);
return *this;
}
std::string DiffractionExperiment::GetExperimentGroup() const {
return dataset.GetExperimentGroup();
}
std::optional<int64_t> DiffractionExperiment::GetPixelValueLowThreshold() const {
return dataset.GetPixelValueLowThreshold();
}
DiffractionExperiment &DiffractionExperiment::PixelValueLowThreshold(const std::optional<int64_t> &input) {
dataset.PixelValueLowThreshold(input);
return *this;
}
DiffractionExperiment &DiffractionExperiment::ImportInstrumentMetadata(const InstrumentMetadata &input) {
instrument = input;
return *this;
}
InstrumentMetadata DiffractionExperiment::GetInstrumentMetadata() const {
return instrument;
}
DiffractionExperiment &DiffractionExperiment::ImportFileWriterSettings(const FileWriterSettings &input) {
file_writer = input;
return *this;
}
FileWriterSettings DiffractionExperiment::GetFileWriterSettings() const {
return file_writer;
}
bool DiffractionExperiment::IsGeometryTransformed() const {
// For DECTRIS detectors always operate in transformed geometry
return (GetDetectorType() == DetectorType::DECTRIS) || image_format_settings.IsGeometryTransformed();
}
DiffractionExperiment &DiffractionExperiment::GeometryTransformation(bool input) {
image_format_settings.GeometryTransformed(input);
return *this;
}
int64_t DiffractionExperiment::GetImageFillValue() const {
switch (GetByteDepthImage()) {
case 1:
if (IsPixelSigned())
return INT8_MIN;
return UINT8_MAX;
case 2:
if (IsPixelSigned())
return INT16_MIN;
return UINT16_MAX;
case 4:
if (IsPixelSigned())
return INT32_MIN;
return UINT32_MAX;
default:
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Pixel depth unsupported");
}
}
int64_t DiffractionExperiment::GetBitDepthReadout() const {
if (GetDetectorType() == DetectorType::EIGER) {
if (detector_settings.GetEigerBitDepth().has_value())
return detector_settings.GetEigerBitDepth().value();
if (GetFrameTime().count() > 1000)
return 32;
if (GetFrameTime().count() < 450)
return 8;
return 16;
}
auto det_value = detector.GetBitDepthReadout();
if (det_value)
return det_value.value();
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"Bit depth readout not configured");
}
bool DiffractionExperiment::IsPedestalRun() const {
switch (GetDetectorMode()) {
case DetectorMode::PedestalG0:
case DetectorMode::PedestalG1:
case DetectorMode::PedestalG2:
return true;
default:
return false;
}
}
bool DiffractionExperiment::GetAutoSummation() const {
if (IsPedestalRun() || (GetStorageCellNumber() > 1))
return false; // for pedestal or more than 1 storage cell summation doesn't make sense and should be always turned off
else
return image_format_settings.IsAutoSummation();
}
DiffractionExperiment &DiffractionExperiment::AutoSummation(bool input) {
image_format_settings.AutoSummation(input);
return *this;
}
DiffractionExperiment &DiffractionExperiment::BitDepthImage(const std::optional<int64_t> &input) {
image_format_settings.BitDepthImage(input);
return *this;
}
DiffractionExperiment &DiffractionExperiment::PixelSigned(const std::optional<bool> &input) {
image_format_settings.PixelSigned(input);
return *this;
}
DiffractionExperiment &DiffractionExperiment::JungfrauConversionFactor_keV(const std::optional<float> &input) {
image_format_settings.JungfrauConvFactor_keV(input);
return *this;
}
std::optional<float> DiffractionExperiment::GetJungfrauConversionFactor_keV() const {
return image_format_settings.GetJungfrauConvFactor_keV();
}
void DiffractionExperiment::Conversion() {
image_format_settings.Conv();
}
void DiffractionExperiment::Raw() {
image_format_settings.Raw();
}
DiffractionExperiment &DiffractionExperiment::ImportDetectorSettings(const DetectorSettings &input) {
check_min("Frame time [us]", input.GetFrameTime().count(), detector.GetMinFrameTime().count());
if (GetDetectorType() == DetectorType::JUNGFRAU) {
if (!input.GetCountTime().has_value()) {
// implicit count time
check_max("Frame time [us]", input.GetFrameTime().count(),
MAX_COUNT_TIME_JUNGFRAU_IN_US + detector.GetReadOutTime().count());
} else {
// explicit count time
check_max("Count time [us]", input.GetCountTime().value().count(),
MAX_COUNT_TIME_JUNGFRAU_IN_US);
}
if ((input.GetTiming() == DetectorTiming::Burst) ||
(input.GetTiming() == DetectorTiming::Gated))
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"Burst and gated timing modes not supported in JUNGFRAU");
}
detector_settings = input;
return *this;
}
DetectorSettings DiffractionExperiment::GetDetectorSettings() const {
return detector_settings;
}
DiffractionExperiment &DiffractionExperiment::ImportImageFormatSettings(const ImageFormatSettings &input) {
image_format_settings = input;
return *this;
}
ImageFormatSettings DiffractionExperiment::GetImageFormatSettings() const {
return image_format_settings;
}
DiffractionExperiment &DiffractionExperiment::ImportAzimuthalIntegrationSettings(const AzimuthalIntegrationSettings &input) {
az_integration_settings = input;
return *this;
}
AzimuthalIntegrationSettings DiffractionExperiment::GetAzimuthalIntegrationSettings() const {
return az_integration_settings;
}
DiffractionExperiment &DiffractionExperiment::PolarizationFactor(const std::optional<float> &input) {
dataset.PolarizationFactor(input);
return *this;
}
std::optional<float> DiffractionExperiment::GetPolarizationFactor() const {
return dataset.GetPolarizationFactor();
}
DiffractionExperiment &DiffractionExperiment::SaveCalibration(const std::optional<bool> &input) {
dataset.SaveCalibration(input);
return *this;
}
float DiffractionExperiment::GetPedestalG0RMSLimit() const {
return image_format_settings.GetPedestalG0RMSLimit();
}
uint32_t DiffractionExperiment::GetPedestalMinImageCount() const {
return detector_settings.GetPedestalMinImageCount();
}
float DiffractionExperiment::GetEigerThreshold_keV() const {
float thr = GetIncidentEnergy_keV() / 2.0f;
auto val = detector_settings.GetEigerThreshold_keV();
if (val)
thr = val.value();
if (thr < detector.GetMinThreshold_keV())
thr = detector.GetMinThreshold_keV();
return thr;
}
DetectorTiming DiffractionExperiment::GetDetectorTiming() const {
return detector_settings.GetTiming();
}
bool DiffractionExperiment::IsDetectorModuleSync() const {
return detector.IsModuleSync();
}
int64_t DiffractionExperiment::GetEigerBitDepth() const {
auto tmp = detector_settings.GetEigerBitDepth();
if (tmp.has_value())
return tmp.value();
else
return 16;
}
DiffractionExperiment &DiffractionExperiment::EigerBitDepth(const std::optional<int64_t> &input) {
detector_settings.EigerBitDepth(input);
return *this;
}
DetectorType DiffractionExperiment::GetDetectorType() const {
return detector.GetDetectorType();
}
bool DiffractionExperiment::IsMaskPixelsWithoutG0() const {
if (GetDetectorType() == DetectorType::JUNGFRAU)
return image_format_settings.IsMaskPixelsWithoutG0();
return false;
}
bool DiffractionExperiment::IsApplyPixelMask() const {
return image_format_settings.IsApplyPixelMask() && !IsPedestalRun();
}
DiffractionExperiment &DiffractionExperiment::CPUSummation(bool input) {
cpu_summation = input;
return *this;
}
DiffractionExperiment &DiffractionExperiment::ApplyPixelMask(bool input) {
image_format_settings.ApplyPixelMask(input);
return *this;
}
bool DiffractionExperiment::IsCPUSummation() const {
if (summation == 1)
return false;
if (summation >= MAX_FPGA_SUMMATION)
return true;
return cpu_summation;
}
DiffractionExperiment & DiffractionExperiment::ElectronSource(bool input) {
instrument.ElectronSource(input);
return *this;
}
bool DiffractionExperiment::IsElectronSource() const {
return instrument.IsElectronSource();
}
DiffractionExperiment &DiffractionExperiment::SetFileWriterFormat(FileWriterFormat input) {
file_writer.HDF5MasterFormatVersion(input);
return *this;
}
FileWriterFormat DiffractionExperiment::GetFileWriterFormat() const {
return file_writer.GetHDF5MasterFormatVersion();
}
DiffractionGeometry DiffractionExperiment::GetDiffractionGeometry() const {
DiffractionGeometry g;
g.Wavelength_A(GetWavelength_A()).PixelSize_mm(GetPixelSize_mm())
.BeamX_pxl(GetBeamX_pxl()).BeamY_pxl(GetBeamY_pxl())
.DetectorDistance_mm(GetDetectorDistance_mm());
return g;
}
void DiffractionExperiment::CalcAzIntCorrRawCoord(float *output, size_t module_number) const {
if (module_number >= GetModulesNum())
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Wrong module number");
auto geom = GetDiffractionGeometry();
for (int i = 0; i < RAW_MODULE_SIZE; i++) {
auto [x,y] = RawToConvertedCoordinate(*this, module_number, i);
if (GetApplySolidAngleCorr())
output[i] /= geom.CalcAzIntSolidAngleCorr(static_cast<float>(x), static_cast<float>(y));
auto p = GetPolarizationFactor();
if (p.has_value())
output[i] /= geom.CalcAzIntPolarizationCorr(static_cast<float>(x), static_cast<float>(y), p.value());
}
}
void DiffractionExperiment::CalcSpotFinderResolutionMap(float *data, size_t module_number) const {
if (module_number >= GetModulesNum())
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Wrong module number");
auto geom = GetDiffractionGeometry();
for (int i = 0; i < RAW_MODULE_SIZE; i++) {
auto [x,y] = RawToConvertedCoordinate(*this, module_number, i);
data[i] = geom.PxlToRes(static_cast<float>(x), static_cast<float>(y));
}
}
CompressedImageMode DiffractionExperiment::GetImageMode() const {
switch (GetByteDepthImage()) {
case 1:
return (IsPixelSigned() ? CompressedImageMode::Int8 : CompressedImageMode::Uint8);
case 2:
return (IsPixelSigned() ? CompressedImageMode::Int16 : CompressedImageMode::Uint16);
case 4:
return (IsPixelSigned() ? CompressedImageMode::Int32 : CompressedImageMode::Uint32);
default:
throw (JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Bit depth not supported"));
}
}
DiffractionExperiment &DiffractionExperiment::IndexingAlgorithm(IndexingAlgorithmEnum input) {
indexing.Algorithm(input);
return *this;
}
IndexingAlgorithmEnum DiffractionExperiment::GetIndexingAlgorithm() const {
auto cell = GetUnitCell().has_value();
switch (indexing.GetAlgorithm()) {
case IndexingAlgorithmEnum::FFBIDX:
if (!cell)
return IndexingAlgorithmEnum::None;
return IndexingAlgorithmEnum::FFBIDX;
case IndexingAlgorithmEnum::Auto:
if (!cell)
return IndexingAlgorithmEnum::FFT;
return IndexingAlgorithmEnum::FFBIDX;
case IndexingAlgorithmEnum::FFT:
return IndexingAlgorithmEnum::FFT;
default:
return IndexingAlgorithmEnum::None;
}
}
IndexingSettings DiffractionExperiment::GetIndexingSettings() const {
return indexing;
}
DiffractionExperiment &DiffractionExperiment::ImportIndexingSettings(const IndexingSettings &input) {
indexing = input;
return *this;
}
float DiffractionExperiment::GetIndexingTolerance() const {
return indexing.GetTolerance();
}
DiffractionExperiment &DiffractionExperiment::IndexingTolerance(float input) {
indexing.Tolerance(input);
return *this;
}
DiffractionExperiment &DiffractionExperiment::GridScan(const std::optional<GridScanSettings> &input) {
dataset.GridScan(input);
return *this;
}
DiffractionExperiment &DiffractionExperiment::SampleTemperature_K(const std::optional<float> &input) {
dataset.SampleTemperature_K(input);
return *this;
}
DiffractionExperiment &DiffractionExperiment::RingCurrent_mA(const std::optional<float> &input) {
dataset.RingCurrent_mA(input);
return *this;
}
std::optional<float> DiffractionExperiment::GetSampleTemeperature_K() const {
return dataset.GetSampleTemperature_K();
}
std::optional<float> DiffractionExperiment::GetRingCurrent_mA() const {
return dataset.GetRingCurrent_mA();
}
DiffractionExperiment &DiffractionExperiment::ImportBraggIntegrationSettings(const BraggIntegrationSettings &input) {
bragg_integration_settings = input;
return *this;
}
BraggIntegrationSettings DiffractionExperiment::GetBraggIntegrationSettings() const {
return bragg_integration_settings;
}