Files
Jungfraujoch/common/DiffractionExperiment.cpp

1023 lines
34 KiB
C++

// Copyright (2019-2023) Paul Scherrer Institute
#include <cmath>
#include "NetworkAddressConvert.h"
#include "JFJochCompressor.h" // For ZSTD_USE_JFJOCH_RLE
#include "GitInfo.h"
#include "DiffractionExperiment.h"
#include "JFJochException.h"
#include "../compression/MaxCompressedSize.h"
#define check_max(param, val, max) if ((val) > (max)) throw JFJochException(JFJochExceptionCategory::InputParameterAboveMax, param)
#define check_min(param, val, min) if ((val) < (min)) throw JFJochException(JFJochExceptionCategory::InputParameterBelowMin, param)
DiffractionExperiment::DiffractionExperiment() : DiffractionExperiment(DetectorGeometry(8, 2))
{}
DiffractionExperiment::DiffractionExperiment(const DetectorSetup& det_setup) : detector(det_setup) {
dataset.photon_energy_keV = WVL_1A_IN_KEV;
dataset.detector_distance_mm = 100;
dataset.data_file_count = 1;
dataset.file_prefix = "test";
dataset.ntrigger = 1;
dataset.images_per_trigger = 1;
dataset.summation = 1;
dataset.fpga_pixel_output = FPGAPixelOutput::Auto;
dataset.space_group_number = 0; // not set
dataset.compression = CompressionAlgorithm::BSHUF_LZ4;
dataset.rad_int_polarization_corr = false;
dataset.rad_int_solid_angle_corr = false;
dataset.save_calibration = false;
internal_fpga_packet_generator = false;
debug_pixel_mask = false;
ndatastreams = 1;
frame_time = std::chrono::microseconds(MIN_FRAME_TIME_HALF_SPEED_IN_US);
count_time = std::chrono::microseconds(MIN_FRAME_TIME_HALF_SPEED_IN_US - READOUT_TIME_IN_US);
frame_time_pedestalG1G2 = std::chrono::microseconds(FRAME_TIME_PEDE_G1G2_IN_US);
mask_chip_edges = false;
mask_module_edges = false;
preview_period = std::chrono::microseconds(1000*1000); // 1s / 1 Hz
low_q = 0.1;
high_q = 5.0;
q_spacing = 0.05;
ipv4_base_addr = 0x0132010a;
git_sha1 = jfjoch_git_sha1();
git_date = jfjoch_git_date();
storage_cells = 1;
storage_cell_start = 15;
storage_cell_delay = std::chrono::nanoseconds(10*1000);
pedestal_g0_frames = 0;
pedestal_g1_frames = 0;
pedestal_g2_frames = 0;
Mode(DetectorMode::Conversion);
}
// setter functions
DiffractionExperiment &DiffractionExperiment::Detector(const DetectorSetup &input) {
detector = input;
return *this;
}
DiffractionExperiment &DiffractionExperiment::Mode(DetectorMode input) {
mode = input;
return *this;
}
DiffractionExperiment &DiffractionExperiment::DataStreams(int64_t input) {
check_max("Number of data streams", input, 16);
check_min("Number of data streams", input, 1);
ndatastreams = input;
return *this;
}
DiffractionExperiment &DiffractionExperiment::ImagesPerTrigger(int64_t input) {
check_max("Total number of images", input, 10*1000*1000);
check_min("Total number of images", input, 0);
dataset.images_per_trigger = input;
return *this;
}
DiffractionExperiment &DiffractionExperiment::NumTriggers(int64_t input) {
check_max("Total number of triggers", input, 10*1000*1000);
check_min("Total number of triggers", input, 1);
dataset.ntrigger = input;
return *this;
}
DiffractionExperiment &DiffractionExperiment::FrameTime(std::chrono::microseconds in_frame_time,
std::chrono::microseconds in_count_time) {
check_min("Frame time (us)", in_frame_time.count(), MIN_FRAME_TIME_FULL_SPEED_IN_US);
check_max("Frame time (us)", in_frame_time.count(), MAX_FRAME_TIME);
check_max("Count time (us)", in_count_time.count(), in_frame_time.count() - READOUT_TIME_IN_US);
if (in_count_time.count() != 0) {
check_min("Count time (us)", in_count_time.count(), MIN_COUNT_TIME_IN_US);
}
frame_time = in_frame_time;
if (in_count_time.count() == 0)
count_time = in_frame_time - std::chrono::microseconds(READOUT_TIME_IN_US);
else
count_time = in_count_time;
return *this;
}
DiffractionExperiment &DiffractionExperiment::PedestalG1G2FrameTime(std::chrono::microseconds input) {
check_min("Pedestal G1G2 frame time (us) ", input.count(), MIN_FRAME_TIME_FULL_SPEED_IN_US);
frame_time_pedestalG1G2 = input;
return *this;
}
DiffractionExperiment &DiffractionExperiment::PedestalG0Frames(int64_t input) {
check_min("Pedestal G0 frames", input, 0);
pedestal_g0_frames = input;
return *this;
}
DiffractionExperiment &DiffractionExperiment::PedestalG1Frames(int64_t input) {
check_min("Pedestal G1 frames", input, 0);
pedestal_g1_frames = input;
return *this;
}
DiffractionExperiment &DiffractionExperiment::PedestalG2Frames(int64_t input) {
check_min("Pedestal G2 frames", input, 0);
pedestal_g2_frames = input;
return *this;
}
DiffractionExperiment &DiffractionExperiment::PhotonEnergy_keV(float input) {
check_min("Energy (keV)", input, MIN_ENERGY);
check_max("Energy (keV)", input, MAX_ENERGY);
dataset.photon_energy_keV = input;
return *this;
}
DiffractionExperiment &DiffractionExperiment::BeamX_pxl(float input) {
dataset.beam_x_pxl = input;
return *this;
}
DiffractionExperiment &DiffractionExperiment::BeamY_pxl(float input) {
dataset.beam_y_pxl = input;
return *this;
}
DiffractionExperiment &DiffractionExperiment::DetectorDistance_mm(float input) {
check_min("Detector distance (mm)", input, 1);
dataset.detector_distance_mm = input;
return *this;
}
DiffractionExperiment &DiffractionExperiment::FilePrefix(std::string input) {
// File prefix with front slash is not allowed for security reasons
if (input.front() == '/')
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"Path cannot start with slash");
if (input.substr(0,3) == "../")
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"Path cannot start with ../");
if (input.find("/../") != std::string::npos)
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"Path cannot contain /../");
if ((input.find("_master.h5") == input.length() - 10) && (input.length() > 10))
dataset.file_prefix = input.substr(0, input.length() - 10);
else
dataset.file_prefix = input;
return *this;
}
DiffractionExperiment &DiffractionExperiment::DataFileCount(int64_t input) {
check_min("File count", input, 1);
check_max("File count", input, 1000);
dataset.data_file_count = input;
return *this;
}
DiffractionExperiment &DiffractionExperiment::UseInternalPacketGenerator(bool input) {
internal_fpga_packet_generator = input;
return *this;
}
DiffractionExperiment &DiffractionExperiment::IPv4BaseAddr(std::string input) {
ipv4_base_addr = IPv4AddressFromStr(input);
return *this;
}
DiffractionExperiment &DiffractionExperiment::MaskModuleEdges(bool input) {
mask_module_edges = input;
return *this;
}
DiffractionExperiment &DiffractionExperiment::Compression(CompressionAlgorithm input) {
dataset.compression = input;
return *this;
}
DiffractionExperiment &DiffractionExperiment::MaskChipEdges(bool input) {
mask_chip_edges = input;
return *this;
}
DiffractionExperiment& DiffractionExperiment::LowResForRadialInt_A(float input) {
check_min("Low Resolution for radial integration", input, 0.1);
check_max("Low Resolution for radial integration", input, 500.0);
low_q = 2 * static_cast<float>(M_PI) / input;
return *this;
}
DiffractionExperiment& DiffractionExperiment::HighResForRadialInt_A(float input) {
check_min("High Resolution for radial integration", input, 0.1);
check_max("High Resolution for radial integration", input, 500.0);
high_q = 2 * static_cast<float>(M_PI) / input;
return *this;
}
DiffractionExperiment& DiffractionExperiment::LowQForRadialInt_recipA(float input) {
check_min("Low Q for radial integration", input, 0.001);
check_max("Low Q for radial integration", input, 10.0);
low_q = input;
return *this;
}
DiffractionExperiment& DiffractionExperiment::HighQForRadialInt_recipA(float input) {
check_min("High Q for radial integration", input, 0.001);
check_max("High Q for radial integration", input, 10.0);
high_q = input;
return *this;
}
DiffractionExperiment& DiffractionExperiment::QSpacingForRadialInt_recipA(float input) {
check_min("Q spacing for radial integration", input, 0.01);
q_spacing = input;
return *this;
}
DiffractionExperiment &DiffractionExperiment::SetUnitCell(const UnitCell &cell) {
dataset.unit_cell = cell;
return *this;
}
DiffractionExperiment &DiffractionExperiment::SetUnitCell() {
dataset.unit_cell.reset();
return *this;
}
DiffractionExperiment &DiffractionExperiment::PreviewPeriod(std::chrono::microseconds input) {
check_min("Preview image generation period", input.count(), 0);
preview_period = input;
return *this;
}
DiffractionExperiment &DiffractionExperiment::SpaceGroupNumber(int64_t input) {
check_min("Space group number", input, 0);
check_max("Space group number", input, 230);
dataset.space_group_number = input;
return *this;
}
DiffractionExperiment &DiffractionExperiment::StorageCells(int64_t input) {
check_min("Storage cell number", input, 1);
check_max("Storage cell number", input, 16);
//if ((input != 1) && (input != 2) && (input != 4) && (input != 8) && (input != 16))
// throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
// "Storage cell count invalid, must be power of 2");
storage_cells = input;
return *this;
}
DiffractionExperiment &DiffractionExperiment::StorageCellStart(int64_t input) {
check_min("Start storage cell", input, 0);
check_max("Start storage cell", input, 15);
storage_cell_start = input;
return *this;
}
DiffractionExperiment &DiffractionExperiment::SampleName(std::string input) {
dataset.sample_name = input;
return *this;
}
// getter functions
int64_t DiffractionExperiment::GetNumTriggers() const {
switch (GetDetectorMode()) {
case DetectorMode::Conversion:
case DetectorMode::Raw:
return dataset.ntrigger;
case DetectorMode::PedestalG0:
if (GetPedestalWithExternalTrigger())
return pedestal_g0_frames;
else
return 1;
case DetectorMode::PedestalG1:
if (GetPedestalWithExternalTrigger())
return pedestal_g1_frames;
else
return 1;
case DetectorMode::PedestalG2:
if (GetPedestalWithExternalTrigger())
return pedestal_g2_frames;
else
return 1;
default:
return 1;
}
}
DetectorMode DiffractionExperiment::GetDetectorMode() const {
return mode;
}
std::chrono::microseconds DiffractionExperiment::GetFrameTime() const {
switch (GetDetectorMode()) {
case DetectorMode::PedestalG1:
case DetectorMode::PedestalG2:
return frame_time_pedestalG1G2;
case DetectorMode::Conversion:
case DetectorMode::Raw:
case DetectorMode::PedestalG0:
default:
return frame_time;
}
}
std::chrono::microseconds DiffractionExperiment::GetImageTime() const {
switch (GetDetectorMode()) {
case DetectorMode::PedestalG1:
case DetectorMode::PedestalG2:
return frame_time_pedestalG1G2;
case DetectorMode::Conversion:
case DetectorMode::Raw:
return GetFrameTime() * GetSummation();
case DetectorMode::PedestalG0:
default:
return GetFrameTime();
}
}
int64_t DiffractionExperiment::GetImageNum() const {
switch (GetDetectorMode()) {
case DetectorMode::Conversion:
case DetectorMode::Raw:
return GetImageNumPerTrigger() * GetNumTriggers();
case DetectorMode::PedestalG0:
case DetectorMode::PedestalG1:
case DetectorMode::PedestalG2:
default:
return 0;
}
}
int64_t DiffractionExperiment::GetImageNumPerTrigger() const {
switch (GetDetectorMode()) {
case DetectorMode::Conversion:
case DetectorMode::Raw:
if (GetStorageCellNumber() > 1)
return GetStorageCellNumber();
return GetFrameNumPerTrigger() / GetSummation();
case DetectorMode::PedestalG0:
case DetectorMode::PedestalG1:
case DetectorMode::PedestalG2:
default:
return 0;
}
}
int64_t DiffractionExperiment::GetFrameNum() const {
return GetFrameNumPerTrigger() * GetNumTriggers();
}
int64_t DiffractionExperiment::GetFrameNumPerTrigger() const {
switch (GetDetectorMode()) {
case DetectorMode::Conversion:
case DetectorMode::Raw:
if (GetStorageCellNumber() > 1)
return GetStorageCellNumber();
else
return dataset.images_per_trigger * GetSummation();
case DetectorMode::PedestalG0:
if (GetPedestalWithExternalTrigger())
return GetStorageCellNumber();
return pedestal_g0_frames * GetStorageCellNumber();
case DetectorMode::PedestalG1:
if (GetPedestalWithExternalTrigger())
return GetStorageCellNumber();
return pedestal_g1_frames * GetStorageCellNumber();
case DetectorMode::PedestalG2:
if (GetPedestalWithExternalTrigger())
return GetStorageCellNumber();
return pedestal_g2_frames * GetStorageCellNumber();
default:
return 0;
}
}
std::chrono::microseconds DiffractionExperiment::GetFrameCountTime() const {
return count_time;
}
std::chrono::microseconds DiffractionExperiment::GetImageCountTime() const {
return GetFrameCountTime() * GetSummation();
}
int64_t DiffractionExperiment::GetPedestalG0Frames() const {
return pedestal_g0_frames;
}
int64_t DiffractionExperiment::GetPedestalG1Frames() const {
return pedestal_g1_frames;
}
int64_t DiffractionExperiment::GetPedestalG2Frames() const {
return pedestal_g2_frames;
}
float DiffractionExperiment::GetPhotonEnergy_keV() const {
return dataset.photon_energy_keV;
}
float DiffractionExperiment::GetWavelength_A() const {
return WVL_1A_IN_KEV / dataset.photon_energy_keV;
}
float DiffractionExperiment::GetBeamX_pxl() const {
return dataset.beam_x_pxl;
}
float DiffractionExperiment::GetBeamY_pxl() const {
return dataset.beam_y_pxl;
}
float DiffractionExperiment::GetDetectorDistance_mm() const {
return dataset.detector_distance_mm;
}
Coord DiffractionExperiment::GetScatteringVector() const {
return {0,0,dataset.photon_energy_keV / WVL_1A_IN_KEV};
}
std::string DiffractionExperiment::GetFilePrefix() const {
return dataset.file_prefix;
}
int64_t DiffractionExperiment::GetDataFileCount() const {
return dataset.data_file_count;
}
CompressionAlgorithm DiffractionExperiment::GetCompressionAlgorithm() const {
if (GetDetectorMode() != DetectorMode::Conversion)
// Compression not supported for raw data and pedestal
return CompressionAlgorithm::NO_COMPRESSION;
return dataset.compression;
}
int64_t DiffractionExperiment::GetPixelDepth() const {
switch (GetFPGAOutputMode()) {
case FPGAPixelOutput::Int16:
case FPGAPixelOutput::Uint16:
return 2;
default:
case FPGAPixelOutput::Auto:
if (GetSummation() > 2)
return 4;
else
return 2;
case FPGAPixelOutput::Int32:
case FPGAPixelOutput::Uint32:
return 4;
}
}
bool DiffractionExperiment::IsPixelSigned() const {
switch (GetFPGAOutputMode()) {
case FPGAPixelOutput::Int16:
case FPGAPixelOutput::Int32:
return true;
case FPGAPixelOutput::Uint16:
case FPGAPixelOutput::Uint32:
return false;
default:
case FPGAPixelOutput::Auto:
if (GetDetectorMode() == DetectorMode::Conversion)
return true;
else
return false;
}
}
int64_t DiffractionExperiment::GetDataStreamsNum() const {
return std::min<int64_t>(ndatastreams, detector.GetModulesNum());
}
int64_t DiffractionExperiment::GetModulesNum(uint16_t data_stream) const {
if (data_stream == TASK_NO_DATA_STREAM)
return detector.GetModulesNum();
if (data_stream >= GetDataStreamsNum())
throw JFJochException(JFJochExceptionCategory::ArrayOutOfBounds, "Non existing data stream");
return (detector.GetModulesNum() + (GetDataStreamsNum() - 1) - data_stream) / GetDataStreamsNum();
}
int64_t DiffractionExperiment::GetFirstModuleOfDataStream(uint16_t data_stream) const {
if (data_stream >= GetDataStreamsNum())
throw JFJochException(JFJochExceptionCategory::ArrayOutOfBounds, "Non exisiting data stream");
int64_t val = 0;
for (int i = 0; i < data_stream; i++) val += GetModulesNum(i);
return val;
}
int64_t DiffractionExperiment::GetMaxCompressedSize() const {
return MaxCompressedSize(GetCompressionAlgorithm(), GetPixelsNum(), GetPixelDepth());
}
int64_t DiffractionExperiment::GetPixelsNum() const {
return GetXPixelsNum() * GetYPixelsNum();
}
int64_t DiffractionExperiment::GetXPixelsNum() const {
if (GetDetectorMode() != DetectorMode::Conversion)
return RAW_MODULE_COLS;
else
return detector.GetGeometry().GetWidth();
}
int64_t DiffractionExperiment::GetYPixelsNum() const {
if (GetDetectorMode() != DetectorMode::Conversion)
return RAW_MODULE_LINES * GetModulesNum();
else
return detector.GetGeometry().GetHeight();
}
int64_t DiffractionExperiment::GetPixel0OfModule(uint16_t module_number) const {
if (module_number >= GetModulesNum())
throw JFJochException(JFJochExceptionCategory::ArrayOutOfBounds, "Module number out of bounds");
if (GetDetectorMode() != DetectorMode::Conversion)
return RAW_MODULE_SIZE * module_number;
else
return detector.GetGeometry().GetPixel0(module_number);
}
int64_t DiffractionExperiment::GetOverflow() const {
if (GetPixelDepth() == 2)
return INT16_MAX;
else
return INT32_MAX;
}
int64_t DiffractionExperiment::GetUnderflow() const {
if (GetPixelDepth() == 2)
return INT16_MIN;
else
return INT32_MIN;
}
std::chrono::microseconds DiffractionExperiment::GetPreviewPeriod() const {
return preview_period;
}
int64_t DiffractionExperiment::GetPreviewStride() const {
return GetPreviewStride(GetPreviewPeriod());
}
int64_t DiffractionExperiment::GetSpotFindingBin() const {
if (GetImageTime().count() >= 200*1000)
return 1;
else
return 200*1000 / GetImageTime().count(); // 1 bin = 1 second
}
int64_t DiffractionExperiment::GetPreviewStride(std::chrono::microseconds period) const {
switch (GetDetectorMode()) {
case DetectorMode::Conversion:
return CalculateStride(GetImageTime(), period);
default:
return 0;
}
}
bool DiffractionExperiment::IsUsingInternalPacketGen() const {
return internal_fpga_packet_generator;
}
uint32_t DiffractionExperiment::GetSrcIPv4Address(uint32_t data_stream, uint32_t half_module) const {
if (data_stream >= GetDataStreamsNum())
throw JFJochException(JFJochExceptionCategory::ArrayOutOfBounds, "Non existing data stream");
if (half_module >= 2 * GetModulesNum(data_stream))
throw JFJochException(JFJochExceptionCategory::ArrayOutOfBounds, "Non existing module");
uint32_t host = half_module + 2 * GetFirstModuleOfDataStream(data_stream);
return ipv4_base_addr + (host << 24);
}
bool DiffractionExperiment::CheckGitSha1Consistent() const {
return (git_sha1 == jfjoch_git_sha1());
}
std::string DiffractionExperiment::CheckGitSha1Msg() const {
if (git_sha1 == jfjoch_git_sha1())
return "";
else {
return "Local component git repo is rev. " + jfjoch_git_sha1().substr(0,6) + " (" + jfjoch_git_date() +") remote component repo is rev. "
+ git_sha1.substr(0,6) + " (" + git_date + ")";
}
}
bool DiffractionExperiment::GetMaskModuleEdges() const {
return mask_module_edges;
}
bool DiffractionExperiment::GetMaskChipEdges() const {
return mask_chip_edges;
}
UnitCell DiffractionExperiment::GetUnitCell() const {
if (dataset.unit_cell.has_value())
return dataset.unit_cell.value();
else
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Cannot return empty unit cell");
}
bool DiffractionExperiment::HasUnitCell() const {
return dataset.unit_cell.has_value();
}
Coord DiffractionExperiment::LabCoord(float detector_x, float detector_y) const {
// Assumes planar detector, 90 deg towards beam
return {(detector_x - GetBeamX_pxl()) * GetPixelSize_mm() ,
(detector_y - GetBeamY_pxl()) * GetPixelSize_mm() ,
GetDetectorDistance_mm()};
}
int64_t DiffractionExperiment::GetSpaceGroupNumber() const {
return dataset.space_group_number;
}
int64_t DiffractionExperiment::GetStorageCellNumber() const {
switch (GetDetectorMode()) {
case DetectorMode::PedestalG1:
case DetectorMode::PedestalG2:
if (storage_cells > 1)
return 2;
else
return 1;
default:
return storage_cells;
}
}
int64_t DiffractionExperiment::GetStorageCellStart() const {
return storage_cell_start;
}
float DiffractionExperiment::GetLowQForRadialInt_recipA() const {
return low_q;
}
float DiffractionExperiment::GetHighQForRadialInt_recipA() const {
return high_q;
}
float DiffractionExperiment::GetQSpacingForRadialInt_recipA() const {
return q_spacing;
}
int64_t DiffractionExperiment::GetMaxSpotCount() const {
return max_spot_count;
}
std::string DiffractionExperiment::GetSampleName() const {
return dataset.sample_name;
}
// Create ProtoBuf structures
DiffractionExperiment::operator JFJochProtoBuf::DetectorInput() const {
JFJochProtoBuf::DetectorInput ret;
ret.set_modules_num(GetModulesNum());
switch (GetDetectorMode()) {
case DetectorMode::Conversion:
ret.set_mode(JFJochProtoBuf::CONVERSION);
break;
case DetectorMode::Raw:
ret.set_mode(JFJochProtoBuf::RAW);
break;
case DetectorMode::PedestalG0:
ret.set_mode(JFJochProtoBuf::PEDESTAL_G0);
break;
case DetectorMode::PedestalG1:
ret.set_mode(JFJochProtoBuf::PEDESTAL_G1);
break;
case DetectorMode::PedestalG2:
ret.set_mode(JFJochProtoBuf::PEDESTAL_G2);
break;
}
if (GetNumTriggers() == 1) {
ret.set_num_frames(GetFrameNumPerTrigger() + DELAY_FRAMES_STOP_AND_QUIT);
ret.set_num_triggers(1);
} else {
// More than 1 trigger - detector needs one trigger or few more trigger
if (GetStorageCellNumber() > 1)
ret.set_num_frames(1);
else
ret.set_num_frames(GetFrameNumPerTrigger());
if (GetFrameNumPerTrigger() < DELAY_FRAMES_STOP_AND_QUIT)
ret.set_num_triggers(GetNumTriggers() + DELAY_FRAMES_STOP_AND_QUIT);
else
ret.set_num_triggers(GetNumTriggers() + 1);
}
ret.set_storage_cell_start(GetStorageCellStart());
ret.set_storage_cell_number(GetStorageCellNumber());
ret.set_storage_cell_delay_ns(GetStorageCellDelay().count());
if (GetStorageCellNumber() > 1) {
ret.set_period_us((GetFrameTime().count() +10) * GetStorageCellNumber());
} else
ret.set_period_us(GetFrameTime().count());
ret.set_count_time_us(GetFrameCountTime().count());
return ret;
}
JFJochProtoBuf::DetectorConfig DiffractionExperiment::DetectorConfig(const std::vector<AcquisitionDeviceNetConfig> &net_config) const {
JFJochProtoBuf::DetectorConfig ret;
if (net_config.size() < GetDataStreamsNum())
throw JFJochException(JFJochExceptionCategory::ArrayOutOfBounds,
"Number of FPGA boards in the receiver is less then necessary");
if (!detector.GetDetectorModuleHostname().empty() && (detector.GetDetectorModuleHostname().size() != GetModulesNum()))
throw JFJochException(JFJochExceptionCategory::ArrayOutOfBounds,
"Inconsistent number of modules and detector module host names");
if (!detector.GetDetectorModuleHostname().empty())
*ret.mutable_module_hostname() = {detector.GetDetectorModuleHostname().begin(),
detector.GetDetectorModuleHostname().end()};
ret.set_udp_interface_count(detector.GetUDPInterfaceCount());
for (int d = 0; d < GetDataStreamsNum(); d++) {
for (int m = 0; m < GetModulesNum(d); m++) {
auto mod_cfg = ret.add_modules();
mod_cfg->set_udp_dest_port_1(net_config[d].udp_port);
mod_cfg->set_udp_dest_port_2(net_config[d].udp_port);
mod_cfg->set_ipv4_src_addr_1(IPv4AddressToStr(GetSrcIPv4Address(d, 2 * m)));
mod_cfg->set_ipv4_src_addr_2(IPv4AddressToStr(GetSrcIPv4Address(d, 2 * m + 1)));
mod_cfg->set_ipv4_dest_addr_1(net_config[d].ipv4_addr);
mod_cfg->set_ipv4_dest_addr_2(net_config[d].ipv4_addr);
mod_cfg->set_mac_addr_dest_1(net_config[d].mac_addr);
mod_cfg->set_mac_addr_dest_2(net_config[d].mac_addr);
mod_cfg->set_module_id_in_data_stream(m);
}
}
return ret;
}
void DiffractionExperiment::CheckDataProcessingSettings(const DataProcessingSettings &settings) {
check_min("Signal to noise threshold", settings.signal_to_noise_threshold, 1);
check_min("Photon count threshold", settings.photon_count_threshold, 0);
check_min("Minimum pixels per spot", settings.min_pix_per_spot, 1);
check_min("Maximum pixels per spot", settings.max_pix_per_spot, settings.min_pix_per_spot + 1);
check_min("Local background size", settings.local_bkg_size, 2);
check_max("Local background size", settings.local_bkg_size, 7);
if (settings.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("Background estimate lowQ", settings.bkg_estimate_low_q, 0.0);
check_min("Background estimate highQ", settings.bkg_estimate_high_q, settings.bkg_estimate_low_q);
}
DataProcessingSettings DiffractionExperiment::DefaultDataProcessingSettings() {
DataProcessingSettings ret{};
ret.local_bkg_size = 5;
ret.signal_to_noise_threshold = 3;
ret.photon_count_threshold = 16;
ret.min_pix_per_spot = 1;
ret.max_pix_per_spot = 50;
ret.bkg_estimate_low_q = 2 * M_PI / 5.0;
ret.bkg_estimate_high_q= 2 * M_PI / 3.0;
return ret;
}
void DiffractionExperiment::FillMessage(StartMessage &message) const {
message.data_file_count = GetDataFileCount();
message.beam_center_x = GetBeamX_pxl();
message.beam_center_y = GetBeamY_pxl();
message.detector_distance = GetDetectorDistance_mm() * 1e-3f;
message.incident_wavelength = GetWavelength_A();
message.incident_energy = GetPhotonEnergy_keV() * 1e3f;
message.image_size_x = GetXPixelsNum();
message.image_size_y = GetYPixelsNum();
message.min_value = GetUnderflow();
message.saturation_value = GetOverflow();
message.frame_time = GetImageTime().count() * 1e-6f;
message.count_time = GetImageCountTime().count() * 1e-6f;
message.number_of_images = GetImageNum();
message.pixel_size_x = GetPixelSize_mm() * 1e-3f;
message.pixel_size_y = GetPixelSize_mm() * 1e-3f;
message.sensor_material = SENSOR_MATERIAL;
message.sensor_thickness = SENSOR_THICKNESS_IN_UM * 1e-6f;
message.compression_algorithm = GetCompressionAlgorithm();
message.compression_block_size = JFJochBitShuffleCompressor::DefaultBlockSize;
message.pixel_bit_depth = GetPixelDepth() * 8;
message.storage_cell_number = GetStorageCellNumber();
message.storage_cell_delay_ns = GetStorageCellDelay().count();
message.file_prefix = GetFilePrefix();
message.pixel_signed = IsPixelSigned();
message.sample_name = GetSampleName();
message.max_spot_count = GetMaxSpotCount();
message.pixel_mask_enabled = GetApplyPixelMaskInFPGA();
message.detector_description = GetDetectorDescription();
message.space_group_number = GetSpaceGroupNumber();
if (HasUnitCell()) {
auto uc = GetUnitCell();
message.unit_cell[0] = uc.a;
message.unit_cell[1] = uc.b;
message.unit_cell[2] = uc.c;
message.unit_cell[3] = uc.alpha;
message.unit_cell[4] = uc.beta;
message.unit_cell[5] = uc.gamma;
} else {
message.unit_cell[0] = 0.0;
}
message.detector_translation[0] = 0.0f;
message.detector_translation[1] = 0.0f;
message.detector_translation[2] = GetDetectorDistance_mm() * 1e-3f;
message.source_name = GetSourceName();
message.source_name_short = GetSourceNameShort();
message.instrument_name = GetInstrumentName();
message.instrument_name_short = GetInstrumentNameShort();
message.summation = GetSummation();
}
DiffractionExperiment &DiffractionExperiment::ApplyPixelMaskInFPGA(bool input) {
debug_pixel_mask = !input;
return *this;
}
bool DiffractionExperiment::GetApplyPixelMaskInFPGA() const {
if (GetDetectorMode() == DetectorMode::Conversion)
return !debug_pixel_mask;
else
return false;
}
float DiffractionExperiment::GetPixelSize_mm() const {
return detector.GetPixelSize_mm();
}
DiffractionExperiment &DiffractionExperiment::SourceName(std::string input) {
source_name = input;
return *this;
}
DiffractionExperiment &DiffractionExperiment::SourceNameShort(std::string input) {
source_name_short = input;
return *this;
}
DiffractionExperiment &DiffractionExperiment::InstrumentName(std::string input) {
instrument_name = input;
return *this;
}
DiffractionExperiment &DiffractionExperiment::InstrumentNameShort(std::string input) {
instrument_name_short = input;
return *this;
}
std::string DiffractionExperiment::GetSourceName() const {
return source_name;
}
std::string DiffractionExperiment::GetSourceNameShort() const {
return source_name_short;
}
std::string DiffractionExperiment::GetInstrumentName() const {
return instrument_name;
}
std::string DiffractionExperiment::GetInstrumentNameShort() const {
return instrument_name_short;
}
int64_t DiffractionExperiment::GetModuleFastDirectionStep(uint16_t module_number) const {
if (module_number >= GetModulesNum())
throw JFJochException(JFJochExceptionCategory::ArrayOutOfBounds, "Module number out of bounds");
return detector.GetGeometry().GetFastDirectionStep(module_number);
}
int64_t DiffractionExperiment::GetModuleSlowDirectionStep(uint16_t module_number) const {
if (module_number >= GetModulesNum())
throw JFJochException(JFJochExceptionCategory::ArrayOutOfBounds, "Module number out of bounds");
return detector.GetGeometry().GetSlowDirectionStep(module_number);
}
void DiffractionExperiment::GetDetectorModuleHostname(std::vector<std::string> &output) const {
for (const auto &iter: detector.GetDetectorModuleHostname())
output.push_back(iter);
}
std::string DiffractionExperiment::GetDetectorDescription() const {
return detector.GetDescription();
}
bool DiffractionExperiment::GetPedestalWithExternalTrigger() const {
return (GetStorageCellNumber() > 1);
}
DiffractionExperiment &DiffractionExperiment::ApplySolidAngleCorr(bool input) {
dataset.rad_int_solid_angle_corr = input;
return *this;
}
DiffractionExperiment &DiffractionExperiment::ApplyPolarizationCorr(bool input) {
dataset.rad_int_polarization_corr = input;
return *this;
}
DiffractionExperiment &DiffractionExperiment::PolarizationFactor(float input) {
dataset.rad_int_polarization_factor = input;
return *this;
}
bool DiffractionExperiment::GetApplySolidAngleCorr() const {
return dataset.rad_int_solid_angle_corr;
}
bool DiffractionExperiment::GetApplyPolarizationCorr() const {
return dataset.rad_int_polarization_corr;
}
float DiffractionExperiment::GetPolarizationFactor() const {
return dataset.rad_int_polarization_factor;
}
DiffractionExperiment &DiffractionExperiment::SaveCalibration(bool input) {
dataset.save_calibration = input;
return *this;
}
bool DiffractionExperiment::GetSaveCalibration() const {
return dataset.save_calibration;
}
DiffractionExperiment &DiffractionExperiment::StorageCellDelay(std::chrono::nanoseconds input) {
check_min("Storage cell delay [ns]", input.count(), MIN_STORAGE_CELL_DELAY_IN_NS);
storage_cell_delay = input;
return *this;
}
std::chrono::nanoseconds DiffractionExperiment::GetStorageCellDelay() const {
return storage_cell_delay;
}
DiffractionExperiment &DiffractionExperiment::Summation(int64_t input) {
check_min("Summation", input, 1);
check_max("Summation", input, MAX_FPGA_SUMMATION);
dataset.summation = input;
return *this;
}
int64_t DiffractionExperiment::GetSummation() const {
switch (GetDetectorMode()) {
case DetectorMode::PedestalG0:
case DetectorMode::PedestalG1:
case DetectorMode::PedestalG2:
return 1;
default:
case DetectorMode::Conversion:
case DetectorMode::Raw:
// FPGA summation for raw data makes zero sense - but it is still available as a means for debug, etc.
return dataset.summation;
}
}
DiffractionExperiment &DiffractionExperiment::FPGAOutputMode(FPGAPixelOutput input) {
dataset.fpga_pixel_output = input;
return *this;
}
FPGAPixelOutput DiffractionExperiment::GetFPGAOutputMode() const {
return dataset.fpga_pixel_output;
}