All checks were successful
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 11m23s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 10m32s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 9m15s
Build Packages / Generate python client (push) Successful in 19s
Build Packages / Build documentation (push) Successful in 49s
Build Packages / Create release (push) Has been skipped
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 9m13s
Build Packages / build:rpm (rocky8) (push) Successful in 9m10s
Build Packages / build:rpm (rocky9) (push) Successful in 9m58s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 8m52s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 8m42s
Build Packages / Unit tests (push) Successful in 1h12m44s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 11m30s
This is an UNSTABLE release. This version significantly rewrites code to predict reflection position and integrate them, especially in case of rotation crystallography. If things go wrong with analysis, it is better to revert to 1.0.0-rc.123. * jfjoch_broker: Improve refection position prediction and Bragg integration code. * jfjoch_broker: Align with XDS way of calculating Lorentz correction and general notation. * jfjoch_writer: Fix saving mosaicity properly in HDF5 file. * jfjoch_viewer: Introduce high-dynamic range mode for images * jfjoch_viewer: Ctrl+mouse wheel has exponential change in foreground (+/-15%) * jfjoch_viewer: Zoom-in numbers have better readability Reviewed-on: #31 Co-authored-by: Filip Leonarski <filip.leonarski@psi.ch> Co-committed-by: Filip Leonarski <filip.leonarski@psi.ch>
1649 lines
54 KiB
C++
1649 lines
54 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 "CUDAWrapper.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::Standard;
|
|
image_format_settings.Conv();
|
|
|
|
summation = 1;
|
|
cpu_summation = false;
|
|
}
|
|
|
|
// setter functions
|
|
DiffractionExperiment &DiffractionExperiment::Detector(const DetectorSetup &input) {
|
|
detector = input;
|
|
|
|
// Conversion is always default mode after switching detectors
|
|
mode = DetectorMode::Standard;
|
|
|
|
auto settings = detector.GetDefaultSettings();
|
|
if (settings)
|
|
detector_settings = *settings;
|
|
return *this;
|
|
}
|
|
|
|
DiffractionExperiment &DiffractionExperiment::Mode(DetectorMode input) {
|
|
// Handle allowed mode settings
|
|
switch (GetDetectorType()) {
|
|
case DetectorType::JUNGFRAU:
|
|
if (input == DetectorMode::DarkMask)
|
|
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Dark mask is not supported for PSI JUNGFRAU detector");
|
|
break;
|
|
case DetectorType::DECTRIS:
|
|
if ((input == DetectorMode::PedestalG0) || (input == DetectorMode::PedestalG1) || (input == DetectorMode::PedestalG2))
|
|
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Pedestal data collection is not supported for DECTRIS detector");
|
|
break;
|
|
case DetectorType::EIGER:
|
|
if ((input == DetectorMode::PedestalG0) || (input == DetectorMode::PedestalG1) || (input == DetectorMode::PedestalG2) || (input == DetectorMode::DarkMask))
|
|
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Pedestal or dark mask data collection is not supported for PSI EIGER detector");
|
|
break;
|
|
}
|
|
|
|
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) {
|
|
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(std::optional<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 (GetDetectorMode() != DetectorMode::Standard)
|
|
// For pedestal and dark mask modes
|
|
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 {
|
|
switch (GetDetectorMode()) {
|
|
case DetectorMode::DarkMask:
|
|
return GetDarkMaskSettings().GetFrameTime();
|
|
case DetectorMode::PedestalG1:
|
|
case DetectorMode::PedestalG2:
|
|
return detector_settings.GetFrameTimePedestalG1G2();
|
|
default:
|
|
if ((GetDetectorType() != DetectorType::JUNGFRAU) && dataset.GetImageTime().has_value())
|
|
return dataset.GetImageTime().value();
|
|
|
|
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 {
|
|
if (GetDetectorMode() == DetectorMode::Standard)
|
|
return GetFrameNum() / GetSummation();
|
|
return 0;
|
|
}
|
|
|
|
int64_t DiffractionExperiment::GetFrameNum() const {
|
|
return GetFrameNumPerTrigger() * GetNumTriggers();
|
|
}
|
|
|
|
int64_t DiffractionExperiment::GetFrameNumPerTrigger() const {
|
|
switch (GetDetectorMode()) {
|
|
case DetectorMode::DarkMask:
|
|
return GetDarkMaskSettings().GetNumberOfFrames();
|
|
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 "-";
|
|
}
|
|
|
|
std::optional<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_finite("Signal to noise threshold", settings.signal_to_noise_threshold);
|
|
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_finite("Spot finding high resolution limit", settings.high_resolution_limit);
|
|
check_finite("Spot finding low resolution limit", settings.low_resolution_limit);
|
|
|
|
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("Ice ring width in Q-space (A^-1)", settings.ice_ring_width_Q_recipA, 0.0);
|
|
check_max("Ice ring width in Q-space (A^-1)", settings.ice_ring_width_Q_recipA, 1.0);
|
|
check_finite("Ice ring width in Q-space (A^-1)", settings.ice_ring_width_Q_recipA);
|
|
|
|
if (settings.high_res_gap_Q_recipA.has_value()) {
|
|
check_min("High resolution gap (A^-1)", settings.high_res_gap_Q_recipA.value(), 0.1);
|
|
check_max("High resolution gap (A^-1)", settings.high_res_gap_Q_recipA.value(), 5.0);
|
|
check_finite("High resolution gap (A^-1)", settings.high_res_gap_Q_recipA.value());
|
|
}
|
|
}
|
|
|
|
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();
|
|
message.indexing_algorithm = GetIndexingAlgorithm();
|
|
message.images_per_trigger = dataset.GetImageNumPerTrigger();
|
|
|
|
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.fluorescence_spectrum = dataset.GetFluorescenceSpectrum();
|
|
|
|
message.poni_rot1 = dataset.GetPoniRot1_rad();
|
|
message.poni_rot2 = dataset.GetPoniRot2_rad();
|
|
message.poni_rot3 = dataset.GetPoniRot3_rad();
|
|
|
|
message.detect_ice_rings = dataset.IsDetectIceRings();
|
|
|
|
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.data_stream = d;
|
|
mod_cfg.udp_dest_port_1 = 1024 + m;
|
|
mod_cfg.udp_dest_port_2 = 1024 + m;
|
|
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::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;
|
|
}
|
|
|
|
std::optional<int64_t> DiffractionExperiment::GetPixelValueHighThreshold() const {
|
|
return dataset.GetPixelValueHighThreshold();
|
|
}
|
|
|
|
DiffractionExperiment &DiffractionExperiment::PixelValueHighThreshold(const std::optional<int64_t> &input) {
|
|
dataset.PixelValueHighThreshold(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)
|
|
return GetEigerBitDepth();
|
|
|
|
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();
|
|
}
|
|
|
|
DiffractionExperiment & DiffractionExperiment::Conversion() {
|
|
image_format_settings.Conv();
|
|
return *this;
|
|
}
|
|
|
|
DiffractionExperiment & DiffractionExperiment::Raw() {
|
|
image_format_settings.Raw();
|
|
return *this;
|
|
}
|
|
|
|
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;
|
|
|
|
if (GetDetectorMode() == DetectorMode::DarkMask)
|
|
thr = GetDarkMaskSettings().GetThreshold_keV();
|
|
else {
|
|
auto val = detector_settings.GetEigerThreshold_keV();
|
|
|
|
if (val)
|
|
thr = val.value();
|
|
else
|
|
thr = GetIncidentEnergy_keV() / 2.0f;
|
|
}
|
|
|
|
if (thr < detector.GetMinThreshold_keV())
|
|
thr = detector.GetMinThreshold_keV();
|
|
|
|
return thr;
|
|
}
|
|
|
|
DetectorTiming DiffractionExperiment::GetDetectorTiming() const {
|
|
// For calibration use Auto timing mode
|
|
switch (GetDetectorMode()) {
|
|
case DetectorMode::DarkMask:
|
|
return DetectorTiming::Auto;
|
|
default:
|
|
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();
|
|
if (GetFrameTime().count() >= 2622)
|
|
return 32;
|
|
if (GetFrameTime().count() < 500)
|
|
return 8;
|
|
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(dataset.GetBeamX_pxl())
|
|
.BeamY_pxl(dataset.GetBeamY_pxl())
|
|
.DetectorDistance_mm(dataset.GetDetectorDistance_mm())
|
|
.PoniRot1_rad(dataset.GetPoniRot1_rad())
|
|
.PoniRot2_rad(dataset.GetPoniRot2_rad())
|
|
.PoniRot3_rad(dataset.GetPoniRot3_rad());
|
|
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 (get_gpu_count() == 0)
|
|
return IndexingAlgorithmEnum::FFTW;
|
|
if (!cell)
|
|
return IndexingAlgorithmEnum::FFT;
|
|
return IndexingAlgorithmEnum::FFBIDX;
|
|
case IndexingAlgorithmEnum::FFT:
|
|
return IndexingAlgorithmEnum::FFT;
|
|
case IndexingAlgorithmEnum::FFTW:
|
|
return IndexingAlgorithmEnum::FFTW;
|
|
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::GetSampleTemperature_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;
|
|
}
|
|
|
|
DiffractionExperiment &DiffractionExperiment::PoniRot1_rad(float input) {
|
|
dataset.PoniRot1_rad(input);
|
|
return *this;
|
|
}
|
|
|
|
DiffractionExperiment &DiffractionExperiment::PoniRot2_rad(float input) {
|
|
dataset.PoniRot2_rad(input);
|
|
return *this;
|
|
}
|
|
|
|
DiffractionExperiment &DiffractionExperiment::PoniRot3_rad(float input) {
|
|
dataset.PoniRot3_rad(input);
|
|
return *this;
|
|
}
|
|
|
|
float DiffractionExperiment::GetPoniRot1_rad() const {
|
|
return dataset.GetPoniRot1_rad();
|
|
}
|
|
|
|
float DiffractionExperiment::GetPoniRot2_rad() const {
|
|
return dataset.GetPoniRot2_rad();
|
|
}
|
|
|
|
float DiffractionExperiment::GetPoniRot3_rad() const {
|
|
return dataset.GetPoniRot3_rad();
|
|
}
|
|
|
|
GeomRefinementAlgorithmEnum DiffractionExperiment::GetGeomRefinementAlgorithm() const {
|
|
return indexing.GetGeomRefinementAlgorithm();
|
|
}
|
|
|
|
DiffractionExperiment &DiffractionExperiment::GeomRefinementAlgorithm(GeomRefinementAlgorithmEnum input) {
|
|
indexing.GeomRefinementAlgorithm(input);
|
|
return *this;
|
|
}
|
|
|
|
gemmi::CrystalSystem DiffractionExperiment::GetCrystalSystem() const {
|
|
auto sg = GetGemmiSpaceGroup();
|
|
if (!sg)
|
|
return gemmi::CrystalSystem::Monoclinic;
|
|
|
|
return sg->crystal_system();
|
|
}
|
|
|
|
std::string DiffractionExperiment::GetSpaceGroupName() const {
|
|
auto sg = GetGemmiSpaceGroup();
|
|
if (!sg)
|
|
return "";
|
|
return sg->short_name();
|
|
}
|
|
|
|
std::optional<gemmi::SpaceGroup> DiffractionExperiment::GetGemmiSpaceGroup() const {
|
|
auto sg = GetSpaceGroupNumber();
|
|
if (!sg)
|
|
return std::nullopt;
|
|
const gemmi::SpaceGroup *g = gemmi::find_spacegroup_by_number(sg.value());
|
|
if (g == nullptr)
|
|
return std::nullopt;
|
|
return *g;
|
|
}
|
|
|
|
char DiffractionExperiment::GetCentering() const {
|
|
auto sg = GetGemmiSpaceGroup();
|
|
if (!sg)
|
|
return 'P';
|
|
return sg->centring_type();
|
|
}
|
|
|
|
DiffractionExperiment &DiffractionExperiment::FluorescenceSpectrum(const XrayFluorescenceSpectrum &input) {
|
|
dataset.FluorescenceSpectrum(input);
|
|
return *this;
|
|
}
|
|
|
|
DiffractionExperiment &DiffractionExperiment::DetectIceRings(bool input) {
|
|
dataset.DetectIceRings(input);
|
|
return *this;
|
|
}
|
|
|
|
bool DiffractionExperiment::IsDetectIceRings() const {
|
|
return dataset.IsDetectIceRings();
|
|
}
|
|
|
|
const XrayFluorescenceSpectrum &DiffractionExperiment::GetFluorescenceSpectrum() const {
|
|
return dataset.GetFluorescenceSpectrum();
|
|
}
|
|
|
|
DarkMaskSettings DiffractionExperiment::GetDarkMaskSettings() const {
|
|
return dark_mask_settings;
|
|
}
|
|
|
|
DiffractionExperiment &DiffractionExperiment::ImportDarkMaskSettings(const DarkMaskSettings &input) {
|
|
dark_mask_settings = input;
|
|
return *this;
|
|
}
|
|
|
|
int64_t DiffractionExperiment::GetDarkMaskNumberOfFrames() const {
|
|
if (GetDetectorType() == DetectorType::DECTRIS)
|
|
return GetDarkMaskSettings().GetNumberOfFrames();
|
|
return 0;
|
|
}
|
|
|
|
bool DiffractionExperiment::IsRotationIndexing() const {
|
|
return GetGoniometer().has_value() && indexing.GetRotationIndexing();
|
|
}
|