From 5e58f20003346f0aa4568d6e7eb6489ae23f6083 Mon Sep 17 00:00:00 2001 From: leonarski_f Date: Mon, 27 Apr 2026 13:16:07 +0200 Subject: [PATCH 01/10] DetectorSimplonClient: Rearrange logic to achieve shorter setup time --- detector_control/DectrisDetectorWrapper.cpp | 6 +- detector_control/DectrisSimplonClient.cpp | 61 +++++++++++---------- detector_control/DectrisSimplonClient.h | 4 +- 3 files changed, 38 insertions(+), 33 deletions(-) diff --git a/detector_control/DectrisDetectorWrapper.cpp b/detector_control/DectrisDetectorWrapper.cpp index 01c9a05d..136fab3c 100644 --- a/detector_control/DectrisDetectorWrapper.cpp +++ b/detector_control/DectrisDetectorWrapper.cpp @@ -91,10 +91,8 @@ void DectrisDetectorWrapper::Configure(const DiffractionExperiment &experiment) void DectrisDetectorWrapper::Start(const DiffractionExperiment &experiment) { CheckBusyOrError(); - if (simplon) { - simplon->ConfigureDetector(experiment); - simplon->StartAcquisition(); - } + if (simplon) + simplon->StartAcquisition(experiment); } void DectrisDetectorWrapper::Stop() { diff --git a/detector_control/DectrisSimplonClient.cpp b/detector_control/DectrisSimplonClient.cpp index 700077fe..8a9367f3 100644 --- a/detector_control/DectrisSimplonClient.cpp +++ b/detector_control/DectrisSimplonClient.cpp @@ -84,9 +84,14 @@ void DectrisSimplonClient::SetConfig(SimplonModule element, const std::string &k } } -std::string DectrisSimplonClient::GenAddr(DectrisSimplonClient::SimplonModule element, - DectrisSimplonClient::SimplonTask task, - const std::string& key) { +void DectrisSimplonClient::SetConfigIfDifferent(SimplonModule element, const std::string &key, float value, float tolerance) { + auto curr_val = GetConfig(element, key).val.get(); + + if (std::abs(curr_val - value) > tolerance) + SetConfig(element, key, value); +} + +std::string DectrisSimplonClient::GenAddr(SimplonModule element, SimplonTask task, const std::string& key) { std::string addr; switch (element) { case SimplonModule::Detector: @@ -120,9 +125,7 @@ std::string DectrisSimplonClient::GenAddr(DectrisSimplonClient::SimplonModule el } SimplonConfig -DectrisSimplonClient::GetConfig(DectrisSimplonClient::SimplonModule element, - DectrisSimplonClient::SimplonTask task, - const std::string &key) { +DectrisSimplonClient::GetConfig(SimplonModule element, SimplonTask task, const std::string &key) { httplib::Client cli_simple(hostname, port); cli_simple.set_connection_timeout(std::chrono::milliseconds(500)); cli_simple.set_read_timeout(std::chrono::seconds(1)); @@ -162,7 +165,7 @@ SimplonConfig DectrisSimplonClient::GetDetCfg(const std::string &key) { return GetConfig(SimplonModule::Detector, key); } -nlohmann::json DectrisSimplonClient::GetStatus(DectrisSimplonClient::SimplonModule element, const std::string &key) { +nlohmann::json DectrisSimplonClient::GetStatus(SimplonModule element, const std::string &key) { return GetConfig(element, SimplonTask::Status, key).val; } @@ -207,6 +210,11 @@ void DectrisSimplonClient::InitializeDetector(DetectorSetup& setup) { "Initialize unsuccessful"); SetConfig(SimplonModule::Detector, "roi_mode", setup.GetDECTRISROI()); + // Configure streaming, disable file writer and monitor + SetConfig(SimplonModule::Stream, "format", "cbor"); + SetConfig(SimplonModule::Stream, "mode", "enabled"); + SetConfig(SimplonModule::Filewriter, "mode", "disabled"); + SetConfig(SimplonModule::Monitor, "mode", "disabled"); ReadDetectorConfig(setup); } @@ -222,24 +230,34 @@ void DectrisSimplonClient::EndAcquisitionFinished() { SendDetectorCommand(SimplonDetectorCommand::Disarm); } -void DectrisSimplonClient::StartAcquisition() { +void DectrisSimplonClient::StartAcquisition(const DiffractionExperiment& experiment) { + // For DECTRIS detectors we assume frame_time == count_time + if (experiment.GetFrameCountTimeAuto()) + SetConfig(SimplonModule::Detector, "count_time", experiment.GetFrameTime().count() / 1e6f); + else + SetConfig(SimplonModule::Detector, "count_time", experiment.GetFrameCountTime().count() / 1e6f); + + SetConfig(SimplonModule::Detector, "frame_time", experiment.GetFrameTime().count() / 1e6f); + SetConfig(SimplonModule::Detector, "nimages", experiment.GetFrameNumPerTrigger()); + SetConfig(SimplonModule::Detector, "ntrigger", experiment.GetNumTriggers()); + + SetConfig(SimplonModule::Detector, "beam_center_x", experiment.GetBeamX_pxl()); + SetConfig(SimplonModule::Detector, "beam_center_y", experiment.GetBeamY_pxl()); + SetConfig(SimplonModule::Detector, "detector_distance", experiment.GetDetectorDistance_mm() / 1e3f); + SendDetectorCommand(SimplonDetectorCommand::Arm); } void DectrisSimplonClient::ConfigureDetector(const DiffractionExperiment &experiment) { - SetConfig(SimplonModule::Stream, "format", "cbor"); - SetConfig(SimplonModule::Stream, "mode", "enabled"); - SetConfig(SimplonModule::Filewriter, "mode", "disabled"); - SetConfig(SimplonModule::Monitor, "mode", "disabled"); - // TODO: Check if counting_mode retrigger is available if (experiment.GetDetectorMode() == DetectorMode::DarkMask) SetConfig(SimplonModule::Detector, "counting_mode", "normal"); else SetConfig(SimplonModule::Detector, "counting_mode", "retrigger"); - SetConfig(SimplonModule::Detector, "photon_energy", experiment.GetIncidentEnergy_keV() * 1e3f); + + SetConfigIfDifferent(SimplonModule::Detector, "photon_energy", experiment.GetIncidentEnergy_keV() * 1e3f, 0.01f); auto thr = experiment.GetEigerThreshold_keV(); - SetConfig(SimplonModule::Detector, "threshold_energy", thr * 1e3f); + SetConfigIfDifferent(SimplonModule::Detector, "threshold_energy", thr * 1e3f, 0.01); switch (experiment.GetDetectorTiming()) { case DetectorTiming::Auto: @@ -256,19 +274,6 @@ void DectrisSimplonClient::ConfigureDetector(const DiffractionExperiment &experi "Burst mode not supported with DECTRIS sytems"); } - // For DECTRIS detectors we assume frame_time == count_time - if (experiment.GetFrameCountTimeAuto()) - SetConfig(SimplonModule::Detector, "count_time", experiment.GetFrameTime().count() / 1e6f); - else - SetConfig(SimplonModule::Detector, "count_time", experiment.GetFrameCountTime().count() / 1e6f); - - SetConfig(SimplonModule::Detector, "frame_time", experiment.GetFrameTime().count() / 1e6f); - SetConfig(SimplonModule::Detector, "nimages", experiment.GetFrameNumPerTrigger()); - SetConfig(SimplonModule::Detector, "ntrigger", experiment.GetNumTriggers()); - - SetConfig(SimplonModule::Detector, "beam_center_x", experiment.GetBeamX_pxl()); - SetConfig(SimplonModule::Detector, "beam_center_y", experiment.GetBeamY_pxl()); - SetConfig(SimplonModule::Detector, "detector_distance", experiment.GetDetectorDistance_mm() / 1e3f); SetConfig(SimplonModule::Detector, "trigger_start_delay", experiment.GetDetectorDelay().count() / 1e9); } diff --git a/detector_control/DectrisSimplonClient.h b/detector_control/DectrisSimplonClient.h index 05ae636f..51f38d97 100644 --- a/detector_control/DectrisSimplonClient.h +++ b/detector_control/DectrisSimplonClient.h @@ -39,12 +39,14 @@ class DectrisSimplonClient { SimplonConfig GetConfig(SimplonModule element, const std::string &key); nlohmann::json GetStatus(SimplonModule element, const std::string &key); void SetConfig(SimplonModule element, const std::string &key, const nlohmann::json &value); + void SetConfigIfDifferent(SimplonModule element, const std::string &key, float value, float tolerance); + void SendDetectorCommand(SimplonDetectorCommand cmd); public: explicit DectrisSimplonClient(const std::string& hostname, uint16_t port = 80); void ReadDetectorConfig(DetectorSetup &setup); void ConfigureDetector(const DiffractionExperiment& experiment); - void StartAcquisition(); + void StartAcquisition(const DiffractionExperiment& experiment); void EndAcquisitionFinished(); void CancelAcquisition(); void TriggerAcquisition(); -- 2.52.0 From 3cf20fb94689daaf3cb7fce106cc968314689a52 Mon Sep 17 00:00:00 2001 From: leonarski_f Date: Mon, 27 Apr 2026 13:39:39 +0200 Subject: [PATCH 02/10] JFJochStateMachine: Enable async workflow to start measurement --- broker/JFJochStateMachine.cpp | 40 ++++++++++++++++++++++++----------- broker/JFJochStateMachine.h | 4 +++- 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/broker/JFJochStateMachine.cpp b/broker/JFJochStateMachine.cpp index d853ce64..137d2811 100644 --- a/broker/JFJochStateMachine.cpp +++ b/broker/JFJochStateMachine.cpp @@ -344,7 +344,7 @@ void JFJochStateMachine::Trigger() { services.Trigger(); } -void JFJochStateMachine::Start(const DatasetSettings &settings) { +void JFJochStateMachine::Start(const DatasetSettings &settings, bool async) { std::unique_lock ul(m); if (state != JFJochState::Idle) @@ -363,18 +363,16 @@ void JFJochStateMachine::Start(const DatasetSettings &settings) { experiment.IncrementRunNumber(); - try { - SetState(JFJochState::Busy, "Preparing measurement", BrokerStatus::MessageSeverity::Info); - services.SetSpotFindingSettings(GetSpotFindingSettings()); - services.Start(experiment, pixel_mask, calibration.get()); + SetState(JFJochState::Busy, "Preparing measurement", BrokerStatus::MessageSeverity::Info); + measurement = std::async(std::launch::async, &JFJochStateMachine::MeasurementThread, this); + if (!async) + c.wait(ul, [&]() { return state != JFJochState::Busy; }); +} - SetState(JFJochState::Measuring, "Measuring ...", BrokerStatus::MessageSeverity::Info); - measurement = std::async(std::launch::async, &JFJochStateMachine::MeasurementThread, this); - } catch (const std::exception &e) { - SetState(JFJochState::Error, e.what(), BrokerStatus::MessageSeverity::Error); - services.Cancel(); - throw; - } +JFJochState JFJochStateMachine::WaitTillNotBusy(std::chrono::milliseconds timeout) { + std::unique_lock ul(m); + c.wait_for(ul, timeout, [&]() { return state != JFJochState::Busy; }); + return state; } void JFJochStateMachine::UpdatePixelMaskStatistics(const PixelMaskStatistics &input) { @@ -388,6 +386,24 @@ PixelMaskStatistics JFJochStateMachine::GetPixelMaskStatistics() const { } void JFJochStateMachine::MeasurementThread() { + try { + services.SetSpotFindingSettings(GetSpotFindingSettings()); + services.Start(experiment, pixel_mask, calibration.get()); + { + std::unique_lock ul(m); + SetState(JFJochState::Measuring, "Measuring ...", BrokerStatus::MessageSeverity::Info); + } + c.notify_all(); + } catch (std::exception &e) { + { + std::unique_lock ul(m); + SetState(JFJochState::Error, e.what(), BrokerStatus::MessageSeverity::Error); + } + services.Cancel(); + c.notify_all(); + return; + } + try { auto tmp_output = services.Stop(); { diff --git a/broker/JFJochStateMachine.h b/broker/JFJochStateMachine.h index 240183c2..cec18d6b 100644 --- a/broker/JFJochStateMachine.h +++ b/broker/JFJochStateMachine.h @@ -152,7 +152,9 @@ public: void Initialize(); void Pedestal(); void Deactivate(); - void Start(const DatasetSettings& settings); + void Start(const DatasetSettings& settings, bool async = false); + JFJochState WaitTillNotBusy(std::chrono::milliseconds timeout); + BrokerStatus WaitTillMeasurementDone(); BrokerStatus WaitTillMeasurementDone(std::chrono::milliseconds timeout); void Trigger(); -- 2.52.0 From 4c88a92dc08a2ca9179177c7a6aac3c6d755438b Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Mon, 27 Apr 2026 14:36:05 +0200 Subject: [PATCH 03/10] OpenAPI: Enable async start --- broker/JFJochBrokerHttp.cpp | 41 ++++++- broker/JFJochBrokerHttp.h | 2 + broker/JFJochStateMachine.cpp | 4 +- broker/JFJochStateMachine.h | 2 +- broker/gen/model/Dataset_settings.cpp | 31 ++++- broker/gen/model/Dataset_settings.h | 9 ++ broker/jfjoch_api.yaml | 42 ++++++- broker/redoc-static.html | 114 ++++++++++-------- docs/python_client/README.md | 1 + docs/python_client/docs/DatasetSettings.md | 1 + docs/python_client/docs/DefaultApi.md | 78 +++++++++++- frontend/package-lock.json | 4 +- .../src/openapi/models/dataset_settings.ts | 4 + .../src/openapi/services/DefaultService.ts | 33 ++++- 14 files changed, 301 insertions(+), 65 deletions(-) diff --git a/broker/JFJochBrokerHttp.cpp b/broker/JFJochBrokerHttp.cpp index dd5c48d1..959ff8e2 100644 --- a/broker/JFJochBrokerHttp.cpp +++ b/broker/JFJochBrokerHttp.cpp @@ -347,6 +347,15 @@ void JFJochBrokerHttp::register_routes(httplib::Server &server) { } }); + server.Post("/wait_until_running", [this](const httplib::Request &req, httplib::Response &res) { + try { + wait_until_running_post(parse_query_value(req, "timeout"), res); + } catch (const std::exception &e) { + auto [c, s] = handleOperationException(e); + send_plain(res, c, s); + } + }); + server.Get("/xfel/event_code", bind_noarg(&JFJochBrokerHttp::xfel_event_code_get)); server.Get("/xfel/pulse_id", bind_noarg(&JFJochBrokerHttp::xfel_pulse_id_get)); } @@ -369,7 +378,7 @@ void JFJochBrokerHttp::initialize_post(httplib::Response &response) { void JFJochBrokerHttp::start_post(const Dataset_settings &datasetSettings, httplib::Response &response) { nlohmann::json j = datasetSettings; logger.Info("Start {}", j.dump()); - state_machine.Start(Convert(datasetSettings)); + state_machine.Start(Convert(datasetSettings), datasetSettings.isAsyncStart()); response.status = 200; } @@ -377,6 +386,36 @@ void JFJochBrokerHttp::status_get(httplib::Response &response) { ProcessOutput(Convert(state_machine.GetStatus()), response); } +void JFJochBrokerHttp::wait_until_running_post(const std::optional &timeout, httplib::Response &response) { + BrokerStatus status; + if (!timeout) + status = state_machine.WaitTillNotBusy(std::chrono::minutes(1)); + else if ((timeout.value() > 3600) || (timeout.value() < 0)) { + response.status = 400; + response.set_content("timeout must be in range 0..3600", "text/plain"); + return; + } else if (timeout.value() == 0) + status = state_machine.GetStatus(); + else + status = state_machine.WaitTillNotBusy(std::chrono::seconds(timeout.value())); + + switch (status.state) { + case JFJochState::Measuring: + response.status = 200; + break; + case JFJochState::Inactive: + response.status = 502; + break; + case JFJochState::Error: + throw WrongDAQStateException(status.message.value_or("Unknown error")); + case JFJochState::Idle: + case JFJochState::Busy: + case JFJochState::Calibration: + response.status = 504; + break; + } +} + void JFJochBrokerHttp::wait_till_done_post(const std::optional &timeout, httplib::Response &response) { BrokerStatus status; if (!timeout) diff --git a/broker/JFJochBrokerHttp.h b/broker/JFJochBrokerHttp.h index 3cfe134e..d69c55e6 100644 --- a/broker/JFJochBrokerHttp.h +++ b/broker/JFJochBrokerHttp.h @@ -77,6 +77,8 @@ class JFJochBrokerHttp { httplib::Response &response); void status_get(httplib::Response &response); void wait_till_done_post(const std::optional &timeout, httplib::Response &response); + void wait_until_running_post(const std::optional &timeout, httplib::Response &response); + void trigger_post(httplib::Response &response); void pedestal_post(httplib::Response &response); diff --git a/broker/JFJochStateMachine.cpp b/broker/JFJochStateMachine.cpp index 137d2811..50b9f87a 100644 --- a/broker/JFJochStateMachine.cpp +++ b/broker/JFJochStateMachine.cpp @@ -369,10 +369,10 @@ void JFJochStateMachine::Start(const DatasetSettings &settings, bool async) { c.wait(ul, [&]() { return state != JFJochState::Busy; }); } -JFJochState JFJochStateMachine::WaitTillNotBusy(std::chrono::milliseconds timeout) { +BrokerStatus JFJochStateMachine::WaitTillNotBusy(std::chrono::milliseconds timeout) { std::unique_lock ul(m); c.wait_for(ul, timeout, [&]() { return state != JFJochState::Busy; }); - return state; + return GetStatus(); } void JFJochStateMachine::UpdatePixelMaskStatistics(const PixelMaskStatistics &input) { diff --git a/broker/JFJochStateMachine.h b/broker/JFJochStateMachine.h index cec18d6b..b2f0413a 100644 --- a/broker/JFJochStateMachine.h +++ b/broker/JFJochStateMachine.h @@ -153,7 +153,7 @@ public: void Pedestal(); void Deactivate(); void Start(const DatasetSettings& settings, bool async = false); - JFJochState WaitTillNotBusy(std::chrono::milliseconds timeout); + BrokerStatus WaitTillNotBusy(std::chrono::milliseconds timeout); BrokerStatus WaitTillMeasurementDone(); BrokerStatus WaitTillMeasurementDone(std::chrono::milliseconds timeout); diff --git a/broker/gen/model/Dataset_settings.cpp b/broker/gen/model/Dataset_settings.cpp index 53ff6dfe..d124109a 100644 --- a/broker/gen/model/Dataset_settings.cpp +++ b/broker/gen/model/Dataset_settings.cpp @@ -84,6 +84,8 @@ Dataset_settings::Dataset_settings() m_Max_spot_countIsSet = false; m_Detect_ice_rings = false; m_Detect_ice_ringsIsSet = false; + m_Async_start = false; + m_Async_startIsSet = false; m_Xray_fluorescence_spectrumIsSet = false; } @@ -423,7 +425,7 @@ bool Dataset_settings::validate(std::stringstream& msg, const std::string& pathP } } - + return success; } @@ -541,6 +543,9 @@ bool Dataset_settings::operator==(const Dataset_settings& rhs) const ((!detectIceRingsIsSet() && !rhs.detectIceRingsIsSet()) || (detectIceRingsIsSet() && rhs.detectIceRingsIsSet() && isDetectIceRings() == rhs.isDetectIceRings())) && + ((!asyncStartIsSet() && !rhs.asyncStartIsSet()) || (asyncStartIsSet() && rhs.asyncStartIsSet() && isAsyncStart() == rhs.isAsyncStart())) && + + ((!xrayFluorescenceSpectrumIsSet() && !rhs.xrayFluorescenceSpectrumIsSet()) || (xrayFluorescenceSpectrumIsSet() && rhs.xrayFluorescenceSpectrumIsSet() && getXrayFluorescenceSpectrum() == rhs.getXrayFluorescenceSpectrum())) ; @@ -622,6 +627,8 @@ void to_json(nlohmann::json& j, const Dataset_settings& o) j["max_spot_count"] = o.m_Max_spot_count; if(o.detectIceRingsIsSet()) j["detect_ice_rings"] = o.m_Detect_ice_rings; + if(o.asyncStartIsSet()) + j["async_start"] = o.m_Async_start; if(o.xrayFluorescenceSpectrumIsSet()) j["xray_fluorescence_spectrum"] = o.m_Xray_fluorescence_spectrum; @@ -793,6 +800,11 @@ void from_json(const nlohmann::json& j, Dataset_settings& o) j.at("detect_ice_rings").get_to(o.m_Detect_ice_rings); o.m_Detect_ice_ringsIsSet = true; } + if(j.find("async_start") != j.end()) + { + j.at("async_start").get_to(o.m_Async_start); + o.m_Async_startIsSet = true; + } if(j.find("xray_fluorescence_spectrum") != j.end()) { j.at("xray_fluorescence_spectrum").get_to(o.m_Xray_fluorescence_spectrum); @@ -1377,6 +1389,23 @@ void Dataset_settings::unsetDetect_ice_rings() { m_Detect_ice_ringsIsSet = false; } +bool Dataset_settings::isAsyncStart() const +{ + return m_Async_start; +} +void Dataset_settings::setAsyncStart(bool const value) +{ + m_Async_start = value; + m_Async_startIsSet = true; +} +bool Dataset_settings::asyncStartIsSet() const +{ + return m_Async_startIsSet; +} +void Dataset_settings::unsetAsync_start() +{ + m_Async_startIsSet = false; +} org::openapitools::server::model::Dataset_settings_xray_fluorescence_spectrum Dataset_settings::getXrayFluorescenceSpectrum() const { return m_Xray_fluorescence_spectrum; diff --git a/broker/gen/model/Dataset_settings.h b/broker/gen/model/Dataset_settings.h index ffc24fac..c83cdf55 100644 --- a/broker/gen/model/Dataset_settings.h +++ b/broker/gen/model/Dataset_settings.h @@ -308,6 +308,13 @@ public: bool detectIceRingsIsSet() const; void unsetDetect_ice_rings(); /// + /// When set to true, `/start` will not wait for detector and Jungfraujoch to be ready for the measurement. + /// + bool isAsyncStart() const; + void setAsyncStart(bool const value); + bool asyncStartIsSet() const; + void unsetAsync_start(); + /// /// /// org::openapitools::server::model::Dataset_settings_xray_fluorescence_spectrum getXrayFluorescenceSpectrum() const; @@ -390,6 +397,8 @@ protected: bool m_Max_spot_countIsSet; bool m_Detect_ice_rings; bool m_Detect_ice_ringsIsSet; + bool m_Async_start; + bool m_Async_startIsSet; org::openapitools::server::model::Dataset_settings_xray_fluorescence_spectrum m_Xray_fluorescence_spectrum; bool m_Xray_fluorescence_spectrumIsSet; diff --git a/broker/jfjoch_api.yaml b/broker/jfjoch_api.yaml index dff58ac0..1e5f2885 100644 --- a/broker/jfjoch_api.yaml +++ b/broker/jfjoch_api.yaml @@ -567,6 +567,10 @@ components: detect_ice_rings: type: boolean description: Flag spots as ice rings and reduce their effect on indexing + async_start: + type: boolean + default: false + description: When set to true, `/start` will not wait for detector and Jungfraujoch to be ready for the measurement. xray_fluorescence_spectrum: type: object required: @@ -2354,15 +2358,15 @@ paths: application/json: schema: $ref: '#/components/schemas/error_message' - /start: post: summary: Start detector description: | Start data acquisition. Detector must be in `Idle` state. - Doesn't run calibration procedure. - When the function returns, detector is ready to accept soft/TTL triggers. + Default behavior is for the call to block until detector is ready to accept soft/TTL triggers. + However, this behavior can be changed by settings `async_start` to true in the request body, + in which case the call will return immediately and one needs to use `/wait_until_running` to ensure detector is ready to run. requestBody: content: application/json: @@ -2384,6 +2388,38 @@ paths: application/json: schema: $ref: '#/components/schemas/error_message' + /wait_until_running: + post: + summary: Wait for acquisition running + parameters: + - in: query + name: timeout + required: false + schema: + type: integer + default: 60 + minimum: 0 + maximum: 3600 + description: Timeout in seconds (0 == immediate response) + description: | + Block execution of external script till detector and Jungfraujoch are ready to collect data. + To not block web server for a indefinite period of time, the procedure is provided with a timeout. + Extending timeout is possible, but requires to ensure safety that client will not close the connection and retry the connection. + responses: + "200": + description: Detector in `Measuring` state + "400": + description: Timeout parameter out of bounds + "500": + description: Error within Jungfraujoch code - see output message. + content: + application/json: + schema: + $ref: '#/components/schemas/error_message' + "502": + description: Detector is inactive mode + "504": + description: Timeout reached, need to restart operation /wait_till_done: post: summary: Wait for acquisition done diff --git a/broker/redoc-static.html b/broker/redoc-static.html index 2d9d9e68..e7cd7ee1 100644 --- a/broker/redoc-static.html +++ b/broker/redoc-static.html @@ -367,7 +367,7 @@ data-styled.g138[id="sc-dxcDKg"]{content:"eajCCh,"}/*!sc*/ -

Start detector

Start data acquisition. Detector must be in Idle state. -Doesn't run calibration procedure. -When the function returns, detector is ready to accept soft/TTL triggers.

+Default behavior is for the call to block until detector is ready to accept soft/TTL triggers. +However, this behavior can be changed by settings async_start to true in the request body, +in which case the call will return immediately and one needs to use /wait_until_running to ensure detector is ready to run.

Request Body schema: application/json
images_per_trigger
integer <int64> >= 1
Default: 1

For standard synchrotron data collection - this is number of images collected per one TTL trigger For XFEL (pulsed source) - this number is ignored and set to 1 For storage cell mode - this number is ignored and set to number of storage cells

@@ -504,11 +505,22 @@ If parameter is not provided calibration will be saved only if more than 4 image
spot_finding
boolean
Default: true

Enable spot finding and save spots

max_spot_count
integer [ 10 .. 2000 ]
Default: 250

Maximum number of spots that are saved/used for indexing; spots with highest intensity are selected

detect_ice_rings
boolean

Flag spots as ice rings and reduce their effect on indexing

+
async_start
boolean
Default: false

When set to true, /start will not wait for detector and Jungfraujoch to be ready for the measurement.

object

Responses

Request samples

Content type
application/json
{
  • "images_per_trigger": 1,
  • "ntrigger": 1,
  • "image_time_us": 0,
  • "beam_x_pxl": 0.1,
  • "beam_y_pxl": 0.1,
  • "detector_distance_mm": 0.1,
  • "incident_energy_keV": 0.001,
  • "file_prefix": "",
  • "images_per_file": 1000,
  • "space_group_number": 1,
  • "sample_name": "",
  • "compression": "bslz4",
  • "total_flux": 0.1,
  • "transmission": 1,
  • "goniometer": {
    },
  • "grid_scan": {
    },
  • "header_appendix": null,
  • "image_appendix": null,
  • "data_reduction_factor_serialmx": 1,
  • "pixel_value_low_threshold": 0,
  • "run_number": 0,
  • "run_name": "string",
  • "experiment_group": "string",
  • "poisson_compression": 16,
  • "write_nxmx_hdf5_master": true,
  • "save_calibration": true,
  • "polarization_factor": -1,
  • "ring_current_mA": 0.1,
  • "sample_temperature_K": 0.1,
  • "poni_rot1_rad": 0,
  • "poni_rot2_rad": 0,
  • "poni_rot3_rad": 0,
  • "unit_cell": {
    },
  • "spot_finding": true,
  • "max_spot_count": 250,
  • "detect_ice_rings": true,
  • "xray_fluorescence_spectrum": {
    }
}

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Wait for acquisition done

Block execution of external script till initialization, data collection or pedestal is finished. +

http://localhost:5232/start

Request samples

Content type
application/json
{
  • "images_per_trigger": 1,
  • "ntrigger": 1,
  • "image_time_us": 0,
  • "beam_x_pxl": 0.1,
  • "beam_y_pxl": 0.1,
  • "detector_distance_mm": 0.1,
  • "incident_energy_keV": 0.001,
  • "file_prefix": "",
  • "images_per_file": 1000,
  • "space_group_number": 1,
  • "sample_name": "",
  • "compression": "bslz4",
  • "total_flux": 0.1,
  • "transmission": 1,
  • "goniometer": {
    },
  • "grid_scan": {
    },
  • "header_appendix": null,
  • "image_appendix": null,
  • "data_reduction_factor_serialmx": 1,
  • "pixel_value_low_threshold": 0,
  • "run_number": 0,
  • "run_name": "string",
  • "experiment_group": "string",
  • "poisson_compression": 16,
  • "write_nxmx_hdf5_master": true,
  • "save_calibration": true,
  • "polarization_factor": -1,
  • "ring_current_mA": 0.1,
  • "sample_temperature_K": 0.1,
  • "poni_rot1_rad": 0,
  • "poni_rot2_rad": 0,
  • "poni_rot3_rad": 0,
  • "unit_cell": {
    },
  • "spot_finding": true,
  • "max_spot_count": 250,
  • "detect_ice_rings": true,
  • "async_start": false,
  • "xray_fluorescence_spectrum": {
    }
}

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Wait for acquisition running

Block execution of external script till detector and Jungfraujoch are ready to collect data. +To not block web server for a indefinite period of time, the procedure is provided with a timeout. +Extending timeout is possible, but requires to ensure safety that client will not close the connection and retry the connection.

+
query Parameters
timeout
integer [ 0 .. 3600 ]
Default: 60

Timeout in seconds (0 == immediate response)

+

Responses

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Wait for acquisition done

Block execution of external script till initialization, data collection or pedestal is finished. Running this command does not affect (cancel) running data collection, it is only to ensure synchronous execution of other software.

To not block web server for a indefinite period of time, the procedure is provided with a timeout. Extending timeout is possible, but requires to ensure safety that client will not close the connection and retry the connection.

@@ -519,7 +531,7 @@ Extending timeout is possible, but requires to ensure safety that client will no

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Send soft trigger to the detector

Generate soft trigger

+
http://localhost:5232/wait_till_done

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Send soft trigger to the detector

Generate soft trigger

Responses

Cancel running data collection

Command will inform FPGA network card to stop pedestal or data collection at the current stage. @@ -534,7 +546,7 @@ Should be used always before turning off power from the detector.

Responses

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Change detector configuration

Detector settings are ones that have effect on calibration, i.e., pedestal has to be collected again after changing these settings. +

http://localhost:5232/deactivate

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Change detector configuration

Detector settings are ones that have effect on calibration, i.e., pedestal has to be collected again after changing these settings. This can only be done when detector is Idle, Error or Inactive states. If detector is in Idle state , pedestal procedure will be executed automatically - there must be no X-rays on the detector during the operation. If detector is in Inactive or Error states, new settings will be saved, but no calibration will be executed.

@@ -564,10 +576,10 @@ This might lead to increased start time.

Request samples

Content type
application/json
{
  • "frame_time_us": 1,
  • "count_time_us": 0,
  • "internal_frame_generator": false,
  • "internal_frame_generator_images": 1,
  • "detector_trigger_delay_ns": 0,
  • "timing": "auto",
  • "eiger_threshold_keV": 1,
  • "eiger_bit_depth": 8,
  • "jungfrau_pedestal_g0_frames": 2000,
  • "jungfrau_pedestal_g1_frames": 300,
  • "jungfrau_pedestal_g2_frames": 300,
  • "jungfrau_pedestal_min_image_count": 128,
  • "jungfrau_storage_cell_count": 1,
  • "jungfrau_storage_cell_delay_ns": 5000,
  • "jungfrau_fixed_gain_g1": false,
  • "jungfrau_use_gain_hg0": false
}

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Get detector configuration

Can be done anytime

+
http://localhost:5232/config/detector

Request samples

Content type
application/json
{
  • "frame_time_us": 1,
  • "count_time_us": 0,
  • "internal_frame_generator": false,
  • "internal_frame_generator_images": 1,
  • "detector_trigger_delay_ns": 0,
  • "timing": "auto",
  • "eiger_threshold_keV": 1,
  • "eiger_bit_depth": 8,
  • "jungfrau_pedestal_g0_frames": 2000,
  • "jungfrau_pedestal_g1_frames": 300,
  • "jungfrau_pedestal_g2_frames": 300,
  • "jungfrau_pedestal_min_image_count": 128,
  • "jungfrau_storage_cell_count": 1,
  • "jungfrau_storage_cell_delay_ns": 5000,
  • "jungfrau_fixed_gain_g1": false,
  • "jungfrau_use_gain_hg0": false
}

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Get detector configuration

Can be done anytime

Responses

Response samples

Content type
application/json
{
  • "frame_time_us": 1,
  • "count_time_us": 0,
  • "internal_frame_generator": false,
  • "internal_frame_generator_images": 1,
  • "detector_trigger_delay_ns": 0,
  • "timing": "auto",
  • "eiger_threshold_keV": 1,
  • "eiger_bit_depth": 8,
  • "jungfrau_pedestal_g0_frames": 2000,
  • "jungfrau_pedestal_g1_frames": 300,
  • "jungfrau_pedestal_g2_frames": 300,
  • "jungfrau_pedestal_min_image_count": 128,
  • "jungfrau_storage_cell_count": 1,
  • "jungfrau_storage_cell_delay_ns": 5000,
  • "jungfrau_fixed_gain_g1": false,
  • "jungfrau_use_gain_hg0": false
}

Change indexing algorithm settings

This can only be done when detector is Idle, Error or Inactive states.

+
http://localhost:5232/config/detector

Response samples

Content type
application/json
{
  • "frame_time_us": 1,
  • "count_time_us": 0,
  • "internal_frame_generator": false,
  • "internal_frame_generator_images": 1,
  • "detector_trigger_delay_ns": 0,
  • "timing": "auto",
  • "eiger_threshold_keV": 1,
  • "eiger_bit_depth": 8,
  • "jungfrau_pedestal_g0_frames": 2000,
  • "jungfrau_pedestal_g1_frames": 300,
  • "jungfrau_pedestal_g2_frames": 300,
  • "jungfrau_pedestal_min_image_count": 128,
  • "jungfrau_storage_cell_count": 1,
  • "jungfrau_storage_cell_delay_ns": 5000,
  • "jungfrau_fixed_gain_g1": false,
  • "jungfrau_use_gain_hg0": false
}

Change indexing algorithm settings

This can only be done when detector is Idle, Error or Inactive states.

Request Body schema: application/json
algorithm
required
string (indexing_algorithm)
Default: "FFBIDX"
Enum: "FFBIDX" "FFT" "FFTW" "Auto" "None"

Selection of an indexing algorithm used by Jungfraujoch

fft_max_unit_cell_A
required
number <float> [ 50 .. 500 ]
Default: 250

Largest unit cell to be indexed by FFT algorithm; parameter value affects execution time of FFT

fft_min_unit_cell_A
required
number <float> [ 5 .. 40 ]
Default: 10

Smallest unit cell to be indexed by FFT algorithm; parameter value affects execution time of FFT

@@ -589,10 +601,10 @@ If set to true, the thread pool will block until a thread is available.

Request samples

Content type
application/json
{
  • "algorithm": "FFBIDX",
  • "fft_max_unit_cell_A": 250,
  • "fft_min_unit_cell_A": 10,
  • "fft_high_resolution_A": 2,
  • "fft_num_vectors": 16384,
  • "tolerance": 0.5,
  • "thread_count": 1,
  • "geom_refinement_algorithm": "BeamCenter",
  • "unit_cell_dist_tolerance": 0.05,
  • "viable_cell_min_spots": 10,
  • "index_ice_rings": false,
  • "rotation_indexing": false,
  • "rotation_indexing_min_angular_range_deg": 20,
  • "rotation_indexing_angular_stride_deg": 0.5,
  • "blocking": true
}

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Get indexing configuration

Can be done anytime

+
http://localhost:5232/config/indexing

Request samples

Content type
application/json
{
  • "algorithm": "FFBIDX",
  • "fft_max_unit_cell_A": 250,
  • "fft_min_unit_cell_A": 10,
  • "fft_high_resolution_A": 2,
  • "fft_num_vectors": 16384,
  • "tolerance": 0.5,
  • "thread_count": 1,
  • "geom_refinement_algorithm": "BeamCenter",
  • "unit_cell_dist_tolerance": 0.05,
  • "viable_cell_min_spots": 10,
  • "index_ice_rings": false,
  • "rotation_indexing": false,
  • "rotation_indexing_min_angular_range_deg": 20,
  • "rotation_indexing_angular_stride_deg": 0.5,
  • "blocking": true
}

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Get indexing configuration

Can be done anytime

Responses

Response samples

Content type
application/json
{
  • "algorithm": "FFBIDX",
  • "fft_max_unit_cell_A": 250,
  • "fft_min_unit_cell_A": 10,
  • "fft_high_resolution_A": 2,
  • "fft_num_vectors": 16384,
  • "tolerance": 0.5,
  • "thread_count": 1,
  • "geom_refinement_algorithm": "BeamCenter",
  • "unit_cell_dist_tolerance": 0.05,
  • "viable_cell_min_spots": 10,
  • "index_ice_rings": false,
  • "rotation_indexing": false,
  • "rotation_indexing_min_angular_range_deg": 20,
  • "rotation_indexing_angular_stride_deg": 0.5,
  • "blocking": true
}

Change file writer settings

This can only be done when detector is Idle, Error or Inactive states.

+
http://localhost:5232/config/indexing

Response samples

Content type
application/json
{
  • "algorithm": "FFBIDX",
  • "fft_max_unit_cell_A": 250,
  • "fft_min_unit_cell_A": 10,
  • "fft_high_resolution_A": 2,
  • "fft_num_vectors": 16384,
  • "tolerance": 0.5,
  • "thread_count": 1,
  • "geom_refinement_algorithm": "BeamCenter",
  • "unit_cell_dist_tolerance": 0.05,
  • "viable_cell_min_spots": 10,
  • "index_ice_rings": false,
  • "rotation_indexing": false,
  • "rotation_indexing_min_angular_range_deg": 20,
  • "rotation_indexing_angular_stride_deg": 0.5,
  • "blocking": true
}

Change file writer settings

This can only be done when detector is Idle, Error or Inactive states.

Request Body schema: application/json
overwrite
boolean
Default: false

Inform jfjoch_write to overwrite existing files. Otherwise files would be saved with .h5.{timestamp}.tmp suffix.

format
string (file_writer_format)
Default: "NXmxLegacy"
Enum: "NXmxOnlyData" "NXmxLegacy" "NXmxVDS" "NXmxIntegrated" "CBF" "TIFF" "NoFileWritten"

NoFileWritten - no files are written at all NXmxOnlyData - only data files are written, no master file @@ -604,10 +616,10 @@ TIFF - TIFF format (no metadata)

Request samples

Content type
application/json
{
  • "overwrite": false,
  • "format": "NXmxOnlyData"
}

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Get file writer settings

Can be done anytime

+
http://localhost:5232/config/file_writer

Request samples

Content type
application/json
{
  • "overwrite": false,
  • "format": "NXmxOnlyData"
}

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Get file writer settings

Can be done anytime

Responses

Response samples

Content type
application/json
{
  • "overwrite": false,
  • "format": "NXmxOnlyData"
}

Change instrument metadata

This can only be done when detector is Idle, Error or Inactive states.

+
http://localhost:5232/config/file_writer

Response samples

Content type
application/json
{
  • "overwrite": false,
  • "format": "NXmxOnlyData"
}

Change instrument metadata

This can only be done when detector is Idle, Error or Inactive states.

Request Body schema: application/json
source_name
required
string
source_type
string
Default: ""

Type of radiation source. NXmx gives a fixed dictionary, though Jungfraujoch is not enforcing compliance. https://manual.nexusformat.org/classes/base_classes/NXsource.html#nxsource NXsource allows the following:

@@ -630,10 +642,10 @@ Metal Jet X-ray

Request samples

Content type
application/json
{
  • "source_name": "Swiss Light Source",
  • "source_type": "Synchrotron X-ray Source",
  • "instrument_name": "CristallinaMX",
  • "pulsed_source": false,
  • "electron_source": false
}

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Get instrument metadata

Can be done anytime

+
http://localhost:5232/config/instrument

Request samples

Content type
application/json
{
  • "source_name": "Swiss Light Source",
  • "source_type": "Synchrotron X-ray Source",
  • "instrument_name": "CristallinaMX",
  • "pulsed_source": false,
  • "electron_source": false
}

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Get instrument metadata

Can be done anytime

Responses

Response samples

Content type
application/json
{
  • "source_name": "Swiss Light Source",
  • "source_type": "Synchrotron X-ray Source",
  • "instrument_name": "CristallinaMX",
  • "pulsed_source": false,
  • "electron_source": false
}

Change image output format

This can only be done when detector is Idle, Error or Inactive states.

+
http://localhost:5232/config/instrument

Response samples

Content type
application/json
{
  • "source_name": "Swiss Light Source",
  • "source_type": "Synchrotron X-ray Source",
  • "instrument_name": "CristallinaMX",
  • "pulsed_source": false,
  • "electron_source": false
}

Change image output format

This can only be done when detector is Idle, Error or Inactive states.

Request Body schema: application/json
summation
required
boolean

Enable summation of images to a given image_time If disabled images are saved according to original detector speed, but image count is adjusted

geometry_transform
required
boolean

Place module read-out into their location on composed detector and extend multipixels

@@ -655,18 +667,18 @@ This should be turned off for cases, where detector is operated at room temperat

Request samples

Content type
application/json
{
  • "summation": true,
  • "geometry_transform": true,
  • "jungfrau_conversion": true,
  • "jungfrau_conversion_factor_keV": 0.001,
  • "bit_depth_image": 8,
  • "signed_output": true,
  • "mask_module_edges": true,
  • "mask_chip_edges": true,
  • "jungfrau_mask_pixels_without_g0": true,
  • "apply_mask": false,
  • "jungfrau_pedestal_g0_rms_limit": 100
}

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Get image output format

Can be done anytime

+
http://localhost:5232/config/image_format

Request samples

Content type
application/json
{
  • "summation": true,
  • "geometry_transform": true,
  • "jungfrau_conversion": true,
  • "jungfrau_conversion_factor_keV": 0.001,
  • "bit_depth_image": 8,
  • "signed_output": true,
  • "mask_module_edges": true,
  • "mask_chip_edges": true,
  • "jungfrau_mask_pixels_without_g0": true,
  • "apply_mask": false,
  • "jungfrau_pedestal_g0_rms_limit": 100
}

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Get image output format

Can be done anytime

Responses

Response samples

Content type
application/json
{
  • "summation": true,
  • "geometry_transform": true,
  • "jungfrau_conversion": true,
  • "jungfrau_conversion_factor_keV": 0.001,
  • "bit_depth_image": 8,
  • "signed_output": true,
  • "mask_module_edges": true,
  • "mask_chip_edges": true,
  • "jungfrau_mask_pixels_without_g0": true,
  • "apply_mask": false,
  • "jungfrau_pedestal_g0_rms_limit": 100
}

Configure format for raw data collection

This can only be done when detector is Idle, Error or Inactive states.

+
http://localhost:5232/config/image_format

Response samples

Content type
application/json
{
  • "summation": true,
  • "geometry_transform": true,
  • "jungfrau_conversion": true,
  • "jungfrau_conversion_factor_keV": 0.001,
  • "bit_depth_image": 8,
  • "signed_output": true,
  • "mask_module_edges": true,
  • "mask_chip_edges": true,
  • "jungfrau_mask_pixels_without_g0": true,
  • "apply_mask": false,
  • "jungfrau_pedestal_g0_rms_limit": 100
}

Configure format for raw data collection

This can only be done when detector is Idle, Error or Inactive states.

Responses

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Configure format for data collection with full conversion

This can only be done when detector is Idle, Error or Inactive states.

+
http://localhost:5232/config/image_format/raw

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Configure format for data collection with full conversion

This can only be done when detector is Idle, Error or Inactive states.

Responses

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Configure spot finding

Can be done anytime, also while data collection is running

+
http://localhost:5232/config/image_format/conversion

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Configure spot finding

Can be done anytime, also while data collection is running

Request Body schema: application/json
enable
required
boolean
Default: true

Enable spot finding. This is temporary setting, i.e. can be changed anytime during data collection. Even if disabled spot finding information will still be send and written, though always with zero spots.

indexing
required
boolean
Default: true

Enable indexing. This is temporary setting, i.e. can be changed anytime during data collection.

@@ -683,10 +695,10 @@ This option should be turned OFF for small molecule datasets or for crystals wit

Responses

Request samples

Content type
application/json
{
  • "enable": true,
  • "indexing": true,
  • "signal_to_noise_threshold": 0.1,
  • "photon_count_threshold": 0,
  • "min_pix_per_spot": 1,
  • "max_pix_per_spot": 1,
  • "high_resolution_limit": 0.1,
  • "low_resolution_limit": 0.1,
  • "high_resolution_limit_for_spot_count_low_res": 2,
  • "quick_integration": false,
  • "ice_ring_width_q_recipA": 0.02,
  • "high_res_gap_Q_recipA": 1.5
}

Get data processing configuration

Can be done anytime

+
http://localhost:5232/config/spot_finding

Request samples

Content type
application/json
{
  • "enable": true,
  • "indexing": true,
  • "signal_to_noise_threshold": 0.1,
  • "photon_count_threshold": 0,
  • "min_pix_per_spot": 1,
  • "max_pix_per_spot": 1,
  • "high_resolution_limit": 0.1,
  • "low_resolution_limit": 0.1,
  • "high_resolution_limit_for_spot_count_low_res": 2,
  • "quick_integration": false,
  • "ice_ring_width_q_recipA": 0.02,
  • "high_res_gap_Q_recipA": 1.5
}

Get data processing configuration

Can be done anytime

Responses

Response samples

Content type
application/json
{
  • "enable": true,
  • "indexing": true,
  • "signal_to_noise_threshold": 0.1,
  • "photon_count_threshold": 0,
  • "min_pix_per_spot": 1,
  • "max_pix_per_spot": 1,
  • "high_resolution_limit": 0.1,
  • "low_resolution_limit": 0.1,
  • "high_resolution_limit_for_spot_count_low_res": 2,
  • "quick_integration": false,
  • "ice_ring_width_q_recipA": 0.02,
  • "high_res_gap_Q_recipA": 1.5
}

Configure azimuthal integration

Can be done when detector is Inactive or Idle

+
http://localhost:5232/config/spot_finding

Response samples

Content type
application/json
{
  • "enable": true,
  • "indexing": true,
  • "signal_to_noise_threshold": 0.1,
  • "photon_count_threshold": 0,
  • "min_pix_per_spot": 1,
  • "max_pix_per_spot": 1,
  • "high_resolution_limit": 0.1,
  • "low_resolution_limit": 0.1,
  • "high_resolution_limit_for_spot_count_low_res": 2,
  • "quick_integration": false,
  • "ice_ring_width_q_recipA": 0.02,
  • "high_res_gap_Q_recipA": 1.5
}

Configure azimuthal integration

Can be done when detector is Inactive or Idle

Request Body schema: application/json
polarization_corr
required
boolean
Default: true

Apply polarization correction for azimuthal integration (polarization factor must be configured in dataset settings)

solid_angle_corr
required
boolean
Default: true

Apply solid angle correction for azimuthal integration

high_q_recipA
required
number <float>
low_q_recipA
required
number <float>
q_spacing
required
number <float>
azimuthal_bins
integer <int64> [ 1 .. 256 ]
Default: 1

Numer of azimuthal (phi) bins; 1 = standard 1D azimuthal integration

@@ -694,10 +706,10 @@ This option should be turned OFF for small molecule datasets or for crystals wit

Request samples

Content type
application/json
{
  • "polarization_corr": true,
  • "solid_angle_corr": true,
  • "high_q_recipA": 0.1,
  • "low_q_recipA": 0.1,
  • "q_spacing": 0.1,
  • "azimuthal_bins": 1
}

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Get azimuthal integration configuration

Can be done anytime

+
http://localhost:5232/config/azim_int

Request samples

Content type
application/json
{
  • "polarization_corr": true,
  • "solid_angle_corr": true,
  • "high_q_recipA": 0.1,
  • "low_q_recipA": 0.1,
  • "q_spacing": 0.1,
  • "azimuthal_bins": 1
}

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Get azimuthal integration configuration

Can be done anytime

Responses

Response samples

Content type
application/json
{
  • "polarization_corr": true,
  • "solid_angle_corr": true,
  • "high_q_recipA": 0.1,
  • "low_q_recipA": 0.1,
  • "q_spacing": 0.1,
  • "azimuthal_bins": 1
}

Load binary image for internal FPGA generator

Load image for internal FPGA generator. This can only happen in Idle state of the detector. +

http://localhost:5232/config/azim_int

Response samples

Content type
application/json
{
  • "polarization_corr": true,
  • "solid_angle_corr": true,
  • "high_q_recipA": 0.1,
  • "low_q_recipA": 0.1,
  • "q_spacing": 0.1,
  • "azimuthal_bins": 1
}

Load binary image for internal FPGA generator

Load image for internal FPGA generator. This can only happen in Idle state of the detector. Requires binary blob with 16-bit integer numbers of size of detector in raw/converted coordinates (depending on detector settings).

query Parameters
id
integer <int64> [ 0 .. 127 ]

Image id to upload

@@ -718,10 +730,10 @@ Changing detector will set detector to Inactive state and will requ

Request samples

Content type
application/json
{
  • "id": 1
}

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

List available detectors

Configured detectors that can be selected by used

+
http://localhost:5232/config/select_detector

Request samples

Content type
application/json
{
  • "id": 1
}

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

List available detectors

Configured detectors that can be selected by used

Responses

Response samples

Content type
application/json
{
  • "detectors": [
    ],
  • "current_id": 0
}

Set ZeroMQ preview settings

Jungfraujoch can generate preview message stream on ZeroMQ SUB socket. +

http://localhost:5232/config/select_detector

Response samples

Content type
application/json
{
  • "detectors": [
    ],
  • "current_id": 0
}

Set ZeroMQ preview settings

Jungfraujoch can generate preview message stream on ZeroMQ SUB socket. Here settings of the socket can be adjusted. While the data structure contains also socket_address, this cannot be changed via HTTP and is ignore in PUT request. Options set with this PUT request have no effect on HTTP based preview.

@@ -737,9 +749,9 @@ Address follows ZeroMQ convention for sockets - in practice ipc://

Request samples

Content type
application/json
{
  • "enabled": true,
  • "period_ms": 1000,
  • "socket_address": "string"
}

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Get ZeroMQ preview settings

Responses

Request samples

Content type
application/json
{
  • "enabled": true,
  • "period_ms": 1000,
  • "socket_address": "string"
}

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Get ZeroMQ preview settings

Responses

Response samples

Content type
application/json
{
  • "enabled": true,
  • "period_ms": 1000,
  • "socket_address": "string"
}

Set ZeroMQ metadata settings

Jungfraujoch can generate metadata message stream on ZeroMQ PUB socket. This stream covers all images. +

http://localhost:5232/config/zeromq_preview

Response samples

Content type
application/json
{
  • "enabled": true,
  • "period_ms": 1000,
  • "socket_address": "string"
}

Set ZeroMQ metadata settings

Jungfraujoch can generate metadata message stream on ZeroMQ PUB socket. This stream covers all images. Here settings of the socket can be adjusted. While the data structure contains also socket_address, this cannot be changed via HTTP and is ignore in PUT request.

Request Body schema: application/json
enabled
required
boolean
Default: true

ZeroMQ metadata socket is enabled.

@@ -752,9 +764,9 @@ Address follows ZeroMQ convention for sockets - in practice ipc://

Request samples

Content type
application/json
{
  • "enabled": true,
  • "period_ms": 1000,
  • "socket_address": "string"
}

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Get ZeroMQ metadata socket settings

Responses

Request samples

Content type
application/json
{
  • "enabled": true,
  • "period_ms": 1000,
  • "socket_address": "string"
}

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Get ZeroMQ metadata socket settings

Responses

Response samples

Content type
application/json
{
  • "enabled": true,
  • "period_ms": 1000,
  • "socket_address": "string"
}

Set configuration for dark data collection to calculate mask

This is only possible when operating DECTRIS detectors at the moment; it will be also available for PSI EIGER at some point. +

http://localhost:5232/config/zeromq_metadata

Response samples

Content type
application/json
{
  • "enabled": true,
  • "period_ms": 1000,
  • "socket_address": "string"
}

Set configuration for dark data collection to calculate mask

This is only possible when operating DECTRIS detectors at the moment; it will be also available for PSI EIGER at some point. This can only be done when detector is Idle, Error or Inactive states.

Request Body schema: application/json
detector_threshold_keV
required
number <float> [ 2.5 .. 100 ]
Default: 3.5

Energy threshold for dark image collection

frame_time_us
required
integer <int64> [ 500 .. 100000 ]
Default: 10000

Time between frames for dark image collection

@@ -765,48 +777,48 @@ This can only be done when detector is Idle, Error or

Request samples

Content type
application/json
{
  • "detector_threshold_keV": 3.5,
  • "frame_time_us": 10000,
  • "number_of_frames": 1000,
  • "max_allowed_pixel_count": 1,
  • "max_frames_with_signal": 10
}

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Get settings for dark data collection to calculate mask

Responses

Request samples

Content type
application/json
{
  • "detector_threshold_keV": 3.5,
  • "frame_time_us": 10000,
  • "number_of_frames": 1000,
  • "max_allowed_pixel_count": 1,
  • "max_frames_with_signal": 10
}

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Get settings for dark data collection to calculate mask

Responses

Response samples

Content type
application/json
{
  • "detector_threshold_keV": 3.5,
  • "frame_time_us": 10000,
  • "number_of_frames": 1000,
  • "max_allowed_pixel_count": 1,
  • "max_frames_with_signal": 10
}

Get Jungfraujoch status

Status of the data acquisition

+
http://localhost:5232/config/dark_mask

Response samples

Content type
application/json
{
  • "detector_threshold_keV": 3.5,
  • "frame_time_us": 10000,
  • "number_of_frames": 1000,
  • "max_allowed_pixel_count": 1,
  • "max_frames_with_signal": 10
}

Get Jungfraujoch status

Status of the data acquisition

Responses

Response samples

Content type
application/json
{
  • "state": "Inactive",
  • "progress": 1,
  • "message": "string",
  • "message_severity": "success",
  • "gpu_count": 0,
  • "broker_version": "1.0.0-rc.128"
}

Get status of FPGA devices

Responses

Response samples

Content type
application/json
{
  • "state": "Inactive",
  • "progress": 1,
  • "message": "string",
  • "message_severity": "success",
  • "gpu_count": 0,
  • "broker_version": "1.0.0-rc.128"
}

Get status of FPGA devices

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Return XFEL pulse IDs for the current data acquisition

Return array of XFEL pulse IDs - (-1) if image not recorded

+
http://localhost:5232/fpga_status

Response samples

Content type
application/json
[
  • {
    }
]

Return XFEL pulse IDs for the current data acquisition

Return array of XFEL pulse IDs - (-1) if image not recorded

Responses

Response samples

Content type
application/json
[
  • 0
]

Return XFEL event codes for the current data acquisition

Return array of XFEL event codes

+
http://localhost:5232/xfel/pulse_id

Response samples

Content type
application/json
[
  • 0
]

Return XFEL event codes for the current data acquisition

Return array of XFEL event codes

Responses

Response samples

Content type
application/json
[
  • 0
]

Get status of image pusher

Responses

Response samples

Content type
application/json
[
  • 0
]

Get status of image pusher

Responses

Response samples

Content type
application/json
{
  • "pusher_type": "ZeroMQ",
  • "addr": [
    ],
  • "connected_writers": 0,
  • "images_written": 0,
  • "images_write_error": 0,
  • "writer_fifo_utilization": [
    ]
}

Get detector status

Status of the JUNGFRAU detector

+
http://localhost:5232/image_pusher/status

Response samples

Content type
application/json
{
  • "pusher_type": "ZeroMQ",
  • "addr": [
    ],
  • "connected_writers": 0,
  • "images_written": 0,
  • "images_write_error": 0,
  • "writer_fifo_utilization": [
    ]
}

Get detector status

Status of the JUNGFRAU detector

Responses

Response samples

Content type
application/json
{
  • "state": "Idle",
  • "powerchip": "PowerOn",
  • "server_version": "string",
  • "number_of_triggers_left": 0,
  • "fpga_temp_degC": [
    ],
  • "high_voltage_V": [
    ]
}

Get ROI definitions

Responses

Response samples

Content type
application/json
{
  • "state": "Idle",
  • "powerchip": "PowerOn",
  • "server_version": "string",
  • "number_of_triggers_left": 0,
  • "fpga_temp_degC": [
    ],
  • "high_voltage_V": [
    ]
}

Get ROI definitions

Responses

Response samples

Content type
application/json
{
  • "box": {
    },
  • "circle": {
    },
  • "azim": {
    }
}

Upload ROI definitions

Request Body schema: application/json
required
object (roi_box_list)

List of box ROIs

+
http://localhost:5232/config/roi

Response samples

Content type
application/json
{
  • "box": {
    },
  • "circle": {
    },
  • "azim": {
    }
}

Upload ROI definitions

Request Body schema: application/json
required
object (roi_box_list)

List of box ROIs

required
object (roi_circle_list)

List of circular ROIs

required
object (roi_azim_list)

List of azimuthal ROIs

Responses

Request samples

Content type
application/json
{
  • "box": {
    },
  • "circle": {
    },
  • "azim": {
    }
}

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Get general statistics

Responses

Request samples

Content type
application/json
{
  • "box": {
    },
  • "circle": {
    },
  • "azim": {
    }
}

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Get general statistics

Responses

Response samples

Content type
application/json
{
  • "detector": {
    },
  • "detector_list": {
    },
  • "detector_settings": {
    },
  • "image_format_settings": {
    },
  • "instrument_metadata": {
    },
  • "file_writer_settings": {
    },
  • "data_processing_settings": {
    },
  • "measurement": {
    },
  • "broker": {
    },
  • "fpga": [
    ],
  • "calibration": [
    ],
  • "zeromq_preview": {
    },
  • "zeromq_metadata": {
    },
  • "dark_mask": {
    },
  • "pixel_mask": {
    },
  • "roi": {
    },
  • "az_int": {
    },
  • "buffer": {
    },
  • "indexing": {
    },
  • "image_pusher": {
    }
}

Get data collection statistics

Results of the last data collection

+
http://localhost:5232/statistics

Response samples

Content type
application/json
{
  • "detector": {
    },
  • "detector_list": {
    },
  • "detector_settings": {
    },
  • "image_format_settings": {
    },
  • "instrument_metadata": {
    },
  • "file_writer_settings": {
    },
  • "data_processing_settings": {
    },
  • "measurement": {
    },
  • "broker": {
    },
  • "fpga": [
    ],
  • "calibration": [
    ],
  • "zeromq_preview": {
    },
  • "zeromq_metadata": {
    },
  • "dark_mask": {
    },
  • "pixel_mask": {
    },
  • "roi": {
    },
  • "az_int": {
    },
  • "buffer": {
    },
  • "indexing": {
    },
  • "image_pusher": {
    }
}

Get data collection statistics

Results of the last data collection

Responses

Response samples

Content type
application/json
{
  • "file_prefix": "string",
  • "run_number": 0,
  • "experiment_group": "string",
  • "images_expected": 0,
  • "images_collected": 0,
  • "images_sent": 0,
  • "images_written": 0,
  • "images_discarded_lossy_compression": 0,
  • "max_image_number_sent": 0,
  • "collection_efficiency": 1,
  • "compression_ratio": 5.3,
  • "cancelled": true,
  • "max_receiver_delay": 0,
  • "indexing_rate": 0.1,
  • "detector_width": 0,
  • "detector_height": 0,
  • "detector_pixel_depth": 2,
  • "bkg_estimate": 0.1,
  • "unit_cell": "string",
  • "error_pixels": 0.1,
  • "saturated_pixels": 0.1,
  • "roi_beam_pixels": 0.1,
  • "roi_beam_sum": 0.1
}

Get calibration statistics

Statistics are provided for each module/storage cell separately

+
http://localhost:5232/statistics/data_collection

Response samples

Content type
application/json
{
  • "file_prefix": "string",
  • "run_number": 0,
  • "experiment_group": "string",
  • "images_expected": 0,
  • "images_collected": 0,
  • "images_sent": 0,
  • "images_written": 0,
  • "images_discarded_lossy_compression": 0,
  • "max_image_number_sent": 0,
  • "collection_efficiency": 1,
  • "compression_ratio": 5.3,
  • "cancelled": true,
  • "max_receiver_delay": 0,
  • "indexing_rate": 0.1,
  • "detector_width": 0,
  • "detector_height": 0,
  • "detector_pixel_depth": 2,
  • "bkg_estimate": 0.1,
  • "unit_cell": "string",
  • "error_pixels": 0.1,
  • "saturated_pixels": 0.1,
  • "roi_beam_pixels": 0.1,
  • "roi_beam_sum": 0.1
}

Get calibration statistics

Statistics are provided for each module/storage cell separately

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Get mask of the detector (binary)

Detector must be Initialized. +

http://localhost:5232/statistics/calibration

Response samples

Content type
application/json
[
  • {
    }
]

Get mask of the detector (binary)

Detector must be Initialized. Get full pixel mask of the detector. See NXmx standard for meaning of pixel values.

Responses

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Get mask of the detector (TIFF)

Should be in Idle state. +

http://localhost:5232/config/user_mask

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Get mask of the detector (TIFF)

Should be in Idle state. Get full pixel mask of the detector See NXmx standard for meaning of pixel values

Responses

Request Body schema: image/tiff
string <binary>

Responses

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Get pedestal in TIFF format

query Parameters
gain_level
required
integer

Gain level (0, 1, 2)

+
http://localhost:5232/config/user_mask.tiff

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Get pedestal in TIFF format

query Parameters
gain_level
required
integer

Gain level (0, 1, 2)

sc
integer

Storage cell number

Responses

Responses

Response samples

Content type
application/json
{
  • "title": "string",
  • "unit_x": "image_number",
  • "size_x": 0.1,
  • "size_y": 0.1,
  • "plot": [
    ]
}

Generate 1D plot from Jungfraujoch and send in raw binary format. +

http://localhost:5232/preview/plot

Response samples

Content type
application/json
{
  • "title": "string",
  • "unit_x": "image_number",
  • "size_x": 0.1,
  • "size_y": 0.1,
  • "plot": [
    ]
}

Generate 1D plot from Jungfraujoch and send in raw binary format. Data are provided as (32-bit) float binary array. This format doesn't transmit information about X-axis, only values, so it is of limited use for azimuthal integration.

query Parameters
type
required
string
Enum: "bkg_estimate" "azint" "azint_1d" "spot_count" "spot_count_low_res" "spot_count_indexed" "spot_count_ice" "indexing_rate" "indexing_unit_cell_length" "indexing_unit_cell_angle" "profile_radius" "mosaicity" "b_factor" "error_pixels" "saturated_pixels" "image_collection_efficiency" "receiver_delay" "receiver_free_send_buf" "strong_pixels" "roi_sum" "roi_mean" "roi_max_count" "roi_pixels" "roi_weighted_x" "roi_weighted_y" "packets_received" "max_pixel_value" "resolution_estimate" "pixel_sum" "processing_time" "beam_center_x" "beam_center_y"

Type of requested plot

@@ -876,18 +888,18 @@ This format doesn't transmit information about X-axis, only values, so it i

Response samples

Content type
application/json
{
  • "file_prefix": "string",
  • "rotation_unit_cell": {
    },
  • "rotation_crystal_lattice": [
    ],
  • "images": [
    ]
}

Get Start message in CBOR format

Contains metadata for a dataset (e.g., experimental geometry)

+
http://localhost:5232/result/scan

Response samples

Content type
application/json
{
  • "file_prefix": "string",
  • "rotation_unit_cell": {
    },
  • "rotation_crystal_lattice": [
    ],
  • "images": [
    ]
}

Get Start message in CBOR format

Contains metadata for a dataset (e.g., experimental geometry)

Responses

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Get image message in CBOR format

Contains full image data and metadata. The image must come from the latest data collection.

+
http://localhost:5232/image_buffer/start.cbor

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Get image message in CBOR format

Contains full image data and metadata. The image must come from the latest data collection.

query Parameters
id
integer <int64> >= -2
Default: -1

Image ID in the image buffer. Special values: -1 - last image in the buffer, -2: last indexed image in the buffer

Responses

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Get preview image in JPEG format using custom settings

query Parameters
id
integer <int64> >= -2
Default: -1

Image ID in the image buffer. Special values: -1 - last image in the buffer, -2: last indexed image in the buffer

+
http://localhost:5232/image_buffer/image.cbor

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Get preview image in JPEG format using custom settings

query Parameters
id
integer <int64> >= -2
Default: -1

Image ID in the image buffer. Special values: -1 - last image in the buffer, -2: last indexed image in the buffer

show_user_mask
boolean
Default: false

Show user mask

show_roi
boolean
Default: false

Show ROI areas on the image

show_spots
boolean
Default: true

Show spot finding results on the image

@@ -902,7 +914,7 @@ This format doesn't transmit information about X-axis, only values, so it i

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Get preview image in TIFF format

query Parameters
id
integer <int64> >= -2
Default: -1

Image ID in the image buffer. Special values: -1 - last image in the buffer, -2: last indexed image in the buffer

+
http://localhost:5232/image_buffer/image.jpeg

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Get preview image in TIFF format

query Parameters
id
integer <int64> >= -2
Default: -1

Image ID in the image buffer. Special values: -1 - last image in the buffer, -2: last indexed image in the buffer

Responses

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Get status of the image buffers

Can be run at any stage of Jungfraujoch operation, including during data collection. +

http://localhost:5232/image_buffer/clear

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Get status of the image buffers

Can be run at any stage of Jungfraujoch operation, including during data collection. The status of the image buffer is volatile during data collection - if data collection goes for more images than available buffer slots, then image might be replaced in the buffer between calling /images and /image.cbor.

Responses

Response samples

Content type
application/json
{
  • "min_image_number": 0,
  • "max_image_number": 0,
  • "image_numbers": [
    ],
  • "total_slots": 0,
  • "available_slots": 0,
  • "in_preparation_slots": 0,
  • "in_sending_slots": 0,
  • "current_counter": 0
}

Get Jungfraujoch version of jfjoch_broker

Responses

Response samples

Content type
application/json
{
  • "min_image_number": 0,
  • "max_image_number": 0,
  • "image_numbers": [
    ],
  • "total_slots": 0,
  • "available_slots": 0,
  • "in_preparation_slots": 0,
  • "in_sending_slots": 0,
  • "current_counter": 0
}

Get Jungfraujoch version of jfjoch_broker

Responses