Files
Jungfraujoch/broker/OpenAPIConvert.cpp
T
leonarski_fandClaude Opus 5 e381d2fd50
Build Packages / build:viewer-tgz:cpu (push) Successful in 12m14s
Build Packages / build:rugnux:aarch64 (cross) (push) Successful in 8m24s
Build Packages / build:rpm (rocky8_nocuda) (push) Failing after 5m36s
Build Packages / build:rugnux-tgz (x86_64) (push) Successful in 12m55s
Build Packages / build:viewer-tgz:cuda (push) Successful in 14m11s
Build Packages / build:rpm (rocky9_nocuda) (push) Failing after 5m6s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Failing after 4m11s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Failing after 3m58s
Build Packages / build:rpm (rocky8) (push) Failing after 3m22s
Build Packages / build:rpm (rocky9_sls9) (push) Failing after 4m12s
Build Packages / build:rpm (rocky9) (push) Failing after 3m20s
Build Packages / build:rpm (rocky8_sls9) (push) Failing after 4m23s
Build Packages / build:rpm (ubuntu2204) (push) Failing after 3m36s
Build Packages / build:windows:nocuda (push) Successful in 17m9s
Build Packages / build:rpm (ubuntu2404) (push) Failing after 4m8s
Build Packages / Generate python client (push) Successful in 35s
Build Packages / Build documentation (push) Successful in 52s
Build Packages / Create release (push) Skipped
Build Packages / build:windows:cuda (push) Successful in 19m32s
Build Packages / XDS test (durin plugin) (push) Successful in 7m22s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 7m28s
Build Packages / XDS test (neggia plugin) (push) Successful in 7m15s
Build Packages / build:rugnux:windows (push) Successful in 12m10s
Build Packages / DIALS test (push) Successful in 17m32s
Build Packages / Unit tests (push) Successful in 1h16m29s
grid scan: review fixes - the ice channel sees its own spots, and a needle is not mirrored
Two independent reviews of the merged grid-scan work. The findings that changed
behaviour:

The ice score's spot channel was fed a list the spot budget had already stripped.
FilterSpotsByCount orders ice-band spots LAST when indexing is not to use them, so on
a frame with more spots than the budget the ice spots are the first discarded - and
the channel that exists for "ice arrives as discrete spots and leaves the radial
profile flat" then read zero on exactly the frames it was written for. Probed at 3000
spots with 1200 on the hexagonal radii and a budget of 1000: 1.000 before the cap,
0.000 after. IceScore now takes d-spacings and is handed the list from before the cap.

The viewer scaled the crystal box by the SIGNED grid step, where every other consumer
takes the magnitude. On a negative step that mirrors the box - +30 deg drawn as -30 -
and hands QRectF a negative width.

rugnux --mode raster never put its settings on the experiment, so the indexing switch
was read at its default while a deprecated per-run flag did the actual work; and
RugnuxCommandLine emitted no --mode for Grid, so a raster job copied to a cluster ran
the default mx - indexing, integrating and merging every cell of the raster.

res_A is NaN where nothing in a blob measured a resolution, and nlohmann writes NaN as
null, which the schema and the generated clients both reject. It is now left unset.

The broker's configuration example named a key that does not exist (calibration, not
calibration_settings); nlohmann ignores unknown keys, so a user copying it got a
silently ignored block. The changelog had lost the rc.166 heading and 21 rc.167
entries to a bad edit of mine, and three entries had been filed under rc.166.

Also: a warning where mode Grid meets a dataset with no grid scan, which was silent
and indistinguishable from finding nothing; the viewer combo still named the retired
ice_ring_score; and the claim that growth "cannot invent a crystal" was too strong -
it cannot start a patch, but the cell count is read over the grown patch, so it does
decide which patches pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EFEJG6WBQv8th4UJFNe53N
2026-09-08 09:04:52 +02:00

1484 lines
66 KiB
C++

// SPDX-FileCopyrightText: 2024 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
// SPDX-License-Identifier: GPL-3.0-only
#include "../common/JFJochMath.h"
#include "../common/GitInfo.h"
#include "OpenAPIConvert.h"
// From https://en.cppreference.com/w/cpp/string/byte/tolower
std::string str_tolower(std::string s) {
std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c){ return std::tolower(c); });
return s;
}
SpotFindingSettings Convert(const org::openapitools::server::model::Spot_finding_settings &input) {
SpotFindingSettings ret{};
ret.signal_to_noise_threshold = input.getSignalToNoiseThreshold();
ret.photon_count_threshold = input.getPhotonCountThreshold();
ret.min_pix_per_spot = input.getMinPixPerSpot();
ret.max_pix_per_spot = input.getMaxPixPerSpot();
// Both limits are optional and unset means "no limit at that end". A value of 0 has meant the same
// thing since rc.161 and clients still send it that way, so fold it into the unset case here - the
// analysis code then has exactly one spelling for "no limit" and no zero to special-case.
if (input.highResolutionLimitIsSet() && input.getHighResolutionLimit() > 0)
ret.high_resolution_limit = input.getHighResolutionLimit();
if (input.lowResolutionLimitIsSet() && input.getLowResolutionLimit() > 0)
ret.low_resolution_limit = input.getLowResolutionLimit();
ret.enable = input.isEnable();
ret.indexing = input.isIndexing();
ret.quick_integration = input.isQuickIntegration();
ret.cutoff_spot_count_low_res = input.getHighResolutionLimitForSpotCountLowRes();
ret.ice_ring_width_Q_recipA = input.getIceRingWidthQRecipA();
if (input.highResGapQRecipAIsSet())
ret.high_res_gap_Q_recipA = input.getHighResGapQRecipA();
if (input.adaptiveThresholdIsSet())
ret.adaptive_threshold = input.isAdaptiveThreshold();
if (input.falsePixelsPerFrameIsSet())
ret.false_pixels_per_frame = input.getFalsePixelsPerFrame();
return ret;
}
org::openapitools::server::model::Spot_finding_settings Convert(const SpotFindingSettings &input) {
org::openapitools::server::model::Spot_finding_settings ret;
ret.setSignalToNoiseThreshold(input.signal_to_noise_threshold);
ret.setPhotonCountThreshold(input.photon_count_threshold);
ret.setMinPixPerSpot(input.min_pix_per_spot.value_or(2));
ret.setMaxPixPerSpot(input.max_pix_per_spot);
if (input.high_resolution_limit.has_value())
ret.setHighResolutionLimit(input.high_resolution_limit.value());
if (input.low_resolution_limit.has_value())
ret.setLowResolutionLimit(input.low_resolution_limit.value());
ret.setEnable(input.enable);
ret.setIndexing(input.indexing);
ret.setHighResolutionLimitForSpotCountLowRes(input.cutoff_spot_count_low_res);
ret.setQuickIntegration(input.quick_integration);
ret.setIceRingWidthQRecipA(input.ice_ring_width_Q_recipA);
if (input.high_res_gap_Q_recipA.has_value())
ret.setHighResGapQRecipA(input.high_res_gap_Q_recipA.value());
ret.setAdaptiveThreshold(input.adaptive_threshold);
ret.setFalsePixelsPerFrame(input.false_pixels_per_frame);
return ret;
}
org::openapitools::server::model::Measurement_statistics Convert(const MeasurementStatistics &input) {
org::openapitools::server::model::Measurement_statistics ret{};
if (!input.file_prefix.empty())
ret.setFilePrefix(input.file_prefix);
ret.setExperimentGroup(input.experiment_group);
ret.setImagesExpected(input.images_expected);
ret.setImagesCollected(input.images_collected);
ret.setImagesSent(input.images_sent);
ret.setImagesDiscardedLossyCompression(input.images_skipped);
ret.setMaxImageNumberSent(input.max_image_number_sent);
if (input.collection_efficiency)
ret.setCollectionEfficiency(input.collection_efficiency.value());
if (input.compression_ratio)
ret.setCompressionRatio(input.compression_ratio.value());
ret.setCancelled(input.cancelled);
if (input.max_receive_delay)
ret.setMaxReceiverDelay(input.max_receive_delay.value());
ret.setDetectorWidth(input.detector_width);
ret.setDetectorHeight(input.detector_height);
ret.setDetectorPixelDepth(input.detector_pixel_depth);
if (input.roi_beam_npixel)
ret.setRoiBeamPixels(input.roi_beam_npixel.value());
if (input.roi_beam_sum)
ret.setRoiBeamSum(input.roi_beam_sum.value());
if (input.error_pixels)
ret.setErrorPixels(input.error_pixels.value());
if (input.saturated_pixels)
ret.setSaturatedPixels(input.saturated_pixels.value());
if (input.indexing_rate)
ret.setIndexingRate(input.indexing_rate.value());
if (input.bkg_estimate)
ret.setBkgEstimate(input.bkg_estimate.value());
ret.setUnitCell(input.unit_cell);
ret.setRunNumber(input.run_number);
if (input.images_written)
ret.setImagesWritten(input.images_written.value());
return ret;
}
DetectorTiming Convert(const org::openapitools::server::model::Detector_timing& input) {
switch (input.getValue()) {
case org::openapitools::server::model::Detector_timing::eDetector_timing::AUTO:
return DetectorTiming::Auto;
case org::openapitools::server::model::Detector_timing::eDetector_timing::TRIGGER:
return DetectorTiming::Trigger;
case org::openapitools::server::model::Detector_timing::eDetector_timing::BURST:
return DetectorTiming::Burst;
case org::openapitools::server::model::Detector_timing::eDetector_timing::GATED:
return DetectorTiming::Gated;
default:
case org::openapitools::server::model::Detector_timing::eDetector_timing::INVALID_VALUE_OPENAPI_GENERATED:
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "invalid input");
}
}
org::openapitools::server::model::Detector_timing Convert(DetectorTiming input) {
org::openapitools::server::model::Detector_timing val;
switch (input) {
case DetectorTiming::Auto:
val.setValue(org::openapitools::server::model::Detector_timing::eDetector_timing::AUTO);
break;
case DetectorTiming::Trigger:
val.setValue(org::openapitools::server::model::Detector_timing::eDetector_timing::TRIGGER);
break;
case DetectorTiming::Burst:
val.setValue(org::openapitools::server::model::Detector_timing::eDetector_timing::BURST);
break;
case DetectorTiming::Gated:
val.setValue(org::openapitools::server::model::Detector_timing::eDetector_timing::GATED);
break;
default:
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "invalid input");
}
return val;
}
DetectorSettings Convert(const org::openapitools::server::model::Detector_settings &input) {
DetectorSettings ret{};
if (input.countTimeUsIsSet())
ret.FrameTime(std::chrono::microseconds(input.getFrameTimeUs()),
std::chrono::microseconds(input.getCountTimeUs()));
else
ret.FrameTime(std::chrono::microseconds(input.getFrameTimeUs()));
ret.InternalGeneratorEnable(input.isInternalFrameGenerator());
ret.InternalGeneratorImages(input.getInternalFrameGeneratorImages());
ret.DetectorDelay(std::chrono::nanoseconds(input.getDetectorTriggerDelayNs()));
ret.StorageCells(input.getJungfrauStorageCellCount());
ret.StorageCellDelay(std::chrono::nanoseconds(input.getJungfrauStorageCellDelayNs()));
ret.FixGainG1(input.isJungfrauFixedGainG1());
ret.UseGainHG0(input.isJungfrauUseGainHg0());
ret.PedestalG0Frames(input.getJungfrauPedestalG0Frames());
ret.PedestalG1Frames(input.getJungfrauPedestalG1Frames());
ret.PedestalG2Frames(input.getJungfrauPedestalG2Frames());
ret.PedestalMinImageCount(input.getJungfrauPedestalMinImageCount());
if (input.eigerBitDepthIsSet())
ret.EigerBitDepth(input.getEigerBitDepth());
if (input.eigerThresholdKeVIsSet())
ret.EigerThreshold_keV(input.getEigerThresholdKeV());
if (input.timingIsSet())
ret.Timing(Convert(input.getTiming()));
else
ret.Timing(DetectorTiming::Trigger);
return ret;
}
org::openapitools::server::model::Detector_settings Convert(const DetectorSettings &input) {
org::openapitools::server::model::Detector_settings ret{};
ret.setFrameTimeUs(std::chrono::round<std::chrono::microseconds>(
std::chrono::duration<float>(input.GetFrameTime())).count());
if (input.GetCountTime().has_value())
ret.setCountTimeUs(std::chrono::round<std::chrono::microseconds>(
std::chrono::duration<float>(input.GetCountTime().value())
).count());
ret.setDetectorTriggerDelayNs(input.GetDetectorDelay().count());
ret.setInternalFrameGeneratorImages(input.GetInternalGeneratorImages());
ret.setInternalFrameGenerator(input.IsInternalGeneratorEnable());
ret.setJungfrauStorageCellCount(input.GetStorageCells());
ret.setJungfrauFixedGainG1(input.IsFixGainG1());
ret.setJungfrauUseGainHg0(input.IsUseGainHG0());
ret.setJungfrauPedestalG0Frames(input.GetPedestalG0Frames());
ret.setJungfrauPedestalG1Frames(input.GetPedestalG1Frames());
ret.setJungfrauPedestalG2Frames(input.GetPedestalG2Frames());
ret.setJungfrauPedestalMinImageCount(input.GetPedestalMinImageCount());
ret.setJungfrauStorageCellDelayNs(input.GetStorageCellDelay().count());
if (input.GetEigerThreshold_keV().has_value())
ret.setEigerThresholdKeV(input.GetEigerThreshold_keV().value());
if (input.GetEigerBitDepth().has_value())
ret.setEigerBitDepth(input.GetEigerBitDepth().value());
ret.setTiming(Convert(input.GetTiming()));
return ret;
}
org::openapitools::server::model::Broker_status Convert(const BrokerStatus& input) {
org::openapitools::server::model::Broker_status ret;
switch (input.state) {
case JFJochState::Inactive:
ret.setState("Inactive");
break;
case JFJochState::Idle:
ret.setState("Idle");
break;
case JFJochState::Measuring:
ret.setState("Measuring");
break;
case JFJochState::Error:
ret.setState("Error");
break;
case JFJochState::Busy:
ret.setState("Busy");
break;
case JFJochState::Calibration:
ret.setState("Pedestal");
break;
}
if (input.message.has_value())
ret.setMessage(input.message.value());
switch (input.message_severity) {
case BrokerStatus::MessageSeverity::Info:
ret.setMessageSeverity("info");
break;
case BrokerStatus::MessageSeverity::Success:
ret.setMessageSeverity("success");
break;
case BrokerStatus::MessageSeverity::Warning:
ret.setMessageSeverity("warning");
break;
default:
ret.setMessageSeverity("error");
break;
}
if (input.progress.has_value())
ret.setProgress(input.progress.value());
ret.setGpuCount(input.gpu_count);
ret.setBrokerVersion(input.broker_version);
return ret;
}
org::openapitools::server::model::Calibration_statistics_inner Convert(const JFCalibrationModuleStatistics& input) {
org::openapitools::server::model::Calibration_statistics_inner output;
output.setModuleNumber(input.module_number);
output.setMaskedPixels(input.bad_pixels);
output.setStorageCellNumber(input.storage_cell_number);
output.setGainG0Mean(input.gain_g0_mean);
output.setGainG1Mean(input.gain_g1_mean);
output.setGainG2Mean(input.gain_g2_mean);
output.setPedestalG0Mean(input.pedestal_g0_mean);
output.setPedestalG1Mean(input.pedestal_g1_mean);
output.setPedestalG2Mean(input.pedestal_g2_mean);
return output;
}
std::vector<org::openapitools::server::model::Calibration_statistics_inner> Convert(const std::vector<JFCalibrationModuleStatistics>& input) {
std::vector<org::openapitools::server::model::Calibration_statistics_inner> ret;
for (const auto &i: input)
ret.push_back(Convert(i));
return ret;
}
org::openapitools::server::model::Instrument_metadata Convert(const InstrumentMetadata& input) {
org::openapitools::server::model::Instrument_metadata output;
output.setInstrumentName(input.GetInstrumentName());
output.setSourceName(input.GetSourceName());
output.setSourceType(input.GetSourceType());
output.setPulsedSource(input.IsPulsedSource());
output.setElectronSource(input.IsElectronSource());
return output;
}
InstrumentMetadata Convert(const org::openapitools::server::model::Instrument_metadata &input) {
InstrumentMetadata output;
output.InstrumentName(input.getInstrumentName())
.SourceName(input.getSourceName())
.SourceType(input.getSourceType())
.PulsedSource(input.isPulsedSource())
.ElectronSource(input.isElectronSource());
return output;
}
org::openapitools::server::model::Detector_state Convert(DetectorState input) {
org::openapitools::server::model::Detector_state ret;
switch (input) {
case DetectorState::IDLE:
ret.setValue(org::openapitools::server::model::Detector_state::eDetector_state::IDLE);
break;
case DetectorState::ERROR:
ret.setValue(org::openapitools::server::model::Detector_state::eDetector_state::ERROR);
break;
case DetectorState::BUSY:
ret.setValue(org::openapitools::server::model::Detector_state::eDetector_state::BUSY);
break;
case DetectorState::WAITING:
ret.setValue(org::openapitools::server::model::Detector_state::eDetector_state::WAITING);
break;
default:
case DetectorState::NOT_CONNECTED:
ret.setValue(org::openapitools::server::model::Detector_state::eDetector_state::NOT_CONNECTED);
break;
}
return ret;
}
org::openapitools::server::model::Detector_power_state Convert(DetectorPowerState input) {
org::openapitools::server::model::Detector_power_state ret;
switch (input) {
case DetectorPowerState::ON:
ret.setValue(org::openapitools::server::model::Detector_power_state::eDetector_power_state::POWERON);
break;
case DetectorPowerState::PARTIAL:
ret.setValue(org::openapitools::server::model::Detector_power_state::eDetector_power_state::PARTIAL);
break;
default:
case DetectorPowerState::OFF:
ret.setValue(org::openapitools::server::model::Detector_power_state::eDetector_power_state::POWEROFF);
break;
}
return ret;
}
org::openapitools::server::model::Detector_status Convert(const DetectorStatus &input) {
org::openapitools::server::model::Detector_status output;
output.setServerVersion(input.detector_server_version);
output.setNumberOfTriggersLeft(input.remaining_triggers);
output.setFpgaTempDegC(input.temperature_fpga_degC);
output.setHighVoltageV(input.high_voltage_V);
output.setPowerchip(Convert(input.power_state));
output.setState(Convert(input.detector_state));
return output;
}
org::openapitools::server::model::Detector_type Convert(const DetectorType &input) {
org::openapitools::server::model::Detector_type dt;
switch (input) {
case DetectorType::EIGER:
dt.setValue(org::openapitools::server::model::Detector_type::eDetector_type::EIGER);
break;
case DetectorType::JUNGFRAU:
dt.setValue(org::openapitools::server::model::Detector_type::eDetector_type::JUNGFRAU);
break;
case DetectorType::DECTRIS:
dt.setValue(org::openapitools::server::model::Detector_type::eDetector_type::DECTRIS);
break;
}
return dt;
}
org::openapitools::server::model::Detector_list Convert(const DetectorList &input) {
org::openapitools::server::model::Detector_list ret;
std::vector<org::openapitools::server::model::Detector_list_element> dets;
for (int i = 0; i < input.detector.size(); i++) {
org::openapitools::server::model::Detector_list_element d;
d.setId(i);
d.setDescription(input.detector[i].description);
d.setNmodules(input.detector[i].nmodules);
d.setHeight(input.detector[i].height);
d.setWidth(input.detector[i].width);
d.setSerialNumber(input.detector[i].serial_number);
d.setBaseIpv4Addr(input.detector[i].base_ipv4_addr);
d.setUdpInterfaceCount(input.detector[i].udp_interface_count);
d.setMinFrameTimeNs(input.detector[i].min_frame_time.count());
d.setMinCountTimeNs(input.detector[i].min_count_time.count());
d.setReadoutTimeNs(input.detector[i].readout_time.count());
d.setPixelSizeMm(input.detector[i].pixel_size_mm);
d.setType(Convert(input.detector[i].detector_type));
dets.emplace_back(std::move(d));
}
ret.setDetectors(dets);
ret.setCurrentId(input.current_id);
return ret;
}
org::openapitools::server::model::Plots Convert(const MultiLinePlot& input) {
std::vector<org::openapitools::server::model::Plot> tmp(input.GetPlots().size());
for (int i = 0; i < input.GetPlots().size(); i++) {
tmp[i].setTitle(input.GetPlots()[i].title);
tmp[i].setX(input.GetPlots()[i].x);
tmp[i].setY(input.GetPlots()[i].y);
tmp[i].setZ(input.GetPlots()[i].z);
}
org::openapitools::server::model::Plots output;
output.setPlot(tmp);
org::openapitools::server::model::Plot_unit_x unit;
switch (input.GetUnits()) {
case MultiLinePlotUnits::ImageNumber:
unit.setValue(org::openapitools::server::model::Plot_unit_x::ePlot_unit_x::IMAGE_NUMBER);
break;
case MultiLinePlotUnits::Angle_deg:
unit.setValue(org::openapitools::server::model::Plot_unit_x::ePlot_unit_x::ANGLE_DEG);
break;
case MultiLinePlotUnits::Q_recipA:
unit.setValue(org::openapitools::server::model::Plot_unit_x::ePlot_unit_x::Q_RECIPA);
break;
case MultiLinePlotUnits::ADU:
unit.setValue(org::openapitools::server::model::Plot_unit_x::ePlot_unit_x::ADU);
break;
case MultiLinePlotUnits::d_A:
unit.setValue(org::openapitools::server::model::Plot_unit_x::ePlot_unit_x::D_A);
break;
case MultiLinePlotUnits::Grid_um:
unit.setValue(org::openapitools::server::model::Plot_unit_x::ePlot_unit_x::GRID_UM);
break;
default:
break;
}
output.setUnitX(unit);
if (input.GetSizeX().has_value())
output.setSizeX(input.GetSizeX().value());
if (input.GetSizeY().has_value())
output.setSizeY(input.GetSizeY().value());
return output;
}
AzimuthalIntegrationSettings Convert(const org::openapitools::server::model::Azim_int_settings& input) {
AzimuthalIntegrationSettings ret{};
ret.SolidAngleCorrection(input.isSolidAngleCorr());
ret.PolarizationCorrection(input.isPolarizationCorr());
ret.QSpacing_recipA(input.getQSpacing());
ret.QRange_recipA(input.getLowQRecipA(),
input.highQRecipAIsSet() ? std::optional<float>(input.getHighQRecipA())
: std::nullopt);
ret.AzimuthalBinCount(input.getAzimuthalBins());
ret.ForceCPUinFPGAWorkflow(input.isForceCpu());
return ret;
}
org::openapitools::server::model::Azim_int_settings Convert(const AzimuthalIntegrationSettings& settings) {
org::openapitools::server::model::Azim_int_settings ret{};
ret.setSolidAngleCorr(settings.IsSolidAngleCorrection());
ret.setPolarizationCorr(settings.IsPolarizationCorrection());
if (const auto high_q = settings.GetRequestedHighQ_recipA())
ret.setHighQRecipA(high_q.value());
ret.setLowQRecipA(settings.GetLowQ_recipA());
ret.setQSpacing(settings.GetQSpacing_recipA());
ret.setAzimuthalBins(settings.GetAzimuthalBinCount());
ret.setForceCpu(settings.IsForceCPUinFPGAWorkflow());
return ret;
}
ROIDefinition Convert(const org::openapitools::server::model::Roi_definitions& input) {
ROIDefinition output{};
for (const auto &i: input.getBox().getRois())
output.boxes.emplace_back(ROIBox(i.getName(), i.getMinXPxl(), i.getMaxXPxl(), i.getMinYPxl(), i.getMaxYPxl()));
for (const auto &i: input.getCircle().getRois())
output.circles.emplace_back(ROICircle(i.getName(), i.getCenterXPxl(), i.getCenterYPxl(), i.getRadiusPxl()));
for (const auto &i: input.getAzim().getRois()) {
// A sector needs both bounds; if only one is given, treat it as a full ring.
float phi_min = 0, phi_max = 0;
if (i.phiMinDegIsSet() && i.phiMaxDegIsSet()) {
phi_min = i.getPhiMinDeg();
phi_max = i.getPhiMaxDeg();
}
output.azimuthal.emplace_back(ROIAzimuthal(i.getName(),
(i.getQMaxRecipA() == 0.0) ? 0.0 : 2.0f * PI / i.getQMaxRecipA(),
(i.getQMinRecipA() == 0.0) ? 0.0 : 2.0f * PI / i.getQMinRecipA(),
phi_min, phi_max));
}
return output;
}
org::openapitools::server::model::Roi_circle_list Convert(const std::vector<ROICircle> &input) {
org::openapitools::server::model::Roi_circle_list ret{};
std::vector<org::openapitools::server::model::Roi_circle> tmp;
for (const auto &i: input) {
org::openapitools::server::model::Roi_circle elem;
elem.setName(i.GetName());
elem.setCenterXPxl(i.GetX());
elem.setCenterYPxl(i.GetY());
elem.setRadiusPxl(i.GetRadius_pxl());
tmp.emplace_back(elem);
}
ret.setRois(tmp);
return ret;
}
org::openapitools::server::model::Roi_azim_list Convert(const std::vector<ROIAzimuthal> &input) {
org::openapitools::server::model::Roi_azim_list ret{};
std::vector<org::openapitools::server::model::Roi_azimuthal> tmp;
for (const auto &i: input) {
org::openapitools::server::model::Roi_azimuthal elem;
elem.setName(i.GetName());
elem.setQMinRecipA(i.GetQMin_recipA());
elem.setQMaxRecipA(i.GetQMax_recipA());
if (i.HasPhi()) {
elem.setPhiMinDeg(i.GetPhiMin_deg());
elem.setPhiMaxDeg(i.GetPhiMax_deg());
}
tmp.emplace_back(elem);
}
ret.setRois(tmp);
return ret;
}
org::openapitools::server::model::Roi_box_list Convert(const std::vector<ROIBox> &input) {
org::openapitools::server::model::Roi_box_list ret{};
std::vector<org::openapitools::server::model::Roi_box> tmp;
for (const auto &i: input) {
org::openapitools::server::model::Roi_box elem;
elem.setName(i.GetName());
elem.setMinXPxl(i.GetXMin());
elem.setMaxXPxl(i.GetXMax());
elem.setMinYPxl(i.GetYMin());
elem.setMaxYPxl(i.GetYMax());
tmp.emplace_back(elem);
}
ret.setRois(tmp);
return ret;
}
org::openapitools::server::model::Roi_definitions Convert(const ROIDefinition &input) {
org::openapitools::server::model::Roi_definitions ret{};
ret.setCircle(Convert(input.circles));
ret.setBox(Convert(input.boxes));
ret.setAzim(Convert(input.azimuthal));
return ret;
}
ImageFormatSettings Convert(const org::openapitools::server::model::Image_format_settings& input) {
ImageFormatSettings ret{};
ret.GeometryTransformed(input.isGeometryTransform());
ret.AutoSummation(input.isSummation());
ret.JungfrauConversion(input.isJungfrauConversion());
ret.MaskChipEdges(input.isMaskChipEdges());
ret.MaskModuleEdges(input.isMaskModuleEdges());
ret.ApplyPixelMask(input.isApplyMask());
ret.PedestalG0RMSLimit(input.getJungfrauPedestalG0RmsLimit());
ret.MaskPixelsWithoutG0(input.isJungfrauMaskPixelsWithoutG0());
if (input.signedOutputIsSet())
ret.PixelSigned(input.isSignedOutput());
if (input.jungfrauConversionFactorKeVIsSet())
ret.JungfrauConvFactor_keV(input.getJungfrauConversionFactorKeV());
if (input.bitDepthImageIsSet())
ret.BitDepthImage(input.getBitDepthImage());
return ret;
}
org::openapitools::server::model::Image_format_settings Convert(const ImageFormatSettings& input) {
org::openapitools::server::model::Image_format_settings ret{};
ret.setGeometryTransform(input.IsGeometryTransformed());
ret.setSummation(input.IsAutoSummation());
ret.setJungfrauConversion(input.IsJungfrauConversion());
ret.setMaskChipEdges(input.IsMaskChipEdges());
ret.setMaskModuleEdges(input.IsMaskModuleEdges());
ret.setApplyMask(input.IsApplyPixelMask());
ret.setJungfrauMaskPixelsWithoutG0(input.IsMaskPixelsWithoutG0());
ret.setJungfrauPedestalG0RmsLimit(input.GetPedestalG0RMSLimit());
if (input.IsPixelSigned().has_value())
ret.setSignedOutput(input.IsPixelSigned().value());
if (input.GetJungfrauConvFactor_keV().has_value())
ret.setJungfrauConversionFactorKeV(input.GetJungfrauConvFactor_keV().value());
if (input.GetBitDepthImage().has_value())
ret.setBitDepthImage(input.GetBitDepthImage().value());
return ret;
}
Coord ConvertOpenAPI(const std::vector<float> &input) {
if (input.size() != 3)
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Wrong size of Coord array");
return {input[0], input[1], input[2]};
}
GoniometerAxis Convert(const org::openapitools::server::model::Rotation_axis& input) {
std::optional<Coord> helical;
if (input.helicalStepUmIsSet())
helical = ConvertOpenAPI(input.getHelicalStepUm());
GoniometerAxis axis{input.getName(), input.getStart(), input.getStep(),
ConvertOpenAPI(input.getVector()), helical};
if (input.screeningWedgeDegIsSet())
axis.ScreeningWedge(input.getScreeningWedgeDeg());
return axis;
}
GridScanSettings Convert(const org::openapitools::server::model::Grid_scan& input) {
return {input.getNFast(), input.getStepXUm(), input.getStepYUm(), input.isSnake(), input.isVertical()};
}
DatasetSettings Convert(const org::openapitools::server::model::Dataset_settings& input) {
DatasetSettings ret;
ret.ImagesPerTrigger(input.getImagesPerTrigger());
ret.NumTriggers(input.getNtrigger());
if (input.runNumberIsSet())
ret.RunNumber(input.getRunNumber());
if (input.runNameIsSet())
ret.RunName(input.getRunName());
ret.ExperimentGroup(input.getExperimentGroup());
if (input.imageTimeUsIsSet())
ret.ImageTime(std::chrono::microseconds(input.getImageTimeUs()));
ret.BeamX_pxl(input.getBeamXPxl());
ret.BeamY_pxl(input.getBeamYPxl());
ret.DetectorDistance_mm(input.getDetectorDistanceMm());
ret.PhotonEnergy_keV(input.getIncidentEnergyKeV());
ret.FilePrefix(input.getFilePrefix());
if (!input.compressionIsSet())
ret.Compression(CompressionAlgorithm::BSHUF_LZ4);
else {
std::string compr = str_tolower(input.getCompression());
if (compr == "bslz4")
ret.Compression(CompressionAlgorithm::BSHUF_LZ4);
else if (compr == "bszstd")
ret.Compression(CompressionAlgorithm::BSHUF_ZSTD);
else if (compr == "bszstd_rle")
ret.Compression(CompressionAlgorithm::BSHUF_ZSTD_RLE);
else if (compr == "bszstd_rlehuf")
ret.Compression(CompressionAlgorithm::BSHUF_ZSTD_RLE_HUFF);
else if (compr == "none")
ret.Compression(CompressionAlgorithm::NO_COMPRESSION);
else
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Unknown compression");
}
if (input.poissonCompressionIsSet())
ret.LossyCompressionPoisson(input.getPoissonCompression());
if (input.unitCellIsSet())
ret.SetUnitCell(UnitCell{
.a = input.getUnitCell().getA(),
.b = input.getUnitCell().getB(),
.c = input.getUnitCell().getC(),
.alpha = input.getUnitCell().getAlpha(),
.beta = input.getUnitCell().getBeta(),
.gamma = input.getUnitCell().getGamma()
});
if (input.totalFluxIsSet())
ret.TotalFlux(input.getTotalFlux());
if (input.beamSizeXUmIsSet())
ret.BeamSizeX_um(input.getBeamSizeXUm());
if (input.beamSizeYUmIsSet())
ret.BeamSizeY_um(input.getBeamSizeYUm());
if (input.transmissionIsSet())
ret.AttenuatorTransmission(input.getTransmission());
// Not alternatives: a grid scan is often collected at a given head position, so an axis and a
// grid can both be set. This used to drop the grid scan silently whenever an axis was present.
if (input.goniometerIsSet())
ret.Goniometer(Convert(input.getGoniometer()));
if (input.gridScanIsSet())
ret.GridScan(Convert(input.getGridScan()));
if (input.spaceGroupNumberIsSet())
ret.SpaceGroupNumber(input.getSpaceGroupNumber());
ret.SampleName(input.getSampleName());
ret.HeaderAppendix(input.getHeaderAppendix());
ret.ImageAppendix(input.getImageAppendix());
if (input.imagesPerFileIsSet())
ret.ImagesPerFile(input.getImagesPerFile());
if (input.dataReductionFactorSerialmxIsSet())
ret.LossyCompressionSerialMX(input.getDataReductionFactorSerialmx());
if (input.pixelValueLowThresholdIsSet())
ret.PixelValueLowThreshold(input.getPixelValueLowThreshold());
if (input.saveCalibrationIsSet())
ret.SaveCalibration(input.isSaveCalibration());
ret.WriteNXmxHDF5Master(input.isWriteNxmxHdf5Master());
if (input.polarizationFactorIsSet())
ret.PolarizationFactor(input.getPolarizationFactor());
ret.PoniRot1_rad(input.getPoniRot1Rad());
ret.PoniRot2_rad(input.getPoniRot2Rad());
ret.PoniRot3_rad(input.getPoniRot3Rad());
if (input.ringCurrentMAIsSet())
ret.RingCurrent_mA(input.getRingCurrentMA());
if (input.sampleTemperatureKIsSet())
ret.SampleTemperature_K(input.getSampleTemperatureK());
ret.SpotFindingEnable(input.isSpotFinding());
ret.MaxSpotCount(input.getMaxSpotCount());
ret.DetectIceRings(input.isDetectIceRings());
if (input.xrayFluorescenceSpectrumIsSet()) {
auto fl = input.getXrayFluorescenceSpectrum();
ret.FluorescenceSpectrum({fl.getEnergyEV(), fl.getData()});
}
if (input.smargonIsSet()) {
auto sm = input.getSmargon();
SmargonPosition smargon;
smargon.phi_deg = sm.getPhiDeg();
smargon.chi_deg = sm.getChiDeg();
if (sm.phiAxisIsSet())
smargon.phi_axis = ConvertOpenAPI(sm.getPhiAxis());
if (sm.chiAxisIsSet())
smargon.chi_axis = ConvertOpenAPI(sm.getChiAxis());
ret.Smargon(smargon);
}
return ret;
}
std::vector<org::openapitools::server::model::Fpga_status_inner> Convert(const std::vector<DeviceStatus> &input) {
std::vector<org::openapitools::server::model::Fpga_status_inner> ret;
for (const auto &d: input) {
org::openapitools::server::model::Fpga_status_inner tmp;
tmp.setPciDevId(d.device_number);
tmp.setSerialNumber(d.serial_number);
tmp.setFwVersion(d.fpga_firmware_version);
tmp.setBaseMacAddr(MacAddressToStr(d.fpga_default_mac_addr));
tmp.setPacketsSls(d.packets_sls);
tmp.setPacketsUdp(d.packets_udp);
tmp.setEthLinkCount(d.eth_link_count);
tmp.setEthLinkStatus(d.eth_link_status);
tmp.setFpgaTempC(static_cast<float>(d.fpga_temp_C));
tmp.setHbmTempC(static_cast<float>(d.hbm_0_temp_C));
tmp.setPowerUsageW(static_cast<float>(d.fpga_pcie_12V_I_mA * d.fpga_pcie_12V_V_mV + d.fpga_pcie_3p3V_I_mA
* d.fpga_pcie_3p3V_V_mV) / (1000.0f * 1000.0f));
tmp.setIdle(d.idle);
tmp.setPcieLinkSpeed(d.pcie_link_speed);
tmp.setPcieLinkWidth(d.pcie_link_width);
ret.emplace_back(std::move(tmp));
}
return ret;
}
ZMQPreviewSettings Convert(const org::openapitools::server::model::Zeromq_preview_settings &input) {
ZMQPreviewSettings ret;
if (input.isEnabled())
ret.period = std::chrono::milliseconds(input.getPeriodMs());
else
ret.period = {};
ret.address = "";
return ret;
}
ZMQMetadataSettings Convert(const org::openapitools::server::model::Zeromq_metadata_settings &input) {
ZMQMetadataSettings ret;
if (input.isEnabled())
ret.period = std::chrono::milliseconds(input.getPeriodMs());
else
ret.period = {};
ret.address = "";
return ret;
}
org::openapitools::server::model::Zeromq_preview_settings Convert(const ZMQPreviewSettings &settings) {
org::openapitools::server::model::Zeromq_preview_settings ret;
ret.setEnabled(settings.period.has_value());
if (settings.period.has_value())
ret.setPeriodMs(std::chrono::round<std::chrono::milliseconds>(settings.period.value()).count());
ret.setSocketAddress(settings.address);
return ret;
}
org::openapitools::server::model::Zeromq_metadata_settings Convert(const ZMQMetadataSettings &settings) {
org::openapitools::server::model::Zeromq_metadata_settings ret;
ret.setEnabled(settings.period.has_value());
if (settings.period.has_value())
ret.setPeriodMs(std::chrono::round<std::chrono::milliseconds>(settings.period.value()).count());
ret.setSocketAddress(settings.address);
return ret;
}
org::openapitools::server::model::Pixel_mask_statistics Convert(const PixelMaskStatistics& input) {
org::openapitools::server::model::Pixel_mask_statistics ret;
ret.setUserMask(input.user_mask);
ret.setWrongGain(input.error_pixel);
ret.setTooHighPedestalRms(input.noisy_pixel);
return ret;
}
org::openapitools::server::model::Image_buffer_status Convert(const ImageBufferStatus& input) {
org::openapitools::server::model::Image_buffer_status ret;
ret.setAvailableSlots(input.available_slots);
ret.setTotalSlots(input.total_slots);
ret.setImageNumbers(input.images_in_the_buffer);
ret.setMaxImageNumber(input.max_image_number);
ret.setMinImageNumber(input.min_image_number);
ret.setInPreparationSlots(input.preparation_slots);
ret.setInSendingSlots(input.sending_slots);
if (input.current_counter.has_value())
ret.setCurrentCounter(input.current_counter.value());
return ret;
}
ImageBufferStatus Convert(const org::openapitools::server::model::Image_buffer_status& input) {
ImageBufferStatus ret;
ret.available_slots = input.getAvailableSlots();
ret.total_slots = input.getTotalSlots();
ret.images_in_the_buffer = input.getImageNumbers();
ret.max_image_number = input.getMaxImageNumber();
ret.min_image_number = input.getMinImageNumber();
ret.sending_slots = input.getInSendingSlots();
ret.preparation_slots = input.getInPreparationSlots();
if (input.currentCounterIsSet())
ret.current_counter = input.getCurrentCounter();
return ret;
}
org::openapitools::server::model::File_writer_settings Convert(const FileWriterSettings& input) {
org::openapitools::server::model::File_writer_settings ret;
ret.setFormat(Convert(input.GetFileFormat()));
ret.setOverwrite(input.IsOverwriteExistingFiles());
return ret;
}
FileWriterSettings Convert(const org::openapitools::server::model::File_writer_settings &input) {
FileWriterSettings ret;
ret.OverwriteExistingFiles(input.isOverwrite());
ret.FileFormat(Convert(input.getFormat()));
return ret;
}
org::openapitools::server::model::File_writer_format Convert(FileWriterFormat input) {
org::openapitools::server::model::File_writer_format ret;
switch (input) {
case FileWriterFormat::DataOnly:
ret.setValue(org::openapitools::server::model::File_writer_format::eFile_writer_format::NXMXONLYDATA);
break;
case FileWriterFormat::NXmxLegacy:
ret.setValue(org::openapitools::server::model::File_writer_format::eFile_writer_format::NXMXLEGACY);
break;
case FileWriterFormat::NXmxVDS:
ret.setValue(org::openapitools::server::model::File_writer_format::eFile_writer_format::NXMXVDS);
break;
case FileWriterFormat::NXmxIntegrated:
ret.setValue(org::openapitools::server::model::File_writer_format::eFile_writer_format::NXMXINTEGRATED);
break;
case FileWriterFormat::NoFile:
ret.setValue(org::openapitools::server::model::File_writer_format::eFile_writer_format::NOFILEWRITTEN);
break;
default:
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Unknown file writer format enum value");
}
return ret;
}
FileWriterFormat Convert(const org::openapitools::server::model::File_writer_format& input) {
switch (input.getValue()) {
case org::openapitools::server::model::File_writer_format::eFile_writer_format::NXMXONLYDATA:
return FileWriterFormat::DataOnly;
case org::openapitools::server::model::File_writer_format::eFile_writer_format::NXMXLEGACY:
return FileWriterFormat::NXmxLegacy;
case org::openapitools::server::model::File_writer_format::eFile_writer_format::NXMXVDS:
return FileWriterFormat::NXmxVDS;
case org::openapitools::server::model::File_writer_format::eFile_writer_format::NXMXINTEGRATED:
return FileWriterFormat::NXmxIntegrated;
case org::openapitools::server::model::File_writer_format::eFile_writer_format::CBF:
case org::openapitools::server::model::File_writer_format::eFile_writer_format::TIFF:
// Deprecated, kept in the OpenAPI enum for back compatibility only - only HDF5 is written now.
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"CBF and TIFF file formats are no longer supported");
case org::openapitools::server::model::File_writer_format::eFile_writer_format::NOFILEWRITTEN:
return FileWriterFormat::NoFile;
default:
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"Unknown file writer format enum value");
}
}
PlotType ConvertPlotType(const std::optional<std::string>& input) {
if (!input.has_value())
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"Plot type is compulsory paramater");
if (input == "bkg_estimate") return PlotType::BkgEstimate;
if (input == "spindle_blind_fraction") return PlotType::SpindleBlindFraction;
// ice_ring_score is the retired spelling of ice_ring_ratio, kept so existing clients keep
// working; both name the same plot.
if (input == "ice_ring_ratio" || input == "ice_ring_score") return PlotType::IceRingRatio;
if (input == "protein_score") return PlotType::ProteinScore;
if (input == "ice_score") return PlotType::IceScore;
if (input == "azint") return PlotType::AzInt;
if (input == "azint_1d") return PlotType::AzInt1D;
if (input == "spot_count") return PlotType::SpotCount;
if (input == "spot_count_low_res") return PlotType::SpotCountLowRes;
if (input == "spot_count_indexed") return PlotType::SpotCountIndexed;
if (input == "spot_count_ice") return PlotType::SpotCountIceRing;
if (input == "indexing_rate") return PlotType::IndexingRate;
if (input == "indexing_unit_cell_length") return PlotType::IndexingUnitCellLength;
if (input == "profile_radius") return PlotType::ProfileRadius;
if (input == "mosaicity") return PlotType::Mosaicity;
if (input == "b_factor") return PlotType::BFactor;
if (input == "indexing_unit_cell_angle") return PlotType::IndexingUnitCellAngle;
if (input == "error_pixels") return PlotType::ErrorPixels;
if (input == "strong_pixels") return PlotType::StrongPixels;
if (input == "saturated_pixels") return PlotType::SaturatedPixels;
if (input == "image_collection_efficiency") return PlotType::ImageCollectionEfficiency;
if (input == "receiver_delay") return PlotType::ReceiverDelay;
if (input == "receiver_free_send_buf") return PlotType::ReceiverFreeSendBuf;
if (input == "roi_sum") return PlotType::ROISum;
if (input == "roi_mean") return PlotType::ROIMean;
if (input == "roi_max_count") return PlotType::ROIMaxCount;
if (input == "roi_pixels") return PlotType::ROIPixels;
if (input == "roi_weighted_x") return PlotType::ROIWeightedX;
if (input == "roi_weighted_y") return PlotType::ROIWeightedY;
if (input == "packets_received") return PlotType::PacketsReceived;
if (input == "max_pixel_value") return PlotType::MaxValue;
if (input == "resolution_estimate") return PlotType::ResolutionEstimate;
if (input == "pixel_sum") return PlotType::PixelSum;
if (input == "processing_time") return PlotType::ImageProcessingTime;
if (input == "beam_center_x") return PlotType::RefinementBeamX;
if (input == "beam_center_y") return PlotType::RefinementBeamY;
if (input == "integrated_reflections") return PlotType::IntegratedReflections;
if (input == "image_scale_factor") return PlotType::ImageScaleFactor;
if (input == "image_scale_cc") return PlotType::ImageScaleCC;
if (input == "compression_ratio") return PlotType::CompressionRatio;
if (input == "indexing_lattice_count") return PlotType::IndexingLatticeCount;
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"Plot type not recognized");
}
ColorScaleEnum ConvertColorScale(const std::optional<std::string> &input) {
std::string color = input.value_or("indigo");
if (color == "viridis")
return ColorScaleEnum::Viridis;
if (color == "bw")
return ColorScaleEnum::BW;
if (color == "wb")
return ColorScaleEnum::WB;
if (color == "green")
return ColorScaleEnum::Green;
if (color == "heat")
return ColorScaleEnum::Heat;
if (color == "indigo")
return ColorScaleEnum::Indigo;
if (color == "magma")
return ColorScaleEnum::Magma;
if (color == "inferno")
return ColorScaleEnum::Inferno;
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"Color scale unknown");
}
IndexingSettings Convert(const org::openapitools::server::model::Indexing_settings &input) {
IndexingSettings ret;
switch (input.getAlgorithm().getValue()) {
case org::openapitools::server::model::Indexing_algorithm::eIndexing_algorithm::FFT:
ret.Algorithm(IndexingAlgorithmEnum::FFT);
break;
case org::openapitools::server::model::Indexing_algorithm::eIndexing_algorithm::FFTW:
ret.Algorithm(IndexingAlgorithmEnum::FFTW);
break;
case org::openapitools::server::model::Indexing_algorithm::eIndexing_algorithm::NONE:
ret.Algorithm(IndexingAlgorithmEnum::None);
break;
case org::openapitools::server::model::Indexing_algorithm::eIndexing_algorithm::FFBIDX:
ret.Algorithm(IndexingAlgorithmEnum::FFBIDX);
break;
case org::openapitools::server::model::Indexing_algorithm::eIndexing_algorithm::AUTO:
ret.Algorithm(IndexingAlgorithmEnum::Auto);
break;
default:
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Unknown indexing algorithm");
}
switch (input.getGeomRefinementAlgorithm().getValue()) {
case org::openapitools::server::model::Geom_refinement_algorithm::eGeom_refinement_algorithm::INVALID_VALUE_OPENAPI_GENERATED:
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Unknown refinement algorithm");
break;
case org::openapitools::server::model::Geom_refinement_algorithm::eGeom_refinement_algorithm::BEAMCENTER:
ret.GeomRefinementAlgorithm(GeomRefinementAlgorithmEnum::BeamCenter);
break;
case org::openapitools::server::model::Geom_refinement_algorithm::eGeom_refinement_algorithm::ORIENTATIONONLY:
ret.GeomRefinementAlgorithm(GeomRefinementAlgorithmEnum::OrientationOnly);
break;
case org::openapitools::server::model::Geom_refinement_algorithm::eGeom_refinement_algorithm::FLEX:
ret.GeomRefinementAlgorithm(GeomRefinementAlgorithmEnum::Flex);
break;
case org::openapitools::server::model::Geom_refinement_algorithm::eGeom_refinement_algorithm::NONE:
ret.GeomRefinementAlgorithm(GeomRefinementAlgorithmEnum::None);
break;
}
ret.FFT_HighResolution_A(input.getFftHighResolutionA());
ret.FFT_MaxUnitCell_A(input.getFftMaxUnitCellA());
ret.FFT_MinUnitCell_A(input.getFftMinUnitCellA());
ret.FFT_NumVectors(input.getFftNumVectors());
ret.Tolerance(input.getTolerance());
ret.IndexingThreads(input.getThreadCount());
ret.UnitCellDistTolerance(input.getUnitCellDistTolerance());
ret.ViableCellMinSpots(input.getViableCellMinSpots());
ret.IndexIceRings(input.isIndexIceRings());
ret.RotationIndexing(input.isRotationIndexing());
ret.RotationIndexingAngularStride_deg(input.getRotationIndexingAngularStrideDeg());
ret.RotationIndexingMinAngularRange_deg(input.getRotationIndexingMinAngularRangeDeg());
ret.BlockingBehavior(input.isBlocking());
return ret;
}
org::openapitools::server::model::Indexing_settings Convert(const IndexingSettings &input) {
org::openapitools::server::model::Indexing_settings ret;
ret.setFftHighResolutionA(input.GetFFT_HighResolution_A());
ret.setFftMinUnitCellA(input.GetFFT_MinUnitCell_A());
ret.setFftMaxUnitCellA(input.GetFFT_MaxUnitCell_A());
ret.setFftNumVectors(input.GetFFT_NumVectors());
ret.setTolerance(input.GetTolerance());
ret.setThreadCount(input.GetIndexingThreads());
ret.setUnitCellDistTolerance(input.GetUnitCellDistTolerance());
ret.setViableCellMinSpots(input.GetViableCellMinSpots());
ret.setRotationIndexing(input.GetRotationIndexing());
ret.setRotationIndexingAngularStrideDeg(input.GetRotationIndexingAngularStride_deg());
ret.setRotationIndexingMinAngularRangeDeg(input.GetRotationIndexingMinAngularRange_deg());
ret.setBlocking(input.GetBlockingBehavior());
org::openapitools::server::model::Geom_refinement_algorithm refinement;
switch (input.GetGeomRefinementAlgorithm()) {
case GeomRefinementAlgorithmEnum::None:
refinement.setValue(org::openapitools::server::model::Geom_refinement_algorithm::eGeom_refinement_algorithm::NONE);
break;
case GeomRefinementAlgorithmEnum::BeamCenter:
refinement.setValue(org::openapitools::server::model::Geom_refinement_algorithm::eGeom_refinement_algorithm::BEAMCENTER);
break;
case GeomRefinementAlgorithmEnum::OrientationOnly:
refinement.setValue(org::openapitools::server::model::Geom_refinement_algorithm::eGeom_refinement_algorithm::ORIENTATIONONLY);
break;
case GeomRefinementAlgorithmEnum::Flex:
refinement.setValue(org::openapitools::server::model::Geom_refinement_algorithm::eGeom_refinement_algorithm::FLEX);
break;
}
ret.setGeomRefinementAlgorithm(refinement);
org::openapitools::server::model::Indexing_algorithm tmp;
switch (input.GetAlgorithm()) {
case IndexingAlgorithmEnum::Auto:
tmp.setValue(org::openapitools::server::model::Indexing_algorithm::eIndexing_algorithm::AUTO);
break;
case IndexingAlgorithmEnum::FFBIDX:
tmp.setValue(org::openapitools::server::model::Indexing_algorithm::eIndexing_algorithm::FFBIDX);
break;
case IndexingAlgorithmEnum::FFT:
tmp.setValue(org::openapitools::server::model::Indexing_algorithm::eIndexing_algorithm::FFT);
break;
case IndexingAlgorithmEnum::FFTW:
tmp.setValue(org::openapitools::server::model::Indexing_algorithm::eIndexing_algorithm::FFTW);
break;
case IndexingAlgorithmEnum::None:
tmp.setValue(org::openapitools::server::model::Indexing_algorithm::eIndexing_algorithm::NONE);
break;
}
ret.setAlgorithm(tmp);
ret.setIndexIceRings(input.GetIndexIceRings());
return ret;
}
BraggIntegrationSettings Convert(const org::openapitools::server::model::Bragg_integration_settings &input) {
BraggIntegrationSettings ret;
switch (input.getIntegrationModel().getValue()) {
case org::openapitools::server::model::Integration_model::eIntegration_model::PROFILEGAUSSIAN:
ret.Integrator(IntegratorMode::ProfileGaussian);
break;
case org::openapitools::server::model::Integration_model::eIntegration_model::PROFILEEMPIRICAL:
ret.Integrator(IntegratorMode::ProfileEmpirical);
break;
case org::openapitools::server::model::Integration_model::eIntegration_model::BOXSUM:
ret.Integrator(IntegratorMode::BoxSum);
break;
default:
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Unknown integration model");
}
// Always a concrete number online, never "derive it from the crystal": the generated model holds
// the schema's default when the request omits the field, so an absent max_hkl arrives here as that
// default rather than as an absent value. Deriving per crystal would make a live acquisition's
// per-image cost depend on whichever sample is mounted.
ret.MaxHKL(input.getMaxHkl());
return ret;
}
org::openapitools::server::model::Bragg_integration_settings Convert(const BraggIntegrationSettings &input) {
org::openapitools::server::model::Bragg_integration_settings ret;
org::openapitools::server::model::Integration_model tmp;
switch (input.GetIntegrator()) {
case IntegratorMode::ProfileGaussian:
tmp.setValue(org::openapitools::server::model::Integration_model::eIntegration_model::PROFILEGAUSSIAN);
break;
case IntegratorMode::ProfileEmpirical:
tmp.setValue(org::openapitools::server::model::Integration_model::eIntegration_model::PROFILEEMPIRICAL);
break;
case IntegratorMode::BoxSum:
tmp.setValue(org::openapitools::server::model::Integration_model::eIntegration_model::BOXSUM);
break;
}
ret.setIntegrationModel(tmp);
if (const auto max_hkl = input.GetMaxHKL())
ret.setMaxHkl(*max_hkl);
return ret;
}
AnalysisSettings Convert(const org::openapitools::server::model::Analysis_settings &input) {
AnalysisSettings ret;
// No default: the compiler must object here when a mode is added to the API, rather than let the
// new value fall through to whatever the last branch was. MXRotation is not in the API at all -
// jfjoch_broker has no rotation analysis path - so there is no case for it.
switch (input.getMode().getValue()) {
case org::openapitools::server::model::Analysis_mode::eAnalysis_mode::INVALID_VALUE_OPENAPI_GENERATED:
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Unknown analysis mode");
case org::openapitools::server::model::Analysis_mode::eAnalysis_mode::NONE:
ret.Mode(AnalysisMode::None);
break;
case org::openapitools::server::model::Analysis_mode::eAnalysis_mode::MXSTILLS:
ret.Mode(AnalysisMode::MXStills);
break;
case org::openapitools::server::model::Analysis_mode::eAnalysis_mode::AZINT:
ret.Mode(AnalysisMode::Azint);
break;
case org::openapitools::server::model::Analysis_mode::eAnalysis_mode::GRID:
ret.Mode(AnalysisMode::Grid);
break;
case org::openapitools::server::model::Analysis_mode::eAnalysis_mode::POWDERCALIBRATION:
ret.Mode(AnalysisMode::PowderCalibration);
break;
}
return ret;
}
org::openapitools::server::model::Analysis_settings Convert(const AnalysisSettings &input) {
org::openapitools::server::model::Analysis_settings ret;
org::openapitools::server::model::Analysis_mode tmp;
switch (input.GetMode()) {
case AnalysisMode::None:
tmp.setValue(org::openapitools::server::model::Analysis_mode::eAnalysis_mode::NONE);
break;
case AnalysisMode::MXStills:
tmp.setValue(org::openapitools::server::model::Analysis_mode::eAnalysis_mode::MXSTILLS);
break;
case AnalysisMode::Azint:
tmp.setValue(org::openapitools::server::model::Analysis_mode::eAnalysis_mode::AZINT);
break;
case AnalysisMode::Grid:
tmp.setValue(org::openapitools::server::model::Analysis_mode::eAnalysis_mode::GRID);
break;
case AnalysisMode::PowderCalibration:
tmp.setValue(org::openapitools::server::model::Analysis_mode::eAnalysis_mode::POWDERCALIBRATION);
break;
case AnalysisMode::MXRotation:
// Unreachable through the API: the setter refuses it, so it can never be stored. Reported
// rather than silently rewritten to stills, which would be the broker claiming to run an
// analysis it does not have.
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"Rotation MX analysis cannot be reported by this API");
}
ret.setMode(tmp);
return ret;
}
GridScanAnalysisSettings Convert(const org::openapitools::server::model::Grid_scan_analysis_settings &input) {
GridScanAnalysisSettings ret;
ret.ProteinScoreThreshold(input.getProteinScoreThreshold());
ret.GrowScoreThreshold(input.getGrowScoreThreshold());
ret.MinBlobCells(input.getMinBlobCells());
ret.DecisiveSingleCellScore(input.getDecisiveSingleCellScore());
// Absent means no cap, so an unset property must not become a cap of zero.
if (input.maxCrystalsIsSet())
ret.MaxCrystals(input.getMaxCrystals());
ret.Indexing(input.isIndexing());
return ret;
}
org::openapitools::server::model::Grid_scan_analysis_settings Convert(const GridScanAnalysisSettings &input) {
org::openapitools::server::model::Grid_scan_analysis_settings ret;
ret.setProteinScoreThreshold(input.GetProteinScoreThreshold());
ret.setGrowScoreThreshold(input.GetGrowScoreThreshold());
ret.setMinBlobCells(input.GetMinBlobCells());
ret.setDecisiveSingleCellScore(input.GetDecisiveSingleCellScore());
if (const auto cap = input.GetMaxCrystals())
ret.setMaxCrystals(*cap);
ret.setIndexing(input.IsIndexing());
return ret;
}
CalibrationSettings Convert(const org::openapitools::server::model::Calibration_settings &input) {
CalibrationSettings ret;
// No default: the compiler must object here when a source is added to the API.
switch (input.getMethod().getValue()) {
case org::openapitools::server::model::Calibration_method::eCalibration_method::INVALID_VALUE_OPENAPI_GENERATED:
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Unknown calibration method");
case org::openapitools::server::model::Calibration_method::eCalibration_method::RINGS:
ret.Method(CalibrationMethod::Rings);
break;
case org::openapitools::server::model::Calibration_method::eCalibration_method::SPOTS:
ret.Method(CalibrationMethod::Spots);
break;
}
if (input.calibrantIsSet())
ret.Calibrant(input.getCalibrant());
return ret;
}
org::openapitools::server::model::Calibration_settings Convert(const CalibrationSettings &input) {
org::openapitools::server::model::Calibration_settings ret;
org::openapitools::server::model::Calibration_method tmp;
switch (input.GetMethod()) {
case CalibrationMethod::Rings:
tmp.setValue(org::openapitools::server::model::Calibration_method::eCalibration_method::RINGS);
break;
case CalibrationMethod::Spots:
tmp.setValue(org::openapitools::server::model::Calibration_method::eCalibration_method::SPOTS);
break;
}
ret.setMethod(tmp);
if (!input.GetCalibrant().empty())
ret.setCalibrant(input.GetCalibrant());
return ret;
}
org::openapitools::server::model::Powder_calibration_output Convert(const CalibrationResult &input) {
org::openapitools::server::model::Powder_calibration_output ret;
const auto &g = input.geometry;
// The geometry under this API's own property names, so it can be PUT back without translating a
// field. Same content as the <prefix>.json rugnux writes (WriteCalibrationJson).
org::openapitools::server::model::Dataset_settings settings;
settings.setBeamXPxl(g.GetBeamX_pxl());
settings.setBeamYPxl(g.GetBeamY_pxl());
settings.setDetectorDistanceMm(g.GetDetectorDistance_mm());
settings.setIncidentEnergyKeV(WVL_1A_IN_KEV / g.GetWavelength_A());
// The rotations go in together or not at all: omitting them would state a FLAT detector, since the
// schema's default is 0.0, rather than leave the tilt unstated.
if (g.GetPoniRot1_rad() != 0.0f || g.GetPoniRot2_rad() != 0.0f || g.GetPoniRot3_rad() != 0.0f) {
settings.setPoniRot1Rad(g.GetPoniRot1_rad());
settings.setPoniRot2Rad(g.GetPoniRot2_rad());
settings.setPoniRot3Rad(g.GetPoniRot3_rad());
}
ret.setDatasetSettings(settings);
org::openapitools::server::model::Powder_calibration_quality quality;
// The verdict first: a caller that reads nothing else must still not mistake a non-fit for a fit.
quality.setConverged(input.converged);
if (!input.converged)
quality.setNotConvergedReason(input.reason);
quality.setRingPoints(input.ring_points);
quality.setRmsRadialPxl(input.rms_radial_pxl);
quality.setBeamSigmaPxl(input.beam_sigma_pxl);
// Where the beam actually lands, which is not the PONI above once the detector is tilted.
const auto [direct_x, direct_y] = g.GetDirectBeam_pxl();
quality.setDirectBeamXPxl(direct_x);
quality.setDirectBeamYPxl(direct_y);
quality.setHeaderDistanceMm(input.header_distance_mm);
quality.setTiltRefined(input.tilt_refined);
quality.setTiltSignificance(input.tilt_significance);
if (input.seed_distance_mm > 0.0f)
quality.setRingSeedDistanceMm(input.seed_distance_mm);
if (input.uncertainty.valid) {
org::openapitools::server::model::Powder_calibration_fit_sigma sigma;
sigma.setBeamXPxl(input.uncertainty.sigma_beam_x_pxl);
sigma.setBeamYPxl(input.uncertainty.sigma_beam_y_pxl);
sigma.setDetectorDistanceMm(input.uncertainty.sigma_distance_mm);
if (input.uncertainty.sigma_rot1_rad > 0.0 || input.uncertainty.sigma_rot2_rad > 0.0) {
sigma.setPoniRot1Rad(input.uncertainty.sigma_rot1_rad);
sigma.setPoniRot2Rad(input.uncertainty.sigma_rot2_rad);
sigma.setCorrelationBeamXRot1(input.uncertainty.corr_beam_x_rot1);
sigma.setCorrelationBeamYRot2(input.uncertainty.corr_beam_y_rot2);
}
quality.setFitSigma(sigma);
}
if (input.spots_geometry) {
org::openapitools::server::model::Powder_calibration_spot_check cross;
cross.setBeamXPxl(input.spots_geometry->GetBeamX_pxl());
cross.setBeamYPxl(input.spots_geometry->GetBeamY_pxl());
cross.setDetectorDistanceMm(input.spots_geometry->GetDetectorDistance_mm());
cross.setDisagreementPxl(input.spots_disagreement_pxl);
quality.setSpotCrossCheck(cross);
}
ret.setCalibration(quality);
ret.setJfjochVersion(jfjoch_version());
return ret;
}
org::openapitools::server::model::Grid_scan_crystal Convert(const GridScanCrystal &input) {
org::openapitools::server::model::Grid_scan_crystal ret;
ret.setNx(input.nx);
ret.setNy(input.ny);
ret.setXUm(input.x_um);
ret.setYUm(input.y_um);
ret.setImageNumber(input.image_number);
ret.setMajorUm(input.major_um);
ret.setMinorUm(input.minor_um);
ret.setAngleDeg(input.angle_deg);
ret.setScore(input.score);
ret.setIceScore(input.ice_score);
// NaN means "nothing in the blob measured a resolution". nlohmann serialises NaN as null,
// which the schema and the generated clients reject, so the property is simply left unset.
if (std::isfinite(input.res_A))
ret.setResA(input.res_A);
ret.setNImages(input.n_images);
return ret;
}
org::openapitools::server::model::Scan_result Convert(const ScanResult& input) {
org::openapitools::server::model::Scan_result ret;
ret.setFilePrefix(input.file_prefix);
std::vector<org::openapitools::server::model::Scan_result_images_inner> v;
for (const auto &i : input.images) {
org::openapitools::server::model::Scan_result_images_inner tmp;
tmp.setEfficiency(i.collection_efficiency);
tmp.setNumber(i.number);
if (i.x.has_value())
tmp.setNx(i.x.value());
if (i.y.has_value())
tmp.setNy(i.y.value());
if (i.bkg.has_value())
tmp.setBkg(i.bkg.value());
if (i.spindle_blind.has_value())
tmp.setSpindleBlind(i.spindle_blind.value());
if (i.angle_deg.has_value())
tmp.setAngle(i.angle_deg.value());
if (i.pixel_sum.has_value())
tmp.setPixelSum(i.pixel_sum.value());
if (i.max_viable_pixel.has_value())
tmp.setMax(i.max_viable_pixel.value());
if (i.sat_pixels.has_value())
tmp.setSat(i.sat_pixels.value());
if (i.spot_count.has_value())
tmp.setSpots(i.spot_count.value());
if (i.spot_count_ice.has_value())
tmp.setSpotsIce(i.spot_count_ice.value());
if (i.ice_ring_ratio.has_value())
tmp.setIce(i.ice_ring_ratio.value());
if (i.protein_score.has_value())
tmp.setProteinScore(i.protein_score.value());
if (i.ice_score.has_value())
tmp.setIceScore(i.ice_score.value());
if (i.spot_count_low_res.has_value())
tmp.setSpotsLowRes(i.spot_count_low_res.value());
if (i.spot_count_indexed.has_value())
tmp.setSpotsIndexed(i.spot_count_indexed.value());
if (i.indexing_solution.has_value())
tmp.setIndex(i.indexing_solution.value());
if (i.profile_radius.has_value())
tmp.setPr(i.profile_radius.value());
if (i.b_factor.has_value())
tmp.setB(i.b_factor.value());
if (i.uc.has_value()) {
org::openapitools::server::model::Unit_cell uc;
uc.setA(i.uc->a);
uc.setB(i.uc->b);
uc.setC(i.uc->c);
uc.setAlpha(i.uc->alpha);
uc.setBeta(i.uc->beta);
uc.setGamma(i.uc->gamma);
tmp.setUc(uc);
}
if (i.indexed_lattice_count.has_value())
tmp.setLattCount(i.indexed_lattice_count.value());
if (i.xfel_pulse_id.has_value())
tmp.setXfelPulseid(i.xfel_pulse_id.value());
if (i.res.has_value())
tmp.setRes(i.res.value());
v.emplace_back(std::move(tmp));
}
ret.setImages(v);
if (input.rotation_lattice) {
ret.setRotationCrystalLattice(input.rotation_lattice->GetVector());
org::openapitools::server::model::Unit_cell uc;
auto i_uc = input.rotation_lattice->GetUnitCell();
uc.setA(i_uc.a);
uc.setB(i_uc.b);
uc.setC(i_uc.c);
uc.setAlpha(i_uc.alpha);
uc.setBeta(i_uc.beta);
uc.setGamma(i_uc.gamma);
ret.setRotationUnitCell(uc);
}
if (input.rotation_crystal_system && input.rotation_centering)
ret.setRotationBravais(BravaisSymbol(*input.rotation_crystal_system, *input.rotation_centering));
// The two mode-specific payloads. Optional and independent, exactly as the rotation_* members
// above are: present when that mode ran, absent otherwise.
if (input.grid) {
org::openapitools::server::model::Grid_scan_result grid;
std::vector<org::openapitools::server::model::Grid_scan_crystal> crystals;
for (const auto &c : input.grid->crystals)
crystals.emplace_back(Convert(c));
grid.setCrystals(crystals);
grid.setBeamSizeXUm(input.grid->beam_size_x_um);
grid.setBeamSizeYUm(input.grid->beam_size_y_um);
ret.setGrid(grid);
}
if (input.calibration)
ret.setCalibration(Convert(input.calibration.value()));
return ret;
}
org::openapitools::server::model::Dark_mask_settings Convert(const DarkMaskSettings &input) {
org::openapitools::server::model::Dark_mask_settings ret{};
ret.setDetectorThresholdKeV(input.GetThreshold_keV());
ret.setFrameTimeUs(std::chrono::round<std::chrono::microseconds>(
std::chrono::duration<float>(input.GetFrameTime())
).count());
ret.setMaxFramesWithSignal(input.GetMaxFramesWithCounts());
ret.setMaxAllowedPixelCount(input.GetMaxCounts());
ret.setNumberOfFrames(input.GetNumberOfFrames());
return ret;
}
DarkMaskSettings Convert(const org::openapitools::server::model::Dark_mask_settings &input) {
DarkMaskSettings ret{};
ret.FrameTime(std::chrono::microseconds(input.getFrameTimeUs()))
.NumberOfFrames(input.getNumberOfFrames())
.MaxCounts(input.getMaxAllowedPixelCount())
.MaxFramesWithCounts(input.getMaxFramesWithSignal())
.Threshold_keV(input.getDetectorThresholdKeV());
return ret;
}
org::openapitools::server::model::Image_pusher_status Convert(const ImagePusherStatus& input) {
org::openapitools::server::model::Image_pusher_status ret;
ret.setAddr(input.address);
ret.setConnectedWriters(input.connected_writers);
org::openapitools::server::model::Image_pusher_type tmp;
switch (input.pusher_type) {
case ImagePusherType::HDF5:
tmp.setValue(org::openapitools::server::model::Image_pusher_type::eImage_pusher_type::HDF5);
break;
case ImagePusherType::CBOR:
tmp.setValue(org::openapitools::server::model::Image_pusher_type::eImage_pusher_type::CBOR);
break;
case ImagePusherType::TCP:
tmp.setValue(org::openapitools::server::model::Image_pusher_type::eImage_pusher_type::TCP);
break;
case ImagePusherType::ZMQ:
tmp.setValue(org::openapitools::server::model::Image_pusher_type::eImage_pusher_type::ZEROMQ);
break;
default:
tmp.setValue(org::openapitools::server::model::Image_pusher_type::eImage_pusher_type::NONE);
break;
}
ret.setPusherType(tmp);
if (input.images_written)
ret.setImagesWritten(input.images_written.value());
if (input.images_write_error)
ret.setImagesWriteError(input.images_write_error.value());
ret.setWriterFifoUtilization(input.writer_fifo_utilization);
return ret;
}