v1.0.0-rc.178 #89

Merged
leonarski_f merged 172 commits from rc178 into main 2026-10-23 16:55:14 +02:00
219 changed files with 55736 additions and 1769 deletions

No files matched your search

+18 -10
View File
@@ -150,19 +150,27 @@ accident; name the files the change actually touches, and read `git status` befo
## Changelog
`docs/CHANGELOG.md` is written **for users**. It does not replace commit messages or developer
notes, so keep out of it anything that belongs there instead:
`docs/CHANGELOG.md` is written **for users**: it tells them what to expect from the new version.
It does not replace commit messages or developer notes, so keep out of it anything that belongs there
instead.
- **One line per entry**, ideally one sentence. Two only when a user genuinely needs both.
- **Say what changed** — not why, not what the investigation found, not how the change was arrived
at, not what it measured on. Rationale, measurements and history go in the commit message.
**When.** The changelog is written **once, just before the release branch is merged into main**, on
the maintainer's request, when the branch's full content is known. Never add or edit
`docs/CHANGELOG.md` as part of a feature, fix or performance change - describe the change in its
commit message instead. Written per change, every piece of work looks important enough for an entry
of its own; written at the end, it takes its true place in the release.
**How.**
- **Condensed.** A release is a handful of one-liners. Fold connected changes into a single entry -
that is the expected outcome, not a loss of detail.
- **What users get, stated as fact.** Describe the capability or the behaviour a user will see.
Leave out the development story: what was tried, what failed, what was found along the way, how
the change was built. Rationale, measurements and history belong in the commit messages.
- **General beats specific.** "Significantly faster processing of serial data" serves a user better
than naming the function that changed, the reason it changed and the percentage it saved on one
dataset.
- **No sample identities**, exactly as everywhere else (see below).
**Entries are written only on the maintainer's explicit request**, normally once per release branch
before it is merged, as a short summary of user-visible changes. Do not add or edit
`docs/CHANGELOG.md` as part of a feature, fix or performance change; describe the change in its
commit message instead.
## Design direction
Three standing preferences. They are **directional**, not absolute: they say which way to lean when a
+39 -1
View File
@@ -3,6 +3,7 @@
// Using OpenAPI licensed with Apache License 2.0
#include "JFJochBrokerHttp.h"
#include "../receiver/RugnuxStructure.h"
#include <set>
@@ -155,7 +156,9 @@ static const std::set<std::string> PROTECTED_PATHS{
"/preview/plot",
"/preview/plot.bin",
"/live/events",
"/rugnux/status"
"/rugnux/status",
"/rugnux/model.cif",
"/rugnux/map.ccp4"
};
std::optional<std::string> JFJochBrokerHttp::AuthorizationHeader(const httplib::Request &req) {
@@ -259,6 +262,14 @@ void JFJochBrokerHttp::register_routes(httplib::Server &server) {
server.Put("/config/rugnux/model", bind_req(&JFJochBrokerHttp::config_rugnux_model_put));
server.Delete("/config/rugnux/model", bind_noarg(&JFJochBrokerHttp::config_rugnux_model_delete));
server.Get("/rugnux/status", bind_noarg(&JFJochBrokerHttp::rugnux_status_get));
server.Get("/rugnux/model.cif", bind_noarg(&JFJochBrokerHttp::rugnux_model_cif_get));
server.Get("/rugnux/map.ccp4", [this](const httplib::Request &req, httplib::Response &res) {
try {
rugnux_map_ccp4_get(parse_query_string(req, "type"), res);
} catch (const std::exception &e) {
send_error(res, handleOperationException(e));
}
});
server.Get("/config/bragg_integration", bind_noarg(&JFJochBrokerHttp::config_bragg_integration_get));
server.Put("/config/bragg_integration", bind_json(&JFJochBrokerHttp::config_bragg_integration_put, Bragg_integration_settings{}));
server.Get("/config/instrument", bind_noarg(&JFJochBrokerHttp::config_instrument_get));
@@ -1025,6 +1036,33 @@ void JFJochBrokerHttp::rugnux_status_get(httplib::Response &response) {
ProcessOutput(Convert(state_machine.GetRugnuxStatus()), response);
}
void JFJochBrokerHttp::rugnux_model_cif_get(httplib::Response &response) {
const auto structure = state_machine.GetRugnuxStatus().structure;
if (!structure) {
response.status = 404;
return;
}
response.set_content(structure->ModelCif(), "chemical/x-mmcif");
}
void JFJochBrokerHttp::rugnux_map_ccp4_get(const std::optional<std::string> &type, httplib::Response &response) {
const std::string t = type.value_or("2fofc");
if (t != "2fofc" && t != "fofc" && t != "anom") {
response.status = 400;
response.set_content("Unknown map type " + t, "text/plain");
return;
}
const auto structure = state_machine.GetRugnuxStatus().structure;
const RugnuxMapType map_type = t == "2fofc" ? RugnuxMapType::TwoFoFc
: t == "fofc" ? RugnuxMapType::FoFc : RugnuxMapType::Anomalous;
const std::string map = structure ? structure->Map(map_type) : std::string();
if (map.empty()) {
response.status = 404;
return;
}
response.set_content(map, "application/octet-stream");
}
void JFJochBrokerHttp::config_bragg_integration_get(httplib::Response &response) {
ProcessOutput(Convert(state_machine.GetBraggIntegrationSettings()), response);
}
+2
View File
@@ -206,6 +206,8 @@ class JFJochBrokerHttp {
void config_rugnux_model_put(const httplib::Request &request, httplib::Response &response);
void config_rugnux_model_delete(httplib::Response &response);
void rugnux_status_get(httplib::Response &response);
void rugnux_model_cif_get(httplib::Response &response);
void rugnux_map_ccp4_get(const std::optional<std::string> &type, httplib::Response &response);
void config_bragg_integration_get(httplib::Response &response);
void config_bragg_integration_put(const org::openapitools::server::model::Bragg_integration_settings &braggIntegrationSettings,
httplib::Response &response);
+3
View File
@@ -3,6 +3,7 @@
#include "../common/JFJochMath.h"
#include "OpenAPIConvert.h"
#include "../receiver/RugnuxStructure.h"
// From https://en.cppreference.com/w/cpp/string/byte/tolower
std::string str_tolower(std::string s) {
@@ -1276,6 +1277,8 @@ org::openapitools::server::model::Rugnux_live_status Convert(const RugnuxLiveSna
}
ret.setSummary(summary);
ret.setWarnings(input.warnings);
ret.setPlacedModel(input.structure != nullptr);
ret.setAnomalousMap(input.structure != nullptr && input.structure->HasAnomalousMap());
return ret;
}
+29 -1
View File
@@ -22,6 +22,8 @@ namespace org::openapitools::server::model
Rugnux_live_status::Rugnux_live_status()
{
m_State = "";
m_Placed_model = false;
m_Anomalous_map = false;
m_Probe = "";
m_Probe_s = 0.0;
m_Probe_sIsSet = false;
@@ -67,7 +69,7 @@ bool Rugnux_live_status::validate(std::stringstream& msg, const std::string& pat
bool success = true;
const std::string _pathPrefix = pathPrefix.empty() ? "Rugnux_live_status" : pathPrefix;
if (stepProgressIsSet())
{
const float& value = m_Step_progress;
@@ -161,6 +163,12 @@ bool Rugnux_live_status::operator==(const Rugnux_live_status& rhs) const
(getState() == rhs.getState())
&&
(isPlacedModel() == rhs.isPlacedModel())
&&
(isAnomalousMap() == rhs.isAnomalousMap())
&&
(getProbe() == rhs.getProbe())
&&
@@ -227,6 +235,8 @@ void to_json(nlohmann::json& j, const Rugnux_live_status& o)
{
j = nlohmann::json::object();
j["state"] = o.m_State;
j["placed_model"] = o.m_Placed_model;
j["anomalous_map"] = o.m_Anomalous_map;
j["probe"] = o.m_Probe;
if(o.probeSIsSet())
j["probe_s"] = o.m_Probe_s;
@@ -259,6 +269,8 @@ void to_json(nlohmann::json& j, const Rugnux_live_status& o)
void from_json(const nlohmann::json& j, Rugnux_live_status& o)
{
j.at("state").get_to(o.m_State);
j.at("placed_model").get_to(o.m_Placed_model);
j.at("anomalous_map").get_to(o.m_Anomalous_map);
j.at("probe").get_to(o.m_Probe);
if(j.find("probe_s") != j.end())
{
@@ -320,6 +332,22 @@ void Rugnux_live_status::setState(std::string const& value)
{
m_State = value;
}
bool Rugnux_live_status::isPlacedModel() const
{
return m_Placed_model;
}
void Rugnux_live_status::setPlacedModel(bool const value)
{
m_Placed_model = value;
}
bool Rugnux_live_status::isAnomalousMap() const
{
return m_Anomalous_map;
}
void Rugnux_live_status::setAnomalousMap(bool const value)
{
m_Anomalous_map = value;
}
std::string Rugnux_live_status::getProbe() const
{
return m_Probe;
+14
View File
@@ -67,6 +67,16 @@ public:
std::string getState() const;
void setState(std::string const& value);
/// <summary>
/// The run placed the model: it can be fetched from &#x60;/rugnux/model.cif&#x60; and its maps from &#x60;/rugnux/map.ccp4&#x60;.
/// </summary>
bool isPlacedModel() const;
void setPlacedModel(bool const value);
/// <summary>
/// The merge kept the Bijvoet pairs, so with the placed model there is an anomalous difference map (&#x60;/rugnux/map.ccp4?type&#x3D;anom&#x60;).
/// </summary>
bool isAnomalousMap() const;
void setAnomalousMap(bool const value);
/// <summary>
/// Answer of the early lattice probe on the first 60 degrees; empty until it answers
/// </summary>
std::string getProbe() const;
@@ -178,6 +188,10 @@ public:
protected:
std::string m_State;
bool m_Placed_model;
bool m_Anomalous_map;
std::string m_Probe;
double m_Probe_s;
+81
View File
@@ -2785,10 +2785,22 @@ components:
- summary
- warnings
- probe
- placed_model
- anomalous_map
properties:
state:
type: string
enum: [Idle, Running, Done, Failed, Cancelled, Skipped]
placed_model:
type: boolean
description: |
The run placed the model: it can be fetched from `/rugnux/model.cif` and its maps from
`/rugnux/map.ccp4`.
anomalous_map:
type: boolean
description: |
The merge kept the Bijvoet pairs, so with the placed model there is an anomalous difference map
(`/rugnux/map.ccp4?type=anom`).
probe:
type: string
description: Answer of the early lattice probe on the first 60 degrees; empty until it answers
@@ -3605,6 +3617,75 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/rugnux_live_status'
/rugnux/model.cif:
get:
summary: Get the model as placed by the last rugnux live run
description: |
The model placed against the data by molecular replacement or validation, as mmCIF - the same text as the
`_model.cif` file written beside the data: the data's cell and space group, with the input model's own
metadata (entities, sequences, references, authors, software) kept. Kept as long as `/rugnux/status`.
security:
- bearerAuth: []
responses:
"200":
description: Placed model
content:
chemical/x-mmcif:
schema:
type: string
format: binary
"401":
description: The current dataset is protected and no valid bearer token was presented.
content:
text/plain:
schema:
type: string
"404":
description: The last rugnux live run placed no model
/rugnux/map.ccp4:
get:
summary: Get an electron-density map of the last rugnux live run
description: |
The map of the placed model (`/rugnux/model.cif`) in CCP4 format (mode 2, float), made from the map
coefficients written to `_maps.mtz` (FWT/PHWT, DELFWT/PHDELWT, ANOM/PHANOM). It covers one unit cell centred on the model - along an axis where
the model reaches further than the cell, the model plus 5 A instead - sampled every d_min/3; the mean and
RMS in its header are those of the unit cell, so contour levels in sigma are the usual ones.
parameters:
- in: query
name: type
required: false
schema:
type: string
enum: [2fofc, fofc, anom]
default: 2fofc
description: |
`2fofc`: the 2mFo-DFc map; `fofc`: the mFo-DFc difference map; `anom`: the anomalous difference map,
(F(+) - F(-)) on the model phases less 90 degrees, where the merge kept the Bijvoet pairs (`anomalous_map`
in `/rugnux/status`)
security:
- bearerAuth: []
responses:
"200":
description: Map
content:
application/octet-stream:
schema:
type: string
format: binary
"400":
description: Unknown map type
content:
text/plain:
schema:
type: string
"401":
description: The current dataset is protected and no valid bearer token was presented.
content:
text/plain:
schema:
type: string
"404":
description: The last rugnux live run placed no model or made no maps, or (`anom`) has no Bijvoet pairs
/config/zeromq_preview:
put:
summary: Set ZeroMQ preview settings
+48 -29
View File
@@ -394,7 +394,7 @@ data-styled.g138[id="sc-dxcDKg"]{content:"eajCCh,"}/*!sc*/
<body>
<div id="redoc"><div class="sc-lnPyaJ eJNCiX redoc-wrap"><div class="sc-eBHhsj dhHelK menu-content" style="top:0px;height:calc(100vh - 0px)"><div role="search" class="sc-iapWAC cNIbYM"><svg class="sc-dxcDKg eajCCh search-icon" version="1.1" viewBox="0 0 1000 1000" x="0px" xmlns="http://www.w3.org/2000/svg" y="0px"><path d="M968.2,849.4L667.3,549c83.9-136.5,66.7-317.4-51.7-435.6C477.1-25,252.5-25,113.9,113.4c-138.5,138.3-138.5,362.6,0,501C219.2,730.1,413.2,743,547.6,666.5l301.9,301.4c43.6,43.6,76.9,14.9,104.2-12.4C981,928.3,1011.8,893,968.2,849.4z M524.5,522c-88.9,88.7-233,88.7-321.8,0c-88.9-88.7-88.9-232.6,0-321.3c88.9-88.7,233-88.7,321.8,0C613.4,289.4,613.4,433.3,524.5,522z"></path></svg><input placeholder="Search..." aria-label="Search" type="text" class="sc-kqGoIF eLSrIr search-input" value=""/></div><div class="sc-dtBdUo hyOGfk scrollbar-container undefined"><ul class="sc-kYxDKI dCbZA-d" role="menu"><li tabindex="0" data-item-id="section/License-Clarification" role="menuitem" aria-label="License Clarification" aria-expanded="false" class="sc-bpUBKd gBkDnc"><label class="sc-eyvILC exZVdx -depth1"><span width="calc(100% - 38px)" title="License Clarification" class="sc-gfoqjT fUixgs">License Clarification</span></label></li><li tabindex="0" data-item-id="/paths/~1initialize/post" role="menuitem" aria-label="Initialize detector and data acquisition" aria-expanded="false" class="sc-bpUBKd gBkDnc"><label class="sc-eyvILC jFtfJP -depth2"><span type="post" class="sc-iHmpnF gXHrXJ operation-type post">post</span><span tabindex="0" width="calc(100% - 38px)" class="sc-gfoqjT fUixgs">Initialize detector and data acquisition</span></label></li><li tabindex="0" data-item-id="/paths/~1pedestal/post" role="menuitem" aria-label="Collect dark current for the detector" aria-expanded="false" class="sc-bpUBKd gBkDnc"><label class="sc-eyvILC jFtfJP -depth2"><span type="post" class="sc-iHmpnF gXHrXJ operation-type post">post</span><span tabindex="0" width="calc(100% - 38px)" class="sc-gfoqjT fUixgs">Collect dark current for the detector</span></label></li><li tabindex="0" data-item-id="/paths/~1start/post" role="menuitem" aria-label="Start detector" aria-expanded="false" class="sc-bpUBKd gBkDnc"><label class="sc-eyvILC jFtfJP -depth2"><span type="post" class="sc-iHmpnF gXHrXJ operation-type post">post</span><span tabindex="0" width="calc(100% - 38px)" class="sc-gfoqjT fUixgs">Start detector</span></label></li><li tabindex="0" data-item-id="/paths/~1wait_until_running/post" role="menuitem" aria-label="Wait for acquisition running" aria-expanded="false" class="sc-bpUBKd gBkDnc"><label class="sc-eyvILC jFtfJP -depth2"><span type="post" class="sc-iHmpnF gXHrXJ operation-type post">post</span><span tabindex="0" width="calc(100% - 38px)" class="sc-gfoqjT fUixgs">Wait for acquisition running</span></label></li><li tabindex="0" data-item-id="/paths/~1wait_till_done/post" role="menuitem" aria-label="Wait for acquisition done" aria-expanded="false" class="sc-bpUBKd gBkDnc"><label class="sc-eyvILC jFtfJP -depth2"><span type="post" class="sc-iHmpnF gXHrXJ operation-type post">post</span><span tabindex="0" width="calc(100% - 38px)" class="sc-gfoqjT fUixgs">Wait for acquisition done</span></label></li><li tabindex="0" data-item-id="/paths/~1trigger/post" role="menuitem" aria-label="Send soft trigger to the detector" aria-expanded="false" class="sc-bpUBKd gBkDnc"><label class="sc-eyvILC jFtfJP -depth2"><span type="post" class="sc-iHmpnF gXHrXJ operation-type post">post</span><span tabindex="0" width="calc(100% - 38px)" class="sc-gfoqjT fUixgs">Send soft trigger to the detector</span></label></li><li tabindex="0" data-item-id="/paths/~1cancel/post" role="menuitem" aria-label="Cancel running data collection" aria-expanded="false" class="sc-bpUBKd gBkDnc"><label class="sc-eyvILC jFtfJP -depth2"><span type="post" class="sc-iHmpnF gXHrXJ operation-type post">post</span><span tabindex="0" width="calc(100% - 38px)" class="sc-gfoqjT fUixgs">Cancel running data collection</span></label></li><li tabindex="0" data-item-id="/paths/~1deactivate/post" role="menuitem" aria-label="Prepare detector to turn off" aria-expanded="false" class="sc-bpUBKd gBkDnc"><label class="sc-eyvILC jFtfJP -depth2"><span type="post" class="sc-iHmpnF gXHrXJ operation-type post">post</span><span tabindex="0" width="calc(100% - 38px)" class="sc-gfoqjT fUixgs">Prepare detector to turn off</span></label></li><li tabindex="0" data-item-id="/paths/~1config~1detector/put" role="menuitem" aria-label="Change detector configuration" aria-expanded="false" class="sc-bpUBKd gBkDnc"><label class="sc-eyvILC jFtfJP -depth2"><span type="put" class="sc-iHmpnF gXHrXJ operation-type put">put</span><span tabindex="0" width="calc(100% - 38px)" class="sc-gfoqjT fUixgs">Change detector configuration</span></label></li><li tabindex="0" data-item-id="/paths/~1config~1detector/get" role="menuitem" aria-label="Get detector configuration" aria-expanded="false" class="sc-bpUBKd gBkDnc"><label class=Line truncated
<div id="redoc"><div class="sc-lnPyaJ eJNCiX redoc-wrap"><div class="sc-eBHhsj dhHelK menu-content" style="top:0px;height:calc(100vh - 0px)"><div role="search" class="sc-iapWAC cNIbYM"><svg class="sc-dxcDKg eajCCh search-icon" version="1.1" viewBox="0 0 1000 1000" x="0px" xmlns="http://www.w3.org/2000/svg" y="0px"><path d="M968.2,849.4L667.3,549c83.9-136.5,66.7-317.4-51.7-435.6C477.1-25,252.5-25,113.9,113.4c-138.5,138.3-138.5,362.6,0,501C219.2,730.1,413.2,743,547.6,666.5l301.9,301.4c43.6,43.6,76.9,14.9,104.2-12.4C981,928.3,1011.8,893,968.2,849.4z M524.5,522c-88.9,88.7-233,88.7-321.8,0c-88.9-88.7-88.9-232.6,0-321.3c88.9-88.7,233-88.7,321.8,0C613.4,289.4,613.4,433.3,524.5,522z"></path></svg><input placeholder="Search..." aria-label="Search" type="text" class="sc-kqGoIF eLSrIr search-input" value=""/></div><div class="sc-dtBdUo hyOGfk scrollbar-container undefined"><ul class="sc-kYxDKI dCbZA-d" role="menu"><li tabindex="0" data-item-id="section/License-Clarification" role="menuitem" aria-label="License Clarification" aria-expanded="false" class="sc-bpUBKd gBkDnc"><label class="sc-eyvILC exZVdx -depth1"><span width="calc(100% - 38px)" title="License Clarification" class="sc-gfoqjT fUixgs">License Clarification</span></label></li><li tabindex="0" data-item-id="/paths/~1initialize/post" role="menuitem" aria-label="Initialize detector and data acquisition" aria-expanded="false" class="sc-bpUBKd gBkDnc"><label class="sc-eyvILC jFtfJP -depth2"><span type="post" class="sc-iHmpnF gXHrXJ operation-type post">post</span><span tabindex="0" width="calc(100% - 38px)" class="sc-gfoqjT fUixgs">Initialize detector and data acquisition</span></label></li><li tabindex="0" data-item-id="/paths/~1pedestal/post" role="menuitem" aria-label="Collect dark current for the detector" aria-expanded="false" class="sc-bpUBKd gBkDnc"><label class="sc-eyvILC jFtfJP -depth2"><span type="post" class="sc-iHmpnF gXHrXJ operation-type post">post</span><span tabindex="0" width="calc(100% - 38px)" class="sc-gfoqjT fUixgs">Collect dark current for the detector</span></label></li><li tabindex="0" data-item-id="/paths/~1start/post" role="menuitem" aria-label="Start detector" aria-expanded="false" class="sc-bpUBKd gBkDnc"><label class="sc-eyvILC jFtfJP -depth2"><span type="post" class="sc-iHmpnF gXHrXJ operation-type post">post</span><span tabindex="0" width="calc(100% - 38px)" class="sc-gfoqjT fUixgs">Start detector</span></label></li><li tabindex="0" data-item-id="/paths/~1wait_until_running/post" role="menuitem" aria-label="Wait for acquisition running" aria-expanded="false" class="sc-bpUBKd gBkDnc"><label class="sc-eyvILC jFtfJP -depth2"><span type="post" class="sc-iHmpnF gXHrXJ operation-type post">post</span><span tabindex="0" width="calc(100% - 38px)" class="sc-gfoqjT fUixgs">Wait for acquisition running</span></label></li><li tabindex="0" data-item-id="/paths/~1wait_till_done/post" role="menuitem" aria-label="Wait for acquisition done" aria-expanded="false" class="sc-bpUBKd gBkDnc"><label class="sc-eyvILC jFtfJP -depth2"><span type="post" class="sc-iHmpnF gXHrXJ operation-type post">post</span><span tabindex="0" width="calc(100% - 38px)" class="sc-gfoqjT fUixgs">Wait for acquisition done</span></label></li><li tabindex="0" data-item-id="/paths/~1trigger/post" role="menuitem" aria-label="Send soft trigger to the detector" aria-expanded="false" class="sc-bpUBKd gBkDnc"><label class="sc-eyvILC jFtfJP -depth2"><span type="post" class="sc-iHmpnF gXHrXJ operation-type post">post</span><span tabindex="0" width="calc(100% - 38px)" class="sc-gfoqjT fUixgs">Send soft trigger to the detector</span></label></li><li tabindex="0" data-item-id="/paths/~1cancel/post" role="menuitem" aria-label="Cancel running data collection" aria-expanded="false" class="sc-bpUBKd gBkDnc"><label class="sc-eyvILC jFtfJP -depth2"><span type="post" class="sc-iHmpnF gXHrXJ operation-type post">post</span><span tabindex="0" width="calc(100% - 38px)" class="sc-gfoqjT fUixgs">Cancel running data collection</span></label></li><li tabindex="0" data-item-id="/paths/~1deactivate/post" role="menuitem" aria-label="Prepare detector to turn off" aria-expanded="false" class="sc-bpUBKd gBkDnc"><label class="sc-eyvILC jFtfJP -depth2"><span type="post" class="sc-iHmpnF gXHrXJ operation-type post">post</span><span tabindex="0" width="calc(100% - 38px)" class="sc-gfoqjT fUixgs">Prepare detector to turn off</span></label></li><li tabindex="0" data-item-id="/paths/~1config~1detector/put" role="menuitem" aria-label="Change detector configuration" aria-expanded="false" class="sc-bpUBKd gBkDnc"><label class="sc-eyvILC jFtfJP -depth2"><span type="put" class="sc-iHmpnF gXHrXJ operation-type put">put</span><span tabindex="0" width="calc(100% - 38px)" class="sc-gfoqjT fUixgs">Change detector configuration</span></label></li><li tabindex="0" data-item-id="/paths/~1config~1detector/get" role="menuitem" aria-label="Get detector configuration" aria-expanded="false" class="sc-bpUBKd gBkDnc"><label class=Line truncated
Get user mask of the detector (binary)
" aria-expanded="false" class="sc-bpUBKd gBkDnc"><label class="sc-eyvILC jFtfJP -depth2"><span type="get" class="sc-iHmpnF gXHrXJ operation-type get">get</span><span tabindex="0" width="calc(100% - 38px)" class="sc-gfoqjT fUixgs">Detector must be Initialized.
Get user mask of the detector (binary)
@@ -864,7 +864,26 @@ and validation of every following rugnux live collection, until it is removed wi
</div></div><div class="sc-jaXxmE eqYzvz"><div class="sc-iMTnTL fkPTul"><h5 class="sc-dAlyuH sc-hwdzOV jbQuod JjoyL">Authorizations:</h5><svg class="sc-cwHptR iZRiKW" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></div><div class="sc-krNlru gkwgxc"><span class="sc-jMakVo bPNrjo"><span class="sc-ihgnxF jlNGfN"><i>bearerAuth</i></span></span></div></div><div><h3 class="sc-fMMURN egoxtT">Responses</h3><div><button class="sc-kzqdkY jgSwKD"><svg class="sc-cwHptR hWEnWx" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">200<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Everything OK</p>
</div></button></div><div><button class="sc-kzqdkY bXzzUN"><svg class="sc-cwHptR cSkZlF" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">401<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>The current dataset is protected and no valid bearer token was presented.</p>
</div></button></div></div></div><div class="sc-iGgWBj sc-gsFSXq ibAZSi eDeKjd"><div class="sc-ejfMa-d bNUPQg"><button class="sc-EgOXT cFEcOl"><span type="get" class="sc-eZYNyq qGfV http-verb get">get</span><span class="sc-iEXKAA gUNSDu">/rugnux/status</span><svg class="sc-cwHptR iVFMLx" style="margin-right:-25px" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></button><div aria-hidden="true" class="sc-dlWCHZ kWacYr"><div class="sc-hHOBiw cndTNO"><div class="sc-eeDRCY sc-eBMEME gTGgei fbXBig"><p>Test Jungfraujoch system</p>
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/rugnux/status</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-success react-tabs__tab--selected" role="tab" id="tab_R_jiia_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jiia_0" tabindex="0" data-rttab="true">200</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jiia_0" aria-labelledby="tab_R_jiia_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button><button> Expand all </button><button> Collapse all </button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"state"</span>: <span class="token string">&quot;Idle&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"probe"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"probe_s"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"start_to_first_image_s"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"message"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"images_expected"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"expected_collection_s"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"images_received"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"elapsed_s"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"step_progress"</span>: <span class="token number">1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"steps"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable collapsed"><button class="collapser" aria-label="expand"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable collapsed"><span class="property token string">"title"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"started_s"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"duration_s"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"notes"</span>: <button class="collapser" aria-label="expand"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable collapsed"><span class="token string">&quot;string&quot;</span></div></li></ul><span class="token punctuation">]</span></div></li></ul><span class="token punctuation">}</span></div></li></ul><span class="token punctuation">]</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"last_image_s"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"cut"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"cut_s"</span>Line truncated
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/rugnux/status</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-success react-tabs__tab--selected" role="tab" id="tab_R_jiia_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jiia_0" tabindex="0" data-rttab="true">200</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jiia_0" aria-labelledby="tab_R_jiia_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button><button> Expand all </button><button> Collapse all </button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"state"</span>: <span class="token string">&quot;Idle&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"placed_model"</span>: <span class="token boolean">true</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"anomalous_map"</span>: <span class="token boolean">true</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"probe"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"probe_s"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"start_to_first_image_s"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"message"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"images_expected"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"expected_collection_s"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"images_received"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"elapsed_s"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"step_progress"</span>: <span class="token number">1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"steps"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable collapsed"><button class="collapser" aria-label="expand"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable collapsed"><span class="property token string">"title"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"started_s"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"duration_s"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"notes"</span>: <button class="collapser" aria-label="expand"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable collapsed"><span class="token string">&quot;string&quot;</span></div></li></ul><span class="token punctuation">]</span></div></li></ul><span class="token punctuation">}</span></div></li></ul><span class="token punctuation">]</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"last_image_s"<Line truncated
<code>_model.cif</code> file written beside the data: the data&#39;s cell and space group, with the input model&#39;s own
metadata (entities, sequences, references, authors, software) kept. Kept as long as <code>/rugnux/status</code>.</p>
</div></div><div class="sc-jaXxmE eqYzvz"><div class="sc-iMTnTL fkPTul"><h5 class="sc-dAlyuH sc-hwdzOV jbQuod JjoyL">Authorizations:</h5><svg class="sc-cwHptR iZRiKW" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></div><div class="sc-krNlru gkwgxc"><span class="sc-jMakVo bPNrjo"><span class="sc-ihgnxF jlNGfN"><i>bearerAuth</i></span></span></div></div><div><h3 class="sc-fMMURN egoxtT">Responses</h3><div><button class="sc-kzqdkY jgSwKD"><svg class="sc-cwHptR hWEnWx" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">200<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Placed model</p>
</div></button></div><div><button class="sc-kzqdkY bXzzUN"><svg class="sc-cwHptR cSkZlF" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">401<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>The current dataset is protected and no valid bearer token was presented.</p>
</div></button></div><div><button class="sc-kzqdkY gnmLmb" disabled=""><strong class="sc-dSIIpw bpEYcE">404<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>The last rugnux live run placed no model</p>
</div></button></div></div></div><div class="sc-iGgWBj sc-gsFSXq ibAZSi eDeKjd"><div class="sc-ejfMa-d bNUPQg"><button class="sc-EgOXT cFEcOl"><span type="get" class="sc-eZYNyq qGfV http-verb get">get</span><span class="sc-iEXKAA gUNSDu">/rugnux/model.cif</span><svg class="sc-cwHptR iVFMLx" style="margin-right:-25px" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></button><div aria-hidden="true" class="sc-dlWCHZ kWacYr"><div class="sc-hHOBiw cndTNO"><div class="sc-eeDRCY sc-eBMEME gTGgei fbXBig"><p>Test Jungfraujoch system</p>
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/rugnux/model.cif</div></div></div></div></div></div></div></div><div id="/paths/~1rugnux~1map.ccp4/get" data-section-id="/paths/~1rugnux~1map.ccp4/get" class="sc-dcJsrY cqVkUp"><div class="sc-kAyceB hBQWIZ"><div class="sc-fqkvVR oJKYx"><h2 class="sc-jXbUNg fWnwAh"><a class="sc-jlZhew kbdRLs" href="#/paths/~1rugnux~1map.ccp4/get" aria-label="/paths/~1rugnux~1map.ccp4/get"></a>Get an electron-density map of the last rugnux live run<!-- --> </h2><div class="sc-bVVIoq icSMtY"><div class="sc-eeDRCY sc-eBMEME gTGgei fMmru"><p>The map of the placed model (<code>/rugnux/model.cif</code>) in CCP4 format (mode 2, float), made from the map
coefficients written to <code>_maps.mtz</code> (FWT/PHWT, DELFWT/PHDELWT, ANOM/PHANOM). It covers one unit cell centred on the model - along an axis where
the model reaches further than the cell, the model plus 5 A instead - sampled every d_min/3; the mean and
RMS in its header are those of the unit cell, so contour levels in sigma are the usual ones.</p>
</div></div><div class="sc-jaXxmE eqYzvz"><div class="sc-iMTnTL fkPTul"><h5 class="sc-dAlyuH sc-hwdzOV jbQuod JjoyL">Authorizations:</h5><svg class="sc-cwHptR iZRiKW" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></div><div class="sc-krNlru gkwgxc"><span class="sc-jMakVo bPNrjo"><span class="sc-ihgnxF jlNGfN"><i>bearerAuth</i></span></span></div></div><div><h5 class="sc-dAlyuH jbQuod">query<!-- --> Parameters</h5><table class="sc-dAbbOL ccPhmY"><tbody><tr class="last "><td class="sc-dLMFU sc-eldPxv hZbWKe jXkfaY" kind="field" title="type"><span class="sc-gFqAkR eRqgPI"></span><span class="property-name">type</span></td><td class="sc-fPXMVe bAXEAa"><div><div><span class="sc-Nxspf sc-cfxfcM cXxAXt jrGEaR"></span><span class="sc-Nxspf sc-gFAWRd cXxAXt dYzdDr">string</span></div><div><span class="sc-Nxspf cXxAXt"> <!-- -->Default:<!-- --> </span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">&quot;2fofc&quot;</span></div><div><span class="sc-Nxspf cXxAXt"> <!-- -->Enum<!-- -->:</span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">&quot;2fofc&quot;</span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">&quot;fofc&quot;</span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">&quot;anom&quot;</span> </div> <div><div class="sc-eeDRCY sc-eBMEME gTGgei fbXBig"><p><code>2fofc</code>: the 2mFo-DFc map; <code>fofc</code>: the mFo-DFc difference map; <code>anom</code>: the anomalous difference map,
(F(+) - F(-)) on the model phases less 90 degrees, where the merge kept the Bijvoet pairs (<code>anomalous_map</code>
in <code>/rugnux/status</code>)</p>
</div></div></div></td></tr></tbody></table></div><div><h3 class="sc-fMMURN egoxtT">Responses</h3><div><button class="sc-kzqdkY jgSwKD"><svg class="sc-cwHptR hWEnWx" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">200<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Map</p>
</div></button></div><div><button class="sc-kzqdkY bXzzUN"><svg class="sc-cwHptR cSkZlF" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">400<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Unknown map type</p>
</div></button></div><div><button class="sc-kzqdkY bXzzUN"><svg class="sc-cwHptR cSkZlF" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">401<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>The current dataset is protected and no valid bearer token was presented.</p>
</div></button></div><div><button class="sc-kzqdkY gnmLmb" disabled=""><strong class="sc-dSIIpw bpEYcE">404<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>The last rugnux live run placed no model or made no maps, or (<code>anom</code>) has no Bijvoet pairs</p>
</div></button></div></div></div><div class="sc-iGgWBj sc-gsFSXq ibAZSi eDeKjd"><div class="sc-ejfMa-d bNUPQg"><button class="sc-EgOXT cFEcOl"><span type="get" class="sc-eZYNyq qGfV http-verb get">get</span><span class="sc-iEXKAA gUNSDu">/rugnux/map.ccp4</span><svg class="sc-cwHptR iVFMLx" style="margin-right:-25px" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></button><div aria-hidden="true" class="sc-dlWCHZ kWacYr"><div class="sc-hHOBiw cndTNO"><div class="sc-eeDRCY sc-eBMEME gTGgei fbXBig"><p>Test Jungfraujoch system</p>
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/rugnux/map.ccp4</div></div></div></div></div></div></div></div><div id="/paths/~1config~1zeromq_preview/put" data-section-id="/paths/~1config~1zeromq_preview/put" class="sc-dcJsrY cqVkUp"><div class="sc-kAyceB hBQWIZ"><div class="sc-fqkvVR oJKYx"><h2 class="sc-jXbUNg fWnwAh"><a class="sc-jlZhew kbdRLs" href="#/paths/~1config~1zeromq_preview/put" aria-label="/paths/~1config~1zeromq_preview/put"></a>Set ZeroMQ preview settings<!-- --> </h2><div class="sc-bVVIoq icSMtY"><div class="sc-eeDRCY sc-eBMEME gTGgei fMmru"><p>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.</p>
@@ -880,9 +899,9 @@ Address follows ZeroMQ convention for sockets - in practice ipc://<socket file>
</div></button></div><div><button class="sc-kzqdkY bXzzUN"><svg class="sc-cwHptR cSkZlF" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">400<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Input parsing or validation error</p>
</div></button></div><div><button class="sc-kzqdkY bXzzUN"><svg class="sc-cwHptR cSkZlF" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">500<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Error within Jungfraujoch code - see output message.</p>
</div></button></div></div></div><div class="sc-iGgWBj sc-gsFSXq ibAZSi eDeKjd"><div class="sc-ejfMa-d bNUPQg"><button class="sc-EgOXT cFEcOl"><span type="put" class="sc-eZYNyq cnqpVw http-verb put">put</span><span class="sc-iEXKAA gUNSDu">/config/zeromq_preview</span><svg class="sc-cwHptR iVFMLx" style="margin-right:-25px" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></button><div aria-hidden="true" class="sc-dlWCHZ kWacYr"><div class="sc-hHOBiw cndTNO"><div class="sc-eeDRCY sc-eBMEME gTGgei fbXBig"><p>Test Jungfraujoch system</p>
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/config/zeromq_preview</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Request samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="react-tabs__tab react-tabs__tab--selected" role="tab" id="tab_R_iiiq_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_iiiq_0" tabindex="0" data-rttab="true">Payload</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_iiiq_0" aria-labelledby="tab_R_iiiq_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"enabled"</span>: <span class="token boolean">true</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"period_ms"</span>: <span class="token number">1000</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"socket_address"</span>: <span class="token string">&quot;string&quot;</span></div></li></ul><span class="token punctuation">}</span></code></div></div></div></div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-error react-tabs__tab--selected" role="tab" id="tab_R_jiiq_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jiiq_0" tabindex="0" data-rttab="true">500</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jiiq_0" aria-labelledby="tab_R_jiiq_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"msg"</span>: <span class="token string">&quot;Detector in wrong state&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"reason"</span>: <span class="token string">&quot;WrongDAQState&quot;</span></div></li></ul><span class="token punctuation">}</span></code></div></div></div></div></div></div></div></div></div></div></div><div id="/paths/~1config~1zeromq_preview/get" data-section-id="/paths/~1config~1zeromq_preview/get" class="sc-dcJsrY cqVkUp"><div class="sc-kAyceB hBQWIZ"><div class="sc-fqkvVR oJKYx"><h2 class="sc-jXbUNg fWnwAh"><a class="sc-jlZhew kbdRLs" href="#/paths/~1config~1zeromq_preview/get" aria-label="/paths/~1config~1zeromq_preview/get"></a>Get ZeroMQ preview settings<!-- --> </h2><div><h3 class="sc-fMMURN egoxtT">Responses</h3><div><button class="sc-kzqdkY jgSwKD"><svg class="sc-cwHptR hWEnWx" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">200<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Everything OK</p>
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/config/zeromq_preview</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Request samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="react-tabs__tab react-tabs__tab--selected" role="tab" id="tab_R_iijq_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_iijq_0" tabindex="0" data-rttab="true">Payload</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_iijq_0" aria-labelledby="tab_R_iijq_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"enabled"</span>: <span class="token boolean">true</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"period_ms"</span>: <span class="token number">1000</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"socket_address"</span>: <span class="token string">&quot;string&quot;</span></div></li></ul><span class="token punctuation">}</span></code></div></div></div></div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-error react-tabs__tab--selected" role="tab" id="tab_R_jijq_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jijq_0" tabindex="0" data-rttab="true">500</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jijq_0" aria-labelledby="tab_R_jijq_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"msg"</span>: <span class="token string">&quot;Detector in wrong state&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"reason"</span>: <span class="token string">&quot;WrongDAQState&quot;</span></div></li></ul><span class="token punctuation">}</span></code></div></div></div></div></div></div></div></div></div></div></div><div id="/paths/~1config~1zeromq_preview/get" data-section-id="/paths/~1config~1zeromq_preview/get" class="sc-dcJsrY cqVkUp"><div class="sc-kAyceB hBQWIZ"><div class="sc-fqkvVR oJKYx"><h2 class="sc-jXbUNg fWnwAh"><a class="sc-jlZhew kbdRLs" href="#/paths/~1config~1zeromq_preview/get" aria-label="/paths/~1config~1zeromq_preview/get"></a>Get ZeroMQ preview settings<!-- --> </h2><div><h3 class="sc-fMMURN egoxtT">Responses</h3><div><button class="sc-kzqdkY jgSwKD"><svg class="sc-cwHptR hWEnWx" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">200<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Everything OK</p>
</div></button></div></div></div><div class="sc-iGgWBj sc-gsFSXq ibAZSi eDeKjd"><div class="sc-ejfMa-d bNUPQg"><button class="sc-EgOXT cFEcOl"><span type="get" class="sc-eZYNyq qGfV http-verb get">get</span><span class="sc-iEXKAA gUNSDu">/config/zeromq_preview</span><svg class="sc-cwHptR iVFMLx" style="margin-right:-25px" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></button><div aria-hidden="true" class="sc-dlWCHZ kWacYr"><div class="sc-hHOBiw cndTNO"><div class="sc-eeDRCY sc-eBMEME gTGgei fbXBig"><p>Test Jungfraujoch system</p>
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/config/zeromq_preview</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-success react-tabs__tab--selected" role="tab" id="tab_R_jija_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jija_0" tabindex="0" data-rttab="true">200</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jija_0" aria-labelledby="tab_R_jija_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"enabled"</span>: <span class="token boolean">true</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"period_ms"</span>: <span class="token number">1000</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"socket_address"</span>: <span class="token string">&quot;string&quot;</span></div></li></ul><span class="token punctuation">}</span></code></div></div></div></div></div></div></div></div></div></div></div><div id="/paths/~1config~1zeromq_metadata/put" data-section-id="/paths/~1config~1zeromq_metadata/put" class="sc-dcJsrY cqVkUp"><div class="sc-kAyceB hBQWIZ"><div class="sc-fqkvVR oJKYx"><h2 class="sc-jXbUNg fWnwAh"><a class="sc-jlZhew kbdRLs" href="#/paths/~1config~1zeromq_metadata/put" aria-label="/paths/~1config~1zeromq_metadata/put"></a>Set ZeroMQ metadata settings<!-- --> </h2><div class="sc-bVVIoq icSMtY"><div class="sc-eeDRCY sc-eBMEME gTGgei fMmru"><p>Jungfraujoch can generate metadata message stream on ZeroMQ PUB socket. This stream covers all images.
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/config/zeromq_preview</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-success react-tabs__tab--selected" role="tab" id="tab_R_jika_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jika_0" tabindex="0" data-rttab="true">200</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jika_0" aria-labelledby="tab_R_jika_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"enabled"</span>: <span class="token boolean">true</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"period_ms"</span>: <span class="token number">1000</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"socket_address"</span>: <span class="token string">&quot;string&quot;</span></div></li></ul><span class="token punctuation">}</span></code></div></div></div></div></div></div></div></div></div></div></div><div id="/paths/~1config~1zeromq_metadata/put" data-section-id="/paths/~1config~1zeromq_metadata/put" class="sc-dcJsrY cqVkUp"><div class="sc-kAyceB hBQWIZ"><div class="sc-fqkvVR oJKYx"><h2 class="sc-jXbUNg fWnwAh"><a class="sc-jlZhew kbdRLs" href="#/paths/~1config~1zeromq_metadata/put" aria-label="/paths/~1config~1zeromq_metadata/put"></a>Set ZeroMQ metadata settings<!-- --> </h2><div class="sc-bVVIoq icSMtY"><div class="sc-eeDRCY sc-eBMEME gTGgei fMmru"><p>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.</p>
</div></div><h5 class="sc-dAlyuH jbQuod">Request Body schema: <span class="sc-cWSHoV fzNksy">application/json</span></h5><div class="sc-eeDRCY sc-eBMEME gTGgei fMmru"></div><table class="sc-dAbbOL ccPhmY"><tbody><tr class=""><td class="sc-dLMFU sc-eldPxv hZbWKe jXkfaY" kind="field" title="enabled"><span class="sc-gFqAkR eRqgPI"></span><span class="property-name">enabled</span><div class="sc-Nxspf sc-hRJfrW cXxAXt kYVhSL">required</div></td><td class="sc-fPXMVe bAXEAa"><div><div><span class="sc-Nxspf sc-cfxfcM cXxAXt jrGEaR"></span><span class="sc-Nxspf sc-gFAWRd cXxAXt dYzdDr">boolean</span></div><div><span class="sc-Nxspf cXxAXt"> <!-- -->Default:<!-- --> </span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">true</span></div> <div><div class="sc-eeDRCY sc-eBMEME gTGgei fbXBig"><p>ZeroMQ metadata socket is enabled.</p>
@@ -895,9 +914,9 @@ Address follows ZeroMQ convention for sockets - in practice ipc://<socket file>
</div></button></div><div><button class="sc-kzqdkY bXzzUN"><svg class="sc-cwHptR cSkZlF" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">400<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Input parsing or validation error</p>
</div></button></div><div><button class="sc-kzqdkY bXzzUN"><svg class="sc-cwHptR cSkZlF" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">500<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Error within Jungfraujoch code - see output message.</p>
</div></button></div></div></div><div class="sc-iGgWBj sc-gsFSXq ibAZSi eDeKjd"><div class="sc-ejfMa-d bNUPQg"><button class="sc-EgOXT cFEcOl"><span type="put" class="sc-eZYNyq cnqpVw http-verb put">put</span><span class="sc-iEXKAA gUNSDu">/config/zeromq_metadata</span><svg class="sc-cwHptR iVFMLx" style="margin-right:-25px" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></button><div aria-hidden="true" class="sc-dlWCHZ kWacYr"><div class="sc-hHOBiw cndTNO"><div class="sc-eeDRCY sc-eBMEME gTGgei fbXBig"><p>Test Jungfraujoch system</p>
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/config/zeromq_metadata</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Request samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="react-tabs__tab react-tabs__tab--selected" role="tab" id="tab_R_iijq_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_iijq_0" tabindex="0" data-rttab="true">Payload</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_iijq_0" aria-labelledby="tab_R_iijq_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"enabled"</span>: <span class="token boolean">true</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"period_ms"</span>: <span class="token number">1000</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"socket_address"</span>: <span class="token string">&quot;string&quot;</span></div></li></ul><span class="token punctuation">}</span></code></div></div></div></div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-error react-tabs__tab--selected" role="tab" id="tab_R_jijq_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jijq_0" tabindex="0" data-rttab="true">500</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jijq_0" aria-labelledby="tab_R_jijq_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"msg"</span>: <span class="token string">&quot;Detector in wrong state&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"reason"</span>: <span class="token string">&quot;WrongDAQState&quot;</span></div></li></ul><span class="token punctuation">}</span></code></div></div></div></div></div></div></div></div></div></div></div><div id="/paths/~1config~1zeromq_metadata/get" data-section-id="/paths/~1config~1zeromq_metadata/get" class="sc-dcJsrY cqVkUp"><div class="sc-kAyceB hBQWIZ"><div class="sc-fqkvVR oJKYx"><h2 class="sc-jXbUNg fWnwAh"><a class="sc-jlZhew kbdRLs" href="#/paths/~1config~1zeromq_metadata/get" aria-label="/paths/~1config~1zeromq_metadata/get"></a>Get ZeroMQ metadata socket settings<!-- --> </h2><div><h3 class="sc-fMMURN egoxtT">Responses</h3><div><button class="sc-kzqdkY jgSwKD"><svg class="sc-cwHptR hWEnWx" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">200<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Everything OK</p>
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/config/zeromq_metadata</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Request samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="react-tabs__tab react-tabs__tab--selected" role="tab" id="tab_R_iikq_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_iikq_0" tabindex="0" data-rttab="true">Payload</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_iikq_0" aria-labelledby="tab_R_iikq_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"enabled"</span>: <span class="token boolean">true</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"period_ms"</span>: <span class="token number">1000</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"socket_address"</span>: <span class="token string">&quot;string&quot;</span></div></li></ul><span class="token punctuation">}</span></code></div></div></div></div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-error react-tabs__tab--selected" role="tab" id="tab_R_jikq_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jikq_0" tabindex="0" data-rttab="true">500</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jikq_0" aria-labelledby="tab_R_jikq_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"msg"</span>: <span class="token string">&quot;Detector in wrong state&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"reason"</span>: <span class="token string">&quot;WrongDAQState&quot;</span></div></li></ul><span class="token punctuation">}</span></code></div></div></div></div></div></div></div></div></div></div></div><div id="/paths/~1config~1zeromq_metadata/get" data-section-id="/paths/~1config~1zeromq_metadata/get" class="sc-dcJsrY cqVkUp"><div class="sc-kAyceB hBQWIZ"><div class="sc-fqkvVR oJKYx"><h2 class="sc-jXbUNg fWnwAh"><a class="sc-jlZhew kbdRLs" href="#/paths/~1config~1zeromq_metadata/get" aria-label="/paths/~1config~1zeromq_metadata/get"></a>Get ZeroMQ metadata socket settings<!-- --> </h2><div><h3 class="sc-fMMURN egoxtT">Responses</h3><div><button class="sc-kzqdkY jgSwKD"><svg class="sc-cwHptR hWEnWx" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">200<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Everything OK</p>
</div></button></div></div></div><div class="sc-iGgWBj sc-gsFSXq ibAZSi eDeKjd"><div class="sc-ejfMa-d bNUPQg"><button class="sc-EgOXT cFEcOl"><span type="get" class="sc-eZYNyq qGfV http-verb get">get</span><span class="sc-iEXKAA gUNSDu">/config/zeromq_metadata</span><svg class="sc-cwHptR iVFMLx" style="margin-right:-25px" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></button><div aria-hidden="true" class="sc-dlWCHZ kWacYr"><div class="sc-hHOBiw cndTNO"><div class="sc-eeDRCY sc-eBMEME gTGgei fbXBig"><p>Test Jungfraujoch system</p>
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/config/zeromq_metadata</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-success react-tabs__tab--selected" role="tab" id="tab_R_jika_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jika_0" tabindex="0" data-rttab="true">200</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jika_0" aria-labelledby="tab_R_jika_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"enabled"</span>: <span class="token boolean">true</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"period_ms"</span>: <span class="token number">1000</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"socket_address"</span>: <span class="token string">&quot;string&quot;</span></div></li></ul><span class="token punctuation">}</span></code></div></div></div></div></div></div></div></div></div></div></div><div id="/paths/~1config~1dark_mask/put" data-section-id="/paths/~1config~1dark_mask/put" class="sc-dcJsrY cqVkUp"><div class="sc-kAyceB hBQWIZ"><div class="sc-fqkvVR oJKYx"><h2 class="sc-jXbUNg fWnwAh"><a class="sc-jlZhew kbdRLs" href="#/paths/~1config~1dark_mask/put" aria-label="/paths/~1config~1dark_mask/put"></a>Set configuration for dark data collection to calculate mask<!-- --> </h2><div class="sc-bVVIoq icSMtY"><div class="sc-eeDRCY sc-eBMEME gTGgei fMmru"><p>This is only possible when operating DECTRIS detectors at the moment; it will be also available for PSI EIGER at some point.
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/config/zeromq_metadata</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-success react-tabs__tab--selected" role="tab" id="tab_R_jila_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jila_0" tabindex="0" data-rttab="true">200</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jila_0" aria-labelledby="tab_R_jila_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"enabled"</span>: <span class="token boolean">true</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"period_ms"</span>: <span class="token number">1000</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"socket_address"</span>: <span class="token string">&quot;string&quot;</span></div></li></ul><span class="token punctuation">}</span></code></div></div></div></div></div></div></div></div></div></div></div><div id="/paths/~1config~1dark_mask/put" data-section-id="/paths/~1config~1dark_mask/put" class="sc-dcJsrY cqVkUp"><div class="sc-kAyceB hBQWIZ"><div class="sc-fqkvVR oJKYx"><h2 class="sc-jXbUNg fWnwAh"><a class="sc-jlZhew kbdRLs" href="#/paths/~1config~1dark_mask/put" aria-label="/paths/~1config~1dark_mask/put"></a>Set configuration for dark data collection to calculate mask<!-- --> </h2><div class="sc-bVVIoq icSMtY"><div class="sc-eeDRCY sc-eBMEME gTGgei fMmru"><p>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 <code>Idle</code>, <code>Error</code> or <code>Inactive</code> states.</p>
</div></div><h5 class="sc-dAlyuH jbQuod">Request Body schema: <span class="sc-cWSHoV fzNksy">application/json</span></h5><div class="sc-eeDRCY sc-eBMEME gTGgei fMmru"></div><table class="sc-dAbbOL ccPhmY"><tbody><tr class=""><td class="sc-dLMFU sc-eldPxv hZbWKe jXkfaY" kind="field" title="detector_threshold_keV"><span class="sc-gFqAkR eRqgPI"></span><span class="property-name">detector_threshold_keV</span><div class="sc-Nxspf sc-hRJfrW cXxAXt kYVhSL">required</div></td><td class="sc-fPXMVe bAXEAa"><div><div><span class="sc-Nxspf sc-cfxfcM cXxAXt jrGEaR"></span><span class="sc-Nxspf sc-gFAWRd cXxAXt dYzdDr">number</span><span class="sc-Nxspf sc-gFAWRd cXxAXt dYzdDr"> <!-- -->&lt;<!-- -->float<!-- -->&gt;<!-- --> </span><span> <span class="sc-Nxspf sc-fxwrCY cXxAXt eMVOei"> <!-- -->[ 2.5 .. 100 ]<!-- --> </span></span></div><div><span class="sc-Nxspf cXxAXt"> <!-- -->Default:<!-- --> </span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">3.5</span></div> <div><div class="sc-eeDRCY sc-eBMEME gTGgei fbXBig"><p>Energy threshold for dark image collection</p>
</div></div></div></td></tr><tr class=""><td class="sc-dLMFU sc-eldPxv hZbWKe jXkfaY" kind="field" title="frame_time_us"><span class="sc-gFqAkR eRqgPI"></span><span class="property-name">frame_time_us</span><div class="sc-Nxspf sc-hRJfrW cXxAXt kYVhSL">required</div></td><td class="sc-fPXMVe bAXEAa"><div><div><span class="sc-Nxspf sc-cfxfcM cXxAXt jrGEaR"></span><span class="sc-Nxspf sc-gFAWRd cXxAXt dYzdDr">integer</span><span class="sc-Nxspf sc-gFAWRd cXxAXt dYzdDr"> <!-- -->&lt;<!-- -->int64<!-- -->&gt;<!-- --> </span><span> <span class="sc-Nxspf sc-fxwrCY cXxAXt eMVOei"> <!-- -->[ 500 .. 100000 ]<!-- --> </span></span></div><div><span class="sc-Nxspf cXxAXt"> <!-- -->Default:<!-- --> </span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">10000</span></div> <div><div class="sc-eeDRCY sc-eBMEME gTGgei fbXBig"><p>Time between frames for dark image collection</p>
@@ -908,51 +927,51 @@ This can only be done when detector is <code>Idle</code>, <code>Error</code> or
</div></button></div><div><button class="sc-kzqdkY bXzzUN"><svg class="sc-cwHptR cSkZlF" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">400<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Input parsing or validation error</p>
</div></button></div><div><button class="sc-kzqdkY bXzzUN"><svg class="sc-cwHptR cSkZlF" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">500<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Error within Jungfraujoch code - see output message.</p>
</div></button></div></div></div><div class="sc-iGgWBj sc-gsFSXq ibAZSi eDeKjd"><div class="sc-ejfMa-d bNUPQg"><button class="sc-EgOXT cFEcOl"><span type="put" class="sc-eZYNyq cnqpVw http-verb put">put</span><span class="sc-iEXKAA gUNSDu">/config/dark_mask</span><svg class="sc-cwHptR iVFMLx" style="margin-right:-25px" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></button><div aria-hidden="true" class="sc-dlWCHZ kWacYr"><div class="sc-hHOBiw cndTNO"><div class="sc-eeDRCY sc-eBMEME gTGgei fbXBig"><p>Test Jungfraujoch system</p>
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/config/dark_mask</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Request samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="react-tabs__tab react-tabs__tab--selected" role="tab" id="tab_R_iikq_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_iikq_0" tabindex="0" data-rttab="true">Payload</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_iikq_0" aria-labelledby="tab_R_iikq_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"detector_threshold_keV"</span>: <span class="token number">3.5</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"frame_time_us"</span>: <span class="token number">10000</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"number_of_frames"</span>: <span class="token number">1000</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"max_allowed_pixel_count"</span>: <span class="token number">1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"max_frames_with_signal"</span>: <span class="token number">10</span></div></li></ul><span class="token punctuation">}</span></code></div></div></div></div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-error react-tabs__tab--selected" role="tab" id="tab_R_jikq_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jikq_0" tabindex="0" data-rttab="true">500</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jikq_0" aria-labelledby="tab_R_jikq_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"msg"</span>: <span class="token string">&quot;Detector in wrong state&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"reason"</span>: <span class="token string">&quot;WrongDAQState&quot;</span></div></li></ul><span class="token punctuation">}</span></code></div></div></div></div></div></div></div></div></div></div></div><div id="/paths/~1config~1dark_mask/get" data-section-id="/paths/~1config~1dark_mask/get" class="sc-dcJsrY cqVkUp"><div class="sc-kAyceB hBQWIZ"><div class="sc-fqkvVR oJKYx"><h2 class="sc-jXbUNg fWnwAh"><a class="sc-jlZhew kbdRLs" href="#/paths/~1config~1dark_mask/get" aria-label="/paths/~1config~1dark_mask/get"></a>Get settings for dark data collection to calculate mask<!-- --> </h2><div><h3 class="sc-fMMURN egoxtT">Responses</h3><div><button class="sc-kzqdkY jgSwKD"><svg class="sc-cwHptR hWEnWx" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">200<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Everything OK</p>
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/config/dark_mask</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Request samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="react-tabs__tab react-tabs__tab--selected" role="tab" id="tab_R_iilq_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_iilq_0" tabindex="0" data-rttab="true">Payload</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_iilq_0" aria-labelledby="tab_R_iilq_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"detector_threshold_keV"</span>: <span class="token number">3.5</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"frame_time_us"</span>: <span class="token number">10000</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"number_of_frames"</span>: <span class="token number">1000</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"max_allowed_pixel_count"</span>: <span class="token number">1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"max_frames_with_signal"</span>: <span class="token number">10</span></div></li></ul><span class="token punctuation">}</span></code></div></div></div></div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-error react-tabs__tab--selected" role="tab" id="tab_R_jilq_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jilq_0" tabindex="0" data-rttab="true">500</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jilq_0" aria-labelledby="tab_R_jilq_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"msg"</span>: <span class="token string">&quot;Detector in wrong state&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"reason"</span>: <span class="token string">&quot;WrongDAQState&quot;</span></div></li></ul><span class="token punctuation">}</span></code></div></div></div></div></div></div></div></div></div></div></div><div id="/paths/~1config~1dark_mask/get" data-section-id="/paths/~1config~1dark_mask/get" class="sc-dcJsrY cqVkUp"><div class="sc-kAyceB hBQWIZ"><div class="sc-fqkvVR oJKYx"><h2 class="sc-jXbUNg fWnwAh"><a class="sc-jlZhew kbdRLs" href="#/paths/~1config~1dark_mask/get" aria-label="/paths/~1config~1dark_mask/get"></a>Get settings for dark data collection to calculate mask<!-- --> </h2><div><h3 class="sc-fMMURN egoxtT">Responses</h3><div><button class="sc-kzqdkY jgSwKD"><svg class="sc-cwHptR hWEnWx" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">200<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Everything OK</p>
</div></button></div></div></div><div class="sc-iGgWBj sc-gsFSXq ibAZSi eDeKjd"><div class="sc-ejfMa-d bNUPQg"><button class="sc-EgOXT cFEcOl"><span type="get" class="sc-eZYNyq qGfV http-verb get">get</span><span class="sc-iEXKAA gUNSDu">/config/dark_mask</span><svg class="sc-cwHptR iVFMLx" style="margin-right:-25px" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></button><div aria-hidden="true" class="sc-dlWCHZ kWacYr"><div class="sc-hHOBiw cndTNO"><div class="sc-eeDRCY sc-eBMEME gTGgei fbXBig"><p>Test Jungfraujoch system</p>
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/config/dark_mask</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-success react-tabs__tab--selected" role="tab" id="tab_R_jila_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jila_0" tabindex="0" data-rttab="true">200</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jila_0" aria-labelledby="tab_R_jila_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"detector_threshold_keV"</span>: <span class="token number">3.5</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"frame_time_us"</span>: <span class="token number">10000</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"number_of_frames"</span>: <span class="token number">1000</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"max_allowed_pixel_count"</span>: <span class="token number">1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"max_frames_with_signal"</span>: <span class="token number">10</span></div></li></ul><span class="token punctuation">}</span></code></div></div></div></div></div></div></div></div></div></div></div><div id="/paths/~1status/get" data-section-id="/paths/~1status/get" class="sc-dcJsrY cqVkUp"><div class="sc-kAyceB hBQWIZ"><div class="sc-fqkvVR oJKYx"><h2 class="sc-jXbUNg fWnwAh"><a class="sc-jlZhew kbdRLs" href="#/paths/~1status/get" aria-label="/paths/~1status/get"></a>Get Jungfraujoch status<!-- --> </h2><div class="sc-bVVIoq icSMtY"><div class="sc-eeDRCY sc-eBMEME gTGgei fMmru"><p>Status of the data acquisition</p>
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/config/dark_mask</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-success react-tabs__tab--selected" role="tab" id="tab_R_jima_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jima_0" tabindex="0" data-rttab="true">200</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jima_0" aria-labelledby="tab_R_jima_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"detector_threshold_keV"</span>: <span class="token number">3.5</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"frame_time_us"</span>: <span class="token number">10000</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"number_of_frames"</span>: <span class="token number">1000</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"max_allowed_pixel_count"</span>: <span class="token number">1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"max_frames_with_signal"</span>: <span class="token number">10</span></div></li></ul><span class="token punctuation">}</span></code></div></div></div></div></div></div></div></div></div></div></div><div id="/paths/~1status/get" data-section-id="/paths/~1status/get" class="sc-dcJsrY cqVkUp"><div class="sc-kAyceB hBQWIZ"><div class="sc-fqkvVR oJKYx"><h2 class="sc-jXbUNg fWnwAh"><a class="sc-jlZhew kbdRLs" href="#/paths/~1status/get" aria-label="/paths/~1status/get"></a>Get Jungfraujoch status<!-- --> </h2><div class="sc-bVVIoq icSMtY"><div class="sc-eeDRCY sc-eBMEME gTGgei fMmru"><p>Status of the data acquisition</p>
</div></div><div><h3 class="sc-fMMURN egoxtT">Responses</h3><div><button class="sc-kzqdkY jgSwKD"><svg class="sc-cwHptR hWEnWx" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">200<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Everything OK</p>
</div></button></div></div></div><div class="sc-iGgWBj sc-gsFSXq ibAZSi eDeKjd"><div class="sc-ejfMa-d bNUPQg"><button class="sc-EgOXT cFEcOl"><span type="get" class="sc-eZYNyq qGfV http-verb get">get</span><span class="sc-iEXKAA gUNSDu">/status</span><svg class="sc-cwHptR iVFMLx" style="margin-right:-25px" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></button><div aria-hidden="true" class="sc-dlWCHZ kWacYr"><div class="sc-hHOBiw cndTNO"><div class="sc-eeDRCY sc-eBMEME gTGgei fbXBig"><p>Test Jungfraujoch system</p>
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/status</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-success react-tabs__tab--selected" role="tab" id="tab_R_jilq_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jilq_0" tabindex="0" data-rttab="true">200</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jilq_0" aria-labelledby="tab_R_jilq_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"state"</span>: <span class="token string">&quot;Inactive&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"progress"</span>: <span class="token number">1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"message"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"message_severity"</span>: <span class="token string">&quot;success&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"gpu_count"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"broker_version"</span>: <span class="token string">&quot;1.0.0-rc.128&quot;</span></div></li></ul><span class="token punctuation">}</span></code></div></div></div></div></div></div></div></div></div></div></div><div id="/paths/~1fpga_status/get" data-section-id="/paths/~1fpga_status/get" class="sc-dcJsrY cqVkUp"><div class="sc-kAyceB hBQWIZ"><div class="sc-fqkvVR oJKYx"><h2 class="sc-jXbUNg fWnwAh"><a class="sc-jlZhew kbdRLs" href="#/paths/~1fpga_status/get" aria-label="/paths/~1fpga_status/get"></a>Get status of FPGA devices<!-- --> </h2><div><h3 class="sc-fMMURN egoxtT">Responses</h3><div><button class="sc-kzqdkY jgSwKD"><svg class="sc-cwHptR hWEnWx" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">200<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Everything OK</p>
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/status</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-success react-tabs__tab--selected" role="tab" id="tab_R_jimq_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jimq_0" tabindex="0" data-rttab="true">200</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jimq_0" aria-labelledby="tab_R_jimq_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"state"</span>: <span class="token string">&quot;Inactive&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"progress"</span>: <span class="token number">1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"message"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"message_severity"</span>: <span class="token string">&quot;success&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"gpu_count"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"broker_version"</span>: <span class="token string">&quot;1.0.0-rc.128&quot;</span></div></li></ul><span class="token punctuation">}</span></code></div></div></div></div></div></div></div></div></div></div></div><div id="/paths/~1fpga_status/get" data-section-id="/paths/~1fpga_status/get" class="sc-dcJsrY cqVkUp"><div class="sc-kAyceB hBQWIZ"><div class="sc-fqkvVR oJKYx"><h2 class="sc-jXbUNg fWnwAh"><a class="sc-jlZhew kbdRLs" href="#/paths/~1fpga_status/get" aria-label="/paths/~1fpga_status/get"></a>Get status of FPGA devices<!-- --> </h2><div><h3 class="sc-fMMURN egoxtT">Responses</h3><div><button class="sc-kzqdkY jgSwKD"><svg class="sc-cwHptR hWEnWx" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">200<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Everything OK</p>
</div></button></div></div></div><div class="sc-iGgWBj sc-gsFSXq ibAZSi eDeKjd"><div class="sc-ejfMa-d bNUPQg"><button class="sc-EgOXT cFEcOl"><span type="get" class="sc-eZYNyq qGfV http-verb get">get</span><span class="sc-iEXKAA gUNSDu">/fpga_status</span><svg class="sc-cwHptR iVFMLx" style="margin-right:-25px" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></button><div aria-hidden="true" class="sc-dlWCHZ kWacYr"><div class="sc-hHOBiw cndTNO"><div class="sc-eeDRCY sc-eBMEME gTGgei fbXBig"><p>Test Jungfraujoch system</p>
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/fpga_status</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-success react-tabs__tab--selected" role="tab" id="tab_R_jima_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jima_0" tabindex="0" data-rttab="true">200</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jima_0" aria-labelledby="tab_R_jima_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button><button> Expand all </button><button> Collapse all </button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable "><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable collapsed"><span class="property token string">"pci_dev_id"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"serial_number"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"fw_version"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"base_mac_addr"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"eth_link_count"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"eth_link_status"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"power_usage_W"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"fpga_temp_C"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"hbm_temp_C"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"packets_udp"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"packets_sls"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"idle"</span>: <span class="token boolean">true</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"pcie_link_speed"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"pcie_link_width"</span>: <span class="token number">0</span></div></li></ul><span class="token punctuation">}</span></div></li></ul><span class="token punctuation">]</span></code></div></div></div></div></div></div></div></div></div></div></div><div id="/paths/~1xfel~1pulse_id/get" data-section-id="/paths/~1xfel~1pulse_id/get" class="sc-dcJsrY cqVkUp"><div class="sc-kAyceB hBQWIZ"><div class="sc-fqkvVR oJKYx"><h2 class="sc-jXbUNg fWnwAh"><a class="sc-jlZhew kbdRLs" href="#/paths/~1xfel~1pulse_id/get" aria-label="/paths/~1xfel~1pulse_id/get"></a>Return XFEL pulse IDs for the current data acquisition<!-- --> </h2><div class="sc-bVVIoq icSMtY"><div class="sc-eeDRCY sc-eBMEME gTGgei fMmru"><p>Return array of XFEL pulse IDs - (-1) if image not recorded</p>
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/fpga_status</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-success react-tabs__tab--selected" role="tab" id="tab_R_jina_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jina_0" tabindex="0" data-rttab="true">200</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jina_0" aria-labelledby="tab_R_jina_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button><button> Expand all </button><button> Collapse all </button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable "><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable collapsed"><span class="property token string">"pci_dev_id"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"serial_number"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"fw_version"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"base_mac_addr"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"eth_link_count"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"eth_link_status"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"power_usage_W"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"fpga_temp_C"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"hbm_temp_C"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"packets_udp"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"packets_sls"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"idle"</span>: <span class="token boolean">true</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"pcie_link_speed"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"pcie_link_width"</span>: <span class="token number">0</span></div></li></ul><span class="token punctuation">}</span></div></li></ul><span class="token punctuation">]</span></code></div></div></div></div></div></div></div></div></div></div></div><div id="/paths/~1xfel~1pulse_id/get" data-section-id="/paths/~1xfel~1pulse_id/get" class="sc-dcJsrY cqVkUp"><div class="sc-kAyceB hBQWIZ"><div class="sc-fqkvVR oJKYx"><h2 class="sc-jXbUNg fWnwAh"><a class="sc-jlZhew kbdRLs" href="#/paths/~1xfel~1pulse_id/get" aria-label="/paths/~1xfel~1pulse_id/get"></a>Return XFEL pulse IDs for the current data acquisition<!-- --> </h2><div class="sc-bVVIoq icSMtY"><div class="sc-eeDRCY sc-eBMEME gTGgei fMmru"><p>Return array of XFEL pulse IDs - (-1) if image not recorded</p>
</div></div><div><h3 class="sc-fMMURN egoxtT">Responses</h3><div><button class="sc-kzqdkY jgSwKD"><svg class="sc-cwHptR hWEnWx" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">200<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Pulse ID collected</p>
</div></button></div><div><button class="sc-kzqdkY gnmLmb" disabled=""><strong class="sc-dSIIpw bpEYcE">404<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Not in XFEL mode or no acquisition recorded</p>
</div></button></div></div></div><div class="sc-iGgWBj sc-gsFSXq ibAZSi eDeKjd"><div class="sc-ejfMa-d bNUPQg"><button class="sc-EgOXT cFEcOl"><span type="get" class="sc-eZYNyq qGfV http-verb get">get</span><span class="sc-iEXKAA gUNSDu">/xfel/pulse_id</span><svg class="sc-cwHptR iVFMLx" style="margin-right:-25px" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></button><div aria-hidden="true" class="sc-dlWCHZ kWacYr"><div class="sc-hHOBiw cndTNO"><div class="sc-eeDRCY sc-eBMEME gTGgei fbXBig"><p>Test Jungfraujoch system</p>
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/xfel/pulse_id</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-success react-tabs__tab--selected" role="tab" id="tab_R_jimq_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jimq_0" tabindex="0" data-rttab="true">200</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jimq_0" aria-labelledby="tab_R_jimq_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable "><span class="token number">0</span></div></li></ul><span class="token punctuation">]</span></code></div></div></div></div></div></div></div></div></div></div></div><div id="/paths/~1xfel~1event_code/get" data-section-id="/paths/~1xfel~1event_code/get" class="sc-dcJsrY cqVkUp"><div class="sc-kAyceB hBQWIZ"><div class="sc-fqkvVR oJKYx"><h2 class="sc-jXbUNg fWnwAh"><a class="sc-jlZhew kbdRLs" href="#/paths/~1xfel~1event_code/get" aria-label="/paths/~1xfel~1event_code/get"></a>Return XFEL event codes for the current data acquisition<!-- --> </h2><div class="sc-bVVIoq icSMtY"><div class="sc-eeDRCY sc-eBMEME gTGgei fMmru"><p>Return array of XFEL event codes</p>
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/xfel/pulse_id</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-success react-tabs__tab--selected" role="tab" id="tab_R_jinq_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jinq_0" tabindex="0" data-rttab="true">200</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jinq_0" aria-labelledby="tab_R_jinq_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable "><span class="token number">0</span></div></li></ul><span class="token punctuation">]</span></code></div></div></div></div></div></div></div></div></div></div></div><div id="/paths/~1xfel~1event_code/get" data-section-id="/paths/~1xfel~1event_code/get" class="sc-dcJsrY cqVkUp"><div class="sc-kAyceB hBQWIZ"><div class="sc-fqkvVR oJKYx"><h2 class="sc-jXbUNg fWnwAh"><a class="sc-jlZhew kbdRLs" href="#/paths/~1xfel~1event_code/get" aria-label="/paths/~1xfel~1event_code/get"></a>Return XFEL event codes for the current data acquisition<!-- --> </h2><div class="sc-bVVIoq icSMtY"><div class="sc-eeDRCY sc-eBMEME gTGgei fMmru"><p>Return array of XFEL event codes</p>
</div></div><div><h3 class="sc-fMMURN egoxtT">Responses</h3><div><button class="sc-kzqdkY jgSwKD"><svg class="sc-cwHptR hWEnWx" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">200<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Event codes collected</p>
</div></button></div><div><button class="sc-kzqdkY gnmLmb" disabled=""><strong class="sc-dSIIpw bpEYcE">404<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Not in XFEL mode or no acquisition recorded</p>
</div></button></div></div></div><div class="sc-iGgWBj sc-gsFSXq ibAZSi eDeKjd"><div class="sc-ejfMa-d bNUPQg"><button class="sc-EgOXT cFEcOl"><span type="get" class="sc-eZYNyq qGfV http-verb get">get</span><span class="sc-iEXKAA gUNSDu">/xfel/event_code</span><svg class="sc-cwHptR iVFMLx" style="margin-right:-25px" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></button><div aria-hidden="true" class="sc-dlWCHZ kWacYr"><div class="sc-hHOBiw cndTNO"><div class="sc-eeDRCY sc-eBMEME gTGgei fbXBig"><p>Test Jungfraujoch system</p>
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/xfel/event_code</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-success react-tabs__tab--selected" role="tab" id="tab_R_jina_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jina_0" tabindex="0" data-rttab="true">200</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jina_0" aria-labelledby="tab_R_jina_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable "><span class="token number">0</span></div></li></ul><span class="token punctuation">]</span></code></div></div></div></div></div></div></div></div></div></div></div><div id="/paths/~1image_pusher~1status/get" data-section-id="/paths/~1image_pusher~1status/get" class="sc-dcJsrY cqVkUp"><div class="sc-kAyceB hBQWIZ"><div class="sc-fqkvVR oJKYx"><h2 class="sc-jXbUNg fWnwAh"><a class="sc-jlZhew kbdRLs" href="#/paths/~1image_pusher~1status/get" aria-label="/paths/~1image_pusher~1status/get"></a>Get status of image pusher<!-- --> </h2><div><h3 class="sc-fMMURN egoxtT">Responses</h3><div><button class="sc-kzqdkY jgSwKD"><svg class="sc-cwHptR hWEnWx" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">200<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Everything OK</p>
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/xfel/event_code</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-success react-tabs__tab--selected" role="tab" id="tab_R_jioa_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jioa_0" tabindex="0" data-rttab="true">200</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jioa_0" aria-labelledby="tab_R_jioa_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable "><span class="token number">0</span></div></li></ul><span class="token punctuation">]</span></code></div></div></div></div></div></div></div></div></div></div></div><div id="/paths/~1image_pusher~1status/get" data-section-id="/paths/~1image_pusher~1status/get" class="sc-dcJsrY cqVkUp"><div class="sc-kAyceB hBQWIZ"><div class="sc-fqkvVR oJKYx"><h2 class="sc-jXbUNg fWnwAh"><a class="sc-jlZhew kbdRLs" href="#/paths/~1image_pusher~1status/get" aria-label="/paths/~1image_pusher~1status/get"></a>Get status of image pusher<!-- --> </h2><div><h3 class="sc-fMMURN egoxtT">Responses</h3><div><button class="sc-kzqdkY jgSwKD"><svg class="sc-cwHptR hWEnWx" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">200<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Everything OK</p>
</div></button></div><div><button class="sc-kzqdkY bXzzUN"><svg class="sc-cwHptR cSkZlF" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">500<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Error encountered when trying to read status</p>
</div></button></div></div></div><div class="sc-iGgWBj sc-gsFSXq ibAZSi eDeKjd"><div class="sc-ejfMa-d bNUPQg"><button class="sc-EgOXT cFEcOl"><span type="get" class="sc-eZYNyq qGfV http-verb get">get</span><span class="sc-iEXKAA gUNSDu">/image_pusher/status</span><svg class="sc-cwHptR iVFMLx" style="margin-right:-25px" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></button><div aria-hidden="true" class="sc-dlWCHZ kWacYr"><div class="sc-hHOBiw cndTNO"><div class="sc-eeDRCY sc-eBMEME gTGgei fbXBig"><p>Test Jungfraujoch system</p>
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/image_pusher/status</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-success react-tabs__tab--selected" role="tab" id="tab_R_jinq_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jinq_0" tabindex="0" data-rttab="true">200</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jinq_0" aria-labelledby="tab_R_jinq_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button><button> Expand all </button><button> Collapse all </button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"pusher_type"</span>: <span class="token string">&quot;ZeroMQ&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"addr"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable collapsed"><span class="token string">&quot;tcp://1.2.3.4:5000&quot;</span>,</div></li><li><div class="hoverable collapsed"><span class="token string">&quot;tcp://1.2.3.4:5001&quot;</span></div></li></ul><span class="token punctuation">]</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"connected_writers"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"images_written"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"images_write_error"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"writer_fifo_utilization"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable collapsed"><span class="token number">0</span></div></li></ul><span class="token punctuation">]</span></div></li></ul><span class="token punctuation">}</span></code></div></div></div></div></div></div></div></div></div></div></div><div id="/paths/~1detector~1status/get" data-section-id="/paths/~1detector~1status/get" class="sc-dcJsrY cqVkUp"><div class="sc-kAyceB hBQWIZ"><div class="sc-fqkvVR oJKYx"><h2 class="sc-jXbUNg fWnwAh"><a class="sc-jlZhew kbdRLs" href="#/paths/~1detector~1status/get" aria-label="/paths/~1detector~1status/get"></a>Get detector status<!-- --> </h2><div class="sc-bVVIoq icSMtY"><div class="sc-eeDRCY sc-eBMEME gTGgei fMmru"><p>Status of the JUNGFRAU detector</p>
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/image_pusher/status</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-success react-tabs__tab--selected" role="tab" id="tab_R_jioq_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jioq_0" tabindex="0" data-rttab="true">200</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jioq_0" aria-labelledby="tab_R_jioq_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button><button> Expand all </button><button> Collapse all </button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"pusher_type"</span>: <span class="token string">&quot;ZeroMQ&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"addr"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable collapsed"><span class="token string">&quot;tcp://1.2.3.4:5000&quot;</span>,</div></li><li><div class="hoverable collapsed"><span class="token string">&quot;tcp://1.2.3.4:5001&quot;</span></div></li></ul><span class="token punctuation">]</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"connected_writers"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"images_written"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"images_write_error"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"writer_fifo_utilization"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable collapsed"><span class="token number">0</span></div></li></ul><span class="token punctuation">]</span></div></li></ul><span class="token punctuation">}</span></code></div></div></div></div></div></div></div></div></div></div></div><div id="/paths/~1detector~1status/get" data-section-id="/paths/~1detector~1status/get" class="sc-dcJsrY cqVkUp"><div class="sc-kAyceB hBQWIZ"><div class="sc-fqkvVR oJKYx"><h2 class="sc-jXbUNg fWnwAh"><a class="sc-jlZhew kbdRLs" href="#/paths/~1detector~1status/get" aria-label="/paths/~1detector~1status/get"></a>Get detector status<!-- --> </h2><div class="sc-bVVIoq icSMtY"><div class="sc-eeDRCY sc-eBMEME gTGgei fMmru"><p>Status of the JUNGFRAU detector</p>
</div></div><div><h3 class="sc-fMMURN egoxtT">Responses</h3><div><button class="sc-kzqdkY jgSwKD"><svg class="sc-cwHptR hWEnWx" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">200<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Everything OK</p>
</div></button></div><div><button class="sc-kzqdkY gnmLmb" disabled=""><strong class="sc-dSIIpw bpEYcE">404<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Running in &quot;simulator&quot; mode - no detector present</p>
</div></button></div><div><button class="sc-kzqdkY bXzzUN"><svg class="sc-cwHptR cSkZlF" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">500<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Error encountered when trying to read status</p>
</div></button></div></div></div><div class="sc-iGgWBj sc-gsFSXq ibAZSi eDeKjd"><div class="sc-ejfMa-d bNUPQg"><button class="sc-EgOXT cFEcOl"><span type="get" class="sc-eZYNyq qGfV http-verb get">get</span><span class="sc-iEXKAA gUNSDu">/detector/status</span><svg class="sc-cwHptR iVFMLx" style="margin-right:-25px" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></button><div aria-hidden="true" class="sc-dlWCHZ kWacYr"><div class="sc-hHOBiw cndTNO"><div class="sc-eeDRCY sc-eBMEME gTGgei fbXBig"><p>Test Jungfraujoch system</p>
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/detector/status</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-success react-tabs__tab--selected" role="tab" id="tab_R_jioa_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jioa_0" tabindex="0" data-rttab="true">200</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jioa_0" aria-labelledby="tab_R_jioa_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button><button> Expand all </button><button> Collapse all </button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"state"</span>: <span class="token string">&quot;Idle&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"powerchip"</span>: <span class="token string">&quot;PowerOn&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"server_version"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"number_of_triggers_left"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"fpga_temp_degC"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable collapsed"><span class="token number">0</span></div></li></ul><span class="token punctuation">]</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"high_voltage_V"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable collapsed"><span class="token number">0</span></div></li></ul><span class="token punctuation">]</span></div></li></ul><span class="token punctuation">}</span></code></div></div></div></div></div></div></div></div></div></div></div><div id="/paths/~1config~1roi/get" data-section-id="/paths/~1config~1roi/get" class="sc-dcJsrY cqVkUp"><div class="sc-kAyceB hBQWIZ"><div class="sc-fqkvVR oJKYx"><h2 class="sc-jXbUNg fWnwAh"><a class="sc-jlZhew kbdRLs" href="#/paths/~1config~1roi/get" aria-label="/paths/~1config~1roi/get"></a>Get ROI definitions<!-- --> </h2><div><h3 class="sc-fMMURN egoxtT">Responses</h3><div><button class="sc-kzqdkY jgSwKD"><svg class="sc-cwHptR hWEnWx" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">200<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>OK</p>
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/detector/status</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-success react-tabs__tab--selected" role="tab" id="tab_R_jipa_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jipa_0" tabindex="0" data-rttab="true">200</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jipa_0" aria-labelledby="tab_R_jipa_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button><button> Expand all </button><button> Collapse all </button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"state"</span>: <span class="token string">&quot;Idle&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"powerchip"</span>: <span class="token string">&quot;PowerOn&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"server_version"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"number_of_triggers_left"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"fpga_temp_degC"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable collapsed"><span class="token number">0</span></div></li></ul><span class="token punctuation">]</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"high_voltage_V"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable collapsed"><span class="token number">0</span></div></li></ul><span class="token punctuation">]</span></div></li></ul><span class="token punctuation">}</span></code></div></div></div></div></div></div></div></div></div></div></div><div id="/paths/~1config~1roi/get" data-section-id="/paths/~1config~1roi/get" class="sc-dcJsrY cqVkUp"><div class="sc-kAyceB hBQWIZ"><div class="sc-fqkvVR oJKYx"><h2 class="sc-jXbUNg fWnwAh"><a class="sc-jlZhew kbdRLs" href="#/paths/~1config~1roi/get" aria-label="/paths/~1config~1roi/get"></a>Get ROI definitions<!-- --> </h2><div><h3 class="sc-fMMURN egoxtT">Responses</h3><div><button class="sc-kzqdkY jgSwKD"><svg class="sc-cwHptR hWEnWx" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">200<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>OK</p>
</div></button></div></div></div><div class="sc-iGgWBj sc-gsFSXq ibAZSi eDeKjd"><div class="sc-ejfMa-d bNUPQg"><button class="sc-EgOXT cFEcOl"><span type="get" class="sc-eZYNyq qGfV http-verb get">get</span><span class="sc-iEXKAA gUNSDu">/config/roi</span><svg class="sc-cwHptR iVFMLx" style="margin-right:-25px" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></button><div aria-hidden="true" class="sc-dlWCHZ kWacYr"><div class="sc-hHOBiw cndTNO"><div class="sc-eeDRCY sc-eBMEME gTGgei fbXBig"><p>Test Jungfraujoch system</p>
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/config/roi</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-success react-tabs__tab--selected" role="tab" id="tab_R_jioq_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jioq_0" tabindex="0" data-rttab="true">200</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jioq_0" aria-labelledby="tab_R_jioq_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button><button> Expand all </button><button> Collapse all </button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"box"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable collapsed"><span class="property token string">"rois"</span>: <button class="collapser" aria-label="expand"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable collapsed"><button class="collapser" aria-label="expand"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable collapsed"><span class="property token string">"name"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"min_x_pxl"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"max_x_pxl"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"min_y_pxl"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"max_y_pxl"</span>: <span class="token number">0</span></div></li></ul><span class="token punctuation">}</span></div></li></ul><span class="token punctuation">]</span></div></li></ul><span class="token punctuation">}</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"circle"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable collapsed"><span class="property token string">"rois"</span>: <button class="collapser" aria-label="expand"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable collapsed"><button class="collapser" aria-label="expand"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable collapsed"><span class="property token string">"name"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"center_x_pxl"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"center_y_pxl"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"radius_pxl"</span>: <span class="token number">0.1</span></div></li></ul><span class="token punctuation">}</span></div></li></ul><span class="token punctuation">]</span></div></li></ul><span class="token punctuation">}</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"azim"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable collapsed"><span class="property token string">"rois"</span>: <button class="collapser" aria-label="expand"></button><span class="token punctuation">[</span><span class="ellipsisLine truncated
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/config/roi</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-success react-tabs__tab--selected" role="tab" id="tab_R_jipq_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jipq_0" tabindex="0" data-rttab="true">200</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jipq_0" aria-labelledby="tab_R_jipq_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button><button> Expand all </button><button> Collapse all </button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"box"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable collapsed"><span class="property token string">"rois"</span>: <button class="collapser" aria-label="expand"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable collapsed"><button class="collapser" aria-label="expand"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable collapsed"><span class="property token string">"name"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"min_x_pxl"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"max_x_pxl"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"min_y_pxl"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"max_y_pxl"</span>: <span class="token number">0</span></div></li></ul><span class="token punctuation">}</span></div></li></ul><span class="token punctuation">]</span></div></li></ul><span class="token punctuation">}</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"circle"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable collapsed"><span class="property token string">"rois"</span>: <button class="collapser" aria-label="expand"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable collapsed"><button class="collapser" aria-label="expand"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable collapsed"><span class="property token string">"name"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"center_x_pxl"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"center_y_pxl"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"radius_pxl"</span>: <span class="token number">0.1</span></div></li></ul><span class="token punctuation">}</span></div></li></ul><span class="token punctuation">]</span></div></li></ul><span class="token punctuation">}</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"azim"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable collapsed"><span class="property token string">"rois"</span>: <button class="collapser" aria-label="expand"></button><span class="token punctuation">[</span><span class="ellipsisLine truncated
</div></div></div></td></tr><tr class=""><td class="sc-dLMFU sc-eldPxv sc-hCPjZK hZbWKe jXkfaY GCgeS" kind="field" title="circle"><span class="sc-gFqAkR eRqgPI"></span><button aria-label="expand circle"><span class="property-name">circle</span><svg class="sc-cwHptR ivsSRP" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></button><div class="sc-Nxspf sc-hRJfrW cXxAXt kYVhSL">required</div></td><td class="sc-fPXMVe bAXEAa"><div><div><span class="sc-Nxspf sc-cfxfcM cXxAXt jrGEaR"></span><span class="sc-Nxspf sc-gFAWRd cXxAXt dYzdDr">object</span><span class="sc-Nxspf sc-gmPhUn cXxAXt hjnRRA"> (<!-- -->roi_circle_list<!-- -->) </span></div> <div><div class="sc-eeDRCY sc-eBMEME gTGgei fbXBig"><p>List of circular ROIs</p>
</div></div></div></td></tr><tr class="last "><td class="sc-dLMFU sc-eldPxv sc-hCPjZK hZbWKe jXkfaY GCgeS" kind="field" title="azim"><span class="sc-gFqAkR eRqgPI"></span><button aria-label="expand azim"><span class="property-name">azim</span><svg class="sc-cwHptR ivsSRP" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></button><div class="sc-Nxspf sc-hRJfrW cXxAXt kYVhSL">required</div></td><td class="sc-fPXMVe bAXEAa"><div><div><span class="sc-Nxspf sc-cfxfcM cXxAXt jrGEaR"></span><span class="sc-Nxspf sc-gFAWRd cXxAXt dYzdDr">object</span><span class="sc-Nxspf sc-gmPhUn cXxAXt hjnRRA"> (<!-- -->roi_azim_list<!-- -->) </span></div> <div><div class="sc-eeDRCY sc-eBMEME gTGgei fbXBig"><p>List of azimuthal ROIs</p>
</div></div></div></td></tr></tbody></table><div><h3 class="sc-fMMURN egoxtT">Responses</h3><div><button class="sc-kzqdkY jkjMMR" disabled=""><strong class="sc-dSIIpw bpEYcE">200<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Everything OK</p>
</div></button></div><div><button class="sc-kzqdkY bXzzUN"><svg class="sc-cwHptR cSkZlF" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">400<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Input parsing or validation error</p>
</div></button></div><div><button class="sc-kzqdkY bXzzUN"><svg class="sc-cwHptR cSkZlF" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">500<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Error within Jungfraujoch code - see output message.</p>
</div></button></div></div></div><div class="sc-iGgWBj sc-gsFSXq ibAZSi eDeKjd"><div class="sc-ejfMa-d bNUPQg"><button class="sc-EgOXT cFEcOl"><span type="put" class="sc-eZYNyq cnqpVw http-verb put">put</span><span class="sc-iEXKAA gUNSDu">/config/roi</span><svg class="sc-cwHptR iVFMLx" style="margin-right:-25px" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></button><div aria-hidden="true" class="sc-dlWCHZ kWacYr"><div class="sc-hHOBiw cndTNO"><div class="sc-eeDRCY sc-eBMEME gTGgei fbXBig"><p>Test Jungfraujoch system</p>
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/config/roi</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Request samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="react-tabs__tab react-tabs__tab--selected" role="tab" id="tab_R_iipa_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_iipa_0" tabindex="0" data-rttab="true">Payload</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_iipa_0" aria-labelledby="tab_R_iipa_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button><button> Expand all </button><button> Collapse all </button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"box"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable collapsed"><span class="property token string">"rois"</span>: <button class="collapser" aria-label="expand"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable collapsed"><button class="collapser" aria-label="expand"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable collapsed"><span class="property token string">"name"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"min_x_pxl"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"max_x_pxl"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"min_y_pxl"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"max_y_pxl"</span>: <span class="token number">0</span></div></li></ul><span class="token punctuation">}</span></div></li></ul><span class="token punctuation">]</span></div></li></ul><span class="token punctuation">}</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"circle"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable collapsed"><span class="property token string">"rois"</span>: <button class="collapser" aria-label="expand"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable collapsed"><button class="collapser" aria-label="expand"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable collapsed"><span class="property token string">"name"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"center_x_pxl"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"center_y_pxl"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"radius_pxl"</span>: <span class="token number">0.1</span></div></li></ul><span class="token punctuation">}</span></div></li></ul><span class="token punctuation">]</span></div></li></ul><span class="token punctuation">}</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"azim"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable collapsed"><span class="property token string">"rois"</span>: <button class="collapser" aria-label="expand"></button><span class="token punctuation">[</span><span class="eLine truncated
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/config/roi</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Request samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="react-tabs__tab react-tabs__tab--selected" role="tab" id="tab_R_iiqa_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_iiqa_0" tabindex="0" data-rttab="true">Payload</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_iiqa_0" aria-labelledby="tab_R_iiqa_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button><button> Expand all </button><button> Collapse all </button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"box"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable collapsed"><span class="property token string">"rois"</span>: <button class="collapser" aria-label="expand"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable collapsed"><button class="collapser" aria-label="expand"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable collapsed"><span class="property token string">"name"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"min_x_pxl"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"max_x_pxl"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"min_y_pxl"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"max_y_pxl"</span>: <span class="token number">0</span></div></li></ul><span class="token punctuation">}</span></div></li></ul><span class="token punctuation">]</span></div></li></ul><span class="token punctuation">}</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"circle"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable collapsed"><span class="property token string">"rois"</span>: <button class="collapser" aria-label="expand"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable collapsed"><button class="collapser" aria-label="expand"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable collapsed"><span class="property token string">"name"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"center_x_pxl"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"center_y_pxl"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"radius_pxl"</span>: <span class="token number">0.1</span></div></li></ul><span class="token punctuation">}</span></div></li></ul><span class="token punctuation">]</span></div></li></ul><span class="token punctuation">}</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"azim"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable collapsed"><span class="property token string">"rois"</span>: <button class="collapser" aria-label="expand"></button><span class="token punctuation">[</span><span class="eLine truncated
dataset (see <code>tokens</code> in <code>/start</code>).</p>
</div></div><div><h3 class="sc-fMMURN egoxtT">Responses</h3><div><button class="sc-kzqdkY jgSwKD"><svg class="sc-cwHptR hWEnWx" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">200<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Everything OK</p>
</div></button></div></div></div><div class="sc-iGgWBj sc-gsFSXq ibAZSi eDeKjd"><div class="sc-ejfMa-d bNUPQg"><button class="sc-EgOXT cFEcOl"><span type="get" class="sc-eZYNyq qGfV http-verb get">get</span><span class="sc-iEXKAA gUNSDu">/statistics</span><svg class="sc-cwHptR iVFMLx" style="margin-right:-25px" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></button><div aria-hidden="true" class="sc-dlWCHZ kWacYr"><div class="sc-hHOBiw cndTNO"><div class="sc-eeDRCY sc-eBMEME gTGgei fbXBig"><p>Test Jungfraujoch system</p>
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/statistics</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-success react-tabs__tab--selected" role="tab" id="tab_R_jipq_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jipq_0" tabindex="0" data-rttab="true">200</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jipq_0" aria-labelledby="tab_R_jipq_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button><button> Expand all </button><button> Collapse all </button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"detector"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable collapsed"><span class="property token string">"state"</span>: <span class="token string">&quot;Idle&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"powerchip"</span>: <span class="token string">&quot;PowerOn&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"server_version"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"number_of_triggers_left"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"fpga_temp_degC"</span>: <button class="collapser" aria-label="expand"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable collapsed"><span class="token number">0</span></div></li></ul><span class="token punctuation">]</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"high_voltage_V"</span>: <button class="collapser" aria-label="expand"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable collapsed"><span class="token number">0</span></div></li></ul><span class="token punctuation">]</span></div></li></ul><span class="token punctuation">}</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"detector_list"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable collapsed"><span class="property token string">"detectors"</span>: <button class="collapser" aria-label="expand"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable collapsed"><button class="collapser" aria-label="expand"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable collapsed"><span class="property token string">"id"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"description"</span>: <span class="token string">&quot;JUNGFRAU 4 Mpixel&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"serial_number"</span>: <span class="token string">&quot;JF17T16V01&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"base_ipv4_addr"</span>: <span class="token string">&quot;10.10.10.1&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"udp_interface_count"</span>: <span class="token number">2</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"nmodules"</span>: <span class="token number">18</span><span class="token punctuationLine truncated
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/statistics</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-success react-tabs__tab--selected" role="tab" id="tab_R_jiqq_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jiqq_0" tabindex="0" data-rttab="true">200</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jiqq_0" aria-labelledby="tab_R_jiqq_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button><button> Expand all </button><button> Collapse all </button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"detector"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable collapsed"><span class="property token string">"state"</span>: <span class="token string">&quot;Idle&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"powerchip"</span>: <span class="token string">&quot;PowerOn&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"server_version"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"number_of_triggers_left"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"fpga_temp_degC"</span>: <button class="collapser" aria-label="expand"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable collapsed"><span class="token number">0</span></div></li></ul><span class="token punctuation">]</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"high_voltage_V"</span>: <button class="collapser" aria-label="expand"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable collapsed"><span class="token number">0</span></div></li></ul><span class="token punctuation">]</span></div></li></ul><span class="token punctuation">}</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"detector_list"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable collapsed"><span class="property token string">"detectors"</span>: <button class="collapser" aria-label="expand"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable collapsed"><button class="collapser" aria-label="expand"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable collapsed"><span class="property token string">"id"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"description"</span>: <span class="token string">&quot;JUNGFRAU 4 Mpixel&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"serial_number"</span>: <span class="token string">&quot;JF17T16V01&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"base_ipv4_addr"</span>: <span class="token string">&quot;10.10.10.1&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"udp_interface_count"</span>: <span class="token number">2</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"nmodules"</span>: <span class="token number">18</span><span class="token punctuationLine truncated
</div></div><div class="sc-jaXxmE eqYzvz"><div class="sc-iMTnTL fkPTul"><h5 class="sc-dAlyuH sc-hwdzOV jbQuod JjoyL">Authorizations:</h5><svg class="sc-cwHptR iZRiKW" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></div><div class="sc-krNlru gkwgxc"><span class="sc-jMakVo bPNrjo"><span class="sc-ihgnxF jlNGfN"><i>bearerAuth</i></span></span></div></div><div><h3 class="sc-fMMURN egoxtT">Responses</h3><div><button class="sc-kzqdkY jgSwKD"><svg class="sc-cwHptR hWEnWx" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">200<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Everything OK</p>
</div></button></div><div><button class="sc-kzqdkY bXzzUN"><svg class="sc-cwHptR cSkZlF" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">401<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>The current dataset is protected and no valid bearer token was presented.</p>
</div></button></div><div><button class="sc-kzqdkY gnmLmb" disabled=""><strong class="sc-dSIIpw bpEYcE">404<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>No data collection performed so far</p>
</div></button></div></div></div><div class="sc-iGgWBj sc-gsFSXq ibAZSi eDeKjd"><div class="sc-ejfMa-d bNUPQg"><button class="sc-EgOXT cFEcOl"><span type="get" class="sc-eZYNyq qGfV http-verb get">get</span><span class="sc-iEXKAA gUNSDu">/statistics/data_collection</span><svg class="sc-cwHptR iVFMLx" style="margin-right:-25px" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></button><div aria-hidden="true" class="sc-dlWCHZ kWacYr"><div class="sc-hHOBiw cndTNO"><div class="sc-eeDRCY sc-eBMEME gTGgei fbXBig"><p>Test Jungfraujoch system</p>
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/statistics/data_collection</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-success react-tabs__tab--selected" role="tab" id="tab_R_jiqa_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jiqa_0" tabindex="0" data-rttab="true">200</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jiqa_0" aria-labelledby="tab_R_jiqa_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"file_prefix"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"run_number"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"experiment_group"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"images_expected"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"images_collected"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"images_sent"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"images_written"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"images_discarded_lossy_compression"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"max_image_number_sent"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"collection_efficiency"</span>: <span class="token number">1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"compression_ratio"</span>: <span class="token number">5.3</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"cancelled"</span>: <span class="token boolean">true</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"max_receiver_delay"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"indexing_rate"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"detector_width"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"detector_height"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"detector_pixel_depth"</span>: <span class="token number">2</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"bkg_estimate"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"unit_cell"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"error_pixels"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"saturated_pixels"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><spLine truncated
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/statistics/data_collection</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-success react-tabs__tab--selected" role="tab" id="tab_R_jira_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jira_0" tabindex="0" data-rttab="true">200</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jira_0" aria-labelledby="tab_R_jira_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"file_prefix"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"run_number"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"experiment_group"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"images_expected"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"images_collected"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"images_sent"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"images_written"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"images_discarded_lossy_compression"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"max_image_number_sent"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"collection_efficiency"</span>: <span class="token number">1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"compression_ratio"</span>: <span class="token number">5.3</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"cancelled"</span>: <span class="token boolean">true</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"max_receiver_delay"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"indexing_rate"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"detector_width"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"detector_height"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"detector_pixel_depth"</span>: <span class="token number">2</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"bkg_estimate"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"unit_cell"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"error_pixels"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"saturated_pixels"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><spLine truncated
</div></div><div><h3 class="sc-fMMURN egoxtT">Responses</h3><div><button class="sc-kzqdkY jgSwKD"><svg class="sc-cwHptR hWEnWx" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">200<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Everything OK</p>
</div></button></div></div></div><div class="sc-iGgWBj sc-gsFSXq ibAZSi eDeKjd"><div class="sc-ejfMa-d bNUPQg"><button class="sc-EgOXT cFEcOl"><span type="get" class="sc-eZYNyq qGfV http-verb get">get</span><span class="sc-iEXKAA gUNSDu">/statistics/calibration</span><svg class="sc-cwHptR iVFMLx" style="margin-right:-25px" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></button><div aria-hidden="true" class="sc-dlWCHZ kWacYr"><div class="sc-hHOBiw cndTNO"><div class="sc-eeDRCY sc-eBMEME gTGgei fbXBig"><p>Test Jungfraujoch system</p>
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/statistics/calibration</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-success react-tabs__tab--selected" role="tab" id="tab_R_jiqq_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jiqq_0" tabindex="0" data-rttab="true">200</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jiqq_0" aria-labelledby="tab_R_jiqq_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button><button> Expand all </button><button> Collapse all </button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable "><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable collapsed"><span class="property token string">"module_number"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"storage_cell_number"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"pedestal_g0_mean"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"pedestal_g1_mean"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"pedestal_g2_mean"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"gain_g0_mean"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"gain_g1_mean"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"gain_g2_mean"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"masked_pixels"</span>: <span class="token number">0</span></div></li></ul><span class="token punctuation">}</span></div></li></ul><span class="token punctuation">]</span></code></div></div></div></div></div></div></div></div></div></div></div><div id="/paths/~1config~1mask/get" data-section-id="/paths/~1config~1mask/get" class="sc-dcJsrY cqVkUp"><div class="sc-kAyceB hBQWIZ"><div class="sc-fqkvVR oJKYx"><h2 class="sc-jXbUNg fWnwAh"><a class="sc-jlZhew kbdRLs" href="#/paths/~1config~1mask/get" aria-label="/paths/~1config~1mask/get"></a>Get mask of the detector (binary)<!-- --> </h2><div class="sc-bVVIoq icSMtY"><div class="sc-eeDRCY sc-eBMEME gTGgei fMmru"><p>Detector must be Initialized.
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/statistics/calibration</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-success react-tabs__tab--selected" role="tab" id="tab_R_jirq_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jirq_0" tabindex="0" data-rttab="true">200</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jirq_0" aria-labelledby="tab_R_jirq_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button><button> Expand all </button><button> Collapse all </button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable "><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable collapsed"><span class="property token string">"module_number"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"storage_cell_number"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"pedestal_g0_mean"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"pedestal_g1_mean"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"pedestal_g2_mean"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"gain_g0_mean"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"gain_g1_mean"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"gain_g2_mean"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"masked_pixels"</span>: <span class="token number">0</span></div></li></ul><span class="token punctuation">}</span></div></li></ul><span class="token punctuation">]</span></code></div></div></div></div></div></div></div></div></div></div></div><div id="/paths/~1config~1mask/get" data-section-id="/paths/~1config~1mask/get" class="sc-dcJsrY cqVkUp"><div class="sc-kAyceB hBQWIZ"><div class="sc-fqkvVR oJKYx"><h2 class="sc-jXbUNg fWnwAh"><a class="sc-jlZhew kbdRLs" href="#/paths/~1config~1mask/get" aria-label="/paths/~1config~1mask/get"></a>Get mask of the detector (binary)<!-- --> </h2><div class="sc-bVVIoq icSMtY"><div class="sc-eeDRCY sc-eBMEME gTGgei fMmru"><p>Detector must be Initialized.
Get full pixel mask of the detector.
See NXmx standard for meaning of pixel values.</p>
</div></div><div><h3 class="sc-fMMURN egoxtT">Responses</h3><div><button class="sc-kzqdkY jgSwKD"><svg class="sc-cwHptR hWEnWx" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">200<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Binary array (4 byte; unsigned)</p>
@@ -973,7 +992,7 @@ User mask is stored in NXmx pixel mask (bit 8), as well as used in spot finding
</div></button></div><div><button class="sc-kzqdkY gnmLmb" disabled=""><strong class="sc-dSIIpw bpEYcE">400<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Mask is not 4-byte unsigned integer array or empty body</p>
</div></button></div><div><button class="sc-kzqdkY bXzzUN"><svg class="sc-cwHptR cSkZlF" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">500<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Error within Jungfraujoch code - see output message.</p>
</div></button></div></div></div><div class="sc-iGgWBj sc-gsFSXq ibAZSi eDeKjd"><div class="sc-ejfMa-d bNUPQg"><button class="sc-EgOXT cFEcOl"><span type="put" class="sc-eZYNyq cnqpVw http-verb put">put</span><span class="sc-iEXKAA gUNSDu">/config/user_mask</span><svg class="sc-cwHptR iVFMLx" style="margin-right:-25px" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></button><div aria-hidden="true" class="sc-dlWCHZ kWacYr"><div class="sc-hHOBiw cndTNO"><div class="sc-eeDRCY sc-eBMEME gTGgei fbXBig"><p>Test Jungfraujoch system</p>
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/config/user_mask</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-error react-tabs__tab--selected" role="tab" id="tab_R_jisa_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jisa_0" tabindex="0" data-rttab="true">500</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jisa_0" aria-labelledby="tab_R_jisa_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"msg"</span>: <span class="token string">&quot;Detector in wrong state&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"reason"</span>: <span class="token string">&quot;WrongDAQState&quot;</span></div></li></ul><span class="token punctuation">}</span></code></div></div></div></div></div></div></div></div></div></div></div><div id="/paths/~1config~1mask.tiff/get" data-section-id="/paths/~1config~1mask.tiff/get" class="sc-dcJsrY cqVkUp"><div class="sc-kAyceB hBQWIZ"><div class="sc-fqkvVR oJKYx"><h2 class="sc-jXbUNg fWnwAh"><a class="sc-jlZhew kbdRLs" href="#/paths/~1config~1mask.tiff/get" aria-label="/paths/~1config~1mask.tiff/get"></a>Get mask of the detector (TIFF)<!-- --> </h2><div class="sc-bVVIoq icSMtY"><div class="sc-eeDRCY sc-eBMEME gTGgei fMmru"><p>Should be in <code>Idle</code> state.
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/config/user_mask</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-error react-tabs__tab--selected" role="tab" id="tab_R_jita_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jita_0" tabindex="0" data-rttab="true">500</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jita_0" aria-labelledby="tab_R_jita_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"msg"</span>: <span class="token string">&quot;Detector in wrong state&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"reason"</span>: <span class="token string">&quot;WrongDAQState&quot;</span></div></li></ul><span class="token punctuation">}</span></code></div></div></div></div></div></div></div></div></div></div></div><div id="/paths/~1config~1mask.tiff/get" data-section-id="/paths/~1config~1mask.tiff/get" class="sc-dcJsrY cqVkUp"><div class="sc-kAyceB hBQWIZ"><div class="sc-fqkvVR oJKYx"><h2 class="sc-jXbUNg fWnwAh"><a class="sc-jlZhew kbdRLs" href="#/paths/~1config~1mask.tiff/get" aria-label="/paths/~1config~1mask.tiff/get"></a>Get mask of the detector (TIFF)<!-- --> </h2><div class="sc-bVVIoq icSMtY"><div class="sc-eeDRCY sc-eBMEME gTGgei fMmru"><p>Should be in <code>Idle</code> state.
Get full pixel mask of the detector
See NXmx standard for meaning of pixel values</p>
</div></div><div><h3 class="sc-fMMURN egoxtT">Responses</h3><div><button class="sc-kzqdkY jgSwKD"><svg class="sc-cwHptR hWEnWx" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">200<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Pixel mask in TIFF format (4 byte; unsigned)</p>
@@ -995,7 +1014,7 @@ User mask is not automatically applied - i.e. pixels with user mask will have a
</div></button></div><div><button class="sc-kzqdkY gnmLmb" disabled=""><strong class="sc-dSIIpw bpEYcE">400<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Not a valid single-channel TIFF or size doesn&#39;t match the detector</p>
</div></button></div><div><button class="sc-kzqdkY bXzzUN"><svg class="sc-cwHptR cSkZlF" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">500<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Error within Jungfraujoch code - see output message.</p>
</div></button></div></div></div><div class="sc-iGgWBj sc-gsFSXq ibAZSi eDeKjd"><div class="sc-ejfMa-d bNUPQg"><button class="sc-EgOXT cFEcOl"><span type="put" class="sc-eZYNyq cnqpVw http-verb put">put</span><span class="sc-iEXKAA gUNSDu">/config/user_mask.tiff</span><svg class="sc-cwHptR iVFMLx" style="margin-right:-25px" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></button><div aria-hidden="true" class="sc-dlWCHZ kWacYr"><div class="sc-hHOBiw cndTNO"><div class="sc-eeDRCY sc-eBMEME gTGgei fbXBig"><p>Test Jungfraujoch system</p>
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/config/user_mask.tiff</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-error react-tabs__tab--selected" role="tab" id="tab_R_jitq_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jitq_0" tabindex="0" data-rttab="true">500</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jitq_0" aria-labelledby="tab_R_jitq_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"msg"</span>: <span class="token string">&quot;Detector in wrong state&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"reason"</span>: <span class="token string">&quot;WrongDAQState&quot;</span></div></li></ul><span class="token punctuation">}</span></code></div></div></div></div></div></div></div></div></div></div></div><div id="/paths/~1preview~1pedestal.tiff/get" data-section-id="/paths/~1preview~1pedestal.tiff/get" class="sc-dcJsrY cqVkUp"><div class="sc-kAyceB hBQWIZ"><div class="sc-fqkvVR oJKYx"><h2 class="sc-jXbUNg fWnwAh"><a class="sc-jlZhew kbdRLs" href="#/paths/~1preview~1pedestal.tiff/get" aria-label="/paths/~1preview~1pedestal.tiff/get"></a>Get pedestal in TIFF format<!-- --> </h2><div><h5 class="sc-dAlyuH jbQuod">query<!-- --> Parameters</h5><table class="sc-dAbbOL ccPhmY"><tbody><tr class=""><td class="sc-dLMFU sc-eldPxv hZbWKe jXkfaY" kind="field" title="gain_level"><span class="sc-gFqAkR eRqgPI"></span><span class="property-name">gain_level</span><div class="sc-Nxspf sc-hRJfrW cXxAXt kYVhSL">required</div></td><td class="sc-fPXMVe bAXEAa"><div><div><span class="sc-Nxspf sc-cfxfcM cXxAXt jrGEaR"></span><span class="sc-Nxspf sc-gFAWRd cXxAXt dYzdDr">integer</span></div> <div><div class="sc-eeDRCY sc-eBMEME gTGgei fbXBig"><p>Gain level (0, 1, 2)</p>
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/config/user_mask.tiff</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-error react-tabs__tab--selected" role="tab" id="tab_R_jiuq_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jiuq_0" tabindex="0" data-rttab="true">500</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jiuq_0" aria-labelledby="tab_R_jiuq_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"msg"</span>: <span class="token string">&quot;Detector in wrong state&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"reason"</span>: <span class="token string">&quot;WrongDAQState&quot;</span></div></li></ul><span class="token punctuation">}</span></code></div></div></div></div></div></div></div></div></div></div></div><div id="/paths/~1preview~1pedestal.tiff/get" data-section-id="/paths/~1preview~1pedestal.tiff/get" class="sc-dcJsrY cqVkUp"><div class="sc-kAyceB hBQWIZ"><div class="sc-fqkvVR oJKYx"><h2 class="sc-jXbUNg fWnwAh"><a class="sc-jlZhew kbdRLs" href="#/paths/~1preview~1pedestal.tiff/get" aria-label="/paths/~1preview~1pedestal.tiff/get"></a>Get pedestal in TIFF format<!-- --> </h2><div><h5 class="sc-dAlyuH jbQuod">query<!-- --> Parameters</h5><table class="sc-dAbbOL ccPhmY"><tbody><tr class=""><td class="sc-dLMFU sc-eldPxv hZbWKe jXkfaY" kind="field" title="gain_level"><span class="sc-gFqAkR eRqgPI"></span><span class="property-name">gain_level</span><div class="sc-Nxspf sc-hRJfrW cXxAXt kYVhSL">required</div></td><td class="sc-fPXMVe bAXEAa"><div><div><span class="sc-Nxspf sc-cfxfcM cXxAXt jrGEaR"></span><span class="sc-Nxspf sc-gFAWRd cXxAXt dYzdDr">integer</span></div> <div><div class="sc-eeDRCY sc-eBMEME gTGgei fbXBig"><p>Gain level (0, 1, 2)</p>
</div></div></div></td></tr><tr class="last "><td class="sc-dLMFU sc-eldPxv hZbWKe jXkfaY" kind="field" title="sc"><span class="sc-gFqAkR eRqgPI"></span><span class="property-name">sc</span></td><td class="sc-fPXMVe bAXEAa"><div><div><span class="sc-Nxspf sc-cfxfcM cXxAXt jrGEaR"></span><span class="sc-Nxspf sc-gFAWRd cXxAXt dYzdDr">integer</span></div> <div><div class="sc-eeDRCY sc-eBMEME gTGgei fbXBig"><p>Storage cell number</p>
</div></div></div></td></tr></tbody></table></div><div><h3 class="sc-fMMURN egoxtT">Responses</h3><div><button class="sc-kzqdkY jgSwKD"><svg class="sc-cwHptR hWEnWx" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">200<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Calibration image</p>
</div></button></div><div><button class="sc-kzqdkY gnmLmb" disabled=""><strong class="sc-dSIIpw bpEYcE">400<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Invalid gain level or storage cell number</p>
@@ -1012,7 +1031,7 @@ For still measurement the number is ignored</p>
</div></button></div><div><button class="sc-kzqdkY bXzzUN"><svg class="sc-cwHptR cSkZlF" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">400<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Input parsing or validation error</p>
</div></button></div><div><button class="sc-kzqdkY bXzzUN"><svg class="sc-cwHptR cSkZlF" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">401<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>The current dataset is protected and no valid bearer token was presented.</p>
</div></button></div></div></div><div class="sc-iGgWBj sc-gsFSXq ibAZSi eDeKjd"><div class="sc-ejfMa-d bNUPQg"><button class="sc-EgOXT cFEcOl"><span type="get" class="sc-eZYNyq qGfV http-verb get">get</span><span class="sc-iEXKAA gUNSDu">/preview/plot</span><svg class="sc-cwHptR iVFMLx" style="margin-right:-25px" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></button><div aria-hidden="true" class="sc-dlWCHZ kWacYr"><div class="sc-hHOBiw cndTNO"><div class="sc-eeDRCY sc-eBMEME gTGgei fbXBig"><p>Test Jungfraujoch system</p>
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/preview/plot</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-success react-tabs__tab--selected" role="tab" id="tab_R_jiuq_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jiuq_0" tabindex="0" data-rttab="true">200</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jiuq_0" aria-labelledby="tab_R_jiuq_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button><button> Expand all </button><button> Collapse all </button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"title"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"unit_x"</span>: <span class="token string">&quot;image_number&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"size_x"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"size_y"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"plot"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable collapsed"><button class="collapser" aria-label="expand"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable collapsed"><span class="property token string">"title"</span>: <span class="token string">&quot;&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"x"</span>: <button class="collapser" aria-label="expand"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable collapsed"><span class="token number">0.1</span></div></li></ul><span class="token punctuation">]</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"y"</span>: <button class="collapser" aria-label="expand"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable collapsed"><span class="token number">0.1</span></div></li></ul><span class="token punctuation">]</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"z"</span>: <button class="collapser" aria-label="expand"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable collapsed"><span class="token number">0.1</span></div></li></ul><span class="token punctuation">]</span></div></li></ul><span class="token punctuation">}</span></div></li></ul><span class="token punctuation">]</span></div></li></ul><span class="token punctuation">}</span></code></div></div></div></div></div></div></div></div></div></div></div><div id="/paths/~1preview~1plot.bin/get" data-section-id="/paths/~1preview~1plot.bin/get" class="sc-dcJsrY cqVkUp"><div class="sc-kAyceB hBQWIZ"><div class="sc-fqkvVR oJKYx"><h2 class="sc-jXbUNg fWnwAh"><a class="sc-jlZhew kbdRLs" href="#/paths/~1preview~1plot.bin/get" aria-label="/paths/~1preview~1plot.bin/get"></a>Generate 1D plot from Jungfraujoch and send in raw binary format.
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/preview/plot</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-success react-tabs__tab--selected" role="tab" id="tab_R_jivq_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jivq_0" tabindex="0" data-rttab="true">200</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jivq_0" aria-labelledby="tab_R_jivq_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button><button> Expand all </button><button> Collapse all </button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"title"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"unit_x"</span>: <span class="token string">&quot;image_number&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"size_x"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"size_y"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"plot"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable collapsed"><button class="collapser" aria-label="expand"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable collapsed"><span class="property token string">"title"</span>: <span class="token string">&quot;&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"x"</span>: <button class="collapser" aria-label="expand"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable collapsed"><span class="token number">0.1</span></div></li></ul><span class="token punctuation">]</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"y"</span>: <button class="collapser" aria-label="expand"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable collapsed"><span class="token number">0.1</span></div></li></ul><span class="token punctuation">]</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"z"</span>: <button class="collapser" aria-label="expand"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable collapsed"><span class="token number">0.1</span></div></li></ul><span class="token punctuation">]</span></div></li></ul><span class="token punctuation">}</span></div></li></ul><span class="token punctuation">]</span></div></li></ul><span class="token punctuation">}</span></code></div></div></div></div></div></div></div></div></div></div></div><div id="/paths/~1preview~1plot.bin/get" data-section-id="/paths/~1preview~1plot.bin/get" class="sc-dcJsrY cqVkUp"><div class="sc-kAyceB hBQWIZ"><div class="sc-fqkvVR oJKYx"><h2 class="sc-jXbUNg fWnwAh"><a class="sc-jlZhew kbdRLs" href="#/paths/~1preview~1plot.bin/get" aria-label="/paths/~1preview~1plot.bin/get"></a>Generate 1D plot from Jungfraujoch and send in raw binary format.
Data are provided as (32-bit) float binary array.
This format doesn&#x27;t transmit information about X-axis, only values, so it is of limited use for azimuthal integration.
<!-- --> </h2><div class="sc-jaXxmE eqYzvz"><div class="sc-iMTnTL fkPTul"><h5 class="sc-dAlyuH sc-hwdzOV jbQuod JjoyL">Authorizations:</h5><svg class="sc-cwHptR iZRiKW" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></div><div class="sc-krNlru gkwgxc"><span class="sc-jMakVo bPNrjo"><span class="sc-ihgnxF jlNGfN"><i>bearerAuth</i></span></span></div></div><div><h5 class="sc-dAlyuH jbQuod">query<!-- --> Parameters</h5><table class="sc-dAbbOL ccPhmY"><tbody><tr class=""><td class="sc-dLMFU sc-eldPxv hZbWKe jXkfaY" kind="field" title="type"><span class="sc-gFqAkR eRqgPI"></span><span class="property-name">type</span><div class="sc-Nxspf sc-hRJfrW cXxAXt kYVhSL">required</div></td><td class="sc-fPXMVe bAXEAa"><div><div><span class="sc-Nxspf sc-cfxfcM cXxAXt jrGEaR"></span><span class="sc-Nxspf sc-gFAWRd cXxAXt dYzdDr">string</span></div><div><span class="sc-Nxspf cXxAXt"> <!-- -->Enum<!-- -->:</span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">&quot;bkg_estimate&quot;</span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">&quot;spindle_blind_fraction&quot;</span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">&quot;azint&quot;</span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">&quot;azint_1d&quot;</span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">&quot;spot_count&quot;</span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">&quot;spot_count_low_res&quot;</span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">&quot;spot_count_indexed&quot;</span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">&quot;spot_count_ice&quot;</span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">&quot;indexing_rate&quot;</span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">&quot;indexing_lattice_count&quot;</span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">&quot;indexing_unit_cell_length&quot;</span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">&quot;indexing_unit_cell_angle&quot;</span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">&quot;profile_radius&quot;</span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">&quot;mosaicity&quot;</span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">&quot;b_factor&quot;</span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">&quot;error_pixels&quot;</span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">&quot;saturated_pixels&quot;</span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">&quot;image_collection_efficiency&quot;</span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">&quot;receiver_delay&quot;</span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">&quot;receiver_free_send_buf&quot;</span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">&quot;strong_pixels&quot;</span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">&quot;roi_sum&quot;</span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">&quot;roi_mean&quot;</span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">&quot;roi_max_count&quot;</span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">&quot;roi_pixels&quot;</span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">&quot;roi_weighted_x&quot;</span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">&quot;roi_weighted_y&quot;</span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">&quot;packets_received&quot;</span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">&quot;max_pixel_value&quot;</span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">&quot;resolution_estimate&quot;</span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">&quot;pixel_sum&quot;</span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">&quot;processing_time&quot;</span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">&quot;beam_center_x&quot;</span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">&quot;beam_center_y&quot;</span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">&quot;integrated_reflections&quot;</span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">&quot;image_scale_factor&quot;</span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">&quot;image_scale_cc&quot;</span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">&quot;compression_ratio&quot;</span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">&quot;ice_ring_score&quot;</span> </div> <div><div class="sc-eeDRCY sc-eBMEME gTGgei fbXBig"><p>Type of requested plot</p>
@@ -1026,13 +1045,13 @@ This format doesn&#x27;t transmit information about X-axis, only values, so it i
</div></button></div><div><button class="sc-kzqdkY gnmLmb" disabled=""><strong class="sc-dSIIpw bpEYcE">404<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>No grid scan recorded</p>
</div></button></div><div><button class="sc-kzqdkY bXzzUN"><svg class="sc-cwHptR cSkZlF" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">500<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Error within Jungfraujoch code - see output message.</p>
</div></button></div></div></div><div class="sc-iGgWBj sc-gsFSXq ibAZSi eDeKjd"><div class="sc-ejfMa-d bNUPQg"><button class="sc-EgOXT cFEcOl"><span type="get" class="sc-eZYNyq qGfV http-verb get">get</span><span class="sc-iEXKAA gUNSDu">/result/scan</span><svg class="sc-cwHptR iVFMLx" style="margin-right:-25px" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></button><div aria-hidden="true" class="sc-dlWCHZ kWacYr"><div class="sc-hHOBiw cndTNO"><div class="sc-eeDRCY sc-eBMEME gTGgei fbXBig"><p>Test Jungfraujoch system</p>
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/result/scan</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-success react-tabs__tab--selected" role="tab" id="tab_R_jivq_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jivq_0" tabindex="0" data-rttab="true">200</li><li class="tab-error" role="tab" id="tab_R_jivq_1" aria-selected="false" aria-disabled="false" aria-controls="panel_R_jivq_1" data-rttab="true">500</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jivq_0" aria-labelledby="tab_R_jivq_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button><button> Expand all </button><button> Collapse all </button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"file_prefix"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"rotation_unit_cell"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable collapsed"><span class="property token string">"a"</span>: <span class="token number">37</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"b"</span>: <span class="token number">37</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"c"</span>: <span class="token number">78</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"alpha"</span>: <span class="token number">90</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"beta"</span>: <span class="token number">90</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"gamma"</span>: <span class="token number">90</span></div></li></ul><span class="token punctuation">}</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"rotation_crystal_lattice"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable collapsed"><span class="token number">0.1</span>,</div></li><li><div class="hoverable collapsed"><span class="token number">0.1</span>,</div></li><li><div class="hoverable collapsed"><span class="token number">0.1</span>,</div></li><li><div class="hoverable collapsed"><span class="token number">0.1</span>,</div></li><li><div class="hoverable collapsed"><span class="token number">0.1</span>,</div></li><li><div class="hoverable collapsed"><span class="token number">0.1</span>,</div></li><li><div class="hoverable collapsed"><span class="token number">0.1</span>,</div></li><li><div class="hoverable collapsed"><span class="token number">0.1</span>,</div></li><li><div class="hoverable collapsed"><span class="token number">0.1</span></div></li></ul><span class="token punctuation">]</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"rotation_bravais"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"images"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable collapsed"><button class="collapser" aria-label="expand"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable collapsed"><span class="property token string">"efficiency"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"number"</span>: <span class="token number">0</span><span class="tLine truncated
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/result/scan</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-success react-tabs__tab--selected" role="tab" id="tab_R_jj0q_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jj0q_0" tabindex="0" data-rttab="true">200</li><li class="tab-error" role="tab" id="tab_R_jj0q_1" aria-selected="false" aria-disabled="false" aria-controls="panel_R_jj0q_1" data-rttab="true">500</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jj0q_0" aria-labelledby="tab_R_jj0q_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button><button> Expand all </button><button> Collapse all </button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"file_prefix"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"rotation_unit_cell"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable collapsed"><span class="property token string">"a"</span>: <span class="token number">37</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"b"</span>: <span class="token number">37</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"c"</span>: <span class="token number">78</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"alpha"</span>: <span class="token number">90</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"beta"</span>: <span class="token number">90</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"gamma"</span>: <span class="token number">90</span></div></li></ul><span class="token punctuation">}</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"rotation_crystal_lattice"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable collapsed"><span class="token number">0.1</span>,</div></li><li><div class="hoverable collapsed"><span class="token number">0.1</span>,</div></li><li><div class="hoverable collapsed"><span class="token number">0.1</span>,</div></li><li><div class="hoverable collapsed"><span class="token number">0.1</span>,</div></li><li><div class="hoverable collapsed"><span class="token number">0.1</span>,</div></li><li><div class="hoverable collapsed"><span class="token number">0.1</span>,</div></li><li><div class="hoverable collapsed"><span class="token number">0.1</span>,</div></li><li><div class="hoverable collapsed"><span class="token number">0.1</span>,</div></li><li><div class="hoverable collapsed"><span class="token number">0.1</span></div></li></ul><span class="token punctuation">]</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"rotation_bravais"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"images"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable collapsed"><button class="collapser" aria-label="expand"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable collapsed"><span class="property token string">"efficiency"</span>: <span class="token number">0.1</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"number"</span>: <span class="token number">0</span><span class="tLine truncated
</div></div><div class="sc-jaXxmE eqYzvz"><div class="sc-iMTnTL fkPTul"><h5 class="sc-dAlyuH sc-hwdzOV jbQuod JjoyL">Authorizations:</h5><svg class="sc-cwHptR iZRiKW" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></div><div class="sc-krNlru gkwgxc"><span class="sc-jMakVo bPNrjo"><span class="sc-ihgnxF jlNGfN"><i>bearerAuth</i></span></span></div></div><div><h3 class="sc-fMMURN egoxtT">Responses</h3><div><button class="sc-kzqdkY jgSwKD"><svg class="sc-cwHptR hWEnWx" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">200<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Return start message</p>
</div></button></div><div><button class="sc-kzqdkY bXzzUN"><svg class="sc-cwHptR cSkZlF" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">401<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>The current dataset is protected and no valid bearer token was presented.</p>
</div></button></div><div><button class="sc-kzqdkY gnmLmb" disabled=""><strong class="sc-dSIIpw bpEYcE">404<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>No measurement so far</p>
</div></button></div><div><button class="sc-kzqdkY bXzzUN"><svg class="sc-cwHptR cSkZlF" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">500<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Error within Jungfraujoch code - see output message.</p>
</div></button></div></div></div><div class="sc-iGgWBj sc-gsFSXq ibAZSi eDeKjd"><div class="sc-ejfMa-d bNUPQg"><button class="sc-EgOXT cFEcOl"><span type="get" class="sc-eZYNyq qGfV http-verb get">get</span><span class="sc-iEXKAA gUNSDu">/image_buffer/start.cbor</span><svg class="sc-cwHptR iVFMLx" style="margin-right:-25px" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></button><div aria-hidden="true" class="sc-dlWCHZ kWacYr"><div class="sc-hHOBiw cndTNO"><div class="sc-eeDRCY sc-eBMEME gTGgei fbXBig"><p>Test Jungfraujoch system</p>
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/image_buffer/start.cbor</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-error react-tabs__tab--selected" role="tab" id="tab_R_jj0a_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jj0a_0" tabindex="0" data-rttab="true">500</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jj0a_0" aria-labelledby="tab_R_jj0a_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"msg"</span>: <span class="token string">&quot;Detector in wrong state&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"reason"</span>: <span class="token string">&quot;WrongDAQState&quot;</span></div></li></ul><span class="token punctuation">}</span></code></div></div></div></div></div></div></div></div></div></div></div><div id="/paths/~1live~1events/get" data-section-id="/paths/~1live~1events/get" class="sc-dcJsrY cqVkUp"><div class="sc-kAyceB hBQWIZ"><div class="sc-fqkvVR oJKYx"><h2 class="sc-jXbUNg fWnwAh"><a class="sc-jlZhew kbdRLs" href="#/paths/~1live~1events/get" aria-label="/paths/~1live~1events/get"></a>Event stream of the collection, for a reader following it<!-- --> </h2><div class="sc-bVVIoq icSMtY"><div class="sc-eeDRCY sc-eBMEME gTGgei fMmru"><p>Server-sent events (text/event-stream) for the current collection, from the moment /start has
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/image_buffer/start.cbor</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-error react-tabs__tab--selected" role="tab" id="tab_R_jj1a_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jj1a_0" tabindex="0" data-rttab="true">500</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jj1a_0" aria-labelledby="tab_R_jj1a_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"msg"</span>: <span class="token string">&quot;Detector in wrong state&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"reason"</span>: <span class="token string">&quot;WrongDAQState&quot;</span></div></li></ul><span class="token punctuation">}</span></code></div></div></div></div></div></div></div></div></div></div></div><div id="/paths/~1live~1events/get" data-section-id="/paths/~1live~1events/get" class="sc-dcJsrY cqVkUp"><div class="sc-kAyceB hBQWIZ"><div class="sc-fqkvVR oJKYx"><h2 class="sc-jXbUNg fWnwAh"><a class="sc-jlZhew kbdRLs" href="#/paths/~1live~1events/get" aria-label="/paths/~1live~1events/get"></a>Event stream of the collection, for a reader following it<!-- --> </h2><div class="sc-bVVIoq icSMtY"><div class="sc-eeDRCY sc-eBMEME gTGgei fMmru"><p>Server-sent events (text/event-stream) for the current collection, from the moment /start has
accepted it: first its whole history, then every change, until it ends or a new collection
begins. Only one reader at a time. Events, each with a JSON <code>data</code> line:</p>
<ul>
@@ -1060,7 +1079,7 @@ A comment line (<code>: keepalive</code>) every 10 s when nothing happens.</li>
</div></button></div><div><button class="sc-kzqdkY gnmLmb" disabled=""><strong class="sc-dSIIpw bpEYcE">404<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Image not present in the buffer - either not yet measured or already replaced by a next image.</p>
</div></button></div><div><button class="sc-kzqdkY bXzzUN"><svg class="sc-cwHptR cSkZlF" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">500<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Error within Jungfraujoch code - see output message.</p>
</div></button></div></div></div><div class="sc-iGgWBj sc-gsFSXq ibAZSi eDeKjd"><div class="sc-ejfMa-d bNUPQg"><button class="sc-EgOXT cFEcOl"><span type="get" class="sc-eZYNyq qGfV http-verb get">get</span><span class="sc-iEXKAA gUNSDu">/image_buffer/image.cbor</span><svg class="sc-cwHptR iVFMLx" style="margin-right:-25px" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></button><div aria-hidden="true" class="sc-dlWCHZ kWacYr"><div class="sc-hHOBiw cndTNO"><div class="sc-eeDRCY sc-eBMEME gTGgei fbXBig"><p>Test Jungfraujoch system</p>
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/image_buffer/image.cbor</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-error react-tabs__tab--selected" role="tab" id="tab_R_jj1a_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jj1a_0" tabindex="0" data-rttab="true">500</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jj1a_0" aria-labelledby="tab_R_jj1a_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"msg"</span>: <span class="token string">&quot;Detector in wrong state&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"reason"</span>: <span class="token string">&quot;WrongDAQState&quot;</span></div></li></ul><span class="token punctuation">}</span></code></div></div></div></div></div></div></div></div></div></div></div><div id="/paths/~1image_buffer~1image.jpeg/get" data-section-id="/paths/~1image_buffer~1image.jpeg/get" class="sc-dcJsrY cqVkUp"><div class="sc-kAyceB hBQWIZ"><div class="sc-fqkvVR oJKYx"><h2 class="sc-jXbUNg fWnwAh"><a class="sc-jlZhew kbdRLs" href="#/paths/~1image_buffer~1image.jpeg/get" aria-label="/paths/~1image_buffer~1image.jpeg/get"></a>Get preview image in JPEG format using custom settings<!-- --> </h2><div class="sc-jaXxmE eqYzvz"><div class="sc-iMTnTL fkPTul"><h5 class="sc-dAlyuH sc-hwdzOV jbQuod JjoyL">Authorizations:</h5><svg class="sc-cwHptR iZRiKW" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></div><div class="sc-krNlru gkwgxc"><span class="sc-jMakVo bPNrjo"><span class="sc-ihgnxF jlNGfN"><i>bearerAuth</i></span></span></div></div><div><h5 class="sc-dAlyuH jbQuod">query<!-- --> Parameters</h5><table class="sc-dAbbOL ccPhmY"><tbody><tr class=""><td class="sc-dLMFU sc-eldPxv hZbWKe jXkfaY" kind="field" title="id"><span class="sc-gFqAkR eRqgPI"></span><span class="property-name">id</span></td><td class="sc-fPXMVe bAXEAa"><div><div><span class="sc-Nxspf sc-cfxfcM cXxAXt jrGEaR"></span><span class="sc-Nxspf sc-gFAWRd cXxAXt dYzdDr">integer</span><span class="sc-Nxspf sc-gFAWRd cXxAXt dYzdDr"> <!-- -->&lt;<!-- -->int64<!-- -->&gt;<!-- --> </span><span> <span class="sc-Nxspf sc-fxwrCY cXxAXt eMVOei"> <!-- -->&gt;= -2<!-- --> </span></span></div><div><span class="sc-Nxspf cXxAXt"> <!-- -->Default:<!-- --> </span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">-1</span></div> <div><div class="sc-eeDRCY sc-eBMEME gTGgei fbXBig"><p>Image ID in the image buffer. Special values: -1 - last image in the buffer, -2: last indexed image in the buffer</p>
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/image_buffer/image.cbor</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-error react-tabs__tab--selected" role="tab" id="tab_R_jj2a_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jj2a_0" tabindex="0" data-rttab="true">500</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jj2a_0" aria-labelledby="tab_R_jj2a_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"msg"</span>: <span class="token string">&quot;Detector in wrong state&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"reason"</span>: <span class="token string">&quot;WrongDAQState&quot;</span></div></li></ul><span class="token punctuation">}</span></code></div></div></div></div></div></div></div></div></div></div></div><div id="/paths/~1image_buffer~1image.jpeg/get" data-section-id="/paths/~1image_buffer~1image.jpeg/get" class="sc-dcJsrY cqVkUp"><div class="sc-kAyceB hBQWIZ"><div class="sc-fqkvVR oJKYx"><h2 class="sc-jXbUNg fWnwAh"><a class="sc-jlZhew kbdRLs" href="#/paths/~1image_buffer~1image.jpeg/get" aria-label="/paths/~1image_buffer~1image.jpeg/get"></a>Get preview image in JPEG format using custom settings<!-- --> </h2><div class="sc-jaXxmE eqYzvz"><div class="sc-iMTnTL fkPTul"><h5 class="sc-dAlyuH sc-hwdzOV jbQuod JjoyL">Authorizations:</h5><svg class="sc-cwHptR iZRiKW" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></div><div class="sc-krNlru gkwgxc"><span class="sc-jMakVo bPNrjo"><span class="sc-ihgnxF jlNGfN"><i>bearerAuth</i></span></span></div></div><div><h5 class="sc-dAlyuH jbQuod">query<!-- --> Parameters</h5><table class="sc-dAbbOL ccPhmY"><tbody><tr class=""><td class="sc-dLMFU sc-eldPxv hZbWKe jXkfaY" kind="field" title="id"><span class="sc-gFqAkR eRqgPI"></span><span class="property-name">id</span></td><td class="sc-fPXMVe bAXEAa"><div><div><span class="sc-Nxspf sc-cfxfcM cXxAXt jrGEaR"></span><span class="sc-Nxspf sc-gFAWRd cXxAXt dYzdDr">integer</span><span class="sc-Nxspf sc-gFAWRd cXxAXt dYzdDr"> <!-- -->&lt;<!-- -->int64<!-- -->&gt;<!-- --> </span><span> <span class="sc-Nxspf sc-fxwrCY cXxAXt eMVOei"> <!-- -->&gt;= -2<!-- --> </span></span></div><div><span class="sc-Nxspf cXxAXt"> <!-- -->Default:<!-- --> </span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">-1</span></div> <div><div class="sc-eeDRCY sc-eBMEME gTGgei fbXBig"><p>Image ID in the image buffer. Special values: -1 - last image in the buffer, -2: last indexed image in the buffer</p>
</div></div></div></td></tr><tr class=""><td class="sc-dLMFU sc-eldPxv hZbWKe jXkfaY" kind="field" title="show_user_mask"><span class="sc-gFqAkR eRqgPI"></span><span class="property-name">show_user_mask</span></td><td class="sc-fPXMVe bAXEAa"><div><div><span class="sc-Nxspf sc-cfxfcM cXxAXt jrGEaR"></span><span class="sc-Nxspf sc-gFAWRd cXxAXt dYzdDr">boolean</span></div><div><span class="sc-Nxspf cXxAXt"> <!-- -->Default:<!-- --> </span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">false</span></div> <div><div class="sc-eeDRCY sc-eBMEME gTGgei fbXBig"><p>Show user mask</p>
</div></div></div></td></tr><tr class=""><td class="sc-dLMFU sc-eldPxv hZbWKe jXkfaY" kind="field" title="show_roi"><span class="sc-gFqAkR eRqgPI"></span><span class="property-name">show_roi</span></td><td class="sc-fPXMVe bAXEAa"><div><div><span class="sc-Nxspf sc-cfxfcM cXxAXt jrGEaR"></span><span class="sc-Nxspf sc-gFAWRd cXxAXt dYzdDr">boolean</span></div><div><span class="sc-Nxspf cXxAXt"> <!-- -->Default:<!-- --> </span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">false</span></div> <div><div class="sc-eeDRCY sc-eBMEME gTGgei fbXBig"><p>Show ROI areas on the image</p>
</div></div></div></td></tr><tr class=""><td class="sc-dLMFU sc-eldPxv hZbWKe jXkfaY" kind="field" title="show_spots"><span class="sc-gFqAkR eRqgPI"></span><span class="property-name">show_spots</span></td><td class="sc-fPXMVe bAXEAa"><div><div><span class="sc-Nxspf sc-cfxfcM cXxAXt jrGEaR"></span><span class="sc-Nxspf sc-gFAWRd cXxAXt dYzdDr">boolean</span></div><div><span class="sc-Nxspf cXxAXt"> <!-- -->Default:<!-- --> </span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">true</span></div> <div><div class="sc-eeDRCY sc-eBMEME gTGgei fbXBig"><p>Show spot finding results on the image</p>
@@ -1077,7 +1096,7 @@ A comment line (<code>: keepalive</code>) every 10 s when nothing happens.</li>
</div></button></div><div><button class="sc-kzqdkY gnmLmb" disabled=""><strong class="sc-dSIIpw bpEYcE">404<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Image not present in the buffer - either not yet measured or already replaced by a next image.</p>
</div></button></div><div><button class="sc-kzqdkY bXzzUN"><svg class="sc-cwHptR cSkZlF" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">500<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Error within Jungfraujoch code - see output message.</p>
</div></button></div></div></div><div class="sc-iGgWBj sc-gsFSXq ibAZSi eDeKjd"><div class="sc-ejfMa-d bNUPQg"><button class="sc-EgOXT cFEcOl"><span type="get" class="sc-eZYNyq qGfV http-verb get">get</span><span class="sc-iEXKAA gUNSDu">/image_buffer/image.jpeg</span><svg class="sc-cwHptR iVFMLx" style="margin-right:-25px" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></button><div aria-hidden="true" class="sc-dlWCHZ kWacYr"><div class="sc-hHOBiw cndTNO"><div class="sc-eeDRCY sc-eBMEME gTGgei fbXBig"><p>Test Jungfraujoch system</p>
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/image_buffer/image.jpeg</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-error react-tabs__tab--selected" role="tab" id="tab_R_jj1q_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jj1q_0" tabindex="0" data-rttab="true">500</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jj1q_0" aria-labelledby="tab_R_jj1q_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"msg"</span>: <span class="token string">&quot;Detector in wrong state&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"reason"</span>: <span class="token string">&quot;WrongDAQState&quot;</span></div></li></ul><span class="token punctuation">}</span></code></div></div></div></div></div></div></div></div></div></div></div><div id="/paths/~1image_buffer~1image.tiff/get" data-section-id="/paths/~1image_buffer~1image.tiff/get" class="sc-dcJsrY cqVkUp"><div class="sc-kAyceB hBQWIZ"><div class="sc-fqkvVR oJKYx"><h2 class="sc-jXbUNg fWnwAh"><a class="sc-jlZhew kbdRLs" href="#/paths/~1image_buffer~1image.tiff/get" aria-label="/paths/~1image_buffer~1image.tiff/get"></a>Get preview image in TIFF format<!-- --> </h2><div class="sc-jaXxmE eqYzvz"><div class="sc-iMTnTL fkPTul"><h5 class="sc-dAlyuH sc-hwdzOV jbQuod JjoyL">Authorizations:</h5><svg class="sc-cwHptR iZRiKW" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></div><div class="sc-krNlru gkwgxc"><span class="sc-jMakVo bPNrjo"><span class="sc-ihgnxF jlNGfN"><i>bearerAuth</i></span></span></div></div><div><h5 class="sc-dAlyuH jbQuod">query<!-- --> Parameters</h5><table class="sc-dAbbOL ccPhmY"><tbody><tr class="last "><td class="sc-dLMFU sc-eldPxv hZbWKe jXkfaY" kind="field" title="id"><span class="sc-gFqAkR eRqgPI"></span><span class="property-name">id</span></td><td class="sc-fPXMVe bAXEAa"><div><div><span class="sc-Nxspf sc-cfxfcM cXxAXt jrGEaR"></span><span class="sc-Nxspf sc-gFAWRd cXxAXt dYzdDr">integer</span><span class="sc-Nxspf sc-gFAWRd cXxAXt dYzdDr"> <!-- -->&lt;<!-- -->int64<!-- -->&gt;<!-- --> </span><span> <span class="sc-Nxspf sc-fxwrCY cXxAXt eMVOei"> <!-- -->&gt;= -2<!-- --> </span></span></div><div><span class="sc-Nxspf cXxAXt"> <!-- -->Default:<!-- --> </span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">-1</span></div> <div><div class="sc-eeDRCY sc-eBMEME gTGgei fbXBig"><p>Image ID in the image buffer. Special values: -1 - last image in the buffer, -2: last indexed image in the buffer</p>
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/image_buffer/image.jpeg</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-error react-tabs__tab--selected" role="tab" id="tab_R_jj2q_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jj2q_0" tabindex="0" data-rttab="true">500</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jj2q_0" aria-labelledby="tab_R_jj2q_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"msg"</span>: <span class="token string">&quot;Detector in wrong state&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"reason"</span>: <span class="token string">&quot;WrongDAQState&quot;</span></div></li></ul><span class="token punctuation">}</span></code></div></div></div></div></div></div></div></div></div></div></div><div id="/paths/~1image_buffer~1image.tiff/get" data-section-id="/paths/~1image_buffer~1image.tiff/get" class="sc-dcJsrY cqVkUp"><div class="sc-kAyceB hBQWIZ"><div class="sc-fqkvVR oJKYx"><h2 class="sc-jXbUNg fWnwAh"><a class="sc-jlZhew kbdRLs" href="#/paths/~1image_buffer~1image.tiff/get" aria-label="/paths/~1image_buffer~1image.tiff/get"></a>Get preview image in TIFF format<!-- --> </h2><div class="sc-jaXxmE eqYzvz"><div class="sc-iMTnTL fkPTul"><h5 class="sc-dAlyuH sc-hwdzOV jbQuod JjoyL">Authorizations:</h5><svg class="sc-cwHptR iZRiKW" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></div><div class="sc-krNlru gkwgxc"><span class="sc-jMakVo bPNrjo"><span class="sc-ihgnxF jlNGfN"><i>bearerAuth</i></span></span></div></div><div><h5 class="sc-dAlyuH jbQuod">query<!-- --> Parameters</h5><table class="sc-dAbbOL ccPhmY"><tbody><tr class="last "><td class="sc-dLMFU sc-eldPxv hZbWKe jXkfaY" kind="field" title="id"><span class="sc-gFqAkR eRqgPI"></span><span class="property-name">id</span></td><td class="sc-fPXMVe bAXEAa"><div><div><span class="sc-Nxspf sc-cfxfcM cXxAXt jrGEaR"></span><span class="sc-Nxspf sc-gFAWRd cXxAXt dYzdDr">integer</span><span class="sc-Nxspf sc-gFAWRd cXxAXt dYzdDr"> <!-- -->&lt;<!-- -->int64<!-- -->&gt;<!-- --> </span><span> <span class="sc-Nxspf sc-fxwrCY cXxAXt eMVOei"> <!-- -->&gt;= -2<!-- --> </span></span></div><div><span class="sc-Nxspf cXxAXt"> <!-- -->Default:<!-- --> </span> <span class="sc-Nxspf sc-ddjGPC cXxAXt jZOCAW">-1</span></div> <div><div class="sc-eeDRCY sc-eBMEME gTGgei fbXBig"><p>Image ID in the image buffer. Special values: -1 - last image in the buffer, -2: last indexed image in the buffer</p>
</div></div></div></td></tr></tbody></table></div><div><h3 class="sc-fMMURN egoxtT">Responses</h3><div><button class="sc-kzqdkY jgSwKD"><svg class="sc-cwHptR hWEnWx" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">200<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Preview image</p>
</div></button></div><div><button class="sc-kzqdkY bXzzUN"><svg class="sc-cwHptR cSkZlF" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">401<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>The current dataset is protected and no valid bearer token was presented.</p>
</div></button></div><div><button class="sc-kzqdkY gnmLmb" disabled=""><strong class="sc-dSIIpw bpEYcE">404<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>No preview image recorded so far</p>
@@ -1086,17 +1105,17 @@ A comment line (<code>: keepalive</code>) every 10 s when nothing happens.</li>
</div></div><div><h3 class="sc-fMMURN egoxtT">Responses</h3><div><button class="sc-kzqdkY jkjMMR" disabled=""><strong class="sc-dSIIpw bpEYcE">200<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Done</p>
</div></button></div><div><button class="sc-kzqdkY bXzzUN"><svg class="sc-cwHptR cSkZlF" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">500<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Error within Jungfraujoch code - see output message.</p>
</div></button></div></div></div><div class="sc-iGgWBj sc-gsFSXq ibAZSi eDeKjd"><div class="sc-ejfMa-d bNUPQg"><button class="sc-EgOXT cFEcOl"><span type="post" class="sc-eZYNyq fPdOXD http-verb post">post</span><span class="sc-iEXKAA gUNSDu">/image_buffer/clear</span><svg class="sc-cwHptR iVFMLx" style="margin-right:-25px" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></button><div aria-hidden="true" class="sc-dlWCHZ kWacYr"><div class="sc-hHOBiw cndTNO"><div class="sc-eeDRCY sc-eBMEME gTGgei fbXBig"><p>Test Jungfraujoch system</p>
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/image_buffer/clear</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-error react-tabs__tab--selected" role="tab" id="tab_R_jj2q_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jj2q_0" tabindex="0" data-rttab="true">500</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jj2q_0" aria-labelledby="tab_R_jj2q_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"msg"</span>: <span class="token string">&quot;Detector in wrong state&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"reason"</span>: <span class="token string">&quot;WrongDAQState&quot;</span></div></li></ul><span class="token punctuation">}</span></code></div></div></div></div></div></div></div></div></div></div></div><div id="/paths/~1image_buffer~1status/get" data-section-id="/paths/~1image_buffer~1status/get" class="sc-dcJsrY cqVkUp"><div class="sc-kAyceB hBQWIZ"><div class="sc-fqkvVR oJKYx"><h2 class="sc-jXbUNg fWnwAh"><a class="sc-jlZhew kbdRLs" href="#/paths/~1image_buffer~1status/get" aria-label="/paths/~1image_buffer~1status/get"></a>Get status of the image buffers<!-- --> </h2><div class="sc-bVVIoq icSMtY"><div class="sc-eeDRCY sc-eBMEME gTGgei fMmru"><p>Can be run at any stage of Jungfraujoch operation, including during data collection.
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/image_buffer/clear</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-error react-tabs__tab--selected" role="tab" id="tab_R_jj3q_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jj3q_0" tabindex="0" data-rttab="true">500</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jj3q_0" aria-labelledby="tab_R_jj3q_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"msg"</span>: <span class="token string">&quot;Detector in wrong state&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"reason"</span>: <span class="token string">&quot;WrongDAQState&quot;</span></div></li></ul><span class="token punctuation">}</span></code></div></div></div></div></div></div></div></div></div></div></div><div id="/paths/~1image_buffer~1status/get" data-section-id="/paths/~1image_buffer~1status/get" class="sc-dcJsrY cqVkUp"><div class="sc-kAyceB hBQWIZ"><div class="sc-fqkvVR oJKYx"><h2 class="sc-jXbUNg fWnwAh"><a class="sc-jlZhew kbdRLs" href="#/paths/~1image_buffer~1status/get" aria-label="/paths/~1image_buffer~1status/get"></a>Get status of the image buffers<!-- --> </h2><div class="sc-bVVIoq icSMtY"><div class="sc-eeDRCY sc-eBMEME gTGgei fMmru"><p>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.</p>
</div></div><div><h3 class="sc-fMMURN egoxtT">Responses</h3><div><button class="sc-kzqdkY jgSwKD"><svg class="sc-cwHptR hWEnWx" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">200<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Done</p>
</div></button></div><div><button class="sc-kzqdkY bXzzUN"><svg class="sc-cwHptR cSkZlF" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">500<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Error within Jungfraujoch code - see output message.</p>
</div></button></div></div></div><div class="sc-iGgWBj sc-gsFSXq ibAZSi eDeKjd"><div class="sc-ejfMa-d bNUPQg"><button class="sc-EgOXT cFEcOl"><span type="get" class="sc-eZYNyq qGfV http-verb get">get</span><span class="sc-iEXKAA gUNSDu">/image_buffer/status</span><svg class="sc-cwHptR iVFMLx" style="margin-right:-25px" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></button><div aria-hidden="true" class="sc-dlWCHZ kWacYr"><div class="sc-hHOBiw cndTNO"><div class="sc-eeDRCY sc-eBMEME gTGgei fbXBig"><p>Test Jungfraujoch system</p>
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/image_buffer/status</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-success react-tabs__tab--selected" role="tab" id="tab_R_jj3a_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jj3a_0" tabindex="0" data-rttab="true">200</li><li class="tab-error" role="tab" id="tab_R_jj3a_1" aria-selected="false" aria-disabled="false" aria-controls="panel_R_jj3a_1" data-rttab="true">500</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jj3a_0" aria-labelledby="tab_R_jj3a_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button><button> Expand all </button><button> Collapse all </button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"min_image_number"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"max_image_number"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"image_numbers"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable collapsed"><span class="token number">0</span></div></li></ul><span class="token punctuation">]</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"total_slots"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"available_slots"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"in_preparation_slots"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"in_sending_slots"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"current_counter"</span>: <span class="token number">0</span></div></li></ul><span class="token punctuation">}</span></code></div></div></div></div></div></div><div class="react-tabs__tab-panel" role="tabpanel" id="panel_R_jj3a_1" aria-labelledby="tab_R_jj3a_1"></div></div></div></div></div></div><div id="/paths/~1version/get" data-section-id="/paths/~1version/get" class="sc-dcJsrY cqVkUp"><div class="sc-kAyceB hBQWIZ"><div class="sc-fqkvVR oJKYx"><h2 class="sc-jXbUNg fWnwAh"><a class="sc-jlZhew kbdRLs" href="#/paths/~1version/get" aria-label="/paths/~1version/get"></a>Get Jungfraujoch version of jfjoch_broker<!-- --> </h2><div><h3 class="sc-fMMURN egoxtT">Responses</h3><div><button class="sc-kzqdkY jgSwKD"><svg class="sc-cwHptR hWEnWx" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">200<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Release number of Jungfraujoch</p>
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/image_buffer/status</div></div></div></div></div><div><h3 class="sc-kpDqfm eBBgSB"> <!-- -->Response samples<!-- --> </h3><div class="sc-bXCLTC dHowgL" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-success react-tabs__tab--selected" role="tab" id="tab_R_jj4a_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_jj4a_0" tabindex="0" data-rttab="true">200</li><li class="tab-error" role="tab" id="tab_R_jj4a_1" aria-selected="false" aria-disabled="false" aria-controls="panel_R_jj4a_1" data-rttab="true">500</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_jj4a_0" aria-labelledby="tab_R_jj4a_0"><div><div class="sc-bbSZdi gCVTxk"><span class="sc-fjvvzt jWReSk">Content type</span><div class="sc-JrDLc iTKzPJ">application/json</div></div><div class="sc-uVWWZ gQROPU"><div class="sc-esYiGF dWQNJI"><div class="sc-koXPp efufqz"><button><div class="sc-fhzFiK kwZDms">Copy</div></button><button> Expand all </button><button> Collapse all </button></div><div tabindex="0" class="sc-eeDRCY gTGgei sc-fXSgeo bnrBiz"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"min_image_number"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"max_image_number"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"image_numbers"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable collapsed"><span class="token number">0</span></div></li></ul><span class="token punctuation">]</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"total_slots"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"available_slots"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"in_preparation_slots"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"in_sending_slots"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"current_counter"</span>: <span class="token number">0</span></div></li></ul><span class="token punctuation">}</span></code></div></div></div></div></div></div><div class="react-tabs__tab-panel" role="tabpanel" id="panel_R_jj4a_1" aria-labelledby="tab_R_jj4a_1"></div></div></div></div></div></div><div id="/paths/~1version/get" data-section-id="/paths/~1version/get" class="sc-dcJsrY cqVkUp"><div class="sc-kAyceB hBQWIZ"><div class="sc-fqkvVR oJKYx"><h2 class="sc-jXbUNg fWnwAh"><a class="sc-jlZhew kbdRLs" href="#/paths/~1version/get" aria-label="/paths/~1version/get"></a>Get Jungfraujoch version of jfjoch_broker<!-- --> </h2><div><h3 class="sc-fMMURN egoxtT">Responses</h3><div><button class="sc-kzqdkY jgSwKD"><svg class="sc-cwHptR hWEnWx" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-dSIIpw bpEYcE">200<!-- --> </strong><div class="sc-eeDRCY sc-eBMEME sc-dCFHLb gTGgei kekOtA kCaLQd"><p>Release number of Jungfraujoch</p>
</div></button></div></div></div><div class="sc-iGgWBj sc-gsFSXq ibAZSi eDeKjd"><div class="sc-ejfMa-d bNUPQg"><button class="sc-EgOXT cFEcOl"><span type="get" class="sc-eZYNyq qGfV http-verb get">get</span><span class="sc-iEXKAA gUNSDu">/version</span><svg class="sc-cwHptR iVFMLx" style="margin-right:-25px" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></button><div aria-hidden="true" class="sc-dlWCHZ kWacYr"><div class="sc-hHOBiw cndTNO"><div class="sc-eeDRCY sc-eBMEME gTGgei fbXBig"><p>Test Jungfraujoch system</p>
</div><div tabindex="0" role="button"><div class="sc-kWtpeL gEncxT"><span>http://localhost:5232</span>/version</div></div></div></div></div></div></div></div></div><div class="sc-dExYaf gZbfaQ"></div></div></div>
<script>
const __redoc_state = {"menu":{"activeItemIdx":-1},"spec":{"data":{"openapi":"3.0.3","info":{"title":"Jungfraujoch","description":"API to control Jungfraujoch developed by the Paul Scherrer Institute (Switzerland).\nJungfraujoch is a data acquisition and analysis system for pixel array detectors, primarly PSI JUNGFRAU.\nJungfraujoch uses FPGA boards to acquire data at high data rates.\n\n# License Clarification\n\nWhile this API definition is licensed under GPL-3.0, **the GPL copyleft provisions do not apply**\nwhen this file is used solely to generate OpenAPI clients or when implementing applications that\ninteract with the API. Generated client code and applications using this API definition are not\nsubject to the GPL license requirements and may be distributed under terms of your choosing.\n\nThis exception is similar in spirit to the Linux Kernel's approach to userspace API headers and\nthe GCC Runtime Library Exception. The Linux Kernel developers have explicitly stated that\nuser programs that merely use the kernel interfaces (syscalls, ioctl definitions, etc.) are not\nderivative works of the kernel and are not subject to the terms of the GPL.\n\nThis exception is intended to allow wider use of this API specification without imposing GPL\nrequirements on applications that merely interact with the API, regardless of whether they\ncommunicate through network calls or other mechanisms.\n","version":"1.0.0-rc.178","contact":{"name":"Filip Leonarski (Paul Scherrer Institute)","email":"filip.leonarski@psi.ch"},"license":{"name":"GPL-3.0","url":"https://www.gnu.org/licenses/gpl-3.0.html"}},"servers":[{"url":"http://localhost:5232","description":"Test Jungfraujoch system"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"Per-dataset secret. `/start` may carry one or more equivalent `tokens`; while the current\ndataset has any, the operations marked with this scheme require `Authorization: Bearer <token>`\nand answer 401 otherwise. A dataset started without `tokens` is not protected and the header is ignored.\n"}},"parameters":{"binning":{"in":"query","name":"binning","required":false,"schema":{"default":1,"type":"integer"},"description":"Binning of frames for the plot (0 = default binning)"},"experimental_coord":{"in":"query","name":"experimental_coord","required":false,"schema":{"type":"boolean","default":false},"description":"If measurement has goniometer axis defined, plot X-axis will represent rotation angle\nIf measurement has grid scan defined, plot X-axis and Y-axis will represent grid position, Z will be used as the final value\nFor still measurement the number is ignored\n"},"azint_unit":{"in":"query","name":"azint_unit","required":false,"schema":{"type":"string","enum":["Q_recipA","d_A","two_theta_deg"],"default":"Q_recipA"},"description":"Unit used for azim int.\n"},"fill_value":{"in":"query","name":"fill","required":false,"schema":{"type":"number","format":"float"},"description":"Fill value for elements that were missed during data collection\n"},"plot_type":{"in":"query","name":"type","required":true,"description":"Type of requested plot","schema":{"type":"string","enum":["bkg_estimate","spindle_blind_fraction","azint","azint_1d","spot_count","spot_count_low_res","spot_count_indexed","spot_count_ice","indexing_rate","indexing_lattice_count","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","integrated_reflections","image_scale_factor","image_scale_cc","compression_ratio","ice_ring_score"]}},"roi":{"in":"query","name":"roi","required":false,"schema":{"type":"string","minLength":1},"description":"Name of ROI for which plot is requested"},"image_id":{"in":"query","name":"id","required":false,"schema":{"type":"integer","format":"int64","default":-1,"minimum":-2},"description":"Image ID in the image buffer. Special values: -1 - last image in the buffer, -2: last indexed image in the buffer"},"saturation":{"in":"query","name":"saturation","required":false,"schema":{"type":"number","format":"float","minimum":-32767,"maximum":32767},"description":"Saturation value to set contrast in the preview image; if not provided, then autocontrast procedure is used"},"background":{"in":"query","name":"background","required":false,"schema":{"type":"number","format":"float","default":0,"minimum":-32767,"maximum":32767},"description":"Background value to set contrast in the preview image"},"show_spots":{"in":"query","name":"show_spots","schema":{"type":"boolean","default":true},"description":"Show spot finding results on the image"},"show_predictions":{"in":"query","name":"show_predictions","schema":Line truncated
const __redoc_state = {"menu":{"activeItemIdx":-1},"spec":{"data":{"openapi":"3.0.3","info":{"title":"Jungfraujoch","description":"API to control Jungfraujoch developed by the Paul Scherrer Institute (Switzerland).\nJungfraujoch is a data acquisition and analysis system for pixel array detectors, primarly PSI JUNGFRAU.\nJungfraujoch uses FPGA boards to acquire data at high data rates.\n\n# License Clarification\n\nWhile this API definition is licensed under GPL-3.0, **the GPL copyleft provisions do not apply**\nwhen this file is used solely to generate OpenAPI clients or when implementing applications that\ninteract with the API. Generated client code and applications using this API definition are not\nsubject to the GPL license requirements and may be distributed under terms of your choosing.\n\nThis exception is similar in spirit to the Linux Kernel's approach to userspace API headers and\nthe GCC Runtime Library Exception. The Linux Kernel developers have explicitly stated that\nuser programs that merely use the kernel interfaces (syscalls, ioctl definitions, etc.) are not\nderivative works of the kernel and are not subject to the terms of the GPL.\n\nThis exception is intended to allow wider use of this API specification without imposing GPL\nrequirements on applications that merely interact with the API, regardless of whether they\ncommunicate through network calls or other mechanisms.\n","version":"1.0.0-rc.178","contact":{"name":"Filip Leonarski (Paul Scherrer Institute)","email":"filip.leonarski@psi.ch"},"license":{"name":"GPL-3.0","url":"https://www.gnu.org/licenses/gpl-3.0.html"}},"servers":[{"url":"http://localhost:5232","description":"Test Jungfraujoch system"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"Per-dataset secret. `/start` may carry one or more equivalent `tokens`; while the current\ndataset has any, the operations marked with this scheme require `Authorization: Bearer <token>`\nand answer 401 otherwise. A dataset started without `tokens` is not protected and the header is ignored.\n"}},"parameters":{"binning":{"in":"query","name":"binning","required":false,"schema":{"default":1,"type":"integer"},"description":"Binning of frames for the plot (0 = default binning)"},"experimental_coord":{"in":"query","name":"experimental_coord","required":false,"schema":{"type":"boolean","default":false},"description":"If measurement has goniometer axis defined, plot X-axis will represent rotation angle\nIf measurement has grid scan defined, plot X-axis and Y-axis will represent grid position, Z will be used as the final value\nFor still measurement the number is ignored\n"},"azint_unit":{"in":"query","name":"azint_unit","required":false,"schema":{"type":"string","enum":["Q_recipA","d_A","two_theta_deg"],"default":"Q_recipA"},"description":"Unit used for azim int.\n"},"fill_value":{"in":"query","name":"fill","required":false,"schema":{"type":"number","format":"float"},"description":"Fill value for elements that were missed during data collection\n"},"plot_type":{"in":"query","name":"type","required":true,"description":"Type of requested plot","schema":{"type":"string","enum":["bkg_estimate","spindle_blind_fraction","azint","azint_1d","spot_count","spot_count_low_res","spot_count_indexed","spot_count_ice","indexing_rate","indexing_lattice_count","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","integrated_reflections","image_scale_factor","image_scale_cc","compression_ratio","ice_ring_score"]}},"roi":{"in":"query","name":"roi","required":false,"schema":{"type":"string","minLength":1},"description":"Name of ROI for which plot is requested"},"image_id":{"in":"query","name":"id","required":false,"schema":{"type":"integer","format":"int64","default":-1,"minimum":-2},"description":"Image ID in the image buffer. Special values: -1 - last image in the buffer, -2: last indexed image in the buffer"},"saturation":{"in":"query","name":"saturation","required":false,"schema":{"type":"number","format":"float","minimum":-32767,"maximum":32767},"description":"Saturation value to set contrast in the preview image; if not provided, then autocontrast procedure is used"},"background":{"in":"query","name":"background","required":false,"schema":{"type":"number","format":"float","default":0,"minimum":-32767,"maximum":32767},"description":"Background value to set contrast in the preview image"},"show_spots":{"in":"query","name":"show_spots","schema":{"type":"boolean","default":true},"description":"Show spot finding results on the image"},"show_predictions":{"in":"query","name":"show_predictions","schema":Line truncated
var container = document.getElementById('redoc');
Redoc.hydrate(__redoc_state, container);
+16
View File
@@ -0,0 +1,16 @@
// SPDX-FileCopyrightText: 2026 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
// SPDX-License-Identifier: GPL-3.0-only
#include "AssembleToPlane.h"
#include <algorithm>
PlaneRaster PlaneRasterOf(const DetectorModules &modules, int64_t width, int64_t height) {
if (modules.empty())
return {0, 0, width, height};
// Raster pixel centres are whole plane coordinates; the first and last that lie on the footprints.
const PlaneBox box = modules.PlaneBounds(width, height);
const auto x0 = std::min<int64_t>(0, static_cast<int64_t>(std::ceil(box.x0)));
const auto y0 = std::min<int64_t>(0, static_cast<int64_t>(std::ceil(box.y0)));
return {x0, y0, static_cast<int64_t>(std::ceil(box.x1)) - x0, static_cast<int64_t>(std::ceil(box.y1)) - y0};
}
+68
View File
@@ -0,0 +1,68 @@
// SPDX-FileCopyrightText: 2026 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
// SPDX-License-Identifier: GPL-3.0-only
#pragma once
#include <algorithm>
#include <cmath>
#include <cstdint>
#include <vector>
#include "DetectorModules.h"
// The detector plane as a picture: raster pixel (i, j) is the plane point (x0 + i, y0 + j). For the
// algorithms that need the detector as it really is - a beam-stop shadow and the gaps it crosses, the point
// symmetry about the beam, a picture of the detector - and not as the panels are stored.
struct PlaneRaster {
int64_t x0 = 0, y0 = 0, width = 0, height = 0;
};
// The raster holding every panel. It starts at the plane origin, so plane and raster coordinates agree,
// unless a panel lies left of or above it. Empty table: the image itself.
PlaneRaster PlaneRasterOf(const DetectorModules &modules, int64_t width, int64_t height);
// The image (width x height) as the plane raster: each raster pixel takes the image pixel nearest its centre
// on the panel it falls on, and `gap` where it falls on none. Empty table, with the image's own raster: a copy.
template<class T>
std::vector<T> AssembleToPlane(const DetectorModules &modules, const std::vector<T> &image,
int64_t width, int64_t height, const PlaneRaster &raster, T gap) {
std::vector<T> out(static_cast<size_t>(raster.width * raster.height), gap);
const auto put = [&](const DetectorModule &m, int64_t i0, int64_t i1, int64_t j0, int64_t j1) {
for (int64_t j = std::max<int64_t>(j0, 0); j < std::min(j1, raster.height); j++)
for (int64_t i = std::max<int64_t>(i0, 0); i < std::min(i1, raster.width); i++) {
const auto [x, y] = m.PlaneToImage(static_cast<double>(raster.x0 + i),
static_cast<double>(raster.y0 + j));
if (m.ContainsImagePixel(x, y))
out[j * raster.width + i] = image[static_cast<size_t>(std::floor(y + 0.5)) * width
+ static_cast<size_t>(std::floor(x + 0.5))];
}
};
if (modules.empty()) {
put(DetectorModule::AsImaged(0, 0, width, height), -raster.x0, width - raster.x0, -raster.y0,
height - raster.y0);
return out;
}
// Panel by panel, over the raster pixels of its footprint's box. Panels do not overlap.
for (const auto &m: modules.Get()) {
const PlaneBox box = DetectorModules({m}).PlaneBounds(width, height);
put(m, static_cast<int64_t>(std::floor(box.x0)) - raster.x0, static_cast<int64_t>(std::ceil(box.x1)) - raster.x0,
static_cast<int64_t>(std::floor(box.y0)) - raster.y0, static_cast<int64_t>(std::ceil(box.y1)) - raster.y0);
}
return out;
}
// The reverse, for a result computed on the raster: each image pixel on a panel takes the raster pixel
// nearest its centre on the plane, `outside` where that is off the raster; a pixel on no panel (a gap)
// is `outside` too. Empty table, with the image's own raster: a copy.
template<class T>
std::vector<T> GatherFromPlane(const DetectorModules &modules, const std::vector<T> &plane,
const PlaneRaster &raster, int64_t width, int64_t height, T outside) {
std::vector<T> out(static_cast<size_t>(width * height), outside);
modules.ForEachPixel(width, height, [&](int64_t, size_t index, double px, double py) {
const auto i = static_cast<int64_t>(std::floor(px + 0.5)) - raster.x0;
const auto j = static_cast<int64_t>(std::floor(py + 0.5)) - raster.y0;
if (i >= 0 && i < raster.width && j >= 0 && j < raster.height)
out[index] = plane[j * raster.width + i];
});
return out;
}
+22 -10
View File
@@ -14,6 +14,7 @@
#include "RawToConvertedGeometry.h"
#include "TableChecksum.h"
#include "ParallelFor.h"
#include "PanelRows.h"
AzimuthalIntegrationMapping::AzimuthalIntegrationMapping(const DiffractionExperiment &experiment,
const PixelMask &mask,
@@ -36,7 +37,8 @@ AzimuthalIntegrationMapping::AzimuthalIntegrationMapping(const DiffractionExperi
// transformed, raw when it is not. They have to match pixel_to_bin, which is sized per mode
// below - the adaptive spot finders walk the image with these and index pixel_to_bin with it.
width(experiment.GetXPixelsNum()),
height(experiment.GetYPixelsNum()) {
height(experiment.GetYPixelsNum()),
modules(experiment.GetModules()) {
if (width <= 0)
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
@@ -74,10 +76,13 @@ AzimuthalIntegrationMapping::AzimuthalIntegrationMapping(const DiffractionExperi
void AzimuthalIntegrationMapping::SetupConvGeomRows(const DiffractionGeometry &geom, const std::vector<uint32_t> *mask,
size_t row0, size_t row_end) {
for (size_t row = row0; row < row_end && row < height; row++) {
for (size_t col = 0; col < width; col++)
SetupPixel(geom, mask, row * width + col, col, row);
}
// Each pixel at its place on the plane. A pixel on no panel keeps what a masked one has.
ForEachPixelInRows(modules, static_cast<int64_t>(width), static_cast<int64_t>(row0),
static_cast<int64_t>(std::min(row_end, height)),
[&](int64_t, size_t pxl, double px, double py) {
SetupPixel(geom, mask, static_cast<uint32_t>(pxl), static_cast<float>(px),
static_cast<float>(py));
});
}
void AzimuthalIntegrationMapping::SetupConvGeom(const DiffractionGeometry &geom, const std::vector<uint32_t> *mask) {
@@ -127,6 +132,15 @@ void AzimuthalIntegrationMapping::SetupConvGeomCached(const DiffractionGeometry
static_cast<uint32_t>(settings.IsPolarizationCorrection()),
static_cast<uint32_t>(polarization_factor.has_value()),
static_cast<uint32_t>(width), static_cast<uint32_t>(height)});
// The panel table: the same geometry places the pixels elsewhere when a panel has moved.
for (const auto &m: modules.Get()) {
for (const int64_t i: {m.x0, m.y0, m.width, m.height})
key.push_back(static_cast<uint32_t>(i));
for (const double d: {m.ox, m.oy, m.fx, m.fy, m.sx, m.sy}) {
const auto bits = std::bit_cast<uint64_t>(d);
key.insert(key.end(), {static_cast<uint32_t>(bits), static_cast<uint32_t>(bits >> 32)});
}
}
std::lock_guard lock(cache.m);
auto &entries = cache.entries;
@@ -169,7 +183,7 @@ void AzimuthalIntegrationMapping::SetupRawGeom(const DiffractionExperiment &expe
for (int m = 0; m < experiment.GetModulesNum(); m++) {
for (int pxl = 0; pxl < RAW_MODULE_SIZE; pxl++) {
auto [x,y] = RawToConvertedCoordinate(experiment, m, pxl);
SetupPixel(geom, &mask, m * RAW_MODULE_SIZE + pxl, x, y);
SetupPixel(geom, &mask, m * RAW_MODULE_SIZE + pxl, static_cast<float>(x), static_cast<float>(y));
}
}
} else {
@@ -185,7 +199,7 @@ void AzimuthalIntegrationMapping::SetupRawGeom(const DiffractionExperiment &expe
for (size_t m = module_begin; m < module_end; ++m) {
for (int pxl = 0; pxl < RAW_MODULE_SIZE; ++pxl) {
auto [x, y] = RawToConvertedCoordinate(experiment, m, pxl);
SetupPixel(geom, &mask, m * RAW_MODULE_SIZE + pxl, x, y);
SetupPixel(geom, &mask, m * RAW_MODULE_SIZE + pxl, static_cast<float>(x), static_cast<float>(y));
}
}
}));
@@ -198,12 +212,10 @@ void AzimuthalIntegrationMapping::SetupRawGeom(const DiffractionExperiment &expe
void AzimuthalIntegrationMapping::SetupPixel(const DiffractionGeometry &geom,
const std::vector<uint32_t> *mask,
uint32_t pxl, uint32_t col, uint32_t row) {
uint32_t pxl, float x, float y) {
if (mask && (*mask)[pxl] != 0)
return;
auto x = static_cast<float>(col);
auto y = static_cast<float>(row);
float d = geom.PxlToRes(x, y);
float phi_rad = geom.Phi_rad(x, y);
+6 -2
View File
@@ -22,7 +22,7 @@ class AzimuthalIntegrationGeometryCache {
friend class AzimuthalIntegrationMapping;
static constexpr size_t MAX_ENTRIES = 6;
struct Entry {
std::vector<uint32_t> key; // bit patterns of everything SetupPixel reads
std::vector<uint32_t> key; // bit patterns of everything SetupPixel reads, and the panel table
std::vector<uint16_t> pixel_to_bin;
std::vector<float> pixel_resolution;
std::vector<float> corrections;
@@ -36,6 +36,9 @@ protected:
const AzimuthalIntegrationSettings settings;
const float wavelength;
const size_t width, height;
// Where the image's pixels are on the plane the geometry describes; empty when they are where the
// image has them.
const DetectorModules modules;
std::vector<float> bin_to_q;
std::vector<float> bin_to_2theta;
@@ -76,8 +79,9 @@ protected:
void SetupConvGeomCached(const DiffractionGeometry &geom, const std::vector<uint32_t> &mask,
AzimuthalIntegrationGeometryCache &cache);
// Pixel pxl of the image, at (x, y) on the plane.
void SetupPixel(const DiffractionGeometry &geom, const std::vector<uint32_t> *mask,
uint32_t pxl, uint32_t col, uint32_t row);
uint32_t pxl, float x, float y);
AzimuthalIntegrationMapping(const DiffractionExperiment& experiment,
const PixelMask& mask,
+11
View File
@@ -177,6 +177,17 @@ float BraggIntegrationSettings::GetBackgroundPixelGain() const {
return bkg_pixel_gain;
}
BraggIntegrationSettings &BraggIntegrationSettings::PixelGain(float input) {
check_finite("Pixel gain", input);
check_min("Pixel gain", input, 1.0);
pixel_gain = input;
return *this;
}
float BraggIntegrationSettings::GetPixelGain() const {
return pixel_gain;
}
BraggIntegrationSettings &BraggIntegrationSettings::BackgroundRadialCorrection(std::optional<bool> input) {
bkg_radial_correction = input;
return *this;
+9
View File
@@ -103,6 +103,13 @@ class BraggIntegrationSettings {
// there the photon clip cuts the background's upper tail at about 2 sigma and adds a positive offset
// to every reflection. Set by rugnux from the pre-scan for SMV and marCCD input (BackgroundGain.h).
float bkg_pixel_gain = 1.0f;
// Detector units per photon of the integrated intensities. Above 1 the variances the integrator
// forms - the box sum's, the profile fit's and the background's - are taken at this many ADU per
// photon, so the strong-spot selection and the profile/summation guard compare in photons, and
// each reflection leaves the integrator converted to photons (I, sigma, bkg, var_bkg), which is
// what the merge's own variance model (var_bkg + I) assumes. Set by rugnux for rotation sweeps of a
// CCD from the same measurement as bkg_pixel_gain; 1 for a detector that counts photons.
float pixel_gain = 1.0f;
// Radial background curvature correction. The signal disk and the background annulus are
// concentric, so for ANY background linear in position their means are equal - a plane fit buys
// nothing and the leading error is the CURVATURE of the radial background, which the flat annulus
@@ -181,6 +188,7 @@ public:
BraggIntegrationSettings& BackgroundTrimFraction(float input);
BraggIntegrationSettings& BackgroundClipNSigma(float input);
BraggIntegrationSettings& BackgroundPixelGain(float input);
BraggIntegrationSettings& PixelGain(float input);
BraggIntegrationSettings& BackgroundRadialCorrection(std::optional<bool> input);
BraggIntegrationSettings& MaxHKL(std::optional<int> input);
BraggIntegrationSettings& Overlap(OverlapMode input);
@@ -202,6 +210,7 @@ public:
[[nodiscard]] float GetBackgroundTrimFraction() const;
[[nodiscard]] float GetBackgroundClipNSigma() const;
[[nodiscard]] float GetBackgroundPixelGain() const;
[[nodiscard]] float GetPixelGain() const;
// Unset = auto (gate per image on the smooth-ice score); see bkg_radial_correction.
[[nodiscard]] std::optional<bool> GetBackgroundRadialCorrection() const;
[[nodiscard]] std::optional<int> GetMaxHKL() const;
+5
View File
@@ -132,6 +132,11 @@ ADD_LIBRARY(JFJochCommon STATIC
DetectorGeometryModular.h
DetectorModules.cpp
DetectorModules.h
PanelRows.h
PanelBoxes.cpp
PanelBoxes.h
AssembleToPlane.cpp
AssembleToPlane.h
ModuleShift.h
DetectorGeometryFixed.cpp
DetectorGeometryFixed.h
+41
View File
@@ -112,6 +112,47 @@ std::pair<double, double> DetectorModules::PlaneToImage(double px, double py) co
return modules[m].PlaneToImage(px, py);
}
std::pair<double, double> DetectorModules::ImageToPlane(int64_t panel, double x, double y) const {
if (panel < 0)
return {x, y};
return modules.at(panel).ImageToPlane(x, y);
}
std::pair<double, double> DetectorModules::PlaneToImage(int64_t panel, double px, double py) const {
if (panel < 0)
return {px, py};
return modules.at(panel).PlaneToImage(px, py);
}
std::optional<PanelPoint> DetectorModules::PlaneToPanel(double px, double py) const {
if (modules.empty())
return PanelPoint{-1, px, py};
for (size_t i = 0; i < modules.size(); i++) {
const auto [x, y] = modules[i].PlaneToImage(px, py);
if (modules[i].ContainsImagePixel(x, y))
return PanelPoint{static_cast<int64_t>(i), x, y};
}
return std::nullopt;
}
PlaneBox DetectorModules::PlaneBounds(int64_t width, int64_t height) const {
if (modules.empty())
return {0.0, 0.0, static_cast<double>(width), static_cast<double>(height)};
PlaneBox box{INFINITY, INFINITY, -INFINITY, -INFINITY};
for (const auto &m: modules) {
const double xa = static_cast<double>(m.x0) - 0.5, xb = static_cast<double>(m.x0 + m.width) - 0.5;
const double ya = static_cast<double>(m.y0) - 0.5, yb = static_cast<double>(m.y0 + m.height) - 0.5;
for (const auto &[x, y]: {std::pair{xa, ya}, std::pair{xb, ya}, std::pair{xa, yb}, std::pair{xb, yb}}) {
const auto [px, py] = m.ImageToPlane(x, y);
box.x0 = std::min(box.x0, px);
box.y0 = std::min(box.y0, py);
box.x1 = std::max(box.x1, px);
box.y1 = std::max(box.y1, py);
}
}
return box;
}
void DetectorModules::Apply(const std::vector<ModuleShift> &shifts) {
for (auto &m: modules) {
const auto [cx, cy] = m.PlaneCentre();
+47
View File
@@ -5,6 +5,7 @@
#include <cstddef>
#include <cstdint>
#include <optional>
#include <utility>
#include <vector>
@@ -39,7 +40,20 @@ struct DetectorModule {
void Apply(const ModuleShift &shift);
};
// A point in the image rugnux reads, on panel `panel` (an index into DetectorModules; -1 when the table is
// empty and the whole image is one flat panel).
struct PanelPoint {
int64_t panel;
double x, y;
};
// An axis-aligned box on the detector plane, x0 <= x < x1, y0 <= y < y1.
struct PlaneBox {
double x0, y0, x1, y1;
};
// The modules of one detector. Empty means the image is one flat detector: every mapping is the identity.
// A module is a panel: one rigid box of the image with one placement. Panel ids are indices into the table.
class DetectorModules {
std::vector<DetectorModule> modules;
public:
@@ -64,6 +78,39 @@ public:
// Plane -> image; a point on no placed module is left as it is.
[[nodiscard]] std::pair<double, double> PlaneToImage(double px, double py) const;
// Image <-> plane on a known panel, no search. Panel -1 (the empty table) is the identity.
[[nodiscard]] std::pair<double, double> ImageToPlane(int64_t panel, double x, double y) const;
[[nodiscard]] std::pair<double, double> PlaneToImage(int64_t panel, double px, double py) const;
// The panel whose placed footprint holds a plane point, and where that point is in the image; nullopt in
// a gap or off every panel. Empty table: panel -1 and the point itself, wherever it is - the caller
// bounds it by the image, as without panels.
[[nodiscard]] std::optional<PanelPoint> PlaneToPanel(double px, double py) const;
// Box on the plane enclosing every panel's pixels (their footprints, half a pixel beyond the edge pixel
// centres): a quick reject before PlaneToPanel. Empty table: [0, width) x [0, height), the image
// rectangle the bounds tests without panels use.
[[nodiscard]] PlaneBox PlaneBounds(int64_t width, int64_t height) const;
// Calls f(panel, index, px, py) for every image pixel on a panel - panel by panel, row by row - with
// index = y * width + x in the image and (px, py) its centre on the plane. Pixels on no panel (gaps) are
// not visited. Empty table: one panel -1 that is the whole image, plane == image.
template<class F>
void ForEachPixel(int64_t width, int64_t height, F &&f) const {
if (modules.empty()) {
for (int64_t y = 0; y < height; y++)
for (int64_t x = 0; x < width; x++)
f(int64_t(-1), static_cast<size_t>(y * width + x), static_cast<double>(x), static_cast<double>(y));
return;
}
for (size_t p = 0; p < modules.size(); p++) {
const DetectorModule &m = modules[p];
for (int64_t y = m.y0; y < m.y0 + m.height; y++)
for (int64_t x = m.x0; x < m.x0 + m.width; x++) {
const auto [px, py] = m.ImageToPlane(static_cast<double>(x), static_cast<double>(y));
f(static_cast<int64_t>(p), static_cast<size_t>(y * width + x), px, py);
}
}
}
// Each module moved by the shift whose centre is nearest its own plane centre (and within it).
void Apply(const std::vector<ModuleShift> &shifts);
// The modules as refinement starting points: their plane centres, no move.
+6 -5
View File
@@ -652,6 +652,7 @@ SpotFindingSettings DiffractionExperiment::DefaultDataProcessingSettings() {
void DiffractionExperiment::FillMessage(StartMessage &message) const {
message.images_per_file = GetImagesPerFile();
message.detector_modules = GetModules().Get();
message.beam_center_x = GetBeamX_pxl();
message.beam_center_y = GetBeamY_pxl();
const auto direct_beam = GetDiffractionGeometry().GetDirectBeam_pxl();
@@ -1160,7 +1161,7 @@ const ROIMap &DiffractionExperiment::ROI() const {
}
std::vector<uint16_t> DiffractionExperiment::ExportROIMap() const {
return roi_mask.GetROIMap(GetDiffractionGeometry(), GetXPixelsNumConv(), GetYPixelsNumConv());
return roi_mask.GetROIMap(GetDiffractionGeometry(), GetModules(), GetXPixelsNumConv(), GetYPixelsNumConv());
}
DiffractionExperiment &DiffractionExperiment::ImagesPerFile(const std::optional<int64_t> &input) {
@@ -1419,13 +1420,13 @@ float DiffractionExperiment::GetDetectorMaxResolution_A() const {
float DiffractionExperiment::GetDetectorMaxQ_recipA() const {
const DiffractionGeometry geom = GetDiffractionGeometry();
const auto width = static_cast<float>(GetXPixelsNumConv());
const auto height = static_cast<float>(GetYPixelsNumConv());
// The plane the panels span; without panels the image.
const PlaneBox box = GetModules().PlaneBounds(GetXPixelsNumConv(), GetYPixelsNumConv());
// The largest scattering angle sits at one of the detector corners, wherever the beam centre is.
float q = 0.0f;
for (const float x: {0.0f, width})
for (const float y: {0.0f, height})
for (const float x: {static_cast<float>(box.x0), static_cast<float>(box.x1)})
for (const float y: {static_cast<float>(box.y0), static_cast<float>(box.y1)})
q = std::max(q, geom.PxlToQ(x, y));
return q;
}
+13 -3
View File
@@ -24,8 +24,9 @@ DiffractionSpot& DiffractionSpot::operator+=(const DiffractionSpot &other) {
}
DiffractionSpot::DiffractionSpot(int64_t x_sum, int64_t y_sum, int64_t in_pixel_count,
int64_t in_photons, int64_t in_max_photons)
: x(x_sum), y(y_sum), pixel_count(in_pixel_count), photons(in_photons), max_photons(in_max_photons) {}
int64_t in_photons, int64_t in_max_photons, int64_t in_panel)
: x(x_sum), y(y_sum), pixel_count(in_pixel_count), photons(in_photons), max_photons(in_max_photons),
panel(in_panel) {}
int64_t DiffractionSpot::Count() const {
return photons;
@@ -44,6 +45,14 @@ Coord DiffractionSpot::RawCoord() const {
static_cast<float>(static_cast<double>(y) / static_cast<double>(photons)), 0};
}
int64_t DiffractionSpot::Panel() const {
return panel;
}
void DiffractionSpot::Panel(int64_t in_panel) {
panel = in_panel;
}
int64_t DiffractionSpot::PixelCount() const {
return pixel_count;
}
@@ -99,6 +108,7 @@ std::optional<SpotToSave> DiffractionSpot::Export(const DiffractionGeometry &geo
.image = image_num,
.d_A = d,
.ice_ring = false,
.indexed = false
.indexed = false,
.panel = static_cast<int16_t>(panel)
};
}
+5 -1
View File
@@ -21,17 +21,21 @@ class DiffractionSpot {
int64_t pixel_count = 0;
int64_t photons = 0; // total photon count
int64_t max_photons = INT64_MIN; // maximum number of counts per pixel in the spot
int64_t panel = -1; // the panel (DetectorModules index) the spot was found on; -1 = no panel table
public:
DiffractionSpot() = default;
DiffractionSpot(uint32_t col, uint32_t line, int64_t photons);
// From already-summed quantities, i.e. the members as AddPixel leaves them, NOT a centroid.
// Used by the GPU spot extractor, which computes those sums on the device.
DiffractionSpot(int64_t x_sum, int64_t y_sum, int64_t pixel_count, int64_t photons, int64_t max_photons);
DiffractionSpot(int64_t x_sum, int64_t y_sum, int64_t pixel_count, int64_t photons, int64_t max_photons,
int64_t panel = -1);
DiffractionSpot& operator+=(const DiffractionSpot& spot);
int64_t PixelCount() const;
int64_t Count() const;
int64_t MaxCount() const;
Coord RawCoord() const;
int64_t Panel() const;
void Panel(int64_t panel);
void ConvertToImageCoordinates(const DiffractionExperiment& experiment, uint16_t module_number);
std::optional<SpotToSave> Export(const DiffractionGeometry &geometry, int64_t image_num = 0) const;
void AddPixel(uint32_t col, uint32_t line, int64_t photons);
+12
View File
@@ -24,6 +24,7 @@
#include "CrystalLattice.h"
#include "IndexingSettings.h"
#include "XrayFluorescenceSpectrum.h"
#include "DetectorModules.h"
#include "../gemmi_gph/gemmi/symmetry.hpp"
constexpr const uint64_t user_data_release = 6;
@@ -324,6 +325,10 @@ struct StartMessage {
// Per-pixel ROI bitmask (converted geometry), bit i set for ROI i in rois.
std::vector<uint16_t> roi_map;
// The detector's panels (DetectorModules.h), where the image's pixels are on the detector plane. Empty
// for one flat detector, the image being the plane; then the CBOR key is absent.
std::vector<DetectorModule> detector_modules;
std::map<std::string, float> threshold_energy;
std::optional<float> total_flux;
@@ -391,6 +396,13 @@ struct PlacedModelMessage {
std::vector<double> x, y, z;
std::vector<float> b_iso, occupancy;
std::vector<float> aniso; // 6 per atom (u11 u22 u33 u12 u13 u23), empty when none has one
// mmCIF label_asym_id, label_entity_id and label_seq_id per atom (label_seq INT32_MIN where none); empty
// in a block from before they were carried
std::vector<std::string> subchain, entity_id;
std::vector<int32_t> label_seq;
// The input model's metadata - entities, sequences, references, authors, software, secondary structure -
// as the mmCIF categories gemmi writes for them, without coordinates; empty where there is none
std::string metadata_mmcif;
};
struct EndMessage {
+17
View File
@@ -0,0 +1,17 @@
// SPDX-FileCopyrightText: 2026 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
// SPDX-License-Identifier: GPL-3.0-only
#include "PanelBoxes.h"
std::vector<PanelBox> PanelBoxes(const DetectorModules &modules, int64_t width, int64_t height) {
if (modules.empty())
return {PanelBox{0, 0, static_cast<int32_t>(width), static_cast<int32_t>(height), -1}};
std::vector<PanelBox> out;
for (size_t p = 0; p < modules.size(); p++) {
const DetectorModule &m = modules[p];
out.push_back(PanelBox{static_cast<int32_t>(m.x0), static_cast<int32_t>(m.y0),
static_cast<int32_t>(m.x0 + m.width), static_cast<int32_t>(m.y0 + m.height),
static_cast<int32_t>(p)});
}
return out;
}
+23
View File
@@ -0,0 +1,23 @@
// SPDX-FileCopyrightText: 2026 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
// SPDX-License-Identifier: GPL-3.0-only
#pragma once
#include <cstdint>
#include <vector>
#include "DetectorModules.h"
// One panel's box in the image rugnux reads, x0 <= x < x1, y0 <= y < y1, and its id in DetectorModules
// (-1 for the one panel of an empty table). What the neighbourhood algorithms on the image - the spot
// finders' windows, the connected-component search, the squares read about a spot - stay inside, the way
// the FPGA spot finder stays inside a JUNGFRAU module: stacked panels lie next to each other in the image
// and far apart on the detector.
struct PanelBox {
int32_t x0, y0, x1, y1;
int32_t panel;
};
// One box per panel. An empty table gives one box, the whole image, so whatever is clamped to it is
// clamped to the image exactly as without panels.
std::vector<PanelBox> PanelBoxes(const DetectorModules &modules, int64_t width, int64_t height);
+39
View File
@@ -0,0 +1,39 @@
// SPDX-FileCopyrightText: 2026 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
// SPDX-License-Identifier: GPL-3.0-only
#pragma once
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <vector>
#include "DetectorModules.h"
// DetectorModules::ForEachPixel cut to the image rows [row0, row1), so that a dense map can be built a band
// of rows per thread. Calls f(panel, index, px, py) for every pixel of those rows that is on a panel, in
// index order: row by row, and within a row panel by panel from left to right. Pixels on no panel are not
// visited. Empty table: every pixel of the rows, panel -1, plane == image.
template<class F>
void ForEachPixelInRows(const DetectorModules &modules, int64_t width, int64_t row0, int64_t row1, F &&f) {
if (modules.empty()) {
for (int64_t y = row0; y < row1; y++)
for (int64_t x = 0; x < width; x++)
f(int64_t(-1), static_cast<size_t>(y * width + x), static_cast<double>(x), static_cast<double>(y));
return;
}
const auto &m = modules.Get();
std::vector<int64_t> on_row;
for (int64_t y = row0; y < row1; y++) {
on_row.clear();
for (size_t p = 0; p < m.size(); p++)
if (y >= m[p].y0 && y < m[p].y0 + m[p].height)
on_row.push_back(static_cast<int64_t>(p));
std::sort(on_row.begin(), on_row.end(), [&](int64_t a, int64_t b) { return m[a].x0 < m[b].x0; });
for (const int64_t p: on_row)
for (int64_t x = m[p].x0; x < m[p].x0 + m[p].width; x++) {
const auto [px, py] = m[p].ImageToPlane(static_cast<double>(x), static_cast<double>(y));
f(p, static_cast<size_t>(y * width + x), px, py);
}
}
}
+10 -8
View File
@@ -4,20 +4,22 @@
#include "JFJochMath.h"
#include "ROIMap.h"
#include "JFJochException.h"
#include "PanelRows.h"
std::vector<uint16_t> ROIMap::GetROIMap(const DiffractionGeometry &geom, size_t xpixel, size_t ypixel) const {
std::vector<uint16_t> ROIMap::GetROIMap(const DiffractionGeometry &geom, const DetectorModules &modules,
size_t xpixel, size_t ypixel) const {
std::vector<uint16_t> map(xpixel * ypixel, 0);
std::vector<float> resolution_map(xpixel * ypixel, 0);
std::vector<float> phi_map;
if (!rois.azimuthal.empty()) {
phi_map.resize(xpixel * ypixel, 0);
for (int y = 0; y < ypixel; y++) {
for (int x = 0; x < xpixel; x++) {
resolution_map[y * xpixel + x] = geom.PxlToRes(static_cast<float>(x), static_cast<float>(y));
phi_map[y * xpixel + x] = geom.Phi_rad(static_cast<float>(x), static_cast<float>(y))
* 180.0f / static_cast<float>(PI);
}
}
// A pixel on no panel keeps resolution and angle 0.
ForEachPixelInRows(modules, static_cast<int64_t>(xpixel), 0, static_cast<int64_t>(ypixel),
[&](int64_t, size_t i, double px, double py) {
const auto x = static_cast<float>(px), y = static_cast<float>(py);
resolution_map[i] = geom.PxlToRes(x, y);
phi_map[i] = geom.Phi_rad(x, y) * 180.0f / static_cast<float>(PI);
});
}
uint16_t roi_id = 0;
+5 -1
View File
@@ -11,6 +11,7 @@
#include "DetectorSetup.h"
#include "ROIDefinition.h"
#include "DiffractionGeometry.h"
#include "DetectorModules.h"
class ROIMap {
ROIDefinition rois;
@@ -18,7 +19,10 @@ class ROIMap {
static constexpr const size_t roi_limit = 16;
public:
void SetROI(const ROIDefinition& input);
[[nodiscard]] std::vector<uint16_t> GetROIMap(const DiffractionGeometry &geom, size_t width, size_t height) const;
// Box and circle ROIs are drawn in image pixels; azimuthal ROIs at each pixel's place on the plane
// (`modules`, empty when that is where the image has it).
[[nodiscard]] std::vector<uint16_t> GetROIMap(const DiffractionGeometry &geom, const DetectorModules &modules,
size_t width, size_t height) const;
[[nodiscard]] std::map<std::string, uint16_t> GetROINameMap() const;
[[nodiscard]] const ROIDefinition& GetROIDefinition() const;
[[nodiscard]] bool empty() const;
+1
View File
@@ -18,6 +18,7 @@ struct SpotToSave {
float dist_ewald_sphere = 0.0;
bool ice_ring = false;
bool indexed = false;
int16_t panel = -1; // index into the experiment's DetectorModules; -1 = no panel table
Coord ReciprocalCoord(const DiffractionGeometry &experiment) const;
};
+6
View File
@@ -541,6 +541,12 @@ This software uses the Viridis, Magma and Inferno colormaps from Matplotlib unde
BSD-compatible license. J. D. Hunter, "Matplotlib: A 2D graphics environment" (2007), Comput. Sci.
Eng. 9, 90-95 [doi:10.1109/MCSE.2007.55](https://doi.org/10.1109/MCSE.2007.55).
The Mol* structure viewer of the web frontend follows the setup Guillaume Gotthard (PSI) tuned for
[AareDB](https://gitea.psi.ch/mx/aaredb), the sample-management and data-pipeline system of the PSI MX
beamlines: its Coot-style mouse controls and trackball, the model representations and colours, and the
display of the density maps (carved wireframe meshes at absolute levels from the whole cell's
statistics, contour-level defaults and colours).
## File formats read from a published specification
**CBF / imgCIF** - the native miniCBF reader implements the `x-CBF_BYTE_OFFSET` compression scheme
+3 -1
View File
@@ -32,6 +32,7 @@ There are minor differences at the moment:
| mirror_y | bool | Whether the assembled image is mirrored in Y relative to the detector's raw readout order. True is the MX convention - row 0 at the top of the detector seen from the sample - and is what absence of the key means | |
| detector_orientation_mirror_y | bool | Whether the assembled image is mirrored in Y relative to the frame the PONI angles are stated in. A different setting from `mirror_y` above, which is about the module layout; this one changes no pixel. Absence means false | |
| detector_orientation_quarter_turns | int | How many multiples of 90 degrees about the beam the assembled image is turned by, relative to the frame the PONI angles are stated in (0-3). Absence means 0 | |
| detector_modules | Array(object) (optional) | Panels: where the image's pixels lie on the detector plane the geometry describes. Each has `x0`, `y0`, `width`, `height` (int, the panel's box in the image) and `ox`, `oy`, `fx`, `fy`, `sx`, `sy` (double, plane pixels): image pixel (x, y) of the panel is at `(ox, oy) + (x - x0) (fx, fy) + (y - y0) (sx, sy)`. Absent for a flat detector, the image being the plane; spot and reflection positions are always plane coordinates | |
| incident_energy | float | X-ray energy \[eV\] | X |
| incident_wavelength | float | X-ray wavelength \[Angstrom\] | X |
| incident_wavelength_spread | float (optional) | FWHM of the X-ray wavelength distribution \[Angstrom\] (NXmx incident_wavelength_spread); omitted when the beam is monochromatic | |
@@ -150,6 +151,7 @@ See [DECTRIS documentation](https://github.com/dectris/documentation/tree/main/s
| - indexed | bool | indexed solution | | |
| - latt | int64 | Lattice to which the peak belongs (negative number = not indexed) | | |
| - image | int64 | image number the spot belongs to | | |
| - panel | int64 (optional) | panel (index into `detector_modules`) the spot was found on; absent for a detector without a panel table | | |
| - h | int64 | Miller index (indexed spots only) | | |
| - k | int64 | Miller index (indexed spots only) | | |
| - l | int64 | Miller index (indexed spots only) | | |
@@ -344,7 +346,7 @@ See [DECTRIS documentation](https://github.com/dectris/documentation/tree/main/s
| image_scale_cc | Array(float) | Scaling result: Image scale CC | |
| merged | object (optional) | Merged reflections of an in-broker analysis run, written by the writer as `<file_prefix>.mtz`. An MTZ table (layout below) | |
| map_coefficients | object (optional) | Map coefficients of an in-broker analysis run, written as `<file_prefix>_maps.mtz`. An MTZ table (layout below) | |
| placed_model | object (optional) | Atomic model placed against the data, written as `<file_prefix>_model.cif` and `<file_prefix>_model.pdb`. `name` (string), `unit_cell` (object, as above), `space_group_name` (the data's, gemmi extended H-M), `model_space_group_name` (the coordinates'), then one array per atom: `model_number`, `seq_num`, `charge` (int32), `chain`, `residue_name`, `atom_name`, `element` (Array(string)), `icode` (uint8, space where none), `het_flag` (uint8, `A`, `H` or 0 where unknown), `altloc` (uint8, 0 where none), `x`, `y`, `z` (double, Angstrom), `b_iso`, `occupancy` (float), `aniso` (float, 6 per atom: U11 U22 U33 U12 U13 U23; empty where no atom has one) | |
| placed_model | object (optional) | Atomic model placed against the data, written as `<file_prefix>_model.cif` and `<file_prefix>_model.pdb`. `name` (string), `unit_cell` (object, as above), `space_group_name` (the data's, gemmi extended H-M), `model_space_group_name` (the coordinates'), then one array per atom: `model_number`, `seq_num`, `charge` (int32), `chain`, `residue_name`, `atom_name`, `element` (Array(string)), `icode` (uint8, space where none), `het_flag` (uint8, `A`, `H` or 0 where unknown), `altloc` (uint8, 0 where none), `x`, `y`, `z` (double, Angstrom), `b_iso`, `occupancy` (float), `aniso` (float, 6 per atom: U11 U22 U33 U12 U13 U23; empty where no atom has one), `subchain`, `entity_id` (Array(string), mmCIF label_asym_id / label_entity_id), `label_seq` (int32, label_seq_id, INT32_MIN where none) - these three optional; `metadata_mmcif` (string, optional): the input model's metadata (entities, sequences, references, authors, software, secondary structure) as mmCIF categories without coordinates, parsed by the writer with gemmi | |
End-message vector fields are optional. When present, they provide master-file summary data so readers can inspect scan-level and per-image analysis results without opening every linked data file. Missing optional per-image values are encoded by the producer as zero unless otherwise noted.
+3 -5
View File
@@ -3,11 +3,9 @@
### 1.0.0-rc.178
* Rugnux: Processes serial crystallography data from XFELs - SACLA (MPCCD), PAL-XFEL and European XFEL (CXI), LCLS (XTC) and SwissFEL Alvra (JUNGFRAU with a CrystFEL module geometry) - with several files or Jungfraujoch master files merged in one run (`rugnux *_master.h5`).
* Rugnux: Stills processing takes a known unit cell and space group as a starting point, finds the beam centre (and, with a cell, the detector distance) from the images, detects the saturation level in other facilities' files and refines the placement of individual detector panels.
* Rugnux: The stills report gives R_split and CC1/2 from frame half-sets, comparable with CrystFEL.
* jfjoch_viewer: Opens the same XFEL file formats.
* Validation: A stills battery checks Rugnux against deposited structures from SACLA, PAL-XFEL, LCLS, European XFEL and SwissFEL.
* Rugnux: Processes serial crystallography data from XFELs - SACLA, PAL-XFEL, European XFEL, LCLS and SwissFEL files, several files in one run - and jfjoch_viewer opens the same formats.
* Rugnux: Stills need only the unit cell and space group: beam centre, detector distance and tilt, panel placement, saturation level and gain are found from the images, and the report gives R_split and CC1/2.
* Web frontend: The Rugnux live page shows the placed model with its electron density and anomalous difference maps in a Mol* viewer.
* Rugnux: More reliable convergence of rotation scaling, and live molecular replacement starts as soon as the model is uploaded.
* jfjoch_broker: Initialize clears the previous dataset's bearer tokens, image buffer and live Rugnux status, and a slow CUDA JIT cache is reported at start.
+1 -1
View File
@@ -156,7 +156,7 @@ with R-free the same sum restricted to the free set. Every parameter $F_\mathrm{
### 14.4 Electron-density maps
Two sets of map coefficients are formed with the model phases $\varphi_\mathrm{model}$, both $\sigma_A$ weighted: $2mF_o-DF_c$ and $mF_o-DF_c$. They are written as a map-coefficient MTZ (`<prefix>_maps.mtz`: `FP`, `FC`, `PHIC`, `FWT`/`PHWT`, `DELFWT`/`PHDELWT`, `FOM`, `FREE`), which Coot / PyMOL open directly as maps. The $2mF_o-DF_c$ coefficients are also inverse-Fourier-transformed to a real-space map internally, for the mean density at the atom centres.
Two sets of map coefficients are formed with the model phases $\varphi_\mathrm{model}$, both $\sigma_A$ weighted: $2mF_o-DF_c$ and $mF_o-DF_c$. They are written as a map-coefficient MTZ (`<prefix>_maps.mtz`: `FP`, `FC`, `PHIC`, `FWT`/`PHWT`, `DELFWT`/`PHDELWT`, `FOM`, `FREE`, and where the merge kept the Bijvoet pairs `ANOM`/`PHANOM`, the anomalous difference map's coefficients), which Coot / PyMOL open directly as maps. The $2mF_o-DF_c$ coefficients are also inverse-Fourier-transformed to a real-space map internally, for the mean density at the atom centres.
$\sigma_A$ is estimated by maximum likelihood **per resolution shell**, on the **free reflections only** — on the working set the model has been fitted to the data, so $\sigma_A$ would come out too high and the weighting would understate exactly the model error the map is meant to reveal. The shells are cut by equal reflection count, and it is the *number of shells* that is chosen from the size of the free set (about 50 free reflections to a shell, at most 20 shells), so no shell is thin by construction; a shell that still ends up with fewer than 10 free reflections takes the estimate made over the whole free set instead. Acentric and centric reflections enter with their own likelihoods (Rice and Woolfson respectively), and the epsilon factor is divided out before normalising both amplitudes to $\langle|E|^2\rangle = 1$ within the shell. The figure of merit is then $m = I_1(X)/I_0(X)$ with $X = 2\sigma_A|E_o||E_c|/(1-\sigma_A^2)$ for an acentric reflection and $m = \tanh(X/2)$ for a centric one, and $D = \sigma_A\sqrt{\Sigma_o/\Sigma_c}$ carries $F_c$ onto the observed amplitudes' scale. The $2F_o-F_c$ combination becomes $2mF_o - DF_c$ for acentric reflections and $mF_o$ for centric ones — a centric reflection's phase is either exactly right or 180° wrong, never in between — while the difference coefficient is $mF_o - DF_c$ throughout.
+11 -7
View File
@@ -295,13 +295,17 @@ measurement above, and the point-symmetry capture (a second estimator, because t
biased where a shadow - a sample-delivery tape, say - covers part of the scattering). Each re-indexes the
same spots and is scored by how many land on their frame's lattice; the file's centre is kept unless
another puts at least 1/0.9 as many there. Where a reference cell is given, the detector distance is a
hypothesis too: a grid over 60-160 % of the file's distance, then a finer one about the best, from every
centre candidate, followed by a local grid of centres at the distance decided. A distance given with
`--detector-distance` is taken as given and not searched. Without a cell nothing is searched in
distance: on its own a wrong distance indexes as a wrong cell, not as fewer indexed spots. The stills
geometry refinement, `--refine-geometry`, then bundle-adjusts the centre, the cells and - where the
frames rejected the file's distance, or the file states it only nominally - the distance over strongly
indexed frames (§7.7); it is on by default where a reference cell is given.
hypothesis too. The spots of the sample are found without resolution limits (a d-spacing depends on the
distance being checked) and spots piled up at one radius - a powder ring - are left out. A scan over
30-3000 mm in 2.5 % steps at every centre candidate finds the peaks, the strongest are looked at more
closely and a finer step about the best decides against the file's distance, which is kept unless the best
puts at least 1/0.9 as many spots on the lattice; a local grid of centres follows at the distance decided.
The range is in millimetres, not in multiples of the file's value, so a stated camera length that is
nominal or wrong does not limit where the search looks, and an input that states no distance (an XTC) is
searched too. A distance given with `--detector-distance` is held: it is neither searched nor refined.
Without a cell nothing is searched in distance: on its own a wrong distance indexes as a wrong cell, not
as fewer indexed spots. The stills geometry refinement, `--refine-geometry`, then bundle-adjusts the
centre and the distance together with the cell over strongly indexed frames (§7.7); it is on by default where a reference cell is given.
**What ends up in the output.** The report's `BEAM_CENTRE` (the PONI) and `DIRECT_BEAM` are the
geometry the result was integrated at, and so is `JFJOCH_DATASET_SETTINGS`; `POSTREFINE_BEAM_CENTRE`
+164 -60
View File
@@ -4,7 +4,7 @@ Jungfraujoch is developed at the Swiss Light Source, but a data-reduction pipeli
ever sees its own detectors is not tested. The datasets below were collected by other people,
on detectors and in file formats we do not produce ourselves, and are used here to check that
`rugnux` reads foreign files correctly and reduces them to sensible results. Most were collected
at other facilities, ten on laboratory X-ray sources; a few come from SLS beamlines, where the data are still written by someone
at other facilities, eleven on laboratory X-ray sources; a few come from SLS beamlines, where the data are still written by someone
else's detector and someone else's acquisition system. Their authors published all of these for
exactly this kind of reuse, and this page is where we credit them.
@@ -18,23 +18,35 @@ This page lists the rotation datasets. The serial (XFEL stills) datasets of the
## Where the values come from
- **Source** is the repository we downloaded from and that repository's own citable DOI for
the archive we took. Every DOI on this page was resolved against DataCite - or, for 6NEN,
whose DOI is registered with Crossref, against Crossref - before it was written down, and the identity of each dataset was taken from the repository's record for
the archive - not from our directory names.
- **Beamline, resolution, space group and cell are the values deposited with the PDB entry**,
read from the RCSB data API. They describe the published experiment. They are *not* our
reprocessing results; no quantity measured by Jungfraujoch appears on this page.
the archive we took. Every DOI on this page was resolved before it was written down - against
DataCite, which registers most of them; 6NEN's DOI is registered with Crossref and the five XRDa
DOIs with JaLC, and those were resolved through doi.org - and the identity of each dataset was
taken from the repository's record for the archive - not from our directory names.
- **Beamline, resolution, space group, cell and title are the values deposited with the PDB
entry**, read from the RCSB data API; the resolution is the entry's refinement resolution
(`resolution_combined`). They describe the published experiment. They are *not* our
reprocessing results; no quantity measured by Jungfraujoch appears in the table.
- **Detector is read out of the image files themselves** - the NXmx
`/entry/instrument/detector/description`, the miniCBF `# Detector:` header, the marCCD
instrument header or the SMV key block - which is authoritative where the PDB entry names a
different detector.
- Anything that could not be established from one of those sources is left blank.
- **Every row of the table is a row of the battery's open arm** (`tools/battery/open.json`)
unless it is listed under
[Datasets in the table that are not in the battery](#datasets-in-the-table-that-are-not-in-the-battery),
and every row of the open arm is in the table or under
[Datasets with no PDB entry](#datasets-with-no-pdb-entry). The manifest keeps the deposited
values at full precision; `tools/battery/doc_check.py` checks that the two agree.
## Datasets
| PDB | Source | Facility / beamline | d<sub>min</sub> (Å) | Space group | Unit cell a b c α β γ (Å, °) | Detector (from file) | Title |
|---|---|---|---|---|---|---|---|
| [11IF](https://www.rcsb.org/structure/11IF) | IRRMC [10.18430/M311IF](https://doi.org/10.18430/M311IF) | NSLS-II 19-ID | 1.51 | P 43 | 51.1 51.1 71.9 90.0 90.0 90.0 | Dectris EIGER2 Si 9M | Crystal Structure of an exported phospholipid binding protein from Bordetella pertussis in complex with Di-palmitoyl-3-sn-phosphatidylethanolamine (DPPE), P43 form 2 |
| [2WNN](https://www.rcsb.org/structure/2WNN) | Zenodo [10.5281/zenodo.54568](https://doi.org/10.5281/zenodo.54568) | Diamond I03 | 1.65 | P 1 21 1 | 54.7 142.5 83.6 90.0 109.2 90.0 | SMV, S/N 920 | Structure of wild type E. coli N-acetylneuraminic acid lyase in complex with pyruvate in space group P21 |
| [2WNQ](https://www.rcsb.org/structure/2WNQ) | Zenodo [10.5281/zenodo.54568](https://doi.org/10.5281/zenodo.54568) | Diamond I04 | 1.80 | P 1 21 1 | 54.6 142.8 84.5 90.0 109.0 90.0 | SMV, S/N 921 | Structure of the E192N mutant of E. coli N-acetylneuraminic acid lyase in space group P21 |
| [2WNZ](https://www.rcsb.org/structure/2WNZ) | Zenodo [10.5281/zenodo.54568](https://doi.org/10.5281/zenodo.54568) | Diamond I02 | 1.85 | P 1 21 1 | 56.9 143.0 83.9 90.0 109.8 90.0 | SMV, S/N 922 | Structure of the E192N mutant of E. coli N-acetylneuraminic acid lyase in complex with pyruvate in space group P21 crystal form I |
| [2XFW](https://www.rcsb.org/structure/2XFW) | Zenodo [10.5281/zenodo.54568](https://doi.org/10.5281/zenodo.54568) | Diamond I02 | 1.65 | P 1 21 1 | 78.1 116.5 83.7 90.0 118.0 90.0 | SMV, S/N 922 | Structure of the E192N mutant of E. coli N-acetylneuraminic acid lyase in complex with pyruvate in crystal form III |
| [36GK](https://www.rcsb.org/structure/36GK) | IRRMC [10.18430/M336GK](https://doi.org/10.18430/M336GK) | CLSI 08ID-1 | 2.28 | I 2 2 2 | 120.6 189.5 199.7 90.0 90.0 90.0 | Dectris Eiger 9M | D-GlcNAc-bound structure of Vibrio vulnificus putative carbohydrate binding module and split domain |
| [3INP](https://www.rcsb.org/structure/3INP) | IRRMC [10.18430/m33inp](https://doi.org/10.18430/m33inp) | APS 21-ID-F | 2.05 | F 41 3 2 | 224.1 224.1 224.1 90.0 90.0 90.0 | marCCD, 225 mm plate | 2.05 Angstrom Resolution Crystal Structure of D-ribulose-phosphate 3-epimerase from Francisella tularensis. |
| [3KY7](https://www.rcsb.org/structure/3KY7) | IRRMC [10.18430/m33ky7](https://doi.org/10.18430/m33ky7) | APS 21-ID-G | 2.35 | P 43 3 2 | 125.2 125.2 125.2 90.0 90.0 90.0 | marCCD, 300 mm plate | 2.35 Angstrom resolution crystal structure of a putative tRNA (guanine-7-)-methyltransferase (trmD) from Staphylococcus aureus subsp. aureus MRSA252 |
@@ -42,6 +54,7 @@ This page lists the rotation datasets. The serial (XFEL stills) datasets of the
| [3MEB](https://www.rcsb.org/structure/3MEB) | IRRMC [10.18430/M33MEB](https://doi.org/10.18430/M33MEB) | Home source, Rigaku MicroMax-007 HF | 1.90 | P 1 21 1 | 58.6 101.2 81.5 90.0 90.6 90.0 | Rigaku Saturn 944 | Structure of cytoplasmic aspartate aminotransferase from giardia lamblia |
| [3P85](https://www.rcsb.org/structure/3P85) | IRRMC [10.18430/M33P85](https://doi.org/10.18430/M33P85) | Home source, Rigaku FR-E+ SuperBright | 1.90 | P 63 2 2 | 127.3 127.3 72.9 90.0 90.0 120.0 | Rigaku Saturn 944+ | Crystal structure enoyl-coa hydratase from mycobacterium avium |
| [3R6O](https://www.rcsb.org/structure/3R6O) | IRRMC [10.18430/M33R6O](https://doi.org/10.18430/M33R6O) | Home source, Rigaku FR-E+ SuperBright | 1.95 | I 41 | 90.7 90.7 76.1 90.0 90.0 90.0 | Rigaku Saturn 944+ | Crystal structure of a probable 2-hydroxyhepta-2,4-diene-1, 7-dioateisomerase from Mycobacterium abscessus |
| [4BWL](https://www.rcsb.org/structure/4BWL) | Zenodo [10.5281/zenodo.54568](https://doi.org/10.5281/zenodo.54568) | Diamond I02 | 2.00 | P 1 21 1 | 56.0 143.2 83.4 90.0 109.5 90.0 | SMV, S/N 922 | Structure of the Y137A mutant of E. coli N-acetylneuraminic acid lyase in complex with pyruvate, N-acetyl-D-mannosamine and N- acetylneuraminic acid |
| [4MTK](https://www.rcsb.org/structure/4MTK) | SBGrid [10.15785/sbgrid/235](https://doi.org/10.15785/sbgrid/235) | SLS X06SA | 3.32 | P 61 | 168.3 168.3 652.8 90.0 90.0 120.0 | PILATUS 6M | Crystal structure of PA0091 VgrG1, the central spike of the Type VI Secretion System |
| [4NWV](https://www.rcsb.org/structure/4NWV) | SBGrid [10.15785/sbgrid/9](https://doi.org/10.15785/sbgrid/9) | APS 21-ID-D | 3.25 | I 2 2 2 | 402.2 369.9 410.5 90.0 90.0 90.0 | Rayonix MX-300 | Crystal structure of Orsay virus-like particle |
| [4P8R](https://www.rcsb.org/structure/4P8R) | IRRMC [10.18430/m34p8r](https://doi.org/10.18430/m34p8r) | APS 21-ID-F | 2.20 | P 65 2 2 | 86.7 86.7 701.4 90.0 90.0 120.0 | Rayonix MX-225 | Structure of a glycosomal glyceraldehyde 3-phosphate dehydrogenase from Trypanosoma brucei |
@@ -51,12 +64,13 @@ This page lists the rotation datasets. The serial (XFEL stills) datasets of the
| [5F6M](https://www.rcsb.org/structure/5F6M) | SBGrid [10.15785/sbgrid/201](https://doi.org/10.15785/sbgrid/201) | SSRL BL11-1 | 1.10 | P 21 21 21 | 54.8 58.5 67.4 90.0 90.0 90.0 | PILATUS 6M | Isotropic Trypsin Model for Comparison of Diffuse Scattering |
| [5J23](https://www.rcsb.org/structure/5J23) | IRRMC [10.18430/M35J23](https://doi.org/10.18430/M35J23) | APS 21-ID-G | 2.30 | H 3 | 175.8 175.8 136.8 90.0 90.0 120.0 | Rayonix MX-300 | Crystal structure of NADPH-dependent glyoxylate/hydroxypyruvate reductase SMc04462 (SmGhrB) from Sinorhizobium meliloti in complex with 2'-phospho-ADP-ribose |
| [5JK4](https://www.rcsb.org/structure/5JK4) | Zenodo [10.5281/zenodo.49859](https://doi.org/10.5281/zenodo.49859) | ESRF ID14-2 | 1.10 | P 1 21 1 | 37.7 77.9 56.3 90.0 102.1 90.0 | ADSC Quantum 4 | Phosphate-Binding Protein from Stenotrophomonas maltophilia. |
| [5JVN](https://www.rcsb.org/structure/5JVN) | IRRMC [10.18430/m35jvn](https://doi.org/10.18430/m35jvn) | ESRF ID29 | 2.90 | P 6 2 2 | 249.4 249.4 84.1 90.0 90.0 120.0 | PILATUS3 6M | C3-type pyruvate phosphate dikinase: intermediate state of the swiveling-domain mechanism |
| [5JVN](https://www.rcsb.org/structure/5JVN) | IRRMC [10.18430/m35jvn](https://doi.org/10.18430/m35jvn) | ESRF ID29 | 2.90 | P 6 2 2 | 249.4 249.4 84.1 90.0 90.0 120.0 | PILATUS3 6M | C3-type pyruvate phosphate dikinase: intermediate state of the central domain in the swiveling mechanism |
| [5KY6](https://www.rcsb.org/structure/5KY6) | MXRDR [10.18150/repod.1494374](https://doi.org/10.18150/repod.1494374) | BESSY 14.2 | 1.94 | P 1 21 1 | 84.5 57.3 164.0 90.0 102.6 90.0 | marCCD, 225 mm plate | Human muscle fructose-1,6-bisphosphate aldolase |
| [5LZL](https://www.rcsb.org/structure/5LZL) | Zenodo [10.5281/zenodo.54757](https://doi.org/10.5281/zenodo.54757) | Diamond I02 | 3.47 | P 31 2 1 | 205.6 205.6 199.2 90.0 90.0 120.0 | PILATUS 6M-F | Pyrobaculum calidifontis 5-aminolaevulinic acid dehydratase |
| [5M17](https://www.rcsb.org/structure/5M17) | Zenodo [10.5281/zenodo.4300323](https://doi.org/10.5281/zenodo.4300323) | Diamond I02 | 1.03 | I 4 | 108.6 108.6 67.7 90.0 90.0 90.0 | PILATUS 6M-F | Structure of the GH99 endo-alpha-mannanase from Bacteroides xylanisolvens |
| [5M17](https://www.rcsb.org/structure/5M17) | Zenodo [10.5281/zenodo.4300323](https://doi.org/10.5281/zenodo.4300323) | Diamond I02 | 1.03 | I 4 | 108.6 108.6 67.7 90.0 90.0 90.0 | PILATUS 6M-F | Structure of the GH99 endo-alpha-mannanase from Bacteroides xylanisolvens in complex with mannose-alpha-1,3-1,2-dideoxymannose |
| [5MLN](https://www.rcsb.org/structure/5MLN) | IRRMC [10.18430/m35mln](https://doi.org/10.18430/m35mln) | ESRF ID23-2 | 1.60 | P 21 2 21 | 74.2 80.4 80.5 90.0 90.0 90.0 | PILATUS3 2M | The crystal structure of alcohol dehydrogenase 10 from Candida magnoliae |
| [5NW5](https://www.rcsb.org/structure/5NW5) | SBGrid [10.15785/sbgrid/446](https://doi.org/10.15785/sbgrid/446) | SLS X06DA | 6.50 | P 21 21 21 | 92.1 169.8 390.2 90.0 90.0 90.0 | PILATUS 2MF | Crystal structure of the Rif1 N-terminal domain (RIF1-NTD) from Saccharomyces cerevisiae in complex with DNA |
| [5OJV](https://www.rcsb.org/structure/5OJV) | SBGrid [10.15785/sbgrid/475](https://doi.org/10.15785/sbgrid/475) | ESRF ID30B | 2.06 | P 21 21 2 | 87.8 158.2 87.6 90.0 90.0 90.0 | PILATUS 6M | Crystal structure of Mycolicibacterium hassiacum glucosylglycerate hydrolase (MhGgH) E419A variant in complex with mannosylglycerate |
| [5REO](https://www.rcsb.org/structure/5REO) | Zenodo [10.5281/zenodo.3730956](https://doi.org/10.5281/zenodo.3730956) | Diamond I04-1 | 1.88 | C 1 2 1 | 112.4 52.6 44.4 90.0 103.0 90.0 | PILATUS 6M-F | PanDDA analysis group deposition -- Crystal Structure of SARS-CoV-2 main protease in complex with PCM-0102578 |
| [5SRC](https://www.rcsb.org/structure/5SRC) | IRRMC [10.18430/M35SRC](https://doi.org/10.18430/M35SRC) | ALS 8.3.1 | 1.05 | P 43 | 88.7 88.7 39.2 90.0 90.0 90.0 | PILATUS3 6M | PanDDA analysis group deposition -- Crystal structure of SARS-CoV-2 NSP3 macrodomain in complex with Z5198562500 - (R,R) and (R,S) isomers |
| [5T39](https://www.rcsb.org/structure/5T39) | SBGrid [10.15785/sbgrid/356](https://doi.org/10.15785/sbgrid/356) | APS 21-ID-F | 1.10 | P 1 21 1 | 50.2 41.3 58.5 90.0 98.6 90.0 | Rayonix MX-300 | Crystal Structure of the N-terminal domain of EvdMO1 in the presence of SAH and D-fucose |
@@ -67,7 +81,7 @@ This page lists the rotation datasets. The serial (XFEL stills) datasets of the
| [6CS9](https://www.rcsb.org/structure/6CS9) | SBGrid [10.15785/SBGRID/568](https://doi.org/10.15785/SBGRID/568) | Australian Synchrotron MX2 | 1.85 | P 1 21 1 | 32.9 25.5 40.2 90.0 98.6 90.0 | ADSC Quantum 210r | Crystal structure of human beta-defensin 2 in complex with PIP2 |
| [6F3P](https://www.rcsb.org/structure/6F3P) | IRRMC [10.18430/M36F3P](https://doi.org/10.18430/M36F3P) | APS 22-ID | 1.35 | C 1 2 1 | 142.9 85.7 112.0 90.0 122.2 90.0 | marCCD, 300 mm plate | Crystal structure of S-adenosyl-L-homocysteine hydrolase from Pseudomonas aeruginosa in complex with 3'-deoxyadenosine and K+ cation |
| [6FID](https://www.rcsb.org/structure/6FID) | SBGrid [10.15785/sbgrid/541](https://doi.org/10.15785/sbgrid/541) | ESRF ID30B | 2.20 | P 21 21 21 | 59.9 64.1 69.7 90.0 90.0 90.0 | PILATUS3 6M | Bovine trypsin solved by S-SAD on ID30B |
| [6FVZ](https://www.rcsb.org/structure/6FVZ) | IRRMC [10.18430/m36fvz](https://doi.org/10.18430/m36fvz) | ESRF ID23-2 | 1.80 | C 2 2 2 | 131.2 222.8 86.5 90.0 90.0 90.0 | PILATUS3 X 2M | Crystal structure of human monoamine oxidase B (MAO B) in complex with an inhibitor |
| [6FVZ](https://www.rcsb.org/structure/6FVZ) | IRRMC [10.18430/m36fvz](https://doi.org/10.18430/m36fvz) | ESRF ID23-2 | 1.80 | C 2 2 2 | 131.2 222.8 86.5 90.0 90.0 90.0 | PILATUS3 X 2M | Crystal structure of human monoamine oxidase B (MAO B) in complex with dimethylphenyl-chromone-carboxamide |
| [6FWC](https://www.rcsb.org/structure/6FWC) | IRRMC [10.18430/m36fwc](https://doi.org/10.18430/m36fwc) | ESRF MASSIF-3 | 1.70 | C 2 2 2 | 131.7 222.1 86.3 90.0 90.0 90.0 | PILATUS 2MF | Crystal structure of human monoamine oxidase B (MAO B) in complex with fluorophenyl-chromone-carboxamide |
| [6G1F](https://www.rcsb.org/structure/6G1F) | Zenodo [10.5281/zenodo.1059413](https://doi.org/10.5281/zenodo.1059413) | Diamond I03 | 2.25 | C 1 2 1 | 329.3 83.9 133.4 90.0 111.6 90.0 | PILATUS3 6M | Crystal structure of D-phenylglycine aninotransferase (D-PhgAT) from Pseudomonas stutzeri with PLP internal aldimine |
| [6GVK](https://www.rcsb.org/structure/6GVK) | Zenodo [10.5281/zenodo.1286854](https://doi.org/10.5281/zenodo.1286854) | ALBA XALOC | 1.55 | C 1 2 1 | 105.6 59.5 42.4 90.0 113.5 90.0 | PILATUS 6M | Second pair of Fibronectin type III domains of integrin beta4 (T1663R mutant) bound to the bullous pemphigoid antigen BP230 (BPAG1e) |
@@ -78,15 +92,17 @@ This page lists the rotation datasets. The serial (XFEL stills) datasets of the
| [6I3J](https://www.rcsb.org/structure/6I3J) | IRRMC [10.18430/m36i3j](https://doi.org/10.18430/m36i3j) | BESSY 14.1 | 2.59 | F 2 2 2 | 134.4 203.8 226.7 90.0 90.0 90.0 | marCCD, 225 mm plate | Bilirubin oxidase from Myrothecium verrucaria in complex with ferricyanide |
| [6IU5](https://www.rcsb.org/structure/6IU5) | Zenodo [10.5281/zenodo.2532134](https://doi.org/10.5281/zenodo.2532134) | SPring-8 BL41XU | 2.25 | P 31 | 84.9 84.9 98.2 90.0 90.0 120.0 | PILATUS3 6M | Crystal structure of cytoplasmic metal binding domain with zinc ions |
| [6IU6](https://www.rcsb.org/structure/6IU6) | Zenodo [10.5281/zenodo.2532134](https://doi.org/10.5281/zenodo.2532134) | SPring-8 BL41XU | 2.90 | P 31 | 84.7 84.7 97.4 90.0 90.0 120.0 | PILATUS3 6M | Crystal structure of cytoplasmic metal binding domain with nickel ions |
| [6IU8](https://www.rcsb.org/structure/6IU8) | Zenodo [10.5281/zenodo.2532134](https://doi.org/10.5281/zenodo.2532134) | SPring-8 BL41XU | 2.70 | P 31 | 85.5 85.5 98.4 90.0 90.0 120.0 | PILATUS3 6M | Crystal structure of cytoplasmic metal binding domain with cobalt |
| [6IU8](https://www.rcsb.org/structure/6IU8) | Zenodo [10.5281/zenodo.2532134](https://doi.org/10.5281/zenodo.2532134) | SPring-8 BL41XU | 2.70 | P 31 | 85.5 85.5 98.4 90.0 90.0 120.0 | PILATUS3 6M | Crystal structure of cytoplasmic metal binding domain with cobalt ions |
| [6IU9](https://www.rcsb.org/structure/6IU9) | Zenodo [10.5281/zenodo.2532134](https://doi.org/10.5281/zenodo.2532134) | SPring-8 BL41XU | 3.00 | P 31 | 85.3 85.3 97.6 90.0 90.0 120.0 | PILATUS3 6M | Crystal structure of cytoplasmic metal binding domain with iron ions |
| [6JGH](https://www.rcsb.org/structure/6JGH) | IRRMC [10.18430/m36jgh](https://doi.org/10.18430/m36jgh) | SPring-8 BL44XU | 0.94 | P 21 21 21 | 50.6 62.5 68.2 90.0 90.0 90.0 | marCCD, 300 mm plate | Crystal structure of the F99S/M153T/V163A/T203I variant of GFP at 0.94 A |
| [6JGI](https://www.rcsb.org/structure/6JGI) | IRRMC [10.18430/m36jgi](https://doi.org/10.18430/m36jgi) | SPring-8 BL44XU | 0.85 | P 21 21 21 | 50.9 62.4 69.2 90.0 90.0 90.0 | marCCD, 300 mm plate | Crystal structure of the S65T/F99S/M153T/V163A variant of GFP at 0.85 A |
| [6JGJ](https://www.rcsb.org/structure/6JGJ) | IRRMC [10.18430/m36jgj](https://doi.org/10.18430/m36jgj) | SPring-8 BL41XU | 0.77 | P 21 21 21 | 50.9 62.3 68.8 90.0 90.0 90.0 | PILATUS3 300K | Crystal structure of the F99S/M153T/V163A/E222Q variant of GFP at 0.78 A |
| [6JGJ](https://www.rcsb.org/structure/6JGJ) | IRRMC [10.18430/m36jgj](https://doi.org/10.18430/m36jgj) | SPring-8 BL41XU | 0.78 | P 21 21 21 | 50.9 62.3 68.8 90.0 90.0 90.0 | PILATUS3 300K | Crystal structure of the F99S/M153T/V163A/E222Q variant of GFP at 0.78 A |
| [6MOJ](https://www.rcsb.org/structure/6MOJ) | SBGrid [10.15785/sbgrid/620](https://doi.org/10.15785/sbgrid/620) | ALS 5.0.1 | 2.43 | I 41 2 2 | 130.4 130.4 293.5 90.0 90.0 90.0 | PILATUS3 6M | Dimeric DARPin A_angle_R5 complex with EpoR |
| [6NEN](https://www.rcsb.org/structure/6NEN) | UQ eSpace [10.14264/uql.2018.843](https://doi.org/10.14264/uql.2018.843) | Australian Synchrotron MX2 | 2.15 | P 3 1 2 | 105.5 105.5 35.1 90.0 90.0 120.0 | SMV, S/N 928 | Catalytic domain of Proteus mirabilis ScsC |
| [6O2H](https://www.rcsb.org/structure/6O2H) | SBGrid [10.15785/sbgrid/747](https://doi.org/10.15785/sbgrid/747) | CHESS F1 | 1.21 | P 1 | 27.4 32.1 34.5 88.7 108.5 111.9 | PILATUS3 6M | Hen lysozyme in triclinic space group at ambient temperature - diffuse scattering dataset |
| [6OEL](https://www.rcsb.org/structure/6OEL) | SBGrid [10.15785/sbgrid/652](https://doi.org/10.15785/sbgrid/652) | ALS 8.2.1 | 3.10 | F 41 3 2 | 328.1 328.1 328.1 90.0 90.0 90.0 | SMV, S/N 905 | Engineered Fab bound to IL-4 receptor |
| [6OWW](https://www.rcsb.org/structure/6OWW) | Zenodo [10.5281/zenodo.2943248](https://doi.org/10.5281/zenodo.2943248) | ALS 8.3.1 | 3.84 | P 1 21 1 | 85.8 86.0 214.3 90.0 89.9 90.0 | PILATUS3 6M | Crystal structure of a Human Cardiac Calsequestrin Filament Complexed with Ytterbium |
| [6P8J](https://www.rcsb.org/structure/6P8J) | SBGrid [10.15785/sbgrid/671](https://doi.org/10.15785/sbgrid/671) | APS 24-ID-E | 1.47 | P 1 21 1 | 46.5 152.2 88.3 90.0 90.1 90.0 | Dectris Eiger 16M | Structure of P. aeruginosa ATCC27853 CdnD D62N/D64N mutant bound to ATP |
| [6P8P](https://www.rcsb.org/structure/6P8P) | SBGrid [10.15785/sbgrid/673](https://doi.org/10.15785/sbgrid/673) | APS 24-ID-C | 1.64 | P 4 | 97.5 97.5 60.1 90.0 90.0 90.0 | PILATUS 6M-F | Structure of P. aeruginosa ATCC27853 HORMA1 |
| [6PB3](https://www.rcsb.org/structure/6PB3) | SBGrid [10.15785/sbgrid/681](https://doi.org/10.15785/sbgrid/681) | APS 24-ID-E | 2.05 | P 6 | 100.4 100.4 48.9 90.0 90.0 120.0 | Dectris Eiger 16M | Structure of Rhizobiales Trip13 |
| [6PXB](https://www.rcsb.org/structure/6PXB) | SBGrid [10.15785/sbgrid/698](https://doi.org/10.15785/sbgrid/698) | APS 24-ID-E | 1.75 | P 32 | 64.0 64.0 119.4 90.0 90.0 120.0 | PILATUS 6M-F | N-Terminal SH2 domain of the p120RasGAP |
@@ -122,15 +138,16 @@ This page lists the rotation datasets. The serial (XFEL stills) datasets of the
| [7K1L](https://www.rcsb.org/structure/7K1L) | IRRMC [10.18430/m37k1l](https://doi.org/10.18430/m37k1l) | APS 19-ID | 2.25 | P 63 | 150.8 150.8 110.7 90.0 90.0 120.0 | PILATUS3 6M | Crystal Structure of NSP15 Endoribonuclease from SARS CoV-2 in the Complex with Uridine-2',3'-Vanadate |
| [7KCN](https://www.rcsb.org/structure/7KCN) | IRRMC [10.18430/m37kcn](https://doi.org/10.18430/m37kcn) | LNLS W01B-MX2 | 1.46 | P 41 2 2 | 67.0 67.0 116.9 90.0 90.0 90.0 | PILATUS 2M | Reconstructed ancestor of HIUases and Transthyretins |
| [7L6J](https://www.rcsb.org/structure/7L6J) | IRRMC [10.18430/m37l6j](https://doi.org/10.18430/m37l6j) | APS 21-ID-F | 1.78 | I 41 3 2 | 171.7 171.7 171.7 90.0 90.0 90.0 | Rayonix MX-300 | Crystal Structure of the Putative Hydrolase from Stenotrophomonas maltophilia |
| [7L84](https://www.rcsb.org/structure/7L84) | SBGrid [10.15785/sbgrid/816](https://doi.org/10.15785/sbgrid/816) | APS 24-ID-C | 1.60 | P 43 21 2 | 79.3 79.3 37.8 90.0 90.0 90.0 | PILATUS 6M-F | Hen Egg White Lysozyme by Native S-SAD at Room Temperature |
| [7L84](https://www.rcsb.org/structure/7L84) | SBGrid [10.15785/sbgrid/816](https://doi.org/10.15785/sbgrid/816) | APS 24-ID-C | 1.70 | P 43 21 2 | 79.3 79.3 37.8 90.0 90.0 90.0 | PILATUS 6M-F | Hen Egg White Lysozyme by Native S-SAD at Room Temperature |
| [7MZT](https://www.rcsb.org/structure/7MZT) | IRRMC [10.18430/m37mzt](https://doi.org/10.18430/m37mzt) | APS 22-ID | 4.07 | P 21 21 2 | 113.6 97.0 108.3 90.0 90.0 90.0 | Dectris Eiger 16M | Borrelia burgdorferi BBK32-C in complex with an autolytic fragment of human C1r at 4.1A |
| [7N0I](https://www.rcsb.org/structure/7N0I) | SBGrid [10.15785/sbgrid/835](https://doi.org/10.15785/sbgrid/835) | ALS 5.0.2 | 2.20 | P 21 21 21 | 75.8 131.6 140.0 90.0 90.0 90.0 | PILATUS3 6M | Structure of the SARS-CoV-2 N protein C-terminal domain bound to single-domain antibody E2 |
| [7N2S](https://www.rcsb.org/structure/7N2S) | SBGrid [10.15785/sbgrid/916](https://doi.org/10.15785/sbgrid/916) | SSRL BL12-1 | 2.37 | P 1 21 1 | 83.2 52.8 106.3 90.0 98.3 90.0 | PILATUS 6M | AS3.1-PRPF3-HLA*B27 |
| [7ORR](https://www.rcsb.org/structure/7ORR) | IRRMC [10.18430/M37ORR](https://doi.org/10.18430/M37ORR) | MAX IV BioMAX | 1.79 | I 21 3 | 105.9 105.9 105.9 90.0 90.0 90.0 | Dectris Eiger 16M | Non-structural protein 10 (nsp10) from SARS CoV-2 in complex with fragment VT00022 |
| [7OS3](https://www.rcsb.org/structure/7OS3) | MXRDR [10.18150/74YTYQ](https://doi.org/10.18150/74YTYQ) | PETRA III, EMBL c/o DESY P13 (MX1) | 2.18 | P 21 21 21 | 78.2 91.0 105.8 90.0 90.0 90.0 | PILATUS 6M-F | Crystal structure of Rhizobium etli inducible L-asparaginase |
| [7OS3](https://www.rcsb.org/structure/7OS3) | MXRDR [10.18150/74YTYQ](https://doi.org/10.18150/74YTYQ) | PETRA III, EMBL c/o DESY P13 (MX1) | 2.18 | P 21 21 21 | 78.2 91.0 105.8 90.0 90.0 90.0 | PILATUS 6M-F | Crystal structure of Rhizobium etli inducible L-asparaginase ReAV solved by S-SAD (orthorhombic form START) |
| [7OU1](https://www.rcsb.org/structure/7OU1) | MXRDR [10.18150/VQQIHQ](https://doi.org/10.18150/VQQIHQ) | BESSY 14.3 | 1.65 | P 1 21 1 | 77.9 91.3 114.2 90.0 97.1 90.0 | marCCD, 225 mm plate | Crystal structure of Rhizobium etli inducible L-asparaginase ReAV (monoclinic form MP2) |
| [7PH1](https://www.rcsb.org/structure/7PH1) | IRRMC [10.18430/M37PH1](https://doi.org/10.18430/M37PH1) | BESSY 14.2 | 1.18 | I 2 2 2 | 75.0 81.3 124.2 90.0 90.0 90.0 | PILATUS3 2M | Trypsin in complex with BPTI mutant (2S)-2-amino-4-monofluorobutanoic acid |
| [7PQ7](https://www.rcsb.org/structure/7PQ7) | IRRMC [10.18430/M3.IRRMC.6072](https://doi.org/10.18430/M3.IRRMC.6072) | ELETTRA 11.2C | 1.55 | C 1 2 1 | 120.9 51.7 75.5 90.0 125.1 90.0 | PILATUS 6M | Crystal structure of Campylobacter jejuni DsbA1 |
| [7Q6J](https://www.rcsb.org/structure/7Q6J) | Zenodo [10.5281/zenodo.4686876](https://doi.org/10.5281/zenodo.4686876) | PETRA III, DESY P11 | 2.20 | P 21 21 21 | 72.7 115.9 116.2 90.0 90.0 90.0 | PILATUS 6MF | Crystal structure of the human GDAP1 CMT2 mutant-H123R |
| [7QIJ](https://www.rcsb.org/structure/7QIJ) | SBGrid [10.15785/sbgrid/907](https://doi.org/10.15785/sbgrid/907) | PETRA III, EMBL c/o DESY P13 (MX1) | 4.10 | P 21 21 21 | 143.5 324.9 369.4 90.0 90.0 90.0 | PILATUS 6M-F | Complex of the Yersinia enterocolitica Type III secretion export gate YscV with substrate:chaperone complex YscX:YscY |
| [7QIS](https://www.rcsb.org/structure/7QIS) | IRRMC [10.18430/M37QIS](https://doi.org/10.18430/M37QIS) | BESSY 14.2 | 1.83 | P 61 | 100.3 100.3 206.2 90.0 90.0 120.0 | PILATUS3 2M | CRYSTAL STRUCTURE OF THE P1 difluoroethylglycine (DfeGly) BPTI MUTANT- BOVINE CHYMOTRYPSIN COMPLEX |
| [7RAA](https://www.rcsb.org/structure/7RAA) | SBGrid [10.15785/sbgrid/881](https://doi.org/10.15785/sbgrid/881) | SSRL BL12-2 | 2.69 | P 43 21 2 | 66.4 66.4 298.3 90.0 90.0 90.0 | PILATUS 6M | Designed StabIL-2 seq15 |
@@ -141,6 +158,7 @@ This page lists the rotation datasets. The serial (XFEL stills) datasets of the
| [7YZX](https://www.rcsb.org/structure/7YZX) | IRRMC [10.18430/M37YZX](https://doi.org/10.18430/M37YZX) | Diamond I24 | 1.90 | P 63 2 2 | 169.4 169.4 141.8 90.0 90.0 120.0 | PILATUS3 6M | ScpA from Streptococcus pyogenes, D783A mutant. |
| [8A1A](https://www.rcsb.org/structure/8A1A) | IRRMC [10.18430/M38A1A](https://doi.org/10.18430/M38A1A) | SLS X06SA | 2.05 | P 65 | 191.9 191.9 122.4 90.0 90.0 120.0 | Dectris Eiger 16M | Structure of a leucinostatin derivative determined by host lattice display : L1F11V1 construct |
| [8AGQ](https://www.rcsb.org/structure/8AGQ) | IRRMC [10.18430/M38AGQ](https://doi.org/10.18430/M38AGQ) | SLS X06DA | 1.09 | C 1 2 1 | 89.9 55.4 54.8 90.0 113.5 90.0 | PILATUS 2MF | Crystal structure of anthocyanin-related GSTF8 from Populus trichocarpa in complex with (-)-catechin and glutathione |
| [8C3E](https://www.rcsb.org/structure/8C3E) | Zenodo [10.5281/zenodo.14555180](https://doi.org/10.5281/zenodo.14555180) | Home source, Rigaku PhotonJet-S | 2.10 | P 31 2 1 | 57.8 57.8 41.5 90.0 90.0 120.0 | CrysAlisPro HPAD, 775 x 800 | Engineered mini-protein LCB2 (blocking ligand of SARS-Cov-2 spike protein) |
| [8DQB](https://www.rcsb.org/structure/8DQB) | IRRMC [10.18430/m38dqb](https://doi.org/10.18430/m38dqb) | NSLS-II 19-ID | 2.50 | I 2 3 | 164.1 164.1 164.1 90.0 90.0 90.0 | Dectris EIGER2 Si 9M | Crystal structure of 3-dehydroquinate dehydratase I from Klebsiella oxytoca (I23 Form) |
| [8DYZ](https://www.rcsb.org/structure/8DYZ) | SBGrid [10.15785/sbgrid/957](https://doi.org/10.15785/sbgrid/957) | CHESS F1 | 1.27 | P 43 21 2 | 79.6 79.6 38.3 90.0 90.0 90.0 | PILATUS3 6M | Hen lysozyme in tetragonal space group at ambient temperature - diffuse scattering dataset |
| [8DZ7](https://www.rcsb.org/structure/8DZ7) | SBGrid [10.15785/sbgrid/958](https://doi.org/10.15785/sbgrid/958) | CHESS F1 | 1.34 | P 21 21 21 | 30.5 56.4 73.9 90.0 90.0 90.0 | PILATUS3 6M | Hen lysozyme in orthorhombic space group at ambient temperature - diffuse scattering dataset |
@@ -175,10 +193,10 @@ This page lists the rotation datasets. The serial (XFEL stills) datasets of the
| [8YS9](https://www.rcsb.org/structure/8YS9) | IRRMC [10.18430/M38YS9](https://doi.org/10.18430/M38YS9) | PAL/PLS 5C (4A) | 1.46 | P 21 21 21 | 71.0 77.7 83.2 90.0 90.0 90.0 | Dectris Eiger 9M | Crystal structure of Phosphatidylethanolamine N-methyltransferase from R. thermophilum complexed with DMPE and SAH |
| [9B22](https://www.rcsb.org/structure/9B22) | IRRMC [10.18430/m39b22](https://doi.org/10.18430/m39b22) | NSLS-II 19-ID | 1.30 | P 1 21 1 | 39.8 92.7 57.7 90.0 91.7 90.0 | Dectris EIGER2 Si 9M | Crystal structure of ADP-ribose diphosphatase from Klebsiella pneumoniae (ADP Ribose and AMP bound) |
| [9BN8](https://www.rcsb.org/structure/9BN8) | IRRMC [10.18430/m39bn8](https://doi.org/10.18430/m39bn8) | NSLS-II 19-ID | 1.35 | P 41 | 65.5 65.5 134.8 90.0 90.0 90.0 | Dectris EIGER2 Si 9M | Crystal Structure of UDP-N-acetylmuramoylalanine--D-glutamate ligase (MurD) from E. coli in complex with UMA and inhibitor A19 |
| [9C18](https://www.rcsb.org/structure/9C18) | Zenodo [10.5281/zenodo.11405662](https://doi.org/10.5281/zenodo.11405662) | NSLS-II 17-ID-1 | 1.90 | P 1 | 41.9 42.0 60.2 84.1 87.2 63.7 | Dectris EIGER1 Si 9M | Human biliverdin IX beta reductase in complex with NADP |
| [9C18](https://www.rcsb.org/structure/9C18) | Zenodo [10.5281/zenodo.11405662](https://doi.org/10.5281/zenodo.11405662) | NSLS-II 17-ID-1 | 1.90 | P 1 | 41.9 42.0 60.2 84.1 87.2 63.7 | Dectris EIGER1 Si 9M | Human biliverdin IX beta reductase in complex with NADP in space group P1 |
| [9CHW](https://www.rcsb.org/structure/9CHW) | SBGrid [10.15785/sbgrid/1124](https://doi.org/10.15785/sbgrid/1124) | APS 21-ID-F | 2.16 | P 61 | 98.7 98.7 82.1 90.0 90.0 120.0 | Rayonix MX-300 | Crystal structure of human polymerase eta with incoming dAMPnPP nucleotide opposite threofuranosyl thymidine in DNA template |
| [9CRW](https://www.rcsb.org/structure/9CRW) | IRRMC [10.18430/m39crw](https://doi.org/10.18430/m39crw) | CLSI 08ID-1 | 2.49 | P 1 21 1 | 84.0 104.6 118.8 90.0 93.4 90.0 | Dectris Eiger 9M | Crystal structure of the Candida albicans kinesin-8 proximal tail domain |
| [9E2T](https://www.rcsb.org/structure/9E2T) | SBGrid [10.15785/sbgrid/1148](https://doi.org/10.15785/sbgrid/1148) | SSRL BL12-1 | 2.28 | P 1 | 75.5 78.1 101.2 94.6 103.4 114.5 | Dectris EIGER2 Si 16M | Structure of a de novo designed interleukin-21 mimetic complex |
| [9E2T](https://www.rcsb.org/structure/9E2T) | SBGrid [10.15785/sbgrid/1148](https://doi.org/10.15785/sbgrid/1148) | SSRL BL12-1 | 2.28 | P 1 | 75.5 78.1 101.2 94.6 103.4 114.5 | Dectris EIGER2 Si 16M | Structure of a de novo designed interleukin-21 mimetic complex with IL-21R and IL-2Rg |
| [9EA5](https://www.rcsb.org/structure/9EA5) | SBGrid [10.15785/sbgrid/1142](https://doi.org/10.15785/sbgrid/1142) | SSRL BL9-2 | 2.00 | P 1 21 1 | 65.9 73.1 98.4 90.0 108.7 90.0 | PILATUS 6M | Structure of Citrobacter BubCD D104A mutant |
| [9FCF](https://www.rcsb.org/structure/9FCF) | MXRDR [10.18150/DGZKW3](https://doi.org/10.18150/DGZKW3) | PETRA III, EMBL c/o DESY P13 (MX1) | 2.36 | P 4 | 91.3 91.3 35.8 90.0 90.0 90.0 | Dectris EIGER1 Si 16M | Medicago truncatula 5'-ProFAR isomerase (HISN3) D57N mutant in complex with ProFAR |
| [9FCG](https://www.rcsb.org/structure/9FCG) | MXRDR [10.18150/LDLSBT](https://doi.org/10.18150/LDLSBT) | PETRA III, EMBL c/o DESY P13 (MX1) | 1.54 | P 4 | 87.8 87.8 35.6 90.0 90.0 90.0 | Dectris EIGER1 Si 16M | Medicago truncatula 5'-ProFAR isomerase (HISN3) D57N mutant in complex with PrFAR |
@@ -187,7 +205,7 @@ This page lists the rotation datasets. The serial (XFEL stills) datasets of the
| [9GJX](https://www.rcsb.org/structure/9GJX) | IRRMC [10.18430/M39GJX](https://doi.org/10.18430/M39GJX) | Diamond I04 | 2.40 | P 1 21 1 | 76.8 115.8 103.8 90.0 110.3 90.0 | Eiger 16M | Bacillus licheniformis nitroreductase |
| [9GQG](https://www.rcsb.org/structure/9GQG) | ESRF [10.15151/ESRF-DC-1900353437](https://doi.org/10.15151/ESRF-DC-1900353437) | ESRF ID30B | 2.00 | P 32 2 1 | 48.2 48.2 188.0 90.0 90.0 120.0 | Dectris EIGER2 Si 9M | The FK1 domain of FKBP51 in complex with the macrocyclic SAFit analog m5(10,7)-(E)-OH |
| [9H0Q](https://www.rcsb.org/structure/9H0Q) | Zenodo [10.5281/zenodo.13912326](https://doi.org/10.5281/zenodo.13912326) | SOLEIL PROXIMA 2 | 2.55 | H 3 2 | 169.5 169.5 344.0 90.0 90.0 120.0 | Dectris EIGER1 Si 9M | N terminal domain of BC2L-C lectin in complex with N-(beta-L-Fucopyranosyl)-biphenyl-3-carboxamide |
| [9HNC](https://www.rcsb.org/structure/9HNC) | MXRDR [10.60884/0K7B68](https://doi.org/10.60884/0K7B68) | PETRA III, EMBL c/o DESY P13 (MX1) | 1.88 | P 1 2 1 | 123.8 123.6 187.7 90.0 90.1 90.0 | PILATUS 6M-F | Crystal structure of potassium-independent L-asparaginase |
| [9HNC](https://www.rcsb.org/structure/9HNC) | MXRDR [10.60884/0K7B68](https://doi.org/10.60884/0K7B68) | PETRA III, EMBL c/o DESY P13 (MX1) | 1.88 | P 1 2 1 | 123.8 123.6 187.7 90.0 90.1 90.0 | PILATUS 6M-F | Crystal structure of potassium-independent L-asparaginase from Phaseolus vulgaris (PvAIII, PvAspG2) |
| [9HS7](https://www.rcsb.org/structure/9HS7) | IRRMC [10.18430/M39HS7](https://doi.org/10.18430/M39HS7) | ALBA XALOC | 1.70 | P 65 | 65.4 65.4 88.8 90.0 90.0 120.0 | PILATUS3 X 6M | Anti-HIV-1 chimeric miniprotein mimicking the N-terminal half of gp41 NHR with an extended region targeting the MPER |
| [9I0A](https://www.rcsb.org/structure/9I0A) | IRRMC [10.18430/M39I0A](https://doi.org/10.18430/M39I0A) | SOLEIL PROXIMA 1 | 2.22 | P 21 21 2 | 75.2 98.7 208.6 90.0 90.0 90.0 | Dectris Eiger 16M | CARM1 in complex with arg-aDMA analog |
| [9I80](https://www.rcsb.org/structure/9I80) | Zenodo [10.5281/zenodo.14844040](https://doi.org/10.5281/zenodo.14844040) | SOLEIL PROXIMA 1 | 1.95 | P 41 | 81.2 81.2 165.0 90.0 90.0 90.0 | Dectris Eiger 16M | LecA in complex with a tolcapone derivative glycomimetic |
@@ -204,7 +222,9 @@ This page lists the rotation datasets. The serial (XFEL stills) datasets of the
| [9PBB](https://www.rcsb.org/structure/9PBB) | IRRMC [10.18430/M39PBB](https://doi.org/10.18430/M39PBB) | SSRL BL12-1 | 2.17 | C 1 2 1 | 97.4 45.9 72.2 90.0 105.0 90.0 | Dectris EIGER2 Si 16M | 293K human S-adenosylmethionine decarboxylase |
| [9Q41](https://www.rcsb.org/structure/9Q41) | SBGrid [10.15785/sbgrid/1194](https://doi.org/10.15785/sbgrid/1194) | CHESS 7B2 | 1.95 | C 2 2 21 | 118.6 133.7 82.4 90.0 90.0 90.0 | Dectris EIGER2 Si 16M | Crystal Structure of Human Apo Spermidine Synthase |
| [9Q66](https://www.rcsb.org/structure/9Q66) | SBGrid [10.15785/sbgrid/1208](https://doi.org/10.15785/sbgrid/1208) | NSLS-II 17-ID-1 | 2.01 | P 1 21 1 | 105.9 67.3 158.0 90.0 99.1 90.0 | Dectris EIGER1 Si 9M | Human prolyl endopeptidase (PREP) - complex with JP-4-1-7 |
| [9QW8](https://www.rcsb.org/structure/9QW8) | ESRF [10.15151/ESRF-DC-2127908021](https://doi.org/10.15151/ESRF-DC-2127908021) | ESRF ID23-1 | 1.80 | P 1 | 35.6 35.6 100.9 86.5 84.2 72.5 | Dectris EIGER2 CdTe 16M | FKBP12 in complex with bifunctional ligand 1ad |
| [9QVV](https://www.rcsb.org/structure/9QVV) | Zenodo [10.5281/zenodo.19456697](https://doi.org/10.5281/zenodo.19456697) | Diamond I03 | 2.72 | I 2 2 2 | 120.1 123.8 123.8 90.0 90.0 90.0 | Eiger 16M | Crystal structure of the 4CHRD domain of human chordin, mutant designed to abolish binding to sulphated glycosaminoglycans |
| [9QW2](https://www.rcsb.org/structure/9QW2) | Keele University [10.21252/yzsx-0e16](https://doi.org/10.21252/yzsx-0e16) | Diamond I03 | 1.92 | P 1 21 1 | 55.4 108.2 55.6 90.0 90.9 90.0 | PILATUS3 6M | Crystal structure of human lung surfactant protein D trimeric fragment with bound synthetic HepII-HepI-PhosI ligand |
| [9QW8](https://www.rcsb.org/structure/9QW8) | ESRF [10.15151/ESRF-DC-2127908021](https://doi.org/10.15151/ESRF-DC-2127908021) | ESRF ID23-1 | 1.80 | P 1 | 35.6 35.6 100.9 86.5 84.2 72.5 | Dectris EIGER2 CdTe 16M | FKBP12 in complex with bifunctional ligand 1ad and the first bromodomain of BRD4 |
| [9RCI](https://www.rcsb.org/structure/9RCI) | Zenodo [10.5281/zenodo.15615368](https://doi.org/10.5281/zenodo.15615368) | SOLEIL PROXIMA 2 | 1.66 | P 1 | 35.9 39.3 100.9 98.3 90.3 90.1 | Dectris Eiger 9M | Crystal Structure of Flap Endonuclease FEN1 with Compound 28 |
| [9RCS](https://www.rcsb.org/structure/9RCS) | XRDa [10.51093/xrd-00383](https://doi.org/10.51093/xrd-00383) | Diamond I24 | 3.01 | P 1 21 1 | 70.0 78.8 82.3 90.0 88.6 90.0 | Eiger 9M | Cardioderma bat coronavirus KY43 receptor binding domain in complex with human CEACAM6 |
| [9RP9](https://www.rcsb.org/structure/9RP9) | IRRMC [10.18430/M39RP9](https://doi.org/10.18430/M39RP9) | SOLEIL PROXIMA 1 | 2.10 | C 1 2 1 | 73.5 59.8 91.7 90.0 100.8 90.0 | Dectris Eiger 16M | Crystal structure of mouse pVHL-ElonginB-ElonginC complex |
@@ -217,22 +237,21 @@ This page lists the rotation datasets. The serial (XFEL stills) datasets of the
| [9VYB](https://www.rcsb.org/structure/9VYB) | IRRMC [10.18430/M39VYB](https://doi.org/10.18430/M39VYB) | PAL/PLS 5C (4A) | 2.12 | P 21 21 21 | 44.4 47.8 48.4 90.0 90.0 90.0 | Dectris Eiger 9M | Antitoxin Phd |
| [9W3Y](https://www.rcsb.org/structure/9W3Y) | IRRMC [10.18430/M39W3Y](https://doi.org/10.18430/M39W3Y) | Photon Factory BL-1A | 1.50 | P 21 21 21 | 60.7 70.0 94.2 90.0 90.0 90.0 | Dectris EIGER1 Si 4M | X-ray Crystal Structure of Pseudoazurin Met16Gly variant (Tris-HCl pH 7.6) |
| [9YL4](https://www.rcsb.org/structure/9YL4) | Zenodo [10.5281/zenodo.17298261](https://doi.org/10.5281/zenodo.17298261) | APS 17-ID | 3.70 | P 21 21 21 | 95.8 111.3 403.0 90.0 90.0 90.0 | PILATUS 6M | Crystal structure of PprA S-F filament from Deinococcus radiodurans |
| [9YZK](https://www.rcsb.org/structure/9YZK) | IRRMC [10.18430/M39YZK](https://doi.org/10.18430/M39YZK) | ALS 8.2.2 | 4.44 | I 1 2 1 | 75.8 163.0 192.3 90.0 98.6 90.0 | PILATUS3 S 2M | Isoreticular co-crystal 1 with symmetrical expanded duplex (42mer) containing insert sequence ACCCTTCTATGACCTACTCCA |
| [9YZK](https://www.rcsb.org/structure/9YZK) | IRRMC [10.18430/M39YZK](https://doi.org/10.18430/M39YZK) | ALS 8.2.2 | 5.10 | I 1 2 1 | 75.8 163.0 192.3 90.0 98.6 90.0 | PILATUS3 S 2M | Isoreticular co-crystal 1 with symmetrical expanded duplex (42mer) containing insert sequence ACCCTTCTATGACCTACTCCA |
| [9Z44](https://www.rcsb.org/structure/9Z44) | IRRMC [10.18430/M39Z44](https://doi.org/10.18430/M39Z44) | ALS 8.2.1 | 7.20 | I 1 2 1 | 73.5 127.7 141.2 90.0 92.0 90.0 | Dectris EIGER2 Si 9M | Isoreticular co-crystal 1 with symmetrical expanded duplex (31mer) containing insert sequence CCCGGCCGGA and loaded with C-clamp domain |
| [9Z72](https://www.rcsb.org/structure/9Z72) | SBGrid [10.15785/sbgrid/1239](https://doi.org/10.15785/sbgrid/1239) | SSRL BL9-2 | 2.38 | P 31 2 1 | 59.2 59.2 426.2 90.0 90.0 120.0 | Dectris EIGER2 Si 16M | Structure of V. cholerae CapS (form 1) |
| [9ZLO](https://www.rcsb.org/structure/9ZLO) | Zenodo [10.5281/zenodo.18652652](https://doi.org/10.5281/zenodo.18652652) | Australian Synchrotron MX2 | 2.00 | P 21 21 21 | 38.4 90.0 107.0 90.0 90.0 90.0 | Dectris EIGER1 Si 16M | Crystal structure of Proteus mirabilis UreE |
| [9ZM0](https://www.rcsb.org/structure/9ZM0) | IRRMC [10.18430/M39ZM0](https://doi.org/10.18430/M39ZM0) | NSLS-II 17-ID-1 | 2.10 | P 1 21 1 | 50.4 30.1 91.2 90.0 97.1 90.0 | Dectris EIGER1 Si 9M | Crystal structure of monomeric Atg23 |
| [9ZMU](https://www.rcsb.org/structure/9ZMU) | IRRMC [10.18430/M39ZMU](https://doi.org/10.18430/M39ZMU) | NSLS-II 19-ID | 1.98 | P 65 2 2 | 47.8 47.8 492.6 90.0 90.0 120.0 | Dectris EIGER2 Si 9M | Crystal structure of an Iole protein from Brucella melitensis (hexagonal P form) |
Seven rows have no PDB code. Six are small-molecule / chemical-crystallography datasets, kept
because they exercise short wavelengths, CdTe sensors, fine slicing and non-zero detector
2θ; the seventh is the second collection in the 6R72 Zenodo record, described below. They have
no deposited macromolecular values, so those columns are blank, and their titles are the
repository record titles verbatim.
The table holds 201 PDB entries. Six more datasets, small-molecule / chemical-crystallography
sets kept because they exercise short wavelengths, CdTe sensors, fine slicing and non-zero
detector 2θ, have no PDB entry and are listed [below](#datasets-with-no-pdb-entry).
Five datasets are in primitive space groups with no screw axis - 6ZQR, 6ZQY,
6ZR0 and 9FCF in P 4, and 6NEN in P 3 1 2. They are in the battery as negative controls for
screw-axis detection: the correct answer for each has no systematic absences.
Twelve datasets are in primitive, non-triclinic space groups with no screw axis - 6P8P, 6ZQR,
6ZQY, 6ZR0, 9FCF and 9FCG in P 4, 6PB3 and 9UPT in P 6, 5JVN in P 6 2 2, 6NEN in P 3 1 2, 8SQO in
P 4 3 2 and 9HNC in P 1 2 1. They are negative controls for screw-axis detection: the correct
answer for each has no systematic absences.
6Z9G is the collection's only index-4 superstructure: its deposited cell is four times the
sublattice a/2, b, c/2, and the four copies of each of its two entities are related by the
@@ -254,8 +273,10 @@ contain).
**6R72 - two collections on one crystal.** The Zenodo record holds two complete 360° sweeps of
3600 × 0.1° frames taken from the same crystal: a helical collection, which produced the
deposited structure, and a low-dose collection from a single position, which was not used for a
deposition and therefore has no PDB entry. Both are in the table, sharing one DOI; the deposited
values belong to the helical collection only. The record also ships the authors' `XDS.INP`.
deposition. The battery's `6r72` row runs the **low-dose** collection (`V-CK63-8-ld_1_master.h5`,
pinned) and scores it against the deposited space group and cell, which describe the same crystal;
the deposited resolution belongs to the helical collection. The helical collection is in the
archive but is not a battery row. The record also ships the authors' `XDS.INP`.
**The three CHESS depositions - wedges plus a measured background.** Each crystal was rotated in
50° wedges of 500 × 0.1° frames and translated between wedges to spread the dose. Each crystal
@@ -292,7 +313,7 @@ the rest were deleted, so a run over the data directory sees a single collection
| 9CRW | a dose pair on one crystal 37 min apart - 0.025 s at 289 mm, 0.010 s at 276 mm | the 0.025 s sweep, whose 2.5 Å target matches the deposited 2.49 Å |
| 7RIS | two crystals at two wavelengths - 1.53494 Å (Ho derivative) and 1.03329 Å (the deposited native) | **both** |
**Eleven further archives hold more than one collection.** Their layout was read from the
**Thirteen further archives hold more than one collection.** Their layout was read from the
image files and repository listings; one sweep is kept for a run over the data directory unless
noted.
@@ -309,8 +330,10 @@ noted.
| 9E2T | one continuous sweep plus screening images | the 2700-frame sweep |
| 8OWM | three MXRDR zips covering one 1800-frame sweep, plus a processed-data zip | the three sweep zips (proc zip skipped) |
| 7D98 | one 250 × 0.5° miniCBF sweep (frames 11-260), plus four HDF5 masters that repeat frames 61-260 in 60-frame pieces | the miniCBF sweep; the HDF5 files stay beside it and the row is pinned |
| 6H2P | two sweeps of one crystal, 1800 × 0.1° at 0.918 Å and 3600 × 0.1° at 1.893 Å (the Mn K edge) | **both**, as two battery rows, `6h2p_native` and `6h2p_1p89A`; the long-wavelength row has no deposited resolution to compare with |
| 8C3E | four 0.5° ω scans of one crystal at different (φ, χ) settings, 56, 150, 150 and 50 frames (`lcb2_8_newt_001` to `_004`) | the 150-frame `_003` scan |
**Three archives needed special handling to obtain the images.**
**Four archives needed special handling to obtain the images.**
- **5KY6** is served by MXRDR as 11 separate RAR archives, one folder of frames per archive, 50
frames per archive except the last, 564 frames in all. Reading them needs a RAR reader with
@@ -320,6 +343,9 @@ noted.
downloaded by hand in a browser.
- **4P8R**'s IRRMC tar holds one 800 × 0.2° sweep as per-frame `.bz2` files, which rugnux does
not read; they were decompressed with `bunzip2` after extraction.
- **2WNN, 2WNQ, 2WNZ, 2XFW and 4BWL** are each served by the Zenodo record as two zips of 180
frames (`<pdb>-images-1-180.zip`, `<pdb>-images-181-360.zip`, or `2wnq-181-360.zip`); both were
extracted into one directory, which holds the one 360 × 0.5° sweep.
## Datasets published as Raw Data Letters
@@ -342,6 +368,57 @@ The authors of the second letter also published their own reciprocal-space recon
6RLR data as a separate Zenodo record,
[10.5281/zenodo.6961763](https://doi.org/10.5281/zenodo.6961763).
## Twinned and pseudo-symmetric datasets
The rows below are twinned, or have a lattice metrically close to a higher symmetry than the
crystal's - the case where a data-reduction program is most easily led into the wrong point group.
What is said here is read from the depositions and their cells, except where a sentence says
otherwise; where the battery keeps further evidence for a row, it is in
`tools/battery/symmetry/<id>/`.
**The pathological-data series.** 2WNN, 2WNQ, 2WNZ, 2XFW and 4BWL come from one Zenodo record,
"A series of pathological macromolecular crystallography datasets with twinning and other lattice
disorders" ([10.5281/zenodo.54568](https://doi.org/10.5281/zenodo.54568)), which was published
for testing data-processing and refinement programs and is described in I. Campeotto, A. Lebedev,
A. M. M. Schreurs, L. M. J. Kroon-Batenburg, E. Lowe, S. E. V. Phillips, G. N. Murshudov and
A. R. Pearson, "Pathological macromolecular crystallographic data affected by twinning,
partial-disorder and exhibiting multiple lattices for testing of data processing and refinement
tools" (2018), Sci. Rep. 8, 14876
[doi:10.1038/s41598-018-32962-6](https://doi.org/10.1038/s41598-018-32962-6). All five are
deposited in P 1 21 1 with c cos β ≈ -a/2, so the lattice is metrically C-centred orthorhombic,
and the twin law four of them declare, -h,-k,h+l, is the two-fold that orthorhombic lattice adds:
| PDB | Deposited twin fraction of -h,-k,h+l |
|---|---|
| 4BWL | 0.488 |
| 2WNQ | 0.463 |
| 2WNN | 0.334 |
| 2XFW | 0.096 |
| 2WNZ | none declared |
At a fraction near 0.5 the intensities have the symmetry of C 2 2 2<sub>1</sub>, so these rows
test whether a twinned P 2<sub>1</sub> crystal is reported as C 2 2 2<sub>1</sub>. For 4BWL and
2WNQ, refining the deposited model in each candidate group keeps P 2<sub>1</sub>, and no
C 2 2 2<sub>1</sub> operator maps the deposited chains onto each other; neither row accepts
C 2 2 2<sub>1</sub> as an alternative.
**8C3E** is a home-source dataset deposited in P 3<sub>1</sub> 2 1 with no twin law declared,
whose intensities, the depositor's included, read Laue class 6/mmm in POINTLESS: the operator that makes
6/mmm out of -3m1 is a merohedral twin law of P 3<sub>1</sub> 2 1, and refining the deposited
model keeps P 3<sub>1</sub> 2 1. The 75° scan also leaves the screw along c open; a run that
names that axis as undetermined and offers the deposited group among its alternatives scores the
row `unscored` (`screw_undetermined`, see `tools/battery/README.md`) rather than failed.
**3MC4 and 3R6O** carry a `reference_mismatch` note in the manifest: the uploaded frames are of a
crystal twinned about 30% (law k,h,-l, seen also by XDS on the same frames), while the deposited
data are of an untwinned crystal of the same form. The row is scored as usual; the note tells the
reader of a report that the merged statistics are not expected to match the deposition's.
**Pseudo-symmetric cells.** 6OWW (P 1 21 1, a ≈ b, β = 89.9°), 6P8J (P 1 21 1, β = 90.1°),
9QW2 (P 1 21 1, a ≈ c, β = 90.9°), 5OJV (P 21 21 2, a ≈ c), 7Q6J (P 21 21 21, b ≈ c) and 9QVV
(I 2 2 2, b ≈ c) all have a deposited cell within a fraction of a degree or of an ångström of a
higher lattice symmetry. 6OWW is one of the rows that accept an alternative answer, below.
## Detector column for marCCD and SMV files
marCCD and SMV files name the detector differently - or not at all. A marCCD file names no model:
@@ -354,16 +431,20 @@ Detector column carries what the file itself establishes: the plate size (`marCC
plate`), the comment's name where one is present (`Rayonix MX-300`), or the serial (`SMV, S/N
930`).
8C3E's files are CBF written by CrysAlisPro's HPAD export, whose header gives the image size
(`# Detector: 775 x 800`) and no model; its row carries that (`CrysAlisPro HPAD, 775 x 800`).
The PDB entry names the detector as a Rigaku HyPix-6000HE.
## Deposited models and structure factors
184 of the 191 datasets have a released PDB entry, and RCSB
reports released structure factors (`status_code_sf = REL`) for every one of them. A merged
All 201 PDB entries in the table are released, and RCSB reports released structure factors
(`status_code_sf = REL`) for every one of them; the six small-molecule datasets have none. A merged
result from this pipeline can therefore be checked against the deposited model or against the
deposited intensities.
## Rows where our reduction and the deposition disagree
Six of the 181 rows are ones where `rugnux` does not reproduce the deposited space group or
Seven of the battery's rows are ones where `rugnux` does not reproduce the deposited space group or
cell, and where we have looked at the disagreement closely enough to change how the row is
scored. They are collected here because a scoring row that silently disagrees with a published
entry is not something a reader should have to discover from the code.
@@ -383,7 +464,7 @@ How the manifest records it, in `tools/battery/open.json`:
fields it names - a space group, a cell, or both - and the row passes if our answer matches any
of the references, the deposited one included. Each must carry `why`; an alternative with no
stated reason is a schema error, not a silent pass, so the mechanism cannot become a way to
turn a failure into a pass quietly. This is how the five knife-edge rows below are recorded:
turn a failure into a pass quietly. This is how the six knife-edge rows below are recorded:
we are not asserting that our answer is right, only that both descriptions are defensible and
that picking either one is acceptable. The report counts these rows separately from ordinary
passes and prints the reason, so a reader can see how many there are and judge each.
@@ -395,7 +476,7 @@ How the manifest records it, in `tools/battery/open.json`:
### 8XBP is a question about provenance, not about symmetry
8XBP is different in kind from the other five and should not be read alongside them. Nothing
8XBP is different in kind from the other six and should not be read alongside them. Nothing
here concerns the deposited model or its space group. The question is whether the raw images
uploaded with the entry are the same crystal the deposited cell describes: the master file
records `data_collection_date` 2023-06-21 where the entry records a collection date of
@@ -452,7 +533,8 @@ Whether this crystal is partially twinned or purely pseudo-symmetric has not bee
Here the better-supported answer is the deposited one, which is the opposite of 8XTE: the two
rows look alike in the table and are not alike in the evidence. Both answers are accepted.
**6PXB.** Unscored rather than overridden, because the evidence does not settle either way. Our
**6PXB.** Both answers accepted rather than overridden, because the evidence does not settle
either way. Our
merge and POINTLESS both read a 312 point group, the added two-folds correlate at or above the
level of the three-folds nobody disputes, and merging in the higher group *lowers*
R<sub>meas</sub> at twice the multiplicity. Against that, the deposited asymmetric unit's six
@@ -463,7 +545,7 @@ accepted and the row still tests everything else about the set.
### 9RCI: two defensible descriptions of one lattice
The sixth row is not about symmetry but about which cell describes the crystal. The Patterson
This row is not about symmetry but about which cell describes the crystal. The Patterson
has an off-origin peak at 62.5% of the origin, so a genuine translational NCS relates the two
halves of the cell `rugnux` reports, and the deposited cell is that supercell's
(0, 1/2, 1/2)-centred sublattice to 0.17%. Both are correct descriptions of the same diffraction:
@@ -473,7 +555,20 @@ not a measurement, so the row accepts either. The alternative cell recorded in t
computed from the deposited cell alone (c' = b + 2c, centring removed), not copied from our
output, so it stays a statement about the deposition's lattice.
### The limit that applies to all four symmetry rows
### 6OWW: a monoclinic deposition whose intensities read tetragonal
6OWW is deposited in P 1 2<sub>1</sub> 1 with eight chains, on a cell with a ≈ b and β = 89.9°.
The deposited model nearly obeys the added operators: a four-fold to 0.13-0.16 Å and a two-fold
to 0.10 Å, and its |F<sub>c</sub>|<sup>2</sup> correlate across the added 422 operators at
0.97-1.00. POINTLESS reads Laue class 4/mmm both on our observations and on the depositor's
amplitudes, and ZANUDA, refining the deposited model in each candidate group, prefers
P 4<sub>3</sub> 2<sub>1</sub> 2 to P 2<sub>1</sub> on our data and on the depositor's, with lower
R-free each time. The row accepts P 4<sub>1</sub> 2<sub>1</sub> 2 (the enantiomorph pair is
counted as one by the scorer) beside the deposited group. As with the trigonal and tetragonal rows
above, an exact pseudo-symmetry would explain the same observations, so this is an accepted
alternative and not a statement that the deposition is wrong.
### The limit that applies to all five symmetry rows
A merohedral twin at a twin fraction of exactly 0.5 and a crystal that genuinely has the higher
symmetry predict **identical** intensities. No amount of data and no refinement R separates them,
@@ -484,11 +579,19 @@ and completeness; where it is a pseudo-symmetry that close, merging in it costs
measurable either. That is why these rows are described as open questions, and why none of them
should be read as a statement that a deposited model is wrong.
## Dataset directories whose name is not the PDB code
## Battery rows whose id is not the PDB code
| Directory | PDB code in the table | Why |
| Battery id | PDB code in the table | Why |
|---|---|---|
| `7brr` | 7D1M | The IRRMC archive and its DOI are published under 7BRR, which the PDB obsoleted on 2020-10-28 and replaced with 7D1M. The directory and the DOI keep the archive's own name; the deposited values are 7D1M's. |
| `7brr` | 7D1M | The IRRMC archive and its DOI are published under 7BRR, which the PDB obsoleted on 2020-10-28 and replaced with 7D1M. The battery id, the directory and the DOI keep the archive's own name; the deposited values are 7D1M's. |
| `6h2p_native` | 6H2P | the 0.918 Å sweep of the 6H2P archive, which the deposition's resolution belongs to |
| `6h2p_1p89A` | 6H2P | the 1.893 Å sweep of the same crystal; scored on the deposited space group and cell only |
## Datasets in the table that are not in the battery
| PDB | Why |
|---|---|
| 9VX7 | The uploaded sweep does not index in the deposited cell, with `rugnux` or with DIALS or XDS given that cell, while XDS indexes it de novo in a different cell; the deposited values cannot be scored against these images, so the row is not in the battery. |
## An archive that ships placeholder images
@@ -500,7 +603,6 @@ reader that globs `*.img` will pick them up, so they are named here rather than
| Dataset | Repository record | Why there is no PDB code |
|---|---|---|
| `6r72/ld` | Zenodo record 10.5281/zenodo.14894181, file prefix `V-CK63-8-ld_1_` | a second collection in the 6R72 record - a low-dose sweep on the same crystal, not the one the deposited structure was built from |
| `cuhf2` | Zenodo record 10.5281/zenodo.6347466 | a small-molecule dataset, not a PDB deposition |
| `dnba` | Zenodo record 10.5281/zenodo.1036416 | a small-molecule dataset, not a PDB deposition |
| `metformin` | Zenodo record 10.5281/zenodo.20135265 | a small-molecule dataset, not a PDB deposition |
@@ -530,24 +632,26 @@ symmetries rather than to be easy to process. The counts below describe where it
like everything else on this page, they are metadata about the depositions and their files, not
measurements.
- **Repository:** IRRMC 95, SBGrid 38, Zenodo 34, MXRDR 16, Keele University 4, ESRF 3, XRDa 5,
UQ eSpace 1.
- **Repository**, over the 207 datasets on this page (the 201 rows of the table and the six
small-molecule sets): IRRMC 95, Zenodo 42, SBGrid 40, MXRDR 16, Keele University 5, XRDa 5,
ESRF 3, UQ eSpace 1.
- **Facility** - counted from the facility part of the Facility / beamline column, the beamline
ignored so that entries deposited with and without one count the same, over the 185 rows that
name one: APS 28, Diamond 20, ESRF 17, NSLS-II 14, BESSY 12, PETRA III 12, SSRL 11, ALS 8,
SLS 8, SPring-8 8, SOLEIL 7, SSRF 7, PAL/PLS 5, CHESS 4, CLSI 4, ALBA 3, Australian
Synchrotron 3, ELETTRA 2, LNLS 2, MAX IV 2, NSLS 2, Photon Factory 2, and one each from NSRRC,
RRCAT Indus-2, SRS Daresbury and EMBL/DESY Hamburg (DORIS) - 26 facilities. The other ten rows were collected on laboratory sources: nine on
rotating anodes and one on a liquid-metal jet.
- **Crystal system, from the deposited space group of the 189 PDB-coded rows:** orthorhombic 47,
monoclinic 44, tetragonal 31, trigonal 21, hexagonal 20, cubic 13, triclinic 13.
- **Pink beam:** none of these datasets was collected with pink beam. All 189 PDB-coded rows
are deposited as `SINGLE WAVELENGTH` (`_diffrn_radiation.pdbx_diffrn_protocol`), and all
but 5REO, which leaves the field blank, as monochromatic (`pdbx_monochromatic_or_laue_m_l`
`M`); 9Q41 is the one row recorded with a multilayer rather than a crystal monochromator
(CHESS Rh/B4C). The battery's pink-beam data are in-house SLS measurements (tag `pink-beam`
in `tools/battery/inhouse.json`), not on this page.
- **Long cell axes:** sixteen PDB-coded rows have a deposited cell axis longer than 320 Å - 4P8R,
ignored so that entries deposited with and without one count the same, over the 190 rows that
name one: APS 29, Diamond 21, ESRF 19, NSLS-II 14, PETRA III 13, BESSY 12, SSRL 11, ALS 9,
SLS 8, SPring-8 8, SOLEIL 7, SSRF 7, PAL/PLS 5, CHESS 4, ALBA 3, Australian Synchrotron 3,
CLSI 3, ELETTRA 2, LNLS 2, MAX IV 2, NSLS 2, Photon Factory 2, and one each from NSRRC,
RRCAT Indus-2, SRS Daresbury and EMBL/DESY Hamburg (DORIS) - 26 facilities. The other eleven
rows were collected on laboratory sources: nine on rotating anodes, one on a liquid-metal jet
and one on a sealed tube.
- **Crystal system, from the deposited space group of the 201 rows:** monoclinic 53,
orthorhombic 50, tetragonal 30, trigonal 22, hexagonal 20, cubic 13, triclinic 13.
- **Pink beam:** none of these datasets was collected with pink beam. All 201 rows are deposited
as `SINGLE WAVELENGTH` (`_diffrn_radiation.pdbx_diffrn_protocol`), and all but 5REO, which
leaves the field blank, as monochromatic (`pdbx_monochromatic_or_laue_m_l` `M`); 9Q41 is the
one row recorded with a multilayer rather than a crystal monochromator (CHESS Rh/B4C). The
battery's pink-beam data are in-house SLS measurements (tag `pink-beam` in
`tools/battery/inhouse.json`), not on this page.
- **Long cell axes:** sixteen rows have a deposited cell axis longer than 320 Å - 4P8R,
4MTK, 7D98, 8V4O, 9ZMU, 9V16, 9Z72, 4NWV, 9YL4, 5NW5, 6QAJ, 7QIJ, 8T7R, 9H0Q, 6G1F and 6OEL.
The marCCD, SMV and gzip-compressed miniCBF datasets are the reason rugnux reads those formats
+32 -26
View File
@@ -13,10 +13,9 @@ the paper of the entry.
- **Dataset DOI**: the CXIDB entry's own DOI, resolved against DataCite before it was written down.
- **Space group, cell, resolution and R-free** are the values deposited with the PDB entry, read from
the RCSB data API. Every entry is a dark or ground state refined against observed data; entries
refined against extrapolated structure factors (the time points of a pump-probe series) are not
used, because a merge of the measured images cannot be compared with them.
- **Images** are the frames in the files we use, counted in the files themselves.
the RCSB data API. Every entry is a dark or ground state refined against observed data.
- **Images used** are the frames in the files we use, counted in the files themselves. Where that is
only part of the entry, the table says so and gives what the entry or the deposition holds.
## Datasets
@@ -29,30 +28,43 @@ the paper of the entry.
| `pal90` | [90](https://cxidb.org/id-90.html), [10.11577/1511590](https://doi.org/10.11577/1511590) | PAL-XFEL NCI | Rayonix MX225-HS; Cheetah CXI | [6IRK](https://www.rcsb.org/structure/6IRK) | I 2 2 2, 1.75 | Lee et al., Sci. Rep. (2019) |
| `lcls222` | [222](https://cxidb.org/id-222.html), [10.11577/2204603](https://doi.org/10.11577/2204603) | LCLS MFX | Rayonix MX340-HS, 1920 x 1920, 177 µm; LCLS-I XTC | [8TDQ](https://www.rcsb.org/structure/8TDQ) | P 65 2 2, 1.65 | Nguyen et al., J. Am. Chem. Soc. (2023) |
| `lcls242_s`, `lcls242_t` | [242](https://cxidb.org/id-242.html), [10.11577/3374214](https://doi.org/10.11577/3374214) | LCLS MFX | Rayonix MX340-HS; LCLS-I XTC | [9O4S](https://www.rcsb.org/structure/9O4S) (small cell), [9O4T](https://www.rcsb.org/structure/9O4T) (large cell) | P 1 21 1, 1.95 | Wolff et al., bioRxiv (2026) |
| `euxfel83` | [83](https://cxidb.org/id-83.html), [10.11577/1464102](https://doi.org/10.11577/1464102) | European XFEL SPB/SFX | AGIPD 1M, 16 x (512 x 128), 200 µm; Cheetah CXI | [6GTH](https://www.rcsb.org/structure/6GTH) | P 32 2 1, 1.69 | Wiedorn et al., Nat. Commun. (2018) |
| `euxfel83` | [83](https://cxidb.org/id-83.html), [10.11577/1464102](https://doi.org/10.11577/1464102) | European XFEL SPB/SFX | AGIPD 1M, 16 modules of 512 x 128, 200 µm; Cheetah CXI | [6GTH](https://www.rcsb.org/structure/6GTH) | P 32 2 1, 1.69 | Wiedorn et al., Nat. Commun. (2018) |
| `euxfel152` | [152](https://cxidb.org/id-152.html), [10.11577/1660970](https://doi.org/10.11577/1660970) | European XFEL SPB/SFX | AGIPD 1M; Cheetah CXI | [6U57](https://www.rcsb.org/structure/6U57) | I 2 3, 2.80 | Echelmeier et al., Nat. Commun. (2020) |
| `alvra103`, `alvra103_int16` | [103](https://cxidb.org/id-103.html), [10.11577/1650020](https://doi.org/10.11577/1650020) | SwissFEL Alvra | JUNGFRAU 16M, 75 µm; SwissFEL HDF5, float32 keV (converted) | [6S0L](https://www.rcsb.org/structure/6S0L) | C 2 2 21, 2.65 | Nass et al., IUCrJ (2020) |
| `alvra213`, `alvra213_int16` | [213](https://cxidb.org/id-213.html), [10.11577/2282689](https://doi.org/10.11577/2282689) | SwissFEL Alvra | JUNGFRAU 4M, 75 µm; SwissFEL HDF5, float32 keV (converted) | [8BKH](https://www.rcsb.org/structure/8BKH) (dark state) | P 1 21 1, 1.35 | Barends et al., Nature (2024) |
Every set of the manifest is in the table and every set in the table is in the manifest, with the
same CXIDB entry, PDB entry, space group and d<sub>min</sub>; `tools/battery/doc_check.py` checks
this. The beamline of `pal90` is the CXIDB entry's (NCI); the PDB entry 6IRK records CSI.
## The files we use
Paths are relative to the still data root of the site config (`tools/battery/README.md`). CXIDB
serves `https://cxidb.org/data/<entry>/...`; most of it accepts HTTP range requests, so a
broken download resumes with `curl -C -`.
| Set | Files | Images | Size |
|---|---|---|---|
| `sacla243` | `sacla_243/raw_all/run*.h5`: all 87 files of `243/Complete_dark/` | 52,151 | 198 GB |
| `sacla237` | `sacla_237/raw/`: the 18 files `run130637-0` to `run130642-2` of `237/SACLA_raw/2022Nov/dark_ref/` (the dark reference; the time points are not used) | 10,792 | 48 GB |
| `sacla236` | `sacla_236/raw/`: the 18 files `run157084-0` to `run157089-2` of `236/Data/lyso01-apo-bigXtal/` | 16,083 | 67 GB |
| `pal86` | `pal_86/raw/`, `pal_86/raw_more/`: `CXIDB_86_themolysin_{2..25}_SFX_Nam.cxi` (file 1 is truncated on the server and cannot be opened) | 49,193 | 111 GB |
| `pal90` | `pal_90/raw/`: `CXIDB_90-GI_SFX-filter-r000{1,2}-c00.cxi` | 11,947 | 25 GB |
| `lcls222` | `lcls_222/xtc/`, `lcls_222/xtc_more/`: `mfx/mfxlu5017/xtc/e1277-r0165-{s00-c00,s00-c01,s01-c00,s01-c01,s02-c00}.xtc` (run 165, the substrate-bound state of 8TDQ) | 8,534 | 72 GB |
| `lcls242_*` | `lcls_242/xtc/`, `lcls_242/xtc_more/`: `xtc/mfxl1013721-r0256` to `r0267` streams (the two crystal forms are in every run; each set keeps its own form) | ~90,000 | ~700 GB |
| `euxfel83` | `euxfel_83/raw/`: `XFEL-r0243-c00.cxi`, `XFEL-r0278-c00.cxi`, `XFEL-r0280-c00.cxi` (Cheetah hits, from the entry's `cheetah-calib-mar-v1/hdf5/` tree on the NERSC archive); `euxfel_83/ref/agipd_mar18_v10.geom` from the entry | 2,790 | 4.7 GB |
| `euxfel152` | `euxfel_152/raw/`: runs r0108, 0110, 0112, 0114, 0115, 0116, 0118, 0123, 0125 extracted from `XFEL2042-runs-cxi.tar` (range requests on the tar members); `euxfel_152/ref/kdo_embedded.geom`, the geometry embedded in the header of the entry's `KDO8PS.stream` | 3,801 | 5.7 GB |
| `alvra103` | `swissfel_103/raw/`: `Raw_Files/2018-08-07/a2a/run{10..24}.JF06T32V01.h5`; `swissfel_103/ref/jf-16M.geom` from the entry | ~11,000 | ~750 GB |
| `alvra213` | `swissfel_213/raw/march_dark_MbCO_II-March-06/data/dark/run_*.JF06T08V01.h5`, from `march/march_dark_MbCO_II-March-06.tar.gz` (425 GB; download it to disk and extract, a streamed extraction does not survive a broken connection); `swissfel_213/ref/mbco_march.geom` from the JUNGFRAU geometry template of `2019-MARCH-SwissFEL-MbCO-supplement.tar.gz` | ~38,000 | ~430 GB |
| Set | Files | Images used | Of the entry | Size |
|---|---|---|---|---|
| `sacla243` | `sacla_243/raw_all/run*.h5`: all 87 files of `243/Complete_dark/` | 52,151 | all (the deposition's 52,151) | 198 GB |
| `sacla237` | `sacla_237/raw/`: the 18 files `run130637-0` to `run130642-2` of `237/SACLA_raw/2022Nov/dark_ref/` | 10,792 | **subset**: 18 of about 1,000 `dark_ref` files, about 1.8% of ~600,000 hits | 48 GB |
| `sacla236` | `sacla_236/raw/`: the 18 files `run157084-0` to `run157089-2` of `236/Data/lyso01-apo-bigXtal/` | 16,083 | all (the deposition's 16,083) | 67 GB |
| `pal86` | `pal_86/raw/`, `pal_86/raw_more/`: `CXIDB_86_themolysin_{2..25}_SFX_Nam.cxi` (file 1 is truncated on the server and cannot be opened) | 49,193 | all but file 1 (24 of 25 files) | 111 GB |
| `pal90` | `pal_90/raw/`: `CXIDB_90-GI_SFX-filter-r000{1,2}-c00.cxi` | 11,947 | all (both files) | 25 GB |
| `lcls222` | `lcls_222/xtc/`, `lcls_222/xtc_more/`: `mfx/mfxlu5017/xtc/e1277-r0165-{s00-c00,s00-c01,s01-c00,s01-c01,s02-c00}.xtc` (run 165, the substrate-bound state of 8TDQ) | 8,534 | **subset**: run 165 of the runs 165-168 behind 8TDQ | 72 GB |
| `lcls242_*` | `lcls_242/xtc/`, `lcls_242/xtc_more/`: `xtc/mfxl1013721-r0256` to `r0267` streams (the two crystal forms are in every run; each set keeps its own form) | ~90,000 | **subset**: runs 256-267 (44 of about 220 stream files; ~610 GB of ~3 TB) | ~700 GB |
| `euxfel83` | `euxfel_83/raw/`: `XFEL-r0243-c00.cxi`, `XFEL-r0278-c00.cxi`, `XFEL-r0280-c00.cxi` (Cheetah hits, from the entry's `cheetah-calib-mar-v1/hdf5/` tree on the NERSC archive); `euxfel_83/ref/agipd_mar18_v10.geom` from the entry | 2,790 | **subset**: 3 files; the deposited stream has 14,445 frames | 4.7 GB |
| `euxfel152` | `euxfel_152/raw/`: runs r0108, 0110, 0112, 0114, 0115, 0116, 0118, 0123, 0125 extracted from `XFEL2042-runs-cxi.tar` (range requests on the tar members); `euxfel_152/ref/kdo_embedded.geom`, the geometry embedded in the header of the entry's `KDO8PS.stream` | 3,801 | **subset**: 9 runs; the deposited stream has 37,006 frames | 5.7 GB |
| `alvra103` | `swissfel_103/raw/`: `Raw_Files/2018-08-07/a2a/run{10..24}.JF06T32V01.h5`; `swissfel_103/ref/jf-16M.geom` and the pixel mask `swissfel_103/ref/run47.JF06T32V01.mask.h5` from the entry; the set reads `swissfel_103/ref/jf-16M_mask.geom`, a copy with `mask_file` pointed at that mask (see below) | ~11,000 | **subset**: 15 runs of one day; the deposition indexed 199,136 of 2,251,787 images | ~750 GB |
| `alvra213` | `swissfel_213/raw/march_dark_MbCO_II-March-06/data/dark/run_*.JF06T08V01.h5`, from `march/march_dark_MbCO_II-March-06.tar.gz` (425 GB; download it to disk and extract, a streamed extraction does not survive a broken connection); `swissfel_213/ref/mbco_march.geom` from the JUNGFRAU geometry template of `2019-MARCH-SwissFEL-MbCO-supplement.tar.gz`; the pixel mask of run 243 (`data/pixel_mask/` in the same tarball) is used for all runs, through `swissfel_213/ref/mbco_march_mask.geom`, a copy with `mask_file` pointed at it (see below) | ~38,000 | all 24 dark runs of the March 2019 series | ~430 GB |
**The masks of the SwissFEL geometry files.** rugnux takes the pixel masks and bad regions a CrystFEL
geometry file names. The SwissFEL files name their mask with an absolute path on the facility's disk,
so each set reads a copy whose `mask_file` is relative to the copy's own directory (a relative mask
file is looked for in the working directory first, as CrystFEL does, then beside the geometry file):
`swissfel_103/ref/jf-16M_mask.geom` is `jf-16M.geom` with `mask_file = run47.JF06T32V01.mask.h5`, and
`swissfel_213/ref/mbco_march_mask.geom` is `mbco_march.geom` with
`mask_file = ../raw/march_dark_MbCO_II-March-06/data/pixel_mask/run_000243.JF06T08V01.mask.h5`. Only
that line differs.
**The `_int16` sets.** The SwissFEL files store converted JUNGFRAU data as uncompressed float32 keV,
68 MB (JF16M) or 17 MB (JF4M) a frame, which caps reading at about 74 or 295 frames/s at 5 GB/s. The
@@ -60,11 +72,5 @@ broken download resumes with `curl -C -`.
by the photon energy, rounded) as int16 with bitshuffle/LZ4, about 25 times smaller; rugnux reads them
with `--gain 1` and merges them to the same numbers. Make them with
`tools/battery/still/float32_to_int16.py <in.h5> <out.h5> <photon energy keV>` (h5py and hdf5plugin),
into `swissfel_103/conv/` (4.57 keV) and `swissfel_213/conv/` (12.037 keV), named `<input>_int16.h5`.
## Not in the battery
- **Time points of pump-probe series** (e.g. the light data of CXIDB 237 and 213): every deposited time
point was refined against extrapolated structure factors.
- **Raw JUNGFRAU data** (ADC values with gain bits that need pedestal and gain correction, e.g. LCLS
CXIDB 189 and 214): only converted detector data are read.
into `swissfel_103/conv/` (4.57 keV) and `swissfel_213/conv/` (12.037 keV, keeping the tarball's
directory tree), named `<input>_int16.h5`. One MbCO dark run (`run_000238`) holds no frames and has no copy.
+1
View File
@@ -342,6 +342,7 @@ In legacy/VDS mode these live in the data files and are linked/virtual-stacked i
| `peakDistEwaldSphere` | Å⁻¹ | distance of the spot from the Ewald sphere | ✓ |
| `peakIndexed` | | spot fits the indexing solution | ✓ |
| `peakLattice` | | lattice the spot belongs to (`-1` = unindexed) | ✓ |
| `peakPanel` | | panel the spot was found on (`-1` = none); written only for a detector with a panel table | |
**Per-image vectors `[n_images]`:**
+1 -1
View File
@@ -495,7 +495,7 @@ Geometry overrides (defaults are taken from the input file; override them to rep
| `--pixel-size <num>` | Pixel size (µm), for a file that does not state it (an XTC stream of an unknown camera) |
| `--gain <num>` | Detector units per photon, for SACLA, CXI, XTC and `--crystfel-geometry` input: the frames are converted to photons with it. Default: for SACLA and CXI input, measured on the background of a few frames; XTC frames stay in detector units ([Serial XFEL inputs](RUGNUX_FORMATS.md#serial-xfel-inputs)) |
| `--saturation <num>` | Pixel value from which a pixel is overloaded, in the units the frames are read in. Replaces the file's limit and the one stills read off the frames |
| `--crystfel-geometry <file>` | Place the panels of an HDF5/CXI input by a CrystFEL geometry file instead of the file's own metadata: module geometry and camera length only (optional; [Serial XFEL inputs](RUGNUX_FORMATS.md#serial-xfel-inputs)) |
| `--crystfel-geometry <file>` | Place the panels of an HDF5/CXI input by a CrystFEL geometry file instead of the file's own metadata: module geometry, camera length, mask arrays and bad regions (optional; [Serial XFEL inputs](RUGNUX_FORMATS.md#serial-xfel-inputs)) |
| `--module-geometry <file>` | Where the detector's modules are: an NXmx file with one NXdetector_module per module (what a run writes as `<prefix>_modules.h5`) or a CrystFEL geometry file whose panels are laid on the image. Overrides the input's own |
| `--refine-modules[=off]` | Stills: place each module as a rigid block in the geometry bundle adjustment, where that predicts held-out spots better (default: on). Used for a foreign multi-panel detector, measured and reported only for a JUNGFRAU; the placement is written to `<prefix>_modules.h5` |
| `--mask-good [<file>:]<dataset>[@<bits>]` / `--mask-bad [<file>:]<dataset>[@<bits>]` | HDF5/CXI stills: a mask array in the frames' stored layout, in `<file>` or in each data file; usable only where non-zero (or with all `<bits>`) / unusable where non-zero (or with any `<bits>`). Repeatable ([Serial XFEL inputs](RUGNUX_FORMATS.md#serial-xfel-inputs)) |
+18 -10
View File
@@ -73,15 +73,16 @@ the file does not state is either measured by rugnux or given on the command lin
at **one wavelength** (the mean of the per-shot photon energies where the file states them), the
**beam centre is measured** (the file's centre, the background-isotropy measurement and the
point-symmetry capture are indexed on a sample of frames and the best is kept), and a SACLA or CXI
file that states **no gain** is converted to photons with the gain its background shows (`--gain`
overrides; XTC frames stay in detector units unless `--gain` is given).
file that states **no gain** is converted to photons with the gain its background shows - where the
pixel values resolve single photons, the spacing of their photon peaks, so a baseline the file left in
does not hide it (`--gain` overrides; XTC frames stay in detector units unless `--gain` is given).
The saturation level is read off the frames where the file states none.
| Format | Read from the file | Measured by rugnux | Given on the command line |
|---|---|---|---|
| **Cheetah HDF5 with per-shot groups and a panel table** (`/tag-N/data`, sensors stacked in one frame, their placement in `/metadata` - as SACLA writes for the MPCCD) | the sensors' positions and in-plane angles, pixel size, nominal camera length and pixel mask (`/metadata`); each shot's photon energy | beam centre, gain, saturation; with a cell, the camera length (the stated one is nominal) and each sensor's placement | nothing; `--detector-distance` to give the camera length |
| **Cheetah CXI, single-panel detector** (`/entry_1/data_1/data`, square frames, e.g. a Rayonix at PAL-XFEL) | pixel size, photon energy per shot, camera length, `mask_shared` | beam centre, gain, saturation | `--detector-distance` where the stated camera length is wrong |
| **LCLS-I XTC, Rayonix** (Camera::FrameV1 events; one or more streams) | photon energy per event (electron-beam record), pixel size (Rayonix model and binning), the camera's pixel offset | beam centre, saturation | `--detector-distance` (not recorded in XTC); `--pixel-size`/`--wavelength` only where the XTC lacks them |
| **Cheetah CXI, single-panel detector** (`/entry_1/data_1/data`, square frames, e.g. a Rayonix at PAL-XFEL) | pixel size, photon energy per shot, camera length, `mask_shared` | beam centre, gain, saturation; with a cell, the camera length | `--detector-distance` to hold a camera length |
| **LCLS-I XTC, Rayonix** (Camera::FrameV1 events; one or more streams) | photon energy per event (electron-beam record), pixel size (Rayonix model and binning), the camera's pixel offset | beam centre, saturation; with a cell, the distance | `--detector-distance` without a cell (not recorded in XTC); `--pixel-size`/`--wavelength` only where the XTC lacks them |
The SACLA sensor positions in `/metadata` are the detector's nominal metrology, a few pixels from a
per-beamtime refined geometry; the stills geometry refinement places each sensor as a module (see
@@ -102,10 +103,17 @@ Damaged or compressed XTC images are left out, and so is a last event that a par
ends inside. An XFEL dataset that has already been assembled into single images in an NXmx master
opens like any other HDF5 input.
`--crystfel-geometry <file>` places the panels of an HDF5/CXI input by a CrystFEL geometry file. Only
the module geometry is taken from it (panel pixel ranges, fast/slow directions, corners, pixel size,
per-panel `coffset`, the frames' data path) and, optionally, the camera length; everything else it may
hold (gain, masks, bad regions, photon energy, value flags) is ignored, with a note in the log. DIALS
`--crystfel-geometry <file>` places the panels of an HDF5/CXI input by a CrystFEL geometry file. Taken
from it are the module geometry (panel pixel ranges, fast/slow directions, corners, pixel size,
per-panel `coffset`, the frames' data path), optionally the camera length, and the pixels to leave out:
the mask arrays (`mask`, `mask_file`, `mask_good`, `mask_bad`, or up to eight as `maskN_data`,
`maskN_file`, `maskN_goodbits`, `maskN_badbits`; a panel may state its own), the bad regions (`bad*`,
a box in the laboratory plane or a pixel range on a panel), `mask_edge_pixels` and `no_index`. A mask
dataset with one plane per frame, or with `%` in its path, is applied frame by frame. A relative
`mask_file` is looked for in the working directory, as CrystFEL does, and then beside the geometry file.
Where the geometry names mask arrays, the data file's own (the CXI `mask_shared` and per-shot mask, a
panel table's `/metadata/pixelmask`) are not taken: the geometry says which bits matter. Everything else
it may hold (gain, saturation, photon energy, value flags) is ignored, with a note in the log. DIALS
`.expt` files are not read.
A mask array the data files do not hold themselves - e.g. a per-run pixel mask beside the frames - is
@@ -113,8 +121,8 @@ given with `--mask-good [<file>:]<dataset>[@<bits>]` (a pixel is usable only whe
or has all of `<bits>`) or `--mask-bad [<file>:]<dataset>[@<bits>]` (unusable where non-zero, or where it
has any of `<bits>`, e.g. `@0xfeff`), in the frames' own layout, as stored. Without `<file>` the dataset is
read from each data file - a per-frame mask stored beside the frames. Both may be given more than once,
and add to the masks the data files state (the CXI `mask_shared` and per-shot mask, the
`/metadata/pixelmask` of a panel-table file). A gain the background shows at or below one detector unit
and add to the masks the data files or the geometry file state (the CXI `mask_shared` and per-shot mask,
the `/metadata/pixelmask` of a panel-table file, a `--crystfel-geometry` file's masks). A gain the background shows at or below one detector unit
per photon is not applied: such frames stay in detector units.
### Module geometry
+6
View File
@@ -604,6 +604,12 @@ they are the strongest reflections the crystal gave, so they concentrate at low
and recommends attenuating the beam or shortening the exposure (or a second, attenuated low-resolution
sweep).
Stills are different: a still has no rocking event, and its overloaded observations are the fully
recorded ones of the strongest reflections, so they are kept in the merge as a lower bound - the box sum
with every saturated pixel at the saturation limit - and are not counted above.
**`OVERLOADED_REFLECTIONS_KEPT=`** counts them and **`OVERLOADED_REFLECTIONS_KEPT_PCT=`** gives their share
of the integrated reflections; the `OVERLOADS` warning fires from 0.05%.
**`OVERLAPPED_REFLECTIONS_PCT=`** is the share of the predicted reflections whose signal disk a nearer
neighbour's prediction takes pixels from, as the integrator's overlap treatment (`--overlap`, default
`exclude`) assigns them, and **`OVERLAPPED_REFLECTIONS_MAJOR_PCT=`** the share left with less than
+2
View File
@@ -159,6 +159,8 @@ Class | Method | HTTP request | Description
*DefaultApi* | [**preview_plot_bin_get**](docs/DefaultApi.md#preview_plot_bin_get) | **GET** /preview/plot.bin | Generate 1D plot from Jungfraujoch and send in raw binary format. Data are provided as (32-bit) float binary array. This format doesn&#39;t transmit information about X-axis, only values, so it is of limited use for azimuthal integration.
*DefaultApi* | [**preview_plot_get**](docs/DefaultApi.md#preview_plot_get) | **GET** /preview/plot | Generate 1D plot from Jungfraujoch
*DefaultApi* | [**result_scan_get**](docs/DefaultApi.md#result_scan_get) | **GET** /result/scan | Get full scan result
*DefaultApi* | [**rugnux_map_ccp4_get**](docs/DefaultApi.md#rugnux_map_ccp4_get) | **GET** /rugnux/map.ccp4 | Get an electron-density map of the last rugnux live run
*DefaultApi* | [**rugnux_model_cif_get**](docs/DefaultApi.md#rugnux_model_cif_get) | **GET** /rugnux/model.cif | Get the model as placed by the last rugnux live run
*DefaultApi* | [**rugnux_status_get**](docs/DefaultApi.md#rugnux_status_get) | **GET** /rugnux/status | Get live rugnux processing status of the last collection
*DefaultApi* | [**start_post**](docs/DefaultApi.md#start_post) | **POST** /start | Start detector
*DefaultApi* | [**statistics_calibration_get**](docs/DefaultApi.md#statistics_calibration_get) | **GET** /statistics/calibration | Get calibration statistics
+164
View File
@@ -62,6 +62,8 @@ Method | HTTP request | Description
[**preview_plot_bin_get**](DefaultApi.md#preview_plot_bin_get) | **GET** /preview/plot.bin | Generate 1D plot from Jungfraujoch and send in raw binary format. Data are provided as (32-bit) float binary array. This format doesn&#39;t transmit information about X-axis, only values, so it is of limited use for azimuthal integration.
[**preview_plot_get**](DefaultApi.md#preview_plot_get) | **GET** /preview/plot | Generate 1D plot from Jungfraujoch
[**result_scan_get**](DefaultApi.md#result_scan_get) | **GET** /result/scan | Get full scan result
[**rugnux_map_ccp4_get**](DefaultApi.md#rugnux_map_ccp4_get) | **GET** /rugnux/map.ccp4 | Get an electron-density map of the last rugnux live run
[**rugnux_model_cif_get**](DefaultApi.md#rugnux_model_cif_get) | **GET** /rugnux/model.cif | Get the model as placed by the last rugnux live run
[**rugnux_status_get**](DefaultApi.md#rugnux_status_get) | **GET** /rugnux/status | Get live rugnux processing status of the last collection
[**start_post**](DefaultApi.md#start_post) | **POST** /start | Start detector
[**statistics_calibration_get**](DefaultApi.md#statistics_calibration_get) | **GET** /statistics/calibration | Get calibration statistics
@@ -4073,6 +4075,168 @@ This endpoint does not need any parameter.
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **rugnux_map_ccp4_get**
> bytearray rugnux_map_ccp4_get(type=type)
Get an electron-density map of the last rugnux live run
The map of the placed model (`/rugnux/model.cif`) in CCP4 format (mode 2, float), made from the map
coefficients written to `_maps.mtz` (FWT/PHWT, DELFWT/PHDELWT, ANOM/PHANOM). It covers one unit cell centred on the model - along an axis where
the model reaches further than the cell, the model plus 5 A instead - sampled every d_min/3; the mean and
RMS in its header are those of the unit cell, so contour levels in sigma are the usual ones.
### Example
* Bearer Authentication (bearerAuth):
```python
import jfjoch_client
from jfjoch_client.rest import ApiException
from pprint import pprint
# Defining the host is optional and defaults to http://localhost:5232
# See configuration.py for a list of all supported configuration parameters.
configuration = jfjoch_client.Configuration(
host = "http://localhost:5232"
)
# The client must configure the authentication and authorization parameters
# in accordance with the API server security policy.
# Examples for each auth method are provided below, use the example that
# satisfies your auth use case.
# Configure Bearer authorization: bearerAuth
configuration = jfjoch_client.Configuration(
access_token = os.environ["BEARER_TOKEN"]
)
# Enter a context with an instance of the API client
with jfjoch_client.ApiClient(configuration) as api_client:
# Create an instance of the API class
api_instance = jfjoch_client.DefaultApi(api_client)
type = 2fofc # str | `2fofc`: the 2mFo-DFc map; `fofc`: the mFo-DFc difference map; `anom`: the anomalous difference map, (F(+) - F(-)) on the model phases less 90 degrees, where the merge kept the Bijvoet pairs (`anomalous_map` in `/rugnux/status`) (optional) (default to 2fofc)
try:
# Get an electron-density map of the last rugnux live run
api_response = api_instance.rugnux_map_ccp4_get(type=type)
print("The response of DefaultApi->rugnux_map_ccp4_get:\n")
pprint(api_response)
except Exception as e:
print("Exception when calling DefaultApi->rugnux_map_ccp4_get: %s\n" % e)
```
### Parameters
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
**type** | **str**| &#x60;2fofc&#x60;: the 2mFo-DFc map; &#x60;fofc&#x60;: the mFo-DFc difference map; &#x60;anom&#x60;: the anomalous difference map, (F(+) - F(-)) on the model phases less 90 degrees, where the merge kept the Bijvoet pairs (&#x60;anomalous_map&#x60; in &#x60;/rugnux/status&#x60;) | [optional] [default to 2fofc]
### Return type
**bytearray**
### Authorization
[bearerAuth](../README.md#bearerAuth)
### HTTP request headers
- **Content-Type**: Not defined
- **Accept**: application/octet-stream, text/plain
### HTTP response details
| Status code | Description | Response headers |
|-------------|-------------|------------------|
**200** | Map | - |
**400** | Unknown map type | - |
**401** | The current dataset is protected and no valid bearer token was presented. | - |
**404** | The last rugnux live run placed no model or made no maps, or (&#x60;anom&#x60;) has no Bijvoet pairs | - |
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **rugnux_model_cif_get**
> bytearray rugnux_model_cif_get()
Get the model as placed by the last rugnux live run
The model placed against the data by molecular replacement or validation, as mmCIF - the same text as the
`_model.cif` file written beside the data: the data's cell and space group, with the input model's own
metadata (entities, sequences, references, authors, software) kept. Kept as long as `/rugnux/status`.
### Example
* Bearer Authentication (bearerAuth):
```python
import jfjoch_client
from jfjoch_client.rest import ApiException
from pprint import pprint
# Defining the host is optional and defaults to http://localhost:5232
# See configuration.py for a list of all supported configuration parameters.
configuration = jfjoch_client.Configuration(
host = "http://localhost:5232"
)
# The client must configure the authentication and authorization parameters
# in accordance with the API server security policy.
# Examples for each auth method are provided below, use the example that
# satisfies your auth use case.
# Configure Bearer authorization: bearerAuth
configuration = jfjoch_client.Configuration(
access_token = os.environ["BEARER_TOKEN"]
)
# Enter a context with an instance of the API client
with jfjoch_client.ApiClient(configuration) as api_client:
# Create an instance of the API class
api_instance = jfjoch_client.DefaultApi(api_client)
try:
# Get the model as placed by the last rugnux live run
api_response = api_instance.rugnux_model_cif_get()
print("The response of DefaultApi->rugnux_model_cif_get:\n")
pprint(api_response)
except Exception as e:
print("Exception when calling DefaultApi->rugnux_model_cif_get: %s\n" % e)
```
### Parameters
This endpoint does not need any parameter.
### Return type
**bytearray**
### Authorization
[bearerAuth](../README.md#bearerAuth)
### HTTP request headers
- **Content-Type**: Not defined
- **Accept**: chemical/x-mmcif, text/plain
### HTTP response details
| Status code | Description | Response headers |
|-------------|-------------|------------------|
**200** | Placed model | - |
**401** | The current dataset is protected and no valid bearer token was presented. | - |
**404** | The last rugnux live run placed no model | - |
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **rugnux_status_get**
> RugnuxLiveStatus rugnux_status_get()
@@ -7,6 +7,8 @@ Live rugnux processing of the last collection; kept until the next collection st
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**state** | **str** | |
**placed_model** | **bool** | The run placed the model: it can be fetched from &#x60;/rugnux/model.cif&#x60; and its maps from &#x60;/rugnux/map.ccp4&#x60;. |
**anomalous_map** | **bool** | The merge kept the Bijvoet pairs, so with the placed model there is an anomalous difference map (&#x60;/rugnux/map.ccp4?type&#x3D;anom&#x60;). |
**probe** | **str** | Answer of the early lattice probe on the first 60 degrees; empty until it answers |
**probe_s** | **float** | When the probe answered, since the first image | [optional]
**start_to_first_image_s** | **float** | From the START message to the first image; set once the first image arrives | [optional]
@@ -59,6 +59,16 @@ namespace {
throw JFJochException(JFJochExceptionCategory::CBORError, "Float expected");
}
double GetCBORDouble(CborValue &value) {
if (cbor_value_is_double(&value)) {
double tmp;
cborErr(cbor_value_get_double(&value, &tmp));
cborErr(cbor_value_advance(&value));
return tmp;
}
return GetCBORFloat(value);
}
bool GetCBORBool(CborValue &value) {
if (!cbor_value_is_boolean(&value)) {
throw JFJochException(JFJochExceptionCategory::CBORError,
@@ -514,6 +524,8 @@ namespace {
s.dist_ewald_sphere = GetCBORFloat(map_value);
else if (key == "image")
s.image = GetCBORInt(map_value);
else if (key == "panel")
s.panel = static_cast<int16_t>(GetCBORInt(map_value));
else
cbor_value_advance(&map_value);
}
@@ -1299,6 +1311,45 @@ namespace {
}
}
void GetDetectorModules(CborValue &value, std::vector<DetectorModule> &modules) {
const size_t array_len = GetCBORArrayLen(value);
CborValue array_value;
cborErr(cbor_value_enter_container(&value, &array_value));
for (size_t i = 0; i < array_len; i++) {
DetectorModule m;
CborValue map_value;
cborErr(cbor_value_enter_container(&array_value, &map_value));
while (!cbor_value_at_end(&map_value)) {
const auto key = GetCBORString(map_value);
if (key == "x0")
m.x0 = GetCBORInt(map_value);
else if (key == "y0")
m.y0 = GetCBORInt(map_value);
else if (key == "width")
m.width = GetCBORInt(map_value);
else if (key == "height")
m.height = GetCBORInt(map_value);
else if (key == "ox")
m.ox = GetCBORDouble(map_value);
else if (key == "oy")
m.oy = GetCBORDouble(map_value);
else if (key == "fx")
m.fx = GetCBORDouble(map_value);
else if (key == "fy")
m.fy = GetCBORDouble(map_value);
else if (key == "sx")
m.sx = GetCBORDouble(map_value);
else if (key == "sy")
m.sy = GetCBORDouble(map_value);
else
cbor_value_advance(&map_value);
}
cborErr(cbor_value_leave_container(&array_value, &map_value));
modules.push_back(m);
}
cborErr(cbor_value_leave_container(&value, &array_value));
}
bool ProcessStartMessageElement(StartMessage &message, CborValue &value) {
if (cbor_value_at_end(&value))
return false;
@@ -1370,6 +1421,8 @@ namespace {
ProcessAzintMapElement(message, value);
else if (key == "roi_map")
ProcessROIMapElement(message, value);
else if (key == "detector_modules")
GetDetectorModules(value, message.detector_modules);
else if (key == "channels")
GetCBORStringArray(value, message.channels);
else if (key == "detector_translation")
@@ -1616,6 +1669,10 @@ namespace {
else if (key == "b_iso") GetCBORFloatArray(map_value, m.b_iso);
else if (key == "occupancy") GetCBORFloatArray(map_value, m.occupancy);
else if (key == "aniso") GetCBORFloatArray(map_value, m.aniso);
else if (key == "subchain") GetCBORStringArray(map_value, m.subchain);
else if (key == "entity_id") GetCBORStringArray(map_value, m.entity_id);
else if (key == "label_seq") GetCBORInt32Array(map_value, m.label_seq);
else if (key == "metadata_mmcif") m.metadata_mmcif = GetCBORString(map_value);
else SkipCBORValue(map_value);
}
cborErr(cbor_value_leave_container(&value, &map_value));
+34
View File
@@ -238,6 +238,8 @@ inline void CBOR_ENC(CborEncoder &encoder, const SpotToSave& spot) {
CBOR_ENC(mapEncoder, "indexed", spot.indexed);
CBOR_ENC(mapEncoder, "latt", spot.lattice);
CBOR_ENC(mapEncoder, "image", spot.image);
if (spot.panel >= 0)
CBOR_ENC(mapEncoder, "panel", static_cast<int64_t>(spot.panel));
if (spot.indexed) {
CBOR_ENC(mapEncoder, "h", spot.h);
CBOR_ENC(mapEncoder, "k", spot.k);
@@ -484,6 +486,33 @@ inline void CBOR_ENC_AZINT_MAP(CborEncoder &encoder, const StartMessage &msg) {
CBOR_ENC_2D_TYPED_ARRAY(encoder, image);
}
// Not a DECTRIS field. Absent for a flat detector (no panel table), which is what every stream written
// before the key existed means.
inline void CBOR_ENC_DETECTOR_MODULES(CborEncoder &encoder, const std::vector<DetectorModule> &modules) {
if (modules.empty())
return;
CborEncoder arrayEncoder;
cborErr(cbor_encode_text_stringz(&encoder, "detector_modules"));
cborErr(cbor_encoder_create_array(&encoder, &arrayEncoder, modules.size()));
for (const auto &m: modules) {
CborEncoder mapEncoder;
cborErr(cbor_encoder_create_map(&arrayEncoder, &mapEncoder, 10));
CBOR_ENC(mapEncoder, "x0", m.x0);
CBOR_ENC(mapEncoder, "y0", m.y0);
CBOR_ENC(mapEncoder, "width", m.width);
CBOR_ENC(mapEncoder, "height", m.height);
const std::pair<const char *, double> placement[] = {
{"ox", m.ox}, {"oy", m.oy}, {"fx", m.fx}, {"fy", m.fy}, {"sx", m.sx}, {"sy", m.sy}
};
for (const auto &[key, val]: placement) {
cborErr(cbor_encode_text_stringz(&mapEncoder, key));
cborErr(cbor_encode_double(&mapEncoder, val));
}
cborErr(cbor_encoder_close_container(&arrayEncoder, &mapEncoder));
}
cborErr(cbor_encoder_close_container(&encoder, &arrayEncoder));
}
inline void CBOR_ENC_ROI_MAP(CborEncoder &encoder, const StartMessage &msg) {
if (msg.roi_map.empty())
return;
@@ -594,6 +623,10 @@ inline void CBOR_ENC(CborEncoder &encoder, const char* key, const PlacedModelMes
CBOR_ENC(mapEncoder, "b_iso", m.b_iso);
CBOR_ENC(mapEncoder, "occupancy", m.occupancy);
CBOR_ENC(mapEncoder, "aniso", m.aniso);
CBOR_ENC(mapEncoder, "subchain", m.subchain);
CBOR_ENC(mapEncoder, "entity_id", m.entity_id);
CBOR_ENC(mapEncoder, "label_seq", m.label_seq);
CBOR_ENC(mapEncoder, "metadata_mmcif", m.metadata_mmcif);
cborErr(cbor_encoder_close_container(&encoder, &mapEncoder));
}
@@ -835,6 +868,7 @@ void CBORStream2Serializer::SerializeSequenceStart(const StartMessage& message)
CBOR_ENC_PIXEL_MASK(mapEncoder, message);
CBOR_ENC_AZINT_MAP(mapEncoder, message);
CBOR_ENC_ROI_MAP(mapEncoder, message);
CBOR_ENC_DETECTOR_MODULES(mapEncoder, message.detector_modules);
CBOR_ENC(mapEncoder, "channels", message.channels);
CBOR_ENC(mapEncoder, "max_spot_count", message.max_spot_count);
+1127 -14
View File
File diff suppressed because it is too large. Load diff
+1
View File
@@ -17,6 +17,7 @@
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react-swc": "^4.2.3",
"lodash": "^4.17.23",
"molstar": "5.11.0",
"plotly.js-cartesian-dist-min": "^3.3.1",
"react": "^19.2.4",
"react-dom": "^19.2.4",
@@ -3,8 +3,8 @@
import { type DefaultError, queryOptions, type UseMutationOptions } from '@tanstack/react-query';
import { client } from '../client.gen';
import { deleteConfigRugnuxModel, getConfigAzimInt, getConfigBraggIntegration, getConfigDarkMask, getConfigDetector, getConfigFileWriter, getConfigImageFormat, getConfigIndexing, getConfigInstrument, getConfigMask, getConfigMaskTiff, getConfigRoi, getConfigRugnux, getConfigSelectDetector, getConfigSpotFinding, getConfigUserMask, getConfigUserMaskTiff, getConfigZeromqMetadata, getConfigZeromqPreview, getDetectorStatus, getFpgaStatus, getImageBufferImageCbor, getImageBufferImageJpeg, getImageBufferImageTiff, getImageBufferStartCbor, getImageBufferStatus, getImagePusherStatus, getPreviewPedestalTiff, getPreviewPlot, getPreviewPlotBin, getResultScan, getRugnuxStatus, getStatistics, getStatisticsCalibration, getStatisticsDataCollection, getStatus, getVersion, getXfelEventCode, getXfelPulseId, type Options, postCancel, postConfigImageFormatConversion, postConfigImageFormatRaw, postDeactivate, postImageBufferClear, postInitialize, postPedestal, postStart, postTrigger, postWaitTillDone, postWaitUntilRunning, putConfigAzimInt, putConfigBraggIntegration, putConfigDarkMask, putConfigDetector, putConfigFileWriter, putConfigImageFormat, putConfigIndexing, putConfigInstrument, putConfigInternalGeneratorImage, putConfigInternalGeneratorImageTiff, putConfigRoi, putConfigRugnux, putConfigRugnuxModel, putConfigSelectDetector, putConfigSpotFinding, putConfigUserMask, putConfigUserMaskTiff, putConfigZeromqMetadata, putConfigZeromqPreview } from '../sdk.gen';
import type { deleteConfigRugnuxModelData, deleteConfigRugnuxModelError, getConfigAzimIntData, getConfigAzimIntResponse, getConfigBraggIntegrationData, getConfigBraggIntegrationResponse, getConfigDarkMaskData, getConfigDarkMaskResponse, getConfigDetectorData, getConfigDetectorResponse, getConfigFileWriterData, getConfigFileWriterResponse, getConfigImageFormatData, getConfigImageFormatResponse, getConfigIndexingData, getConfigIndexingResponse, getConfigInstrumentData, getConfigInstrumentResponse, getConfigMaskData, getConfigMaskResponse, getConfigMaskTiffData, getConfigMaskTiffResponse, getConfigRoiData, getConfigRoiResponse, getConfigRugnuxData, getConfigRugnuxResponse, getConfigSelectDetectorData, getConfigSelectDetectorResponse, getConfigSpotFindingData, getConfigSpotFindingResponse, getConfigUserMaskData, getConfigUserMaskResponse, getConfigUserMaskTiffData, getConfigUserMaskTiffResponse, getConfigZeromqMetadataData, getConfigZeromqMetadataResponse, getConfigZeromqPreviewData, getConfigZeromqPreviewResponse, getDetectorStatusData, getDetectorStatusError, getDetectorStatusResponse, getFpgaStatusData, getFpgaStatusResponse, getImageBufferImageCborData, getImageBufferImageCborError, getImageBufferImageCborResponse, getImageBufferImageJpegData, getImageBufferImageJpegError, getImageBufferImageJpegResponse, getImageBufferImageTiffData, getImageBufferImageTiffError, getImageBufferImageTiffResponse, getImageBufferStartCborData, getImageBufferStartCborError, getImageBufferStartCborResponse, getImageBufferStatusData, getImageBufferStatusError, getImageBufferStatusResponse, getImagePusherStatusData, getImagePusherStatusError, getImagePusherStatusResponse, getPreviewPedestalTiffData, getPreviewPedestalTiffResponse, getPreviewPlotBinData, getPreviewPlotBinError, getPreviewPlotBinResponse, getPreviewPlotData, getPreviewPlotError, getPreviewPlotResponse, getResultScanData, getResultScanError, getResultScanResponse, getRugnuxStatusData, getRugnuxStatusError, getRugnuxStatusResponse, getStatisticsCalibrationData, getStatisticsCalibrationResponse, getStatisticsData, getStatisticsDataCollectionData, getStatisticsDataCollectionError, getStatisticsDataCollectionResponse, getStatisticsResponse, getStatusData, getStatusResponse, getVersionData, getVersionResponse, getXfelEventCodeData, getXfelEventCodeResponse, getXfelPulseIdData, getXfelPulseIdResponse, postCancelData, postConfigImageFormatConversionData, postConfigImageFormatConversionError, postConfigImageFormatRawData, postConfigImageFormatRawError, postDeactivateData, postDeactivateError, postImageBufferClearData, postImageBufferClearError, postInitializeData, postInitializeError, postPedestalData, postPedestalError, postStartData, postStartError, postTriggerData, postWaitTillDoneData, postWaitTillDoneError, postWaitUntilRunningData, postWaitUntilRunningError, putConfigAzimIntData, putConfigAzimIntError, putConfigBraggIntegrationData, putConfigBraggIntegrationError, putConfigDarkMaskData, putConfigDarkMaskError, putConfigDetectorData, putConfigDetectorError, putConfigFileWriterData, putConfigFileWriterError, putConfigImageFormatData, putConfigImageFormatError, putConfigIndexingData, putConfigIndexingError, putConfigInstrumentData, putConfigInstrumentError, putConfigInternalGeneratorImageData, putConfigInternalGeneratorImageError, putConfigInternalGeneratorImageTiffData, putConfigInternalGeneratorImageTiffError, putConfigRoiData, putConfigRoiError, putConfigRugnuxData, putConfigRugnuxError, putConfigRugnuxModelData, putConfigRugnuxModelError, putConfigSelectDetectorData, putConfigSelectDetectorError, putConfigSpotFindingData, putConfigSpotFindingError, putConfigUserMaskData, putConfigUserMaskError, putConfigUserMaskTiffData, putConfigUserMaskTiffError, putConfigZeromqMetadataData, putConfigZeromqMetadataError, putConfigZeromqPreviewData, putConfigZeromqPreviewError } from '../types.gen';
import { deleteConfigRugnuxModel, getConfigAzimInt, getConfigBraggIntegration, getConfigDarkMask, getConfigDetector, getConfigFileWriter, getConfigImageFormat, getConfigIndexing, getConfigInstrument, getConfigMask, getConfigMaskTiff, getConfigRoi, getConfigRugnux, getConfigSelectDetector, getConfigSpotFinding, getConfigUserMask, getConfigUserMaskTiff, getConfigZeromqMetadata, getConfigZeromqPreview, getDetectorStatus, getFpgaStatus, getImageBufferImageCbor, getImageBufferImageJpeg, getImageBufferImageTiff, getImageBufferStartCbor, getImageBufferStatus, getImagePusherStatus, getPreviewPedestalTiff, getPreviewPlot, getPreviewPlotBin, getResultScan, getRugnuxMapCcp4, getRugnuxModelCif, getRugnuxStatus, getStatistics, getStatisticsCalibration, getStatisticsDataCollection, getStatus, getVersion, getXfelEventCode, getXfelPulseId, type Options, postCancel, postConfigImageFormatConversion, postConfigImageFormatRaw, postDeactivate, postImageBufferClear, postInitialize, postPedestal, postStart, postTrigger, postWaitTillDone, postWaitUntilRunning, putConfigAzimInt, putConfigBraggIntegration, putConfigDarkMask, putConfigDetector, putConfigFileWriter, putConfigImageFormat, putConfigIndexing, putConfigInstrument, putConfigInternalGeneratorImage, putConfigInternalGeneratorImageTiff, putConfigRoi, putConfigRugnux, putConfigRugnuxModel, putConfigSelectDetector, putConfigSpotFinding, putConfigUserMask, putConfigUserMaskTiff, putConfigZeromqMetadata, putConfigZeromqPreview } from '../sdk.gen';
import type { deleteConfigRugnuxModelData, deleteConfigRugnuxModelError, getConfigAzimIntData, getConfigAzimIntResponse, getConfigBraggIntegrationData, getConfigBraggIntegrationResponse, getConfigDarkMaskData, getConfigDarkMaskResponse, getConfigDetectorData, getConfigDetectorResponse, getConfigFileWriterData, getConfigFileWriterResponse, getConfigImageFormatData, getConfigImageFormatResponse, getConfigIndexingData, getConfigIndexingResponse, getConfigInstrumentData, getConfigInstrumentResponse, getConfigMaskData, getConfigMaskResponse, getConfigMaskTiffData, getConfigMaskTiffResponse, getConfigRoiData, getConfigRoiResponse, getConfigRugnuxData, getConfigRugnuxResponse, getConfigSelectDetectorData, getConfigSelectDetectorResponse, getConfigSpotFindingData, getConfigSpotFindingResponse, getConfigUserMaskData, getConfigUserMaskResponse, getConfigUserMaskTiffData, getConfigUserMaskTiffResponse, getConfigZeromqMetadataData, getConfigZeromqMetadataResponse, getConfigZeromqPreviewData, getConfigZeromqPreviewResponse, getDetectorStatusData, getDetectorStatusError, getDetectorStatusResponse, getFpgaStatusData, getFpgaStatusResponse, getImageBufferImageCborData, getImageBufferImageCborError, getImageBufferImageCborResponse, getImageBufferImageJpegData, getImageBufferImageJpegError, getImageBufferImageJpegResponse, getImageBufferImageTiffData, getImageBufferImageTiffError, getImageBufferImageTiffResponse, getImageBufferStartCborData, getImageBufferStartCborError, getImageBufferStartCborResponse, getImageBufferStatusData, getImageBufferStatusError, getImageBufferStatusResponse, getImagePusherStatusData, getImagePusherStatusError, getImagePusherStatusResponse, getPreviewPedestalTiffData, getPreviewPedestalTiffResponse, getPreviewPlotBinData, getPreviewPlotBinError, getPreviewPlotBinResponse, getPreviewPlotData, getPreviewPlotError, getPreviewPlotResponse, getResultScanData, getResultScanError, getResultScanResponse, getRugnuxMapCcp4Data, getRugnuxMapCcp4Error, getRugnuxMapCcp4Response, getRugnuxModelCifData, getRugnuxModelCifError, getRugnuxModelCifResponse, getRugnuxStatusData, getRugnuxStatusError, getRugnuxStatusResponse, getStatisticsCalibrationData, getStatisticsCalibrationResponse, getStatisticsData, getStatisticsDataCollectionData, getStatisticsDataCollectionError, getStatisticsDataCollectionResponse, getStatisticsResponse, getStatusData, getStatusResponse, getVersionData, getVersionResponse, getXfelEventCodeData, getXfelEventCodeResponse, getXfelPulseIdData, getXfelPulseIdResponse, postCancelData, postConfigImageFormatConversionData, postConfigImageFormatConversionError, postConfigImageFormatRawData, postConfigImageFormatRawError, postDeactivateData, postDeactivateError, postImageBufferClearData, postImageBufferClearError, postInitializeData, postInitializeError, postPedestalData, postPedestalError, postStartData, postStartError, postTriggerData, postWaitTillDoneData, postWaitTillDoneError, postWaitUntilRunningData, postWaitUntilRunningError, putConfigAzimIntData, putConfigAzimIntError, putConfigBraggIntegrationData, putConfigBraggIntegrationError, putConfigDarkMaskData, putConfigDarkMaskError, putConfigDetectorData, putConfigDetectorError, putConfigFileWriterData, putConfigFileWriterError, putConfigImageFormatData, putConfigImageFormatError, putConfigIndexingData, putConfigIndexingError, putConfigInstrumentData, putConfigInstrumentError, putConfigInternalGeneratorImageData, putConfigInternalGeneratorImageError, putConfigInternalGeneratorImageTiffData, putConfigInternalGeneratorImageTiffError, putConfigRoiData, putConfigRoiError, putConfigRugnuxData, putConfigRugnuxError, putConfigRugnuxModelData, putConfigRugnuxModelError, putConfigSelectDetectorData, putConfigSelectDetectorError, putConfigSpotFindingData, putConfigSpotFindingError, putConfigUserMaskData, putConfigUserMaskError, putConfigUserMaskTiffData, putConfigUserMaskTiffError, putConfigZeromqMetadataData, putConfigZeromqMetadataError, putConfigZeromqPreviewData, putConfigZeromqPreviewError } from '../types.gen';
/**
* Initialize detector and data acquisition
@@ -785,6 +785,53 @@ export const getRugnuxStatusOptions = (options?: Options<getRugnuxStatusData>) =
queryKey: getRugnuxStatusQueryKey(options)
});
export const getRugnuxModelCifQueryKey = (options?: Options<getRugnuxModelCifData>) => createQueryKey('getRugnuxModelCif', options);
/**
* Get the model as placed by the last rugnux live run
*
* The model placed against the data by molecular replacement or validation, as mmCIF - the same text as the
* `_model.cif` file written beside the data: the data's cell and space group, with the input model's own
* metadata (entities, sequences, references, authors, software) kept. Kept as long as `/rugnux/status`.
*
*/
export const getRugnuxModelCifOptions = (options?: Options<getRugnuxModelCifData>) => queryOptions<getRugnuxModelCifResponse, getRugnuxModelCifError, getRugnuxModelCifResponse, ReturnType<typeof getRugnuxModelCifQueryKey>>({
queryFn: async ({ queryKey, signal }) => {
const { data } = await getRugnuxModelCif({
...options,
...queryKey[0],
signal,
throwOnError: true
});
return data;
},
queryKey: getRugnuxModelCifQueryKey(options)
});
export const getRugnuxMapCcp4QueryKey = (options?: Options<getRugnuxMapCcp4Data>) => createQueryKey('getRugnuxMapCcp4', options);
/**
* Get an electron-density map of the last rugnux live run
*
* The map of the placed model (`/rugnux/model.cif`) in CCP4 format (mode 2, float), made from the map
* coefficients written to `_maps.mtz` (FWT/PHWT, DELFWT/PHDELWT, ANOM/PHANOM). It covers one unit cell centred on the model - along an axis where
* the model reaches further than the cell, the model plus 5 A instead - sampled every d_min/3; the mean and
* RMS in its header are those of the unit cell, so contour levels in sigma are the usual ones.
*
*/
export const getRugnuxMapCcp4Options = (options?: Options<getRugnuxMapCcp4Data>) => queryOptions<getRugnuxMapCcp4Response, getRugnuxMapCcp4Error, getRugnuxMapCcp4Response, ReturnType<typeof getRugnuxMapCcp4QueryKey>>({
queryFn: async ({ queryKey, signal }) => {
const { data } = await getRugnuxMapCcp4({
...options,
...queryKey[0],
signal,
throwOnError: true
});
return data;
},
queryKey: getRugnuxMapCcp4QueryKey(options)
});
export const getConfigZeromqPreviewQueryKey = (options?: Options<getConfigZeromqPreviewData>) => createQueryKey('getConfigZeromqPreview', options);
/**
+2 -2
View File
@@ -1,4 +1,4 @@
// This file is auto-generated by @hey-api/openapi-ts
export { deleteConfigRugnuxModel, getConfigAzimInt, getConfigBraggIntegration, getConfigDarkMask, getConfigDetector, getConfigFileWriter, getConfigImageFormat, getConfigIndexing, getConfigInstrument, getConfigMask, getConfigMaskTiff, getConfigRoi, getConfigRugnux, getConfigSelectDetector, getConfigSpotFinding, getConfigUserMask, getConfigUserMaskTiff, getConfigZeromqMetadata, getConfigZeromqPreview, getDetectorStatus, getFpgaStatus, getImageBufferImageCbor, getImageBufferImageJpeg, getImageBufferImageTiff, getImageBufferStartCbor, getImageBufferStatus, getImagePusherStatus, getLiveEvents, getPreviewPedestalTiff, getPreviewPlot, getPreviewPlotBin, getResultScan, getRugnuxStatus, getStatistics, getStatisticsCalibration, getStatisticsDataCollection, getStatus, getVersion, getXfelEventCode, getXfelPulseId, type Options, postCancel, postConfigImageFormatConversion, postConfigImageFormatRaw, postDeactivate, postImageBufferClear, postInitialize, postPedestal, postStart, postTrigger, postWaitTillDone, postWaitUntilRunning, putConfigAzimInt, putConfigBraggIntegration, putConfigDarkMask, putConfigDetector, putConfigFileWriter, putConfigImageFormat, putConfigIndexing, putConfigInstrument, putConfigInternalGeneratorImage, putConfigInternalGeneratorImageTiff, putConfigRoi, putConfigRugnux, putConfigRugnuxModel, putConfigSelectDetector, putConfigSpotFinding, putConfigUserMask, putConfigUserMaskTiff, putConfigZeromqMetadata, putConfigZeromqPreview } from './sdk.gen';
export { type azim_int_settings, azint_unit, type background, type binning, type bragg_integration_settings, type broker_status, type calibration_statistics, type ClientOptions, color_scale, type crystal_lattice, type dark_mask_settings, type dataset_settings, type dataset_settingsWritable, type deleteConfigRugnuxModelData, type deleteConfigRugnuxModelError, type deleteConfigRugnuxModelErrors, type deleteConfigRugnuxModelResponses, type detector, type detector_list, type detector_list_element, type detector_module, detector_module_direction, detector_power_state, type detector_selection, type detector_settings, detector_state, type detector_status, detector_timing, detector_type, type error_message, type experimental_coord, file_writer_format, type file_writer_settings, type fill_value, type fpga_status, geom_refinement_algorithm, type getConfigAzimIntData, type getConfigAzimIntResponse, type getConfigAzimIntResponses, type getConfigBraggIntegrationData, type getConfigBraggIntegrationResponse, type getConfigBraggIntegrationResponses, type getConfigDarkMaskData, type getConfigDarkMaskResponse, type getConfigDarkMaskResponses, type getConfigDetectorData, type getConfigDetectorResponse, type getConfigDetectorResponses, type getConfigFileWriterData, type getConfigFileWriterResponse, type getConfigFileWriterResponses, type getConfigImageFormatData, type getConfigImageFormatResponse, type getConfigImageFormatResponses, type getConfigIndexingData, type getConfigIndexingResponse, type getConfigIndexingResponses, type getConfigInstrumentData, type getConfigInstrumentResponse, type getConfigInstrumentResponses, type getConfigMaskData, type getConfigMaskResponse, type getConfigMaskResponses, type getConfigMaskTiffData, type getConfigMaskTiffResponse, type getConfigMaskTiffResponses, type getConfigRoiData, type getConfigRoiResponse, type getConfigRoiResponses, type getConfigRugnuxData, type getConfigRugnuxResponse, type getConfigRugnuxResponses, type getConfigSelectDetectorData, type getConfigSelectDetectorResponse, type getConfigSelectDetectorResponses, type getConfigSpotFindingData, type getConfigSpotFindingResponse, type getConfigSpotFindingResponses, type getConfigUserMaskData, type getConfigUserMaskResponse, type getConfigUserMaskResponses, type getConfigUserMaskTiffData, type getConfigUserMaskTiffResponse, type getConfigUserMaskTiffResponses, type getConfigZeromqMetadataData, type getConfigZeromqMetadataResponse, type getConfigZeromqMetadataResponses, type getConfigZeromqPreviewData, type getConfigZeromqPreviewResponse, type getConfigZeromqPreviewResponses, type getDetectorStatusData, type getDetectorStatusError, type getDetectorStatusErrors, type getDetectorStatusResponse, type getDetectorStatusResponses, type getFpgaStatusData, type getFpgaStatusResponse, type getFpgaStatusResponses, type getImageBufferImageCborData, type getImageBufferImageCborError, type getImageBufferImageCborErrors, type getImageBufferImageCborResponse, type getImageBufferImageCborResponses, type getImageBufferImageJpegData, type getImageBufferImageJpegError, type getImageBufferImageJpegErrors, type getImageBufferImageJpegResponse, type getImageBufferImageJpegResponses, type getImageBufferImageTiffData, type getImageBufferImageTiffError, type getImageBufferImageTiffErrors, type getImageBufferImageTiffResponse, type getImageBufferImageTiffResponses, type getImageBufferStartCborData, type getImageBufferStartCborError, type getImageBufferStartCborErrors, type getImageBufferStartCborResponse, type getImageBufferStartCborResponses, type getImageBufferStatusData, type getImageBufferStatusError, type getImageBufferStatusErrors, type getImageBufferStatusResponse, type getImageBufferStatusResponses, type getImagePusherStatusData, type getImagePusherStatusError, type getImagePusherStatusErrors, type getImagePusherStatusResponse, type getImagePusherStatusResponses, type getLiveEventsData, type getLiveEventsError, type getLiveEventsErrors, type getLiveEventsResponse, type getLiveEventsResponses, type getPreviewPedestalTiffData, type getPreviewPedestalTiffErrors, type getPreviewPedestalTiffResponse, type getPreviewPedestalTiffResponses, type getPreviewPlotBinData, type getPreviewPlotBinError, type getPreviewPlotBinErrors, type getPreviewPlotBinResponse, type getPreviewPlotBinResponses, type getPreviewPlotData, type getPreviewPlotError, type getPreviewPlotErrors, type getPreviewPlotResponse, type getPreviewPlotResponses, type getResultScanData, type getResultScanError, type getResultScanErrors, type getResultScanResponse, type getResultScanResponses, type getRugnuxStatusData, type getRugnuxStatusError, type getRugnuxStatusErrors, type getRugnuxStatusResponse, type getRugnuxStatusResponses, type getStatisticsCalibrationData, type getStatisticsCalibrationResponse, type getStatisticsCalibrationResponses, type getStatisticsData, type getStatisticsDataCollectionData, type getStatisticsDataCollectionError, type getStatisticsDataCollectionErrors, type getStatiLine truncated
export { deleteConfigRugnuxModel, getConfigAzimInt, getConfigBraggIntegration, getConfigDarkMask, getConfigDetector, getConfigFileWriter, getConfigImageFormat, getConfigIndexing, getConfigInstrument, getConfigMask, getConfigMaskTiff, getConfigRoi, getConfigRugnux, getConfigSelectDetector, getConfigSpotFinding, getConfigUserMask, getConfigUserMaskTiff, getConfigZeromqMetadata, getConfigZeromqPreview, getDetectorStatus, getFpgaStatus, getImageBufferImageCbor, getImageBufferImageJpeg, getImageBufferImageTiff, getImageBufferStartCbor, getImageBufferStatus, getImagePusherStatus, getLiveEvents, getPreviewPedestalTiff, getPreviewPlot, getPreviewPlotBin, getResultScan, getRugnuxMapCcp4, getRugnuxModelCif, getRugnuxStatus, getStatistics, getStatisticsCalibration, getStatisticsDataCollection, getStatus, getVersion, getXfelEventCode, getXfelPulseId, type Options, postCancel, postConfigImageFormatConversion, postConfigImageFormatRaw, postDeactivate, postImageBufferClear, postInitialize, postPedestal, postStart, postTrigger, postWaitTillDone, postWaitUntilRunning, putConfigAzimInt, putConfigBraggIntegration, putConfigDarkMask, putConfigDetector, putConfigFileWriter, putConfigImageFormat, putConfigIndexing, putConfigInstrument, putConfigInternalGeneratorImage, putConfigInternalGeneratorImageTiff, putConfigRoi, putConfigRugnux, putConfigRugnuxModel, putConfigSelectDetector, putConfigSpotFinding, putConfigUserMask, putConfigUserMaskTiff, putConfigZeromqMetadata, putConfigZeromqPreview } from './sdk.gen';
export { type azim_int_settings, azint_unit, type background, type binning, type bragg_integration_settings, type broker_status, type calibration_statistics, type ClientOptions, color_scale, type crystal_lattice, type dark_mask_settings, type dataset_settings, type dataset_settingsWritable, type deleteConfigRugnuxModelData, type deleteConfigRugnuxModelError, type deleteConfigRugnuxModelErrors, type deleteConfigRugnuxModelResponses, type detector, type detector_list, type detector_list_element, type detector_module, detector_module_direction, detector_power_state, type detector_selection, type detector_settings, detector_state, type detector_status, detector_timing, detector_type, type error_message, type experimental_coord, file_writer_format, type file_writer_settings, type fill_value, type fpga_status, geom_refinement_algorithm, type getConfigAzimIntData, type getConfigAzimIntResponse, type getConfigAzimIntResponses, type getConfigBraggIntegrationData, type getConfigBraggIntegrationResponse, type getConfigBraggIntegrationResponses, type getConfigDarkMaskData, type getConfigDarkMaskResponse, type getConfigDarkMaskResponses, type getConfigDetectorData, type getConfigDetectorResponse, type getConfigDetectorResponses, type getConfigFileWriterData, type getConfigFileWriterResponse, type getConfigFileWriterResponses, type getConfigImageFormatData, type getConfigImageFormatResponse, type getConfigImageFormatResponses, type getConfigIndexingData, type getConfigIndexingResponse, type getConfigIndexingResponses, type getConfigInstrumentData, type getConfigInstrumentResponse, type getConfigInstrumentResponses, type getConfigMaskData, type getConfigMaskResponse, type getConfigMaskResponses, type getConfigMaskTiffData, type getConfigMaskTiffResponse, type getConfigMaskTiffResponses, type getConfigRoiData, type getConfigRoiResponse, type getConfigRoiResponses, type getConfigRugnuxData, type getConfigRugnuxResponse, type getConfigRugnuxResponses, type getConfigSelectDetectorData, type getConfigSelectDetectorResponse, type getConfigSelectDetectorResponses, type getConfigSpotFindingData, type getConfigSpotFindingResponse, type getConfigSpotFindingResponses, type getConfigUserMaskData, type getConfigUserMaskResponse, type getConfigUserMaskResponses, type getConfigUserMaskTiffData, type getConfigUserMaskTiffResponse, type getConfigUserMaskTiffResponses, type getConfigZeromqMetadataData, type getConfigZeromqMetadataResponse, type getConfigZeromqMetadataResponses, type getConfigZeromqPreviewData, type getConfigZeromqPreviewResponse, type getConfigZeromqPreviewResponses, type getDetectorStatusData, type getDetectorStatusError, type getDetectorStatusErrors, type getDetectorStatusResponse, type getDetectorStatusResponses, type getFpgaStatusData, type getFpgaStatusResponse, type getFpgaStatusResponses, type getImageBufferImageCborData, type getImageBufferImageCborError, type getImageBufferImageCborErrors, type getImageBufferImageCborResponse, type getImageBufferImageCborResponses, type getImageBufferImageJpegData, type getImageBufferImageJpegError, type getImageBufferImageJpegErrors, type getImageBufferImageJpegResponse, type getImageBufferImageJpegResponses, type getImageBufferImageTiffData, type getImageBufferImageTiffError, type getImageBufferImageTiffErrors, type getImageBufferImageTiffResponse, type getImageBufferImageTiffResponses, type getImageBufferStartCborData, type getImageBufferStartCborError, type getImageBufferStartCborErrors, type getImageBufferStartCborResponse, type getImageBufferStartCborResponses, type getImageBufferStatusData, type getImageBufferStatusError, type getImageBufferStatusErrors, type getImageBufferStatusResponse, type getImageBufferStatusResponses, type getImagePusherStatusData, type getImagePusherStatusError, type getImagePusherStatusErrors, type getImagePusherStatusResponse, type getImagePusherStatusResponses, type getLiveEventsData, type getLiveEventsError, type getLiveEventsErrors, type getLiveEventsResponse, type getLiveEventsResponses, type getPreviewPedestalTiffData, type getPreviewPedestalTiffErrors, type getPreviewPedestalTiffResponse, type getPreviewPedestalTiffResponses, type getPreviewPlotBinData, type getPreviewPlotBinError, type getPreviewPlotBinErrors, type getPreviewPlotBinResponse, type getPreviewPlotBinResponses, type getPreviewPlotData, type getPreviewPlotError, type getPreviewPlotErrors, type getPreviewPlotResponse, type getPreviewPlotResponses, type getResultScanData, type getResultScanError, type getResultScanErrors, type getResultScanResponse, type getResultScanResponses, type getRugnuxMapCcp4Data, type getRugnuxMapCcp4Error, type getRugnuxMapCcp4Errors, type getRugnuxMapCcp4Response, type getRugnuxMapCcp4Responses, type getRugnuxModelCifData, type getRugnuxModelCifError, type getRugnuxModelCifErrors, type getRugnuxModelCifResponse, type getRugnuxModelCifResponses, type getRugnuxStatusData, type getRugnuxStatusError, type getRugnuxStatusErrors, type getRugnuxStatusResponse, Line truncated
+30 -1
View File
@@ -2,7 +2,7 @@
import type { Client, ClientMeta, Options as Options2, RequestResult, ServerSentEventsResult, TDataShape } from './client';
import { client } from './client.gen';
import type { deleteConfigRugnuxModelData, deleteConfigRugnuxModelErrors, deleteConfigRugnuxModelResponses, getConfigAzimIntData, getConfigAzimIntResponses, getConfigBraggIntegrationData, getConfigBraggIntegrationResponses, getConfigDarkMaskData, getConfigDarkMaskResponses, getConfigDetectorData, getConfigDetectorResponses, getConfigFileWriterData, getConfigFileWriterResponses, getConfigImageFormatData, getConfigImageFormatResponses, getConfigIndexingData, getConfigIndexingResponses, getConfigInstrumentData, getConfigInstrumentResponses, getConfigMaskData, getConfigMaskResponses, getConfigMaskTiffData, getConfigMaskTiffResponses, getConfigRoiData, getConfigRoiResponses, getConfigRugnuxData, getConfigRugnuxResponses, getConfigSelectDetectorData, getConfigSelectDetectorResponses, getConfigSpotFindingData, getConfigSpotFindingResponses, getConfigUserMaskData, getConfigUserMaskResponses, getConfigUserMaskTiffData, getConfigUserMaskTiffResponses, getConfigZeromqMetadataData, getConfigZeromqMetadataResponses, getConfigZeromqPreviewData, getConfigZeromqPreviewResponses, getDetectorStatusData, getDetectorStatusErrors, getDetectorStatusResponses, getFpgaStatusData, getFpgaStatusResponses, getImageBufferImageCborData, getImageBufferImageCborErrors, getImageBufferImageCborResponses, getImageBufferImageJpegData, getImageBufferImageJpegErrors, getImageBufferImageJpegResponses, getImageBufferImageTiffData, getImageBufferImageTiffErrors, getImageBufferImageTiffResponses, getImageBufferStartCborData, getImageBufferStartCborErrors, getImageBufferStartCborResponses, getImageBufferStatusData, getImageBufferStatusErrors, getImageBufferStatusResponses, getImagePusherStatusData, getImagePusherStatusErrors, getImagePusherStatusResponses, getLiveEventsData, getLiveEventsErrors, getLiveEventsResponse, getLiveEventsResponses, getPreviewPedestalTiffData, getPreviewPedestalTiffErrors, getPreviewPedestalTiffResponses, getPreviewPlotBinData, getPreviewPlotBinErrors, getPreviewPlotBinResponses, getPreviewPlotData, getPreviewPlotErrors, getPreviewPlotResponses, getResultScanData, getResultScanErrors, getResultScanResponses, getRugnuxStatusData, getRugnuxStatusErrors, getRugnuxStatusResponses, getStatisticsCalibrationData, getStatisticsCalibrationResponses, getStatisticsData, getStatisticsDataCollectionData, getStatisticsDataCollectionErrors, getStatisticsDataCollectionResponses, getStatisticsResponses, getStatusData, getStatusResponses, getVersionData, getVersionResponses, getXfelEventCodeData, getXfelEventCodeErrors, getXfelEventCodeResponses, getXfelPulseIdData, getXfelPulseIdErrors, getXfelPulseIdResponses, postCancelData, postCancelResponses, postConfigImageFormatConversionData, postConfigImageFormatConversionErrors, postConfigImageFormatConversionResponses, postConfigImageFormatRawData, postConfigImageFormatRawErrors, postConfigImageFormatRawResponses, postDeactivateData, postDeactivateErrors, postDeactivateResponses, postImageBufferClearData, postImageBufferClearErrors, postImageBufferClearResponses, postInitializeData, postInitializeErrors, postInitializeResponses, postPedestalData, postPedestalErrors, postPedestalResponses, postStartData, postStartErrors, postStartResponses, postTriggerData, postTriggerResponses, postWaitTillDoneData, postWaitTillDoneErrors, postWaitTillDoneResponses, postWaitUntilRunningData, postWaitUntilRunningErrors, postWaitUntilRunningResponses, putConfigAzimIntData, putConfigAzimIntErrors, putConfigAzimIntResponses, putConfigBraggIntegrationData, putConfigBraggIntegrationErrors, putConfigBraggIntegrationResponses, putConfigDarkMaskData, putConfigDarkMaskErrors, putConfigDarkMaskResponses, putConfigDetectorData, putConfigDetectorErrors, putConfigDetectorResponses, putConfigFileWriterData, putConfigFileWriterErrors, putConfigFileWriterResponses, putConfigImageFormatData, putConfigImageFormatErrors, putConfigImageFormatResponses, putConfigIndexingData, putConfigIndexingErrors, putConfigIndexingResponses, putConfigInstrumentData, putConfigInstrumentErrors, putConfigInstrumentResponses, putConfigInternalGeneratorImageData, putConfigInternalGeneratorImageErrors, putConfigInternalGeneratorImageResponses, putConfigInternalGeneratorImageTiffData, putConfigInternalGeneratorImageTiffErrors, putConfigInternalGeneratorImageTiffResponses, putConfigRoiData, putConfigRoiErrors, putConfigRoiResponses, putConfigRugnuxData, putConfigRugnuxErrors, putConfigRugnuxModelData, putConfigRugnuxModelErrors, putConfigRugnuxModelResponses, putConfigRugnuxResponses, putConfigSelectDetectorData, putConfigSelectDetectorErrors, putConfigSelectDetectorResponses, putConfigSpotFindingData, putConfigSpotFindingErrors, putConfigSpotFindingResponses, putConfigUserMaskData, putConfigUserMaskErrors, putConfigUserMaskResponses, putConfigUserMaskTiffData, putConfigUserMaskTiffErrors, putConfigUserMaskTiffResponses, putConfigZeromqMetadataData, putConfigZeromqMetadataErrors, putConfigZeromqMetadataResponses, putConfigZeromqPreviewData, putConfigZeroLine truncated
import type { deleteConfigRugnuxModelData, deleteConfigRugnuxModelErrors, deleteConfigRugnuxModelResponses, getConfigAzimIntData, getConfigAzimIntResponses, getConfigBraggIntegrationData, getConfigBraggIntegrationResponses, getConfigDarkMaskData, getConfigDarkMaskResponses, getConfigDetectorData, getConfigDetectorResponses, getConfigFileWriterData, getConfigFileWriterResponses, getConfigImageFormatData, getConfigImageFormatResponses, getConfigIndexingData, getConfigIndexingResponses, getConfigInstrumentData, getConfigInstrumentResponses, getConfigMaskData, getConfigMaskResponses, getConfigMaskTiffData, getConfigMaskTiffResponses, getConfigRoiData, getConfigRoiResponses, getConfigRugnuxData, getConfigRugnuxResponses, getConfigSelectDetectorData, getConfigSelectDetectorResponses, getConfigSpotFindingData, getConfigSpotFindingResponses, getConfigUserMaskData, getConfigUserMaskResponses, getConfigUserMaskTiffData, getConfigUserMaskTiffResponses, getConfigZeromqMetadataData, getConfigZeromqMetadataResponses, getConfigZeromqPreviewData, getConfigZeromqPreviewResponses, getDetectorStatusData, getDetectorStatusErrors, getDetectorStatusResponses, getFpgaStatusData, getFpgaStatusResponses, getImageBufferImageCborData, getImageBufferImageCborErrors, getImageBufferImageCborResponses, getImageBufferImageJpegData, getImageBufferImageJpegErrors, getImageBufferImageJpegResponses, getImageBufferImageTiffData, getImageBufferImageTiffErrors, getImageBufferImageTiffResponses, getImageBufferStartCborData, getImageBufferStartCborErrors, getImageBufferStartCborResponses, getImageBufferStatusData, getImageBufferStatusErrors, getImageBufferStatusResponses, getImagePusherStatusData, getImagePusherStatusErrors, getImagePusherStatusResponses, getLiveEventsData, getLiveEventsErrors, getLiveEventsResponse, getLiveEventsResponses, getPreviewPedestalTiffData, getPreviewPedestalTiffErrors, getPreviewPedestalTiffResponses, getPreviewPlotBinData, getPreviewPlotBinErrors, getPreviewPlotBinResponses, getPreviewPlotData, getPreviewPlotErrors, getPreviewPlotResponses, getResultScanData, getResultScanErrors, getResultScanResponses, getRugnuxMapCcp4Data, getRugnuxMapCcp4Errors, getRugnuxMapCcp4Responses, getRugnuxModelCifData, getRugnuxModelCifErrors, getRugnuxModelCifResponses, getRugnuxStatusData, getRugnuxStatusErrors, getRugnuxStatusResponses, getStatisticsCalibrationData, getStatisticsCalibrationResponses, getStatisticsData, getStatisticsDataCollectionData, getStatisticsDataCollectionErrors, getStatisticsDataCollectionResponses, getStatisticsResponses, getStatusData, getStatusResponses, getVersionData, getVersionResponses, getXfelEventCodeData, getXfelEventCodeErrors, getXfelEventCodeResponses, getXfelPulseIdData, getXfelPulseIdErrors, getXfelPulseIdResponses, postCancelData, postCancelResponses, postConfigImageFormatConversionData, postConfigImageFormatConversionErrors, postConfigImageFormatConversionResponses, postConfigImageFormatRawData, postConfigImageFormatRawErrors, postConfigImageFormatRawResponses, postDeactivateData, postDeactivateErrors, postDeactivateResponses, postImageBufferClearData, postImageBufferClearErrors, postImageBufferClearResponses, postInitializeData, postInitializeErrors, postInitializeResponses, postPedestalData, postPedestalErrors, postPedestalResponses, postStartData, postStartErrors, postStartResponses, postTriggerData, postTriggerResponses, postWaitTillDoneData, postWaitTillDoneErrors, postWaitTillDoneResponses, postWaitUntilRunningData, postWaitUntilRunningErrors, postWaitUntilRunningResponses, putConfigAzimIntData, putConfigAzimIntErrors, putConfigAzimIntResponses, putConfigBraggIntegrationData, putConfigBraggIntegrationErrors, putConfigBraggIntegrationResponses, putConfigDarkMaskData, putConfigDarkMaskErrors, putConfigDarkMaskResponses, putConfigDetectorData, putConfigDetectorErrors, putConfigDetectorResponses, putConfigFileWriterData, putConfigFileWriterErrors, putConfigFileWriterResponses, putConfigImageFormatData, putConfigImageFormatErrors, putConfigImageFormatResponses, putConfigIndexingData, putConfigIndexingErrors, putConfigIndexingResponses, putConfigInstrumentData, putConfigInstrumentErrors, putConfigInstrumentResponses, putConfigInternalGeneratorImageData, putConfigInternalGeneratorImageErrors, putConfigInternalGeneratorImageResponses, putConfigInternalGeneratorImageTiffData, putConfigInternalGeneratorImageTiffErrors, putConfigInternalGeneratorImageTiffResponses, putConfigRoiData, putConfigRoiErrors, putConfigRoiResponses, putConfigRugnuxData, putConfigRugnuxErrors, putConfigRugnuxModelData, putConfigRugnuxModelErrors, putConfigRugnuxModelResponses, putConfigRugnuxResponses, putConfigSelectDetectorData, putConfigSelectDetectorErrors, putConfigSelectDetectorResponses, putConfigSpotFindingData, putConfigSpotFindingErrors, putConfigSpotFindingResponses, putConfigUserMaskData, putConfigUserMaskErrors, putConfigUserMaskResponses, putConfigUserMaskTiffData, putConfigUserMaskTiffErrors, putConfigUserMaskTLine truncated
export type Options<TData extends TDataShape = TDataShape, ThrowOnError extends boolean = boolean, TResponse = unknown> = Options2<TData, ThrowOnError, TResponse> & {
/**
@@ -438,6 +438,35 @@ export const getRugnuxStatus = <ThrowOnError extends boolean = false>(options?:
...options
});
/**
* Get the model as placed by the last rugnux live run
*
* The model placed against the data by molecular replacement or validation, as mmCIF - the same text as the
* `_model.cif` file written beside the data: the data's cell and space group, with the input model's own
* metadata (entities, sequences, references, authors, software) kept. Kept as long as `/rugnux/status`.
*
*/
export const getRugnuxModelCif = <ThrowOnError extends boolean = false>(options?: Options<getRugnuxModelCifData, ThrowOnError>): RequestResult<getRugnuxModelCifResponses, getRugnuxModelCifErrors, ThrowOnError> => (options?.client ?? client).get<getRugnuxModelCifResponses, getRugnuxModelCifErrors, ThrowOnError>({
security: [{ scheme: 'bearer', type: 'http' }],
url: '/rugnux/model.cif',
...options
});
/**
* Get an electron-density map of the last rugnux live run
*
* The map of the placed model (`/rugnux/model.cif`) in CCP4 format (mode 2, float), made from the map
* coefficients written to `_maps.mtz` (FWT/PHWT, DELFWT/PHDELWT, ANOM/PHANOM). It covers one unit cell centred on the model - along an axis where
* the model reaches further than the cell, the model plus 5 A instead - sampled every d_min/3; the mean and
* RMS in its header are those of the unit cell, so contour levels in sigma are the usual ones.
*
*/
export const getRugnuxMapCcp4 = <ThrowOnError extends boolean = false>(options?: Options<getRugnuxMapCcp4Data, ThrowOnError>): RequestResult<getRugnuxMapCcp4Responses, getRugnuxMapCcp4Errors, ThrowOnError> => (options?.client ?? client).get<getRugnuxMapCcp4Responses, getRugnuxMapCcp4Errors, ThrowOnError>({
security: [{ scheme: 'bearer', type: 'http' }],
url: '/rugnux/map.ccp4',
...options
});
/**
* Get ZeroMQ preview settings
*/
+82
View File
@@ -1950,6 +1950,18 @@ export type rugnux_summary_row = {
*/
export type rugnux_live_status = {
state: 'Idle' | 'Running' | 'Done' | 'Failed' | 'Cancelled' | 'Skipped';
/**
* The run placed the model: it can be fetched from `/rugnux/model.cif` and its maps from
* `/rugnux/map.ccp4`.
*
*/
placed_model: boolean;
/**
* The merge kept the Bijvoet pairs, so with the placed model there is an anomalous difference map
* (`/rugnux/map.ccp4?type=anom`).
*
*/
anomalous_map: boolean;
/**
* Answer of the early lattice probe on the first 60 degrees; empty until it answers
*/
@@ -3312,6 +3324,76 @@ export type getRugnuxStatusResponses = {
export type getRugnuxStatusResponse = getRugnuxStatusResponses[keyof getRugnuxStatusResponses];
export type getRugnuxModelCifData = {
body?: never;
path?: never;
query?: never;
url: '/rugnux/model.cif';
};
export type getRugnuxModelCifErrors = {
/**
* The current dataset is protected and no valid bearer token was presented.
*/
401: string;
/**
* The last rugnux live run placed no model
*/
404: unknown;
};
export type getRugnuxModelCifError = getRugnuxModelCifErrors[keyof getRugnuxModelCifErrors];
export type getRugnuxModelCifResponses = {
/**
* Placed model
*/
200: Blob | File;
};
export type getRugnuxModelCifResponse = getRugnuxModelCifResponses[keyof getRugnuxModelCifResponses];
export type getRugnuxMapCcp4Data = {
body?: never;
path?: never;
query?: {
/**
* `2fofc`: the 2mFo-DFc map; `fofc`: the mFo-DFc difference map; `anom`: the anomalous difference map,
* (F(+) - F(-)) on the model phases less 90 degrees, where the merge kept the Bijvoet pairs (`anomalous_map`
* in `/rugnux/status`)
*
*/
type?: '2fofc' | 'fofc' | 'anom';
};
url: '/rugnux/map.ccp4';
};
export type getRugnuxMapCcp4Errors = {
/**
* Unknown map type
*/
400: string;
/**
* The current dataset is protected and no valid bearer token was presented.
*/
401: string;
/**
* The last rugnux live run placed no model or made no maps, or (`anom`) has no Bijvoet pairs
*/
404: unknown;
};
export type getRugnuxMapCcp4Error = getRugnuxMapCcp4Errors[keyof getRugnuxMapCcp4Errors];
export type getRugnuxMapCcp4Responses = {
/**
* Map
*/
200: Blob | File;
};
export type getRugnuxMapCcp4Response = getRugnuxMapCcp4Responses[keyof getRugnuxMapCcp4Responses];
export type getConfigZeromqPreviewData = {
body?: never;
path?: never;
+20
View File
@@ -838,6 +838,8 @@ export const zRugnuxLiveStatus = z.object({
'Cancelled',
'Skipped'
]),
placed_model: z.boolean(),
anomalous_map: z.boolean(),
probe: z.string(),
probe_s: z.number().optional(),
start_to_first_image_s: z.number().optional(),
@@ -1267,6 +1269,24 @@ export const zPutConfigRugnuxModelBody = z.string();
*/
export const zGetRugnuxStatusResponse = zRugnuxLiveStatus;
/**
* Placed model
*/
export const zGetRugnuxModelCifResponse = z.string();
export const zGetRugnuxMapCcp4Query = z.object({
type: z.enum([
'2fofc',
'fofc',
'anom'
]).optional().default('2fofc')
});
/**
* Map
*/
export const zGetRugnuxMapCcp4Response = z.string();
/**
* Everything OK
*/
+10
View File
@@ -9,6 +9,10 @@ import RugnuxTimeline from "./RugnuxTimeline";
import RugnuxSettings from "./RugnuxSettings";
import {CutAlert, lastImageTime, ProbeAlert, RunMessage, StateChip, StepTable, VerdictAlert} from "./RugnuxParts";
import BoltIcon from "@mui/icons-material/Bolt";
import {lazy, Suspense} from "react";
// Mol* is large: loaded only when there is a model to show.
const RugnuxStructureViewer = lazy(() => import("./RugnuxStructureViewer"));
// The summary rows rugnux writes; the ones a crystallographer looks at first get a stronger tile, and
// space group and cell share a row.
@@ -151,6 +155,12 @@ function RugnuxPage({measuring}: { measuring: boolean }) {
</Stack>
</Section>
</Box>
{s.placed_model && s.state !== 'Running' &&
<Section title="Placed model and electron density">
<Suspense fallback={<Typography color="text.secondary">Loading viewer...</Typography>}>
<RugnuxStructureViewer resultKey={`${s.elapsed_s}`} anomalous={s.anomalous_map}/>
</Suspense>
</Section>}
</Stack>
);
@@ -0,0 +1,248 @@
import React, {useCallback, useEffect, useRef, useState} from "react";
import {Alert, Box, Slider, Switch, Typography} from "@mui/material";
import type {PluginContext} from "molstar/lib/mol-plugin/context";
import {authHeaders, noteResponse} from "../auth";
import MolstarCanvas from "./structure/MolstarCanvas";
import {applyModelDisplay, clearScene, getStructureAtoms, getStructureBox, LoadedModel, loadModel, ReprMode}
from "./structure/loadModel";
import {loadMapLayer, MAP_COLORS, MapLayer, setLayerVisible, updateLayerSigma} from "./structure/loadMaps";
import {fullCellFromCcp4, prepareMap} from "./structure/densityCrop";
// The model rugnux live placed, with its 2mFo-DFc, mFo-DFc and (where the merge kept the Bijvoet pairs) anomalous
// difference maps, in Mol*. Set up as aaredb's structure viewer (gitea.psi.ch/mx/aaredb, pages/StructureView.tsx
// and components/Structure/, the PSI MX group's own code): its plugin, Coot mouse controls, model presets, map
// meshes, crop and carve, panel and defaults - on a black stage. Mol* is only loaded with this component
// (React.lazy in RugnuxPage), and every Mol* import lives in ./structure.
type Kind = 'twofofc' | 'fofc' | 'anom';
const hex = (c: number) => '#' + c.toString(16).padStart(6, '0');
const SectionTitle: React.FC<{ children: React.ReactNode }> = ({children}) => (
<Typography sx={{fontSize: '0.6786rem', letterSpacing: '.05em', textTransform: 'uppercase',
color: 'text.secondary', mt: 2, mb: 1}}>{children}</Typography>
);
// one map row: colored dot · name · switch · σ slider + readout (aaredb StructureView.tsx:47-77)
const MapRow: React.FC<{
label: string;
dotColor: string;
on: boolean;
onToggle: (v: boolean) => void;
sigma: number;
min: number;
max: number;
step: number;
onSigma: (v: number) => void;
disabled?: boolean;
}> = ({label, dotColor, on, onToggle, sigma, min, max, step, onSigma, disabled}) => (
<Box sx={{mb: 1}}>
<Box sx={{display: 'flex', alignItems: 'center', gap: 1}}>
<Box sx={{width: 10, height: 10, borderRadius: '3px', bgcolor: dotColor, flex: 'none'}}/>
<Typography sx={{fontSize: '0.8125rem', flex: 1}}>{label}</Typography>
<Typography sx={{fontSize: '0.8125rem', color: 'text.secondary', width: 44, textAlign: 'right'}}>
{sigma.toFixed(1)} σ</Typography>
<Switch size="small" checked={on} disabled={disabled} onChange={(e) => onToggle(e.target.checked)}/>
</Box>
<Slider size="small" value={sigma} min={min} max={max} step={step} disabled={disabled || !on}
onChange={(_, v) => onSigma(v as number)} aria-label={`${label} contour level`}
sx={{mx: 0.5, width: 'calc(100% - 8px)', color: dotColor, '& .MuiSlider-thumb': {width: 12, height: 12}}}/>
</Box>
);
async function fetchBytes(path: string, signal: AbortSignal): Promise<ArrayBuffer | undefined> {
const res = await fetch(path, {headers: authHeaders(), signal});
noteResponse(res);
if (res.status === 404)
return undefined;
if (!res.ok)
throw new Error(`${path}: HTTP ${res.status}`);
return res.arrayBuffer();
}
// resultKey: changes when a new result is there to load; anomalous: it has an anomalous difference map.
function RugnuxStructureViewer({resultKey, anomalous}: { resultKey: string, anomalous: boolean }) {
const pluginRef = useRef<PluginContext | null>(null);
const [pluginReady, setPluginReady] = useState(0);
const [error, setError] = useState<string>();
const [modelLoading, setModelLoading] = useState(true);
const [mapsLoading, setMapsLoading] = useState(false);
const layersRef = useRef<Partial<Record<Kind, MapLayer>>>({});
const modelRefsRef = useRef<LoadedModel['refs']>({});
const sigmaTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
// First load frames the molecule; later results keep the user's camera and clip (aaredb StructureView.tsx:117-121)
const sceneLoadedRef = useRef(false);
const [hasMap, setHasMap] = useState<Record<Kind, boolean>>({twofofc: false, fofc: false, anom: false});
// aaredb factory defaults (state/viewerDefaults.ts:16-23); anomalous as a difference map, +4 sigma
const [show, setShow] = useState<Record<Kind, boolean>>({twofofc: true, fofc: true, anom: true});
const [sigma, setSigma] = useState<Record<Kind, number>>({twofofc: 1.0, fofc: 3.0, anom: 4.0});
const [reprMode, setReprMode] = useState<ReprMode>('cartoon');
const [showWaters, setShowWaters] = useState(false);
const displayRef = useRef({show, sigma, reprMode, showWaters});
displayRef.current = {show, sigma, reprMode, showWaters};
const onPluginReady = useCallback((plugin: PluginContext) => {
pluginRef.current = plugin;
setPluginReady(n => n + 1);
}, []);
// The model, then its maps (aaredb StructureView.tsx maybeLoad / computeAndAttachMaps, 212-295): 2Fo-Fc cropped
// to the model's box + 6 A and carved 4.5 A around the atoms; the difference maps cropped only.
useEffect(() => {
const plugin = pluginRef.current;
if (!plugin)
return;
const abort = new AbortController();
(async () => {
setModelLoading(true);
setMapsLoading(false);
setError(undefined);
try {
await clearScene(plugin);
layersRef.current = {};
setHasMap({twofofc: false, fofc: false, anom: false});
const [cif, map2, map1, mapA] = await Promise.all([
fetchBytes("/rugnux/model.cif", abort.signal),
fetchBytes("/rugnux/map.ccp4?type=2fofc", abort.signal),
fetchBytes("/rugnux/map.ccp4?type=fofc", abort.signal),
anomalous ? fetchBytes("/rugnux/map.ccp4?type=anom", abort.signal) : undefined]);
if (abort.signal.aborted)
return;
if (!cif) {
setError("No placed model");
return;
}
const loaded = await loadModel(plugin, cif, 'model', {resetCamera: !sceneLoadedRef.current, format: 'mmcif'});
sceneLoadedRef.current = true;
modelRefsRef.current = loaded.refs;
const d = displayRef.current;
applyModelDisplay(plugin, loaded.refs, d.reprMode, d.showWaters);
const box = getStructureBox(loaded.structure);
const crop = box ? {...box, marginA: 6} : null;
const atoms = getStructureAtoms(loaded.structure);
setModelLoading(false);
setMapsLoading(true);
const maps: [Kind, '2fofc' | 'fofc' | 'anom', ArrayBuffer | undefined][] =
[['twofofc', '2fofc', map2], ['fofc', 'fofc', map1], ['anom', 'anom', mapA]];
for (const [kind, name, bytes] of maps) {
if (!bytes || abort.signal.aborted)
continue;
const computed = prepareMap(name, fullCellFromCcp4(bytes), crop,
kind === 'twofofc' && atoms.length ? atoms : null);
const layer = await loadMapLayer(plugin, computed, name, d.sigma[kind]);
layersRef.current[kind] = layer;
if (!displayRef.current.show[kind])
setLayerVisible(plugin, layer, false);
setHasMap(h => ({...h, [kind]: true}));
}
} catch (e) {
if (!abort.signal.aborted)
setError(e instanceof Error ? e.message : String(e));
} finally {
if (!abort.signal.aborted) {
setModelLoading(false);
setMapsLoading(false);
}
}
})();
return () => abort.abort();
}, [pluginReady, resultKey, anomalous]);
// σ sliders: debounced param-only updates (re-mesh, no recompute) - aaredb StructureView.tsx:321-330
const applySigma = useCallback((kind: Kind, value: number) => {
setSigma(s => ({...s, [kind]: value}));
if (sigmaTimer.current)
clearTimeout(sigmaTimer.current);
sigmaTimer.current = setTimeout(() => {
const plugin = pluginRef.current;
const layer = layersRef.current[kind];
if (plugin && layer)
void updateLayerSigma(plugin, layer, value);
}, 90);
}, []);
const toggleLayer = useCallback((kind: Kind, visible: boolean) => {
setShow(s => ({...s, [kind]: visible}));
const plugin = pluginRef.current;
const layer = layersRef.current[kind];
if (plugin && layer)
setLayerVisible(plugin, layer, visible);
}, []);
const setDisplay = useCallback((mode: ReprMode, waters: boolean) => {
setReprMode(mode);
setShowWaters(waters);
const plugin = pluginRef.current;
if (plugin)
applyModelDisplay(plugin, modelRefsRef.current, mode, waters);
}, []);
const mapsDisabled = mapsLoading;
return (
<Box sx={{display: 'grid', gridTemplateColumns: {xs: '1fr', md: '1fr 300px'}, border: '1px solid',
borderColor: 'divider', borderRadius: 1, overflow: 'hidden'}}>
<Box sx={{position: 'relative', bgcolor: '#000', height: {xs: '55vh', md: 560}}}>
<MolstarCanvas onReady={onPluginReady}/>
{modelLoading && !error && <Box sx={{position: 'absolute', inset: 0, display: 'flex', alignItems: 'center',
justifyContent: 'center', pointerEvents: 'none'}}>
<Typography sx={{fontSize: '0.875rem', color: '#8aa0b5'}}>loading model…</Typography>
</Box>}
</Box>
<Box sx={{borderLeft: {md: '1px solid'}, borderColor: {md: 'divider'}, p: 1.75}}>
{error && <Alert severity="warning" sx={{mb: 1}}>{error}</Alert>}
<SectionTitle>Model</SectionTitle>
<Box sx={{display: 'flex', gap: 0.75, flexWrap: 'wrap', alignItems: 'center', mb: 0.75}}>
{(['cartoon', 'sticks', 'both'] as const).map((m) => (
<Typography key={m} role="button" tabIndex={0}
onClick={() => setDisplay(m, showWaters)}
onKeyDown={(e) => { if (e.key === 'Enter') setDisplay(m, showWaters); }}
sx={{fontSize: '0.8125rem', px: 1, py: '3px', borderRadius: '8px',
border: '1px solid', cursor: 'pointer',
color: reprMode === m ? 'primary.main' : 'text.secondary',
borderColor: reprMode === m ? 'primary.main' : 'divider'}}
>{m === 'both' ? 'cartoon + sticks' : m}</Typography>
))}
</Box>
<Box sx={{display: 'flex', alignItems: 'center', justifyContent: 'space-between'}}>
<Typography sx={{fontSize: '0.8125rem'}}>Waters</Typography>
<Switch size="small" checked={showWaters} onChange={(e) => setDisplay(reprMode, e.target.checked)}/>
</Box>
<SectionTitle>Maps</SectionTitle>
{hasMap.twofofc && <MapRow label="2Fo−Fc" dotColor={hex(MAP_COLORS.twofofc)} on={show.twofofc}
onToggle={(v) => toggleLayer('twofofc', v)} sigma={sigma.twofofc}
min={0.5} max={4} step={0.1} onSigma={(v) => applySigma('twofofc', v)}
disabled={mapsDisabled}/>}
{hasMap.fofc && <MapRow label="Fo−Fc (±)" dotColor={hex(MAP_COLORS.fofcPos)} on={show.fofc}
onToggle={(v) => toggleLayer('fofc', v)} sigma={sigma.fofc}
min={1} max={8} step={0.5} onSigma={(v) => applySigma('fofc', v)}
disabled={mapsDisabled}/>}
{hasMap.anom && <MapRow label="Anomalous (+)" dotColor={hex(MAP_COLORS.anom)} on={show.anom}
onToggle={(v) => toggleLayer('anom', v)} sigma={sigma.anom}
min={1} max={8} step={0.5} onSigma={(v) => applySigma('anom', v)}
disabled={mapsDisabled}/>}
{mapsLoading && <Typography sx={{fontSize: '0.8125rem', color: 'text.secondary'}}>
computing density maps…</Typography>}
{!modelLoading && !mapsLoading && !hasMap.twofofc &&
<Typography sx={{fontSize: '0.8125rem', color: 'text.secondary'}}>No maps</Typography>}
<SectionTitle>Controls</SectionTitle>
{([
['left drag', 'rotate'],
['right drag', 'zoom'],
['middle drag', 'pan'],
['middle click', 'center on residue'],
['scroll', 'clip'],
] as const).map(([k, v]) => (
<Box key={k} sx={{display: 'flex', justifyContent: 'space-between', py: '1px'}}>
<Typography component="span" sx={{fontSize: '0.75rem', color: 'text.secondary'}}>{k}</Typography>
<Typography component="span" sx={{fontSize: '0.75rem'}}>{v}</Typography>
</Box>
))}
</Box>
</Box>
);
}
export default RugnuxStructureViewer;
@@ -0,0 +1,107 @@
// Adapted from aaredb (gitea.psi.ch/mx/aaredb, the PSI MX group's own code), frontend/src/components/Structure/MolstarCanvas.tsx at 8ece2c2.
import React, { useEffect, useRef, useState } from 'react';
import { Box, Typography } from '@mui/material';
import type { PluginContext } from 'molstar/lib/mol-plugin/context';
import { createStructurePlugin } from './createPlugin';
import { applyCootBindings, wireCootRotate, wireMiddleClickRecenter, wireScrollClip, wireModifierDragRestart } from './cootControls';
// A Mol* WebGL surface: owns the plugin lifecycle (init → onReady → dispose on
// unmount), resize handling and context-loss recovery. At most TWO mount at a
// time (the viewer + its side-by-side compare pane — WebGL contexts are a
// limited browser resource); cards and lists show <img> snapshots only.
const MolstarCanvas: React.FC<{
onReady: (plugin: PluginContext) => void;
}> = ({ onReady }) => {
const containerRef = useRef<HTMLDivElement>(null);
const pluginRef = useRef<PluginContext | null>(null);
const [contextLost, setContextLost] = useState(false);
const [initError, setInitError] = useState<string | null>(null);
useEffect(() => {
let disposed = false;
const container = containerRef.current;
if (!container) return undefined;
// A FRESH canvas per effect run: Mol*'s dispose() deliberately loses the
// WebGL context, so under StrictMode's mount→unmount→mount the second
// init on a reused <canvas> would start dead ("context lost").
const canvas = document.createElement('canvas');
canvas.style.width = '100%';
canvas.style.height = '100%';
canvas.style.display = 'block';
container.appendChild(canvas);
let unwireControls: (() => void) | null = null;
(async () => {
try {
// One-tick deferral: StrictMode's throwaway first pass unmounts
// synchronously, so this skips its WebGL init entirely (and with
// it the ResizeObserver noise from aborting Mol* mid-attach).
await new Promise((r) => setTimeout(r, 0));
if (disposed) return;
const plugin = await createStructurePlugin(canvas, container);
if (disposed) {
plugin.dispose();
return;
}
pluginRef.current = plugin;
// coot control profile: left rotate · right zoom · middle pan ·
// middle-click recenter on residue · scroll clip
applyCootBindings(plugin);
const unRecenter = wireMiddleClickRecenter(plugin);
const unClip = wireScrollClip(plugin);
const unRestart = wireModifierDragRestart(canvas);
const unRotate = wireCootRotate(plugin);
unwireControls = () => { unRecenter(); unClip(); unRestart(); unRotate(); };
if (import.meta.env.DEV) {
(window as unknown as Record<string, unknown>).__structurePlugin = plugin;
}
onReady(plugin);
} catch (e) {
if (!disposed) setInitError(e instanceof Error ? e.message : 'viewer init failed');
}
})();
const onLost = (e: Event) => {
e.preventDefault();
if (!disposed) setContextLost(true);
};
canvas.addEventListener('webglcontextlost', onLost);
const ro = new ResizeObserver(() => pluginRef.current?.handleResize());
ro.observe(container);
return () => {
disposed = true;
ro.disconnect();
canvas.removeEventListener('webglcontextlost', onLost);
unwireControls?.();
pluginRef.current?.dispose();
pluginRef.current = null;
canvas.remove();
setContextLost(false);
setInitError(null);
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return (
<Box ref={containerRef} sx={{ position: 'absolute', inset: 0, overflow: 'hidden' }}>
{(contextLost || initError) && (
<Box sx={{ position: 'absolute', inset: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', bgcolor: 'rgba(0,0,0,.88)' }}>
<Typography
role={contextLost ? 'button' : undefined}
tabIndex={contextLost ? 0 : undefined}
onClick={contextLost ? () => window.location.reload() : undefined}
sx={{ fontSize: '0.875rem', color: '#dfe7ef', cursor: contextLost ? 'pointer' : 'default' }}
>
{contextLost ? 'Graphics context lost — click to reload the viewer' : `Viewer failed to start: ${initError}`}
</Typography>
</Box>
)}
</Box>
);
};
export default MolstarCanvas;
@@ -0,0 +1,198 @@
// Adapted from aaredb (gitea.psi.ch/mx/aaredb, the PSI MX group's own code), frontend/src/components/Structure/molstar/cootControls.ts (camera sync and residue pick left out) at 8ece2c2.
import { PluginContext } from 'molstar/lib/mol-plugin/context';
import { DefaultTrackballBindings } from 'molstar/lib/mol-canvas3d/controls/trackball';
import { Binding } from 'molstar/lib/mol-util/binding';
import { ButtonsType, ModifiersKeys } from 'molstar/lib/mol-util/input/input-observer';
import { StructureElement } from 'molstar/lib/mol-model/structure';
import { Loci } from 'molstar/lib/mol-model/loci';
import { Vec3, Quat } from 'molstar/lib/mol-math/linear-algebra';
import { cootTrackball, toTrackballCoords } from './cootTrackball';
// The "coot" control profile — the mouse language crystallographers already
// know from Coot:
// left drag rotate — Coot 0.9.8's virtual trackball (wireCootRotate)
// right drag zoom in/out
// middle drag pan (translate)
// middle CLICK recenter on the clicked residue (distance/orientation kept)
// scroll clip (slab through the density around the center)
// shift+scroll zoom (kept as an escape hatch)
// Future settings can add other profiles; this is the default.
const B = ButtonsType;
const M = ModifiersKeys;
const T = Binding.Trigger;
export const COOT_TRACKBALL_BINDINGS = {
...DefaultTrackballBindings, // keep key/gamepad bindings intact
// plain left drag is rotate, but NOT via Mol*'s trackball (linear, ~2× faster
// than Coot and never rolls) — wireCootRotate below runs Coot 0.9.8's instead.
dragRotate: Binding.Empty,
dragRotateZ: Binding(
[T(B.Flag.Primary, M.create({ shift: true, control: true }))],
'Rotate around z-axis (roll)', 'Drag using ${triggers}',
),
dragPan: Binding(
[T(B.Flag.Auxilary, M.create()), T(B.Flag.Primary, M.create({ control: true }))],
'Pan', 'Drag using ${triggers}',
),
dragZoom: Binding([T(B.Flag.Secondary, M.create())], 'Zoom', 'Drag using ${triggers}'),
dragFocus: Binding.Empty,
dragFocusZoom: Binding.Empty,
scrollZoom: Binding([T(B.Flag.Auxilary, M.create({ shift: true }))], 'Zoom', 'Scroll using ${triggers}'),
// plain scroll = clip, implemented in wireScrollClip below (the trackball's
// own scrollFocus accumulator proved unreliable; direct camera radius
// updates are deterministic) — keep it Empty here to avoid double handling.
scrollFocus: Binding.Empty,
scrollFocusZoom: Binding.Empty,
};
export function applyCootBindings(plugin: PluginContext): void {
// Bindings are TrackballControls ATTRIBS (construction-time config), not
// props — setProps silently ignores them; setAttribs is the live setter
// (Canvas3D.setAttribs → controls.setAttribs → Object.assign).
plugin.canvas3d?.setAttribs({ trackball: { bindings: COOT_TRACKBALL_BINDINGS } });
// Negative zoomSpeed flips the drag→zoom direction to match Coot's feel
// (Mol*'s default is the opposite); shift+scroll zoom flips with it, which
// keeps the whole zoom gesture family consistent. The PD min/max on this
// param are UI hints only — runtime accepts the negative value.
plugin.canvas3d?.setProps({ trackball: { zoomSpeed: -7 } });
}
/** Left-drag rotation with Coot 0.9.8's virtual trackball (cootTrackball.ts):
* spherical surface, incremental from the previous pointer position, x and y
* normalised by the canvas width and height like Coot's glarea. Mutates the
* camera the way Mol*'s own controls do (position/up in place + requestDraw),
* so camera.changed still fires and the split-view mirror keeps working.
* Returns an unsubscribe. */
export function wireCootRotate(plugin: PluginContext): () => void {
const canvas3d = plugin.canvas3d;
const input = canvas3d?.input;
if (!canvas3d || !input) return () => undefined;
const camera = canvas3d.camera;
let prev: [number, number] | null = null;
const eye = Vec3(), eyeDir = Vec3(), up = Vec3(), side = Vec3(), axis = Vec3();
const q = Quat();
const sub = input.drag.subscribe((e) => {
const m = e.modifiers;
if (e.buttons !== B.Flag.Primary || m.shift || m.control || m.alt || m.meta) { prev = null; return; }
// e.x/e.y are CSS px from the canvas top-left; input.width/height are device px
const pr = input.pixelRatio || 1;
const cur = toTrackballCoords(e.x, e.y, input.width / pr, input.height / pr);
if (e.isStart || !prev) { prev = cur; return; }
const rot = cootTrackball(prev[0], prev[1], cur[0], cur[1]);
prev = cur;
if (!rot) return;
// screen basis in world space: x right, y up, z toward the viewer
Vec3.sub(eye, camera.position, camera.target);
Vec3.normalize(eyeDir, eye);
Vec3.normalize(up, camera.up);
Vec3.normalize(side, Vec3.cross(side, up, eyeDir));
Vec3.scale(axis, side, rot.axis[0]);
Vec3.scaleAndAdd(axis, axis, up, rot.axis[1]);
Vec3.scaleAndAdd(axis, axis, eyeDir, rot.axis[2]);
// the scene turns by +angle about the axis, so the camera turns by the inverse
Quat.setAxisAngle(q, axis, -rot.angle);
Vec3.transformQuat(eye, eye, q);
Vec3.transformQuat(camera.up, camera.up, q);
Vec3.add(camera.position, camera.target, eye);
canvas3d.requestDraw();
});
const end = input.interactionEnd.subscribe(() => { prev = null; });
return () => { sub.unsubscribe(); end.unsubscribe(); };
}
/** Plain scroll adjusts the clip slab (Coot-style): shrinks/grows the visible
* radius around the camera target so the user can focus where the center is.
* Returns an unsubscribe. */
export function wireScrollClip(plugin: PluginContext): () => void {
const input = plugin.canvas3d?.input;
if (!input) return () => undefined;
const sub = input.wheel.subscribe(({ spinY, modifiers }) => {
// shift+scroll stays zoom (trackball binding)
if (modifiers.shift || modifiers.control || modifiers.alt || modifiers.meta) return;
const camera = plugin.canvas3d?.camera;
if (!camera || !spinY) return;
const r = camera.state.radius;
const max = camera.state.radiusMax || r;
const next = Math.min(max, Math.max(1.5, r * (1 - spinY * 0.08)));
if (next !== r) camera.setState({ radius: next });
});
return () => sub.unsubscribe();
}
/** Coot-style recenter: move the camera target to `center`, preserving
* orientation — and distance, unless `distanceA` asks for a specific one
* (blob deep-links arrive zoomed to the scene, not at overview distance).
* Shared by middle-click and the sequence strip. */
export function recenterCamera(plugin: PluginContext, center: Vec3 | number[], distanceA?: number): void {
const camera = plugin.canvas3d?.camera;
if (!camera) return;
const c = Vec3.create(center[0], center[1], center[2]);
const { target, position } = camera.state;
const dir = Vec3.sub(Vec3(), position, target);
if (distanceA) Vec3.setMagnitude(dir, dir, distanceA);
camera.setState(
{
target: c,
position: Vec3.add(Vec3(), c, dir),
// an explicit distance is "frame this spot": clip a coot-like slab
// around it too, so the point of interest isn't buried in density
...(distanceA ? { radius: distanceA * 0.45 } : {}),
},
250,
);
}
/** Mol*'s trackball re-matches drag bindings per event but initializes a
* gesture's anchor only on isStart — pressing/releasing a modifier MID-drag
* (e.g. Ctrl while rotating) switches rotate→pan against a stale anchor and
* the view jumps (measured 18 Å per 10 px). Restart the drag synthetically
* when a modifier toggles while a button is down, so the newly-matched
* gesture starts from the current pointer position. */
export function wireModifierDragRestart(el: HTMLElement): () => void {
let buttons = 0;
let last: { x: number; y: number } | null = null;
const down = (e: MouseEvent) => { buttons = e.buttons; last = { x: e.clientX, y: e.clientY }; };
const move = (e: MouseEvent) => { if (e.buttons) { buttons = e.buttons; last = { x: e.clientX, y: e.clientY }; } };
const up = () => { buttons = 0; last = null; };
const restart = (e: KeyboardEvent) => {
if (!buttons || !last) return;
if (!['Control', 'Shift', 'Alt', 'Meta'].includes(e.key)) return;
const mods = { ctrlKey: e.ctrlKey, shiftKey: e.shiftKey, altKey: e.altKey, metaKey: e.metaKey };
const base = { bubbles: true, clientX: last.x, clientY: last.y, ...mods };
// primary button of the held combination — enough for our bindings.
// Mol*'s InputObserver listens to MOUSE events (not pointer events).
const button = buttons & 4 ? 1 : buttons & 2 ? 2 : 0;
el.dispatchEvent(new MouseEvent('mouseup', { ...base, button, buttons: 0 }));
el.dispatchEvent(new MouseEvent('mousedown', { ...base, button, buttons }));
};
el.addEventListener('mousedown', down);
window.addEventListener('mousemove', move);
window.addEventListener('mouseup', up);
window.addEventListener('keydown', restart);
window.addEventListener('keyup', restart);
return () => {
el.removeEventListener('mousedown', down);
window.removeEventListener('mousemove', move);
window.removeEventListener('mouseup', up);
window.removeEventListener('keydown', restart);
window.removeEventListener('keyup', restart);
};
}
/** Middle-click recenters the view on the clicked residue, Coot-style: the
* camera target moves, orientation and distance stay. Returns an unsubscribe. */
export function wireMiddleClickRecenter(plugin: PluginContext): () => void {
const sub = plugin.behaviors.interaction.click.subscribe((e) => {
if (!(e.button & B.Flag.Auxilary)) return;
let loci = e.current?.loci;
if (!loci || Loci.isEmpty(loci)) return;
if (StructureElement.Loci.is(loci)) {
loci = StructureElement.Loci.extendToWholeResidues(loci);
}
const sphere = Loci.getBoundingSphere(loci);
if (!sphere) return;
recenterCamera(plugin, sphere.center);
});
return () => sub.unsubscribe();
}
@@ -0,0 +1,55 @@
// Adapted from aaredb (gitea.psi.ch/mx/aaredb, the PSI MX group's own code), frontend/src/components/Structure/molstar/cootTrackball.ts at 8ece2c2.
// Coot 0.9.8's virtual trackball — a port of the SGI trackball.c call Coot made
// on every mouse-motion event (globjects.cc, glarea_motion_notify): spherical
// surface, trackball_size 0.8, incremental from the previous pointer position.
// Coot 1.x kept the very same code but defaults to a "flat" surface
// (trackball_size 12.8, graphics-info-statics.cc), which is near-linear, about
// twice as fast per pixel and never rolls — that is what makes new Coot feel
// different. This module is the old feel.
//
// Coordinates are Coot's: x, y in [-1, 1] with (0, 0) at the window centre and
// +y up; x is normalised by the width and y by the height, so on a wide window a
// vertical drag turns more per pixel than a horizontal one — exactly like Coot.
export const COOT_TRACKBALL_SIZE = 0.8;
export type TrackballRotation = {
/** unit axis in screen space: x right, y up, z toward the viewer */
axis: [number, number, number];
/** radians; the scene turns by this about `axis` (the near face follows the pointer) */
angle: number;
};
/** Coot's window → trackball mapping for a pointer at (x, y) CSS px from the top-left. */
export function toTrackballCoords(x: number, y: number, width: number, height: number): [number, number] {
return [(2 * x - width) / width, (height - 2 * y) / height];
}
/** SGI's tb_project_to_sphere: a sphere of radius r out to r/√2, then a
* hyperbolic sheet, so the surface never ends at the window edge. */
export function projectToSphere(r: number, x: number, y: number): number {
const d = Math.hypot(x, y);
const t = r * Math.SQRT1_2;
return d < t ? Math.sqrt(r * r - d * d) : (t * t) / d;
}
/** The scene rotation for a pointer move p1 → p2. Returns null when the pointer
* did not move. Angle = 2·asin(|p1 − p2|·(size − 0.3)/size), clamped, as in
* Coot's trackball() with its d_mult fudge. */
export function cootTrackball(
p1x: number, p1y: number, p2x: number, p2y: number, size = COOT_TRACKBALL_SIZE,
): TrackballRotation | null {
if (p1x === p2x && p1y === p2y) return null;
const p1z = projectToSphere(size, p1x, p1y);
const p2z = projectToSphere(size, p2x, p2y);
// p1 × p2: for a rightward drag from the centre this is +y, and turning the
// scene about +y by a positive angle moves its near face to the right.
const ax = p1y * p2z - p1z * p2y;
const ay = p1z * p2x - p1x * p2z;
const az = p1x * p2y - p1y * p2x;
const len = Math.hypot(ax, ay, az);
if (!len) return null;
const d = Math.hypot(p1x - p2x, p1y - p2y, p1z - p2z);
const t = Math.max(-1, Math.min(1, (d * (size - 0.3)) / size));
return { axis: [ax / len, ay / len, az / len], angle: 2 * Math.asin(t) };
}
@@ -0,0 +1,37 @@
// Mol* setup follows AareDB (G. Gotthard, PSI): adapted from its frontend/src/components/Structure/molstar/createPlugin.ts at 8ece2c2.
// Headless Mol* plugin (no mol-plugin-ui): the render core + state tree +
// builders, driven entirely by our own charter-styled controls. ALL molstar
// imports in the app live under components/structure/ so the lazy
// chunk boundary holds and a version upgrade touches one directory.
// molstar is pinned EXACTLY (5.11.0) — these are lib/ internal paths.
import { PluginContext } from 'molstar/lib/mol-plugin/context';
import { DefaultPluginSpec } from 'molstar/lib/mol-plugin/spec';
import { Color } from 'molstar/lib/mol-util/color';
export type { PluginContext };
export const CANVAS_BG = 0x000000; // black (aaredb: 0x0d1a26, steel/cryo dark stage)
export async function createStructurePlugin(
canvas: HTMLCanvasElement,
container: HTMLDivElement,
): Promise<PluginContext> {
const spec = DefaultPluginSpec();
const plugin = new PluginContext(spec);
await plugin.init();
const ok = await plugin.initViewerAsync(canvas, container);
if (!ok) {
plugin.dispose();
throw new Error('WebGL initialization failed');
}
plugin.canvas3d?.setProps({
renderer: { backgroundColor: Color(CANVAS_BG) },
// No automatic camera resets when the scene's bounds change: the maps
// and the blob marker land seconds after the model (async worker), and
// the default behaviour zoomed the camera back out — losing a blob
// deep-link position and its clip slab. All camera moves are ours
// (loadModel's explicit reset, recenterCamera, flyToBlob).
camera: { manualReset: true },
});
return plugin;
}
@@ -0,0 +1,249 @@
// The density preparation of aaredb's density worker (gitea.psi.ch/mx/aaredb, the PSI MX group's own code,
// frontend/public/structure-worker/density-worker.js at 8ece2c2): crop the periodic map to the model's box plus a
// margin, carve the 2Fo-Fc map around the atoms, encode as CCP4 with the full cell's mean and RMS. aaredb computes
// the full-cell map from an MTZ with gemmi wasm; here the broker serves it (/rugnux/map.ccp4), so it is first read
// back into aaredb's full-cell z-fastest grid (fullCellFromCcp4).
export interface ComputedMap {
name: string;
ccp4: ArrayBuffer;
rmsd: number;
mean: number;
dims: [number, number, number];
}
export interface Cell { a: number; b: number; c: number; alpha: number; beta: number; gamma: number }
export interface CropBox {
min: number[];
max: number[];
marginA: number;
}
export interface FullCellMap {
data: Float32Array; // value(u,v,w) = data[w + nz*(v + ny*u)]
n: [number, number, number];
cell: Cell;
mean: number;
rms: number;
}
// The broker's CCP4 map (any axis order, any start, at least one period along each axis, mean and RMS of the
// whole cell in the header) as the full periodic cell.
export function fullCellFromCcp4(bytes: ArrayBuffer): FullCellMap {
const i32 = new Int32Array(bytes, 0, 256);
const f32 = new Float32Array(bytes, 0, 256);
const count = [i32[0], i32[1], i32[2]]; // NC NR NS
const start = [i32[4], i32[5], i32[6]];
const n: [number, number, number] = [i32[7], i32[8], i32[9]]; // MX MY MZ
const axis = [i32[16] - 1, i32[17] - 1, i32[18] - 1]; // MAPC MAPR MAPS -> x/y/z
const values = new Float32Array(bytes, 1024 + i32[23], count[0] * count[1] * count[2]);
const data = new Float32Array(n[0] * n[1] * n[2]);
const wrap = (i: number, nn: number) => ((i % nn) + nn) % nn;
const g = [0, 0, 0];
let p = 0;
for (let s = 0; s < count[2]; s++)
for (let r = 0; r < count[1]; r++)
for (let c = 0; c < count[0]; c++) {
g[axis[0]] = wrap(start[0] + c, n[axis[0]]);
g[axis[1]] = wrap(start[1] + r, n[axis[1]]);
g[axis[2]] = wrap(start[2] + s, n[axis[2]]);
data[g[2] + n[2] * (g[1] + n[1] * g[0])] = values[p++];
}
return {
data, n,
cell: {a: f32[10], b: f32[11], c: f32[12], alpha: f32[13], beta: f32[14], gamma: f32[15]},
mean: f32[21], rms: f32[54],
};
}
function encodeCcp4(data: Float32Array, dims: number[], start: number[], full: number[], cell: Cell,
mean: number, rms: number): ArrayBuffer {
// dims/start are [x,y,z] grid extents/origins of the (possibly cropped)
// block; full = full-cell sampling counts.
const nx = dims[0], ny = dims[1], nz = dims[2];
const header = new ArrayBuffer(1024);
const i32 = new Int32Array(header);
const f32 = new Float32Array(header);
i32[0] = nz; i32[1] = ny; i32[2] = nx; // NC NR NS (cols=Z fastest)
i32[3] = 2; // MODE 2 = float32
i32[4] = start[2]; i32[5] = start[1]; i32[6] = start[0]; // NCSTART NRSTART NSSTART
i32[7] = full[0]; i32[8] = full[1]; i32[9] = full[2]; // MX MY MZ (full-cell sampling)
f32[10] = cell.a; f32[11] = cell.b; f32[12] = cell.c;
f32[13] = cell.alpha; f32[14] = cell.beta; f32[15] = cell.gamma;
i32[16] = 3; i32[17] = 2; i32[18] = 1; // MAPC MAPR MAPS
let mn = Infinity, mx = -Infinity;
for (let i = 0; i < data.length; i++) {
const v = data[i];
if (v < mn) mn = v;
if (v > mx) mx = v;
}
f32[19] = mn; f32[20] = mx; f32[21] = mean; // DMIN DMAX DMEAN
i32[22] = 1; i32[23] = 0; // ISPG=P1 NSYMBT=0
const u8 = new Uint8Array(header);
u8[208] = 0x4d; u8[209] = 0x41; u8[210] = 0x50; u8[211] = 0x20; // 'MAP '
u8[212] = 0x44; u8[213] = 0x41; u8[214] = 0x00; u8[215] = 0x00; // machst LE
f32[54] = rms; // RMS
i32[55] = 0; // NLABL
const out = new ArrayBuffer(1024 + data.length * 4);
new Uint8Array(out).set(u8, 0);
new Float32Array(out, 1024).set(data);
return out;
}
/* Fractionalization matrix (upper-triangular inverse of the standard
* orthogonalization: a along x, b in the xy-plane). */
function fracMatrix(cell: Cell) {
const d = Math.PI / 180;
const ca = Math.cos(cell.alpha * d), cb = Math.cos(cell.beta * d);
const cg = Math.cos(cell.gamma * d), sg = Math.sin(cell.gamma * d);
const ax = cell.a, bx = cell.b * cg, by = cell.b * sg;
const cx = cell.c * cb, cy = cell.c * (ca - cb * cg) / sg;
const cz = Math.sqrt(Math.max(0, cell.c * cell.c - cx * cx - cy * cy));
return {
m00: 1 / ax, m01: -bx / (ax * by), m02: (bx * cy - by * cx) / (ax * by * cz),
m11: 1 / by, m12: -cy / (by * cz),
m22: 1 / cz,
};
}
function toFrac(M: ReturnType<typeof fracMatrix>, x: number, y: number, z: number) {
return [
M.m00 * x + M.m01 * y + M.m02 * z,
M.m11 * y + M.m12 * z,
M.m22 * z,
];
}
/* Resample the periodic full-cell grid over the model's bounding box (+margin).
* The FFT grid covers exactly one unit cell, but a refined model routinely
* sits partly OUTSIDE the [0,1) box — without this wrap-around crop the mesh
* renders as a displaced cell-shaped block next to the model. Returns
* { data, start: [i0,j0,k0], dims: [ni,nj,nk] } in grid indices (x,y,z axes). */
function cropToBox(data: Float32Array, nx: number, ny: number, nz: number, cell: Cell, box: CropBox) {
const M = fracMatrix(cell);
const m = box.marginA;
const lo = [Infinity, Infinity, Infinity], hi = [-Infinity, -Infinity, -Infinity];
for (let corner = 0; corner < 8; corner++) {
const x = (corner & 1 ? box.max[0] + m : box.min[0] - m);
const y = (corner & 2 ? box.max[1] + m : box.min[1] - m);
const z = (corner & 4 ? box.max[2] + m : box.min[2] - m);
const f = toFrac(M, x, y, z);
for (let t = 0; t < 3; t++) {
if (f[t] < lo[t]) lo[t] = f[t];
if (f[t] > hi[t]) hi[t] = f[t];
}
}
const n = [nx, ny, nz];
const start: number[] = [], count: number[] = [];
for (let u = 0; u < 3; u++) {
const i0 = Math.floor(lo[u] * n[u]) - 1;
const i1 = Math.ceil(hi[u] * n[u]) + 1;
// The block is anchored on the MODEL (starts may be negative) and may
// span MORE than one period: refined models routinely extend across
// cell boundaries (a real case spans 1.2 cells along a and b), and the
// map is periodic so repeated samples are correct. Cap at 3 periods as
// a memory sanity bound.
const cnt = Math.min(i1 - i0 + 1, 3 * n[u]);
start.push(i0);
count.push(cnt);
}
const wrap = (i: number, nn: number) => ((i % nn) + nn) % nn;
const out = new Float32Array(count[0] * count[1] * count[2]);
let p = 0;
// output stays z-fastest to match the full-grid layout
for (let iu = 0; iu < count[0]; iu++) {
const gu = wrap(start[0] + iu, nx);
for (let iv = 0; iv < count[1]; iv++) {
const gv = wrap(start[1] + iv, ny);
const rowBase = nz * (gv + ny * gu);
for (let iw = 0; iw < count[2]; iw++) {
out[p++] = data[wrap(start[2] + iw, nz) + rowBase];
}
}
}
return { data: out, start, dims: count };
}
/* Orthogonalization matrix (fractional -> Cartesian), same convention as
* fracMatrix (a along x, b in the xy-plane). */
function orthoMatrix(cell: Cell) {
const d = Math.PI / 180;
const ca = Math.cos(cell.alpha * d), cb = Math.cos(cell.beta * d);
const cg = Math.cos(cell.gamma * d), sg = Math.sin(cell.gamma * d);
const cx = cell.c * cb;
const cy = cell.c * (ca - cb * cg) / sg;
const cz = Math.sqrt(Math.max(0, cell.c * cell.c - cx * cx - cy * cy));
return { ax: cell.a, bx: cell.b * cg, by: cell.b * sg, cx, cy, cz };
}
/* Carve: zero all block values farther than radiusA from every model atom, so
* the mesh hugs the model instead of filling the whole crop box (the classic
* carved map — also a large triangle-count win). Atoms come as a flat xyz
* Float32Array in Cartesian Å. Masked values become exactly 0, which crosses
* neither a positive nor a negative iso level. */
function carveBlock(block: Float32Array, start: number[], dims: number[], n: number[], cell: Cell,
atoms: Float32Array, radiusA: number) {
const M = fracMatrix(cell);
const O = orthoMatrix(cell);
const mask = new Uint8Array(block.length);
const stepR = [
Math.ceil(radiusA / (cell.a / n[0])) + 1,
Math.ceil(radiusA / (cell.b / n[1])) + 1,
Math.ceil(radiusA / (cell.c / n[2])) + 1,
];
const r2 = radiusA * radiusA;
for (let a = 0; a < atoms.length; a += 3) {
const x = atoms[a], y = atoms[a + 1], z = atoms[a + 2];
const f = toFrac(M, x, y, z);
const gi = [f[0] * n[0] - start[0], f[1] * n[1] - start[1], f[2] * n[2] - start[2]];
const lo0 = Math.max(0, Math.floor(gi[0] - stepR[0]));
const hi0 = Math.min(dims[0] - 1, Math.ceil(gi[0] + stepR[0]));
const lo1 = Math.max(0, Math.floor(gi[1] - stepR[1]));
const hi1 = Math.min(dims[1] - 1, Math.ceil(gi[1] + stepR[1]));
const lo2 = Math.max(0, Math.floor(gi[2] - stepR[2]));
const hi2 = Math.min(dims[2] - 1, Math.ceil(gi[2] + stepR[2]));
for (let iu = lo0; iu <= hi0; iu++) {
const fu = (start[0] + iu) / n[0];
for (let iv = lo1; iv <= hi1; iv++) {
const fv = (start[1] + iv) / n[1];
const rowBase = dims[2] * (iv + dims[1] * iu);
for (let iw = lo2; iw <= hi2; iw++) {
const idx = rowBase + iw;
if (mask[idx]) continue;
const fw = (start[2] + iw) / n[2];
const px = O.ax * fu + O.bx * fv + O.cx * fw;
const py = O.by * fv + O.cy * fw;
const pz = O.cz * fw;
const dx = px - x, dy = py - y, dz = pz - z;
if (dx * dx + dy * dy + dz * dz <= r2) mask[idx] = 1;
}
}
}
}
for (let i = 0; i < block.length; i++) {
if (!mask[i]) block[i] = 0;
}
}
/* One map as the worker's onmessage loop makes it: cropped to `crop`, carved around `carveAtoms` (2Fo-Fc only -
* never a difference map: unmodelled blobs sit away from every atom), with the full cell's mean and RMS. */
export function prepareMap(name: string, full: FullCellMap, crop: CropBox | null, carveAtoms: Float32Array | null,
carveRadiusA = 4.5): ComputedMap {
const [nx, ny, nz] = full.n;
let data = full.data;
let start = [0, 0, 0];
let dims = [nx, ny, nz];
if (crop) {
const cropped = cropToBox(data, nx, ny, nz, full.cell, crop);
data = cropped.data;
start = cropped.start;
dims = cropped.dims;
} else {
data = data.slice();
}
if (carveAtoms)
carveBlock(data, start, dims, [nx, ny, nz], full.cell, carveAtoms, carveRadiusA);
const ccp4 = encodeCcp4(data, dims, start, [nx, ny, nz], full.cell, full.mean, full.rms);
return { name, ccp4, rmsd: full.rms, mean: full.mean, dims: [dims[0], dims[1], dims[2]] };
}
@@ -0,0 +1,109 @@
// Adapted from aaredb (gitea.psi.ch/mx/aaredb, the PSI MX group's own code), frontend/src/components/Structure/molstar/loadMaps.ts (+ the anomalous layer) at 8ece2c2.
import { PluginContext } from 'molstar/lib/mol-plugin/context';
import { StateTransforms } from 'molstar/lib/mol-plugin-state/transforms';
import { createVolumeRepresentationParams } from 'molstar/lib/mol-plugin-state/helpers/volume-representation-params';
import { Volume } from 'molstar/lib/mol-model/volume';
import { Color } from 'molstar/lib/mol-util/color';
import { setSubtreeVisibility } from 'molstar/lib/mol-plugin/behavior/static/state';
import type { ComputedMap } from './densityCrop';
// Density volumes in the Mol* state tree. σ sliders map user-σ to ABSOLUTE iso
// values via the map's full-grid mean/rms (reported by the worker) — Mol*'s own
// relative sigma would re-derive stats from whatever grid it holds, which stops
// being crystallographically meaningful the moment we crop. A σ change is a
// representation param update (re-mesh only — no FFT, no re-upload).
export const MAP_COLORS = {
twofofc: 0x4d94d6, // steel-blue
fofcPos: 0x35b96a, // green
fofcNeg: 0xd6564d, // red
anom: 0xe040e0, // magenta (anomalous difference map, +sigma only)
} as const;
export interface MapLayer {
volumeRef: string;
reprRefs: string[]; // one for 2fofc and anom, two (+/−) for fofc
rmsd: number;
mean: number;
}
const abs = (map: { mean: number; rmsd: number }, sigma: number) =>
Volume.IsoValue.absolute(map.mean + sigma * map.rmsd);
async function addIso(
plugin: PluginContext,
volumeRef: string,
map: ComputedMap,
sigma: number,
color: number,
): Promise<string> {
const volumeCell = plugin.state.data.select(volumeRef)[0];
const repr = plugin
.build()
.to(volumeRef)
.apply(
StateTransforms.Representation.VolumeRepresentation3D,
createVolumeRepresentationParams(plugin, volumeCell?.obj?.data, {
type: 'isosurface',
typeParams: { isoValue: abs(map, sigma), visuals: ['wireframe'], sizeFactor: 1 },
color: 'uniform',
colorParams: { value: Color(color) },
}),
);
await repr.commit();
// The mesh must NOT be pickable: a pickable isosurface shields the model,
// so residue clicks and middle-click recenter would hit map cells instead
// of atoms. Pickability is runtime state on the INNER representation
// (cell.obj.data.repr — the cell data itself has no setState), and the
// pick buffer needs a redraw to drop the mesh.
const reprCell = plugin.state.data.select(repr.ref)[0];
const reprObj = (reprCell?.obj?.data as { repr?: { setState?: (s: { pickable: boolean }) => void } })?.repr;
reprObj?.setState?.({ pickable: false });
plugin.canvas3d?.requestDraw?.();
return repr.ref;
}
export async function loadMapLayer(
plugin: PluginContext,
map: ComputedMap,
kind: '2fofc' | 'fofc' | 'anom',
sigma: number,
): Promise<MapLayer> {
const data = await plugin.builders.data.rawData({
data: new Uint8Array(map.ccp4),
label: kind,
});
const parsed = await plugin.dataFormats.get('ccp4')!.parse(plugin, data);
const volumeRef: string = parsed.volume.ref;
const reprRefs: string[] = [];
if (kind === '2fofc') {
reprRefs.push(await addIso(plugin, volumeRef, map, sigma, MAP_COLORS.twofofc));
} else if (kind === 'anom') {
reprRefs.push(await addIso(plugin, volumeRef, map, sigma, MAP_COLORS.anom));
} else {
reprRefs.push(await addIso(plugin, volumeRef, map, +sigma, MAP_COLORS.fofcPos));
reprRefs.push(await addIso(plugin, volumeRef, map, -sigma, MAP_COLORS.fofcNeg));
}
return { volumeRef, reprRefs, rmsd: map.rmsd, mean: map.mean };
}
/** σ slider update: param-only change, re-mesh without recompute. */
export async function updateLayerSigma(
plugin: PluginContext,
layer: MapLayer,
sigma: number,
): Promise<void> {
const sigmas = layer.reprRefs.length === 2 ? [+sigma, -sigma] : [sigma];
const b = plugin.build();
layer.reprRefs.forEach((ref, i) => {
b.to(ref).update((old: { type: { params: { isoValue: unknown } } }) => {
old.type.params.isoValue = abs(layer, sigmas[i]);
});
});
await b.commit();
}
export function setLayerVisible(plugin: PluginContext, layer: MapLayer, visible: boolean): void {
setSubtreeVisibility(plugin.state.data, layer.volumeRef, !visible); // arg = isHidden
}
@@ -0,0 +1,129 @@
// Adapted from aaredb (gitea.psi.ch/mx/aaredb, the PSI MX group's own code), frontend/src/components/Structure/molstar/loadModel.ts (format option, atom coordinates) at 8ece2c2.
import { PluginContext } from 'molstar/lib/mol-plugin/context';
import { StateObjectSelector } from 'molstar/lib/mol-state';
import { setSubtreeVisibility } from 'molstar/lib/mol-plugin/behavior/static/state';
import { Color } from 'molstar/lib/mol-util/color';
// Chain palette chosen to stay clear of the density colors: no greens (Fo-Fc+),
// no reds/oranges (Fo-Fc− reads orange on some screens) and no strong blues
// (2Fo-Fc). Silver → violet → pink → sand → slate, cycled per chain.
const CHAIN_COLORS = [0xc2cbd6, 0xb18ae0, 0xe08ac2, 0xd8c9a3, 0x8291a5].map(Color);
const CHAIN_PALETTE = {
palette: {
name: 'colors' as const,
params: { list: { kind: 'set' as const, colors: CHAIN_COLORS } },
},
};
// Load a PDB model from bytes into the plugin's state tree. All representations
// are built up front with stable refs; "representation mode" and waters are
// pure visibility flips (setSubtreeVisibility), so switching is instant.
export type ReprMode = 'cartoon' | 'sticks' | 'both';
export interface LoadedModel {
structure: StateObjectSelector;
refs: {
polymerCartoon?: string;
polymerSticks?: string;
ligand?: string;
water?: string;
};
}
export async function loadModel(
plugin: PluginContext,
bytes: ArrayBuffer,
label: string,
opts?: { resetCamera?: boolean, format?: 'pdb' | 'mmcif' },
): Promise<LoadedModel> {
const text = new TextDecoder().decode(bytes);
const data = await plugin.builders.data.rawData({ data: text, label });
const trajectory = await plugin.builders.structure.parseTrajectory(data, opts?.format ?? 'pdb');
const model = await plugin.builders.structure.createModel(trajectory);
const structure = await plugin.builders.structure.createStructure(model);
const refs: LoadedModel['refs'] = {};
const polymer = await plugin.builders.structure.tryCreateComponentStatic(structure, 'polymer');
if (polymer) {
const cartoon = await plugin.builders.structure.representation.addRepresentation(polymer, {
type: 'cartoon',
color: 'chain-id',
colorParams: CHAIN_PALETTE,
});
refs.polymerCartoon = cartoon.ref;
const sticks = await plugin.builders.structure.representation.addRepresentation(polymer, {
type: 'ball-and-stick',
color: 'element-symbol',
});
refs.polymerSticks = sticks.ref;
}
const ligand = await plugin.builders.structure.tryCreateComponentStatic(structure, 'ligand');
if (ligand) {
const r = await plugin.builders.structure.representation.addRepresentation(ligand, {
type: 'ball-and-stick',
});
refs.ligand = r.ref;
}
const water = await plugin.builders.structure.tryCreateComponentStatic(structure, 'water');
if (water) {
const r = await plugin.builders.structure.representation.addRepresentation(water, {
type: 'ball-and-stick',
});
refs.water = r.ref;
}
// defaults: cartoon + ligand sticks; polymer sticks and waters hidden
if (refs.polymerSticks) setSubtreeVisibility(plugin.state.data, refs.polymerSticks, true);
if (refs.water) setSubtreeVisibility(plugin.state.data, refs.water, true);
// Skippable so a pipeline/pair switch keeps the user's view and clip —
// the models of one run share the same crystal frame (assuming they align).
if (opts?.resetCamera !== false) plugin.managers.camera.reset();
return { structure, refs };
}
/** Apply a representation mode + waters flag as visibility flips. */
export function applyModelDisplay(
plugin: PluginContext,
refs: LoadedModel['refs'],
mode: ReprMode,
showWaters: boolean,
): void {
const s = plugin.state.data;
// setSubtreeVisibility's boolean is "isHidden"
if (refs.polymerCartoon) setSubtreeVisibility(s, refs.polymerCartoon, mode === 'sticks');
if (refs.polymerSticks) setSubtreeVisibility(s, refs.polymerSticks, mode === 'cartoon');
if (refs.water) setSubtreeVisibility(s, refs.water, !showWaters);
}
export async function clearScene(plugin: PluginContext): Promise<void> {
await plugin.clear();
}
/** Cartesian bounding box (Å) of a loaded structure — the density worker crops
* the periodic map to this region (+margin) so the mesh hugs the model instead
* of drawing one displaced unit-cell block. */
export function getStructureBox(
structure: StateObjectSelector,
): { min: number[]; max: number[] } | null {
const data = (structure as { data?: { boundary?: { box?: { min: ArrayLike<number>; max: ArrayLike<number> } } } }).data;
const box = data?.boundary?.box;
if (!box) return null;
return { min: Array.from(box.min).slice(0, 3), max: Array.from(box.max).slice(0, 3) };
}
/** Cartesian coordinates (A) of every atom of a loaded structure, xyz flat - what the 2Fo-Fc map is carved
* around (aaredb reads them from the PDB text, parsePdbAtoms; here the model comes as mmCIF). */
export function getStructureAtoms(structure: StateObjectSelector): Float32Array {
const s = (structure as { data?: { units: ReadonlyArray<{ elements: ArrayLike<number>, conformation: {
x: (e: number) => number, y: (e: number) => number, z: (e: number) => number } }> } }).data;
if (!s) return new Float32Array(0);
const xyz: number[] = [];
for (const unit of s.units)
for (let i = 0; i < unit.elements.length; i++) {
const e = unit.elements[i];
xyz.push(unit.conformation.x(e), unit.conformation.y(e), unit.conformation.z(e));
}
return new Float32Array(xyz);
}
+6 -1
View File
@@ -983,11 +983,16 @@ std::optional<UnitCell> IndexAndRefine::GetConsensusUnitCell() const {
return result->lattice.GetUnitCell();
}
// The cell of the frames that are merged: where the per-image outcomes are kept, a frame the merge
// has left out (its reflections cleared, e.g. by the given-cell population filter) does not count.
std::vector<UnitCell> cells;
{
std::unique_lock ul(reflections_mutex);
cells.reserve(unit_cells.size());
for (const auto &cell: unit_cells) {
for (size_t i = 0; i < unit_cells.size(); i++) {
const auto &cell = unit_cells[i];
if (retain_outcomes_ && integration_outcome[i].reflections.empty())
continue;
if (cell && cell->is_finite())
cells.emplace_back(*cell);
}
+4 -2
View File
@@ -37,8 +37,10 @@ MXAnalysisAfterFPGA::MXAnalysisAfterFPGA(const DiffractionExperiment &in_experim
indexer(indexer),
prediction(CreateBraggPrediction(experiment.IsRotationIndexing())),
// No pixel mask reaches this path: the FPGA image marks its own masked pixels, so only a
// saturated pixel is read as an overload here.
bragg_engine(std::make_unique<BraggIntegrationEngineCPU>(in_experiment, PixelMask(in_experiment))) {
// saturated pixel is read as an overload here. The edge mask is taken in the image's own layout,
// which is the raw one when the geometry is not transformed.
bragg_engine(std::make_unique<BraggIntegrationEngineCPU>(
in_experiment, PixelMask(PixelMask(in_experiment).GetMask(in_experiment)))) {
if (experiment.IsSpotFindingEnabled())
find_spots = true;
+52 -17
View File
@@ -106,6 +106,11 @@ MXAnalysisWithoutFPGA::MXAnalysisWithoutFPGA(const DiffractionExperiment &in_exp
}
adaptiveSpotFinder = std::move(cpu);
}
// The panels the image is made of: the spot finders' windows and components, and the squares read
// about a spot, stay inside one (one, the whole image, without a module table).
adaptiveSpotFinder->SetPanels(experiment.GetModules());
preprocessor_buffer->SetPanels(PanelBoxes(experiment.GetModules(), experiment.GetXPixelsNum(),
experiment.GetYPixelsNum()));
}
void MXAnalysisWithoutFPGA::Analyze(DataMessage &output,
@@ -221,6 +226,7 @@ void MXAnalysisWithoutFPGA::Analyze(DataMessage &output,
probe_counts.profile_fallback += after.profile_fallback - before.profile_fallback;
probe_counts.overlapped += after.overlapped - before.overlapped;
probe_counts.overlapped_major += after.overlapped_major - before.overlapped_major;
probe_counts.overloads_kept += after.overloads_kept - before.overloads_kept;
return ret;
};
@@ -230,22 +236,38 @@ void MXAnalysisWithoutFPGA::Analyze(DataMessage &output,
// soon as it has detected - so this must be called after detection and before integration.
// Where no such background exists (no adaptive finder), auto leaves the correction off: the
// plain profile carries the Bragg peaks and cannot support an absolute threshold.
//
// On stills the correction also takes its CURVE from that background, and auto applies it to
// every image that has one (rugnux's pre-scan turns it off for a run whose empty apertures say
// the radial model does not hold there). A serial frame has a few dozen predicted reflections, so their own
// ring pixels - where the curve comes from otherwise - sample the radial background sparsely,
// while the finder's rings hold every pixel of the frame. And the correction is the measured
// curvature itself: where the background has none it is zero, so there is nothing for a gate
// to decide. The ice score is the wrong gate there: a smooth hump that is not ice - the
// solvent or a carrier medium - curves the background as much as an ice ring does, and the
// score does not see it.
const auto decide_radial_background = [this, &spot_finding_settings, &output]() {
if (!bragg_engine->IsBackgroundRadialAuto())
return;
// Same condition as the score at the end of this function: the adaptive finder holds its
// ring background from whenever it last ran, so requiring that it ran for THIS image is
// what keeps a stale curve out.
if (!spot_finding_settings.adaptive_threshold)
return;
const std::vector<float> &ring_bkg = adaptiveSpotFinder->GetRingBackground();
if (ring_bkg.empty())
const std::vector<float> no_rings;
const std::vector<float> &ring_bkg = spot_finding_settings.adaptive_threshold
? adaptiveSpotFinder->GetRingBackground() : no_rings;
const bool stills = !experiment.IsRotationIndexing();
if (stills)
bragg_engine->RadialBackgroundFromRings(ring_bkg, integration.GetQBinCount(),
integration.Settings().GetLowQ_recipA(),
integration.Settings().GetQSpacing_recipA());
if (!bragg_engine->IsBackgroundRadialAuto() || ring_bkg.empty())
return;
output.ice_ring_score = AzimuthalIntegrationProfile::IceRingScore(
ring_bkg, integration.GetQBinCount(), integration.Settings(),
spot_finding_settings.ice_ring_width_Q_recipA);
bragg_engine->BackgroundRadial(*output.ice_ring_score
>= experiment.GetScalingSettings().GetIceMinScore());
if (stills)
bragg_engine->BackgroundRadial(!bragg_engine->GetRadialBackground().empty());
else
bragg_engine->BackgroundRadial(*output.ice_ring_score
>= experiment.GetScalingSettings().GetIceMinScore());
};
// A missing min-pix (std::nullopt) means "choose it per image". This applies only to the stills
@@ -387,6 +409,7 @@ ImageSpotFinder &MXAnalysisWithoutFPGA::FixedThresholdFinder() {
#endif
spotFinder = std::make_unique<ImageSpotFinderCPU>(experiment.GetXPixelsNum(),
experiment.GetYPixelsNum());
spotFinder->SetPanels(experiment.GetModules());
// It missed every mask update that happened before it existed, so it takes the current one
// now. Without this it would find spots outside the resolution limits.
if (mask_resolution)
@@ -478,6 +501,7 @@ BraggIntegrationCounts MXAnalysisWithoutFPGA::BraggCounts() const {
c.profile_fallback -= probe_counts.profile_fallback;
c.overlapped -= probe_counts.overlapped;
c.overlapped_major -= probe_counts.overlapped_major;
c.overloads_kept -= probe_counts.overloads_kept;
return c;
}
@@ -513,20 +537,31 @@ std::vector<Reflection> MXAnalysisWithoutFPGA::IntegrateOnImage(const std::vecto
return bragg_engine->Run(*preprocessor_buffer, predicted, npredicted, image_number);
// Predictions are where the reflections fall on the detector plane; the engine reads the image, so
// each goes to where its module put those pixels, and comes back to the plane once integrated.
std::vector<Reflection> on_image(predicted.begin(), predicted.begin() + static_cast<int64_t>(npredicted));
for (auto &r: on_image) {
const auto [x, y] = modules.PlaneToImage(r.predicted_x, r.predicted_y);
r.predicted_x = static_cast<float>(x);
r.predicted_y = static_cast<float>(y);
// each goes to where its panel put those pixels, and comes back to the plane once integrated. One in
// a gap, or off every panel, has no pixels and is not integrated. The engine finds a reflection's
// panel from its image position, as the way back below does; a position that rounding to float put
// on another panel's edge is dropped, so that the two agree.
std::vector<Reflection> on_image;
on_image.reserve(npredicted);
for (size_t i = 0; i < npredicted; i++) {
const auto p = modules.PlaneToPanel(predicted[i].predicted_x, predicted[i].predicted_y);
if (!p)
continue;
Reflection r = predicted[i];
r.predicted_x = static_cast<float>(p->x);
r.predicted_y = static_cast<float>(p->y);
if (modules.ModuleOfImagePixel(r.predicted_x, r.predicted_y) != p->panel)
continue;
on_image.push_back(r);
}
auto ret = bragg_engine->Run(*preprocessor_buffer, on_image, npredicted, image_number);
auto ret = bragg_engine->Run(*preprocessor_buffer, on_image, on_image.size(), image_number);
for (auto &r: ret) {
const auto [px, py] = modules.ImageToPlane(r.predicted_x, r.predicted_y);
const int64_t panel = modules.ModuleOfImagePixel(r.predicted_x, r.predicted_y);
const auto [px, py] = modules.ImageToPlane(panel, r.predicted_x, r.predicted_y);
r.predicted_x = static_cast<float>(px);
r.predicted_y = static_cast<float>(py);
if (std::isfinite(r.observed_x) && std::isfinite(r.observed_y)) {
const auto [ox, oy] = modules.ImageToPlane(r.observed_x, r.observed_y);
const auto [ox, oy] = modules.ImageToPlane(panel, r.observed_x, r.observed_y);
r.observed_x = static_cast<float>(ox);
r.observed_y = static_cast<float>(oy);
}
+17 -7
View File
@@ -197,13 +197,23 @@ beam-stop mask is an **offline** (Rugnux + viewer) feature and never goes to the
fit moves it by a few pixels, three orders below what the ring comparison notices. What remains
is the case where the fit declines to place a centre at all, where the file's is used as before.
Another caller that reads the mask at the file's centre keeps the old exposure.
- **The polarization plane is taken from the experiment, not measured.** The correction follows
`DiffractionGeometry::CalcAzIntPolarizationCorr`, which fixes the plane on the lab x axis and
expresses a vertically polarized source as a negative coefficient — the same assumption azimuthal
integration already makes, so a beamline where it is wrong is wrong there first. Measured over the
corpus the plane sits within a degree of lab x on every dataset, and the amplitude within tens of
per cent of the prediction, which is far inside the margin the 0.50 threshold leaves. An
experiment that states no polarization is left uncorrected, as before.
- **The polarization degree is taken from the experiment; the plane, where the background shows one,
from the background.** The correction follows `DiffractionGeometry::CalcAzIntPolarizationCorr`,
which fixes the plane on the lab x axis and expresses a vertically polarized source as a negative
coefficient. The degree cannot be told from the data, but the plane can, and it is not always the
one assumed: a detector mounted a quarter turn from another puts the suppressed direction along the
image's other axis. Divided by the factor of the wrong plane, the background comes out less flat
than it went in - on one stills run the outer rings carried dim lobes over the detector's corners,
sitting on the arm search's thresholds, so that the third decimal of the stated degree moved
thousands of pixels in and out of the mask. So before the correction the mean projection is
compared ring by ring with the profile a polarized source gives each 64 px band (each ring relative
to its upper decile, each sector the brighter of itself and the one opposite, since a shadow is
rarely on both sides; a band counted where three quarters of the azimuth are seen). The stated
degree is applied in the plane the background follows when it follows one clearly - a correlation
above 0.5 and at least 0.3 of a fully polarized source's modulation - and as stated otherwise. Over
the rotation and stills corpora only the run whose plane lies along the image's y axis is turned; on
every other run the correction, and so the mask, is what it was. An experiment that states no
polarization is left uncorrected, as before.
- **Unsigned saturation**: for unsigned images a detector-saturating reflection collides with the
no-data sentinel and is skipped; harmless in practice (such reflections do not sit under the
stop), and absent entirely on the signed/preprocessed path.
+181 -17
View File
@@ -11,10 +11,12 @@
#include <future>
#include <thread>
#include <numbers>
#include <optional>
#include <type_traits>
#include <spdlog/spdlog.h>
#include "../../common/AssembleToPlane.h"
#include "../../common/CUDAWrapper.h"
#include "../../common/ParallelFor.h"
#include "../../common/JFJochException.h"
@@ -398,6 +400,86 @@ RingValues bin_by_ring(const Plane<float> &values, const Plane<char> &valid,
return rv;
}
// The plane the background shows (PolarizationPlane): +1, -1, or 0 where it does not show one.
// The degree of polarization cannot be told from the data, but the plane can, and it is not always the
// one the experiment assumes - a detector mounted a quarter turn from another on the same kind of
// beamline puts the suppressed direction along the image's other axis. Divided by the factor of the
// wrong plane, the background is made less flat rather than more: on a stills run the outer rings
// then carried dim lobes over the detector's corners that sat on the arm search's thresholds, so that
// the third decimal of p moved thousands of pixels in and out of the mask.
// `mean` is the mean projection (W x H, NaN where unusable), compared ring by ring about the centre.
float measured_plane(const std::vector<float> &mean, int W, int H, float centre_x, float centre_y,
const float *det_matrix, float distance_px, size_t nthreads) {
const int n_pixels = W * H;
Plane<float> value(n_pixels);
Plane<char> valid(n_pixels);
Plane<int> radius(n_pixels);
std::atomic<int> max_radius_atomic{0};
ParallelChunks(H, nthreads, [&](int ylo, int yhi) {
int local_max = 0;
for (int y = ylo; y < yhi; y++)
for (int x = 0; x < W; x++) {
const int i = y * W + x;
const RingPosition ring = ring_position(det_matrix, distance_px, x - centre_x, y - centre_y);
valid[i] = std::isfinite(mean[i]) && ring.obliquity > 0.0f;
value[i] = valid[i] ? mean[i] / ring.obliquity : 0.0f;
radius[i] = static_cast<int>(std::lround(ring.radius));
local_max = std::max(local_max, radius[i]);
}
int prev = max_radius_atomic.load();
while (prev < local_max && !max_radius_atomic.compare_exchange_weak(prev, local_max)) {}
});
const int max_radius = max_radius_atomic.load();
const int n_bands = max_radius / HARMONIC_BAND_PX + 1;
// Each ring is taken relative to its upper decile rather than its median: where a shadow covers
// half of a ring the median sits on the shadow's edge and jumps from ring to ring.
const RingValues rings = bin_by_ring(value, valid, radius, max_radius, nthreads);
std::vector<float> level(max_radius + 1, 0.0f);
for (int r = 0; r <= max_radius; r++) {
const int n = rings.offset[r + 1] - rings.offset[r];
if (n > 0)
level[r] = rings.values[rings.offset[r] + n * 9 / 10];
}
// The median of each sector of each band, relative to its rings.
const size_t n_sectors = static_cast<size_t>(n_bands) * HARMONIC_SECTORS;
std::vector<std::vector<float>> sector_values(n_sectors);
for (int i = 0; i < n_pixels; i++) {
if (!valid[i] || level[radius[i]] <= 0.0f)
continue;
const RingPosition ring = ring_position(det_matrix, distance_px, static_cast<float>(i % W) - centre_x,
static_cast<float>(i / W) - centre_y);
const double phi = std::atan2(ring.ly, ring.lx) + std::numbers::pi;
const int sector = std::min(HARMONIC_SECTORS - 1, static_cast<int>(phi / (2.0 * std::numbers::pi) * HARMONIC_SECTORS));
sector_values[static_cast<size_t>(radius[i] / HARMONIC_BAND_PX) * HARMONIC_SECTORS + sector]
.push_back(value[i] / level[radius[i]]);
}
std::vector<double> sector_median(n_sectors, -1.0);
ParallelFor(static_cast<int>(n_sectors), nthreads, [&](int k) {
auto &v = sector_values[k];
if (v.size() >= MIN_SECTOR_PIXELS) {
std::nth_element(v.begin(), v.begin() + v.size() / 2, v.end());
sector_median[k] = v[v.size() / 2];
}
});
// The modulation a fully polarized source gives each band, at the 2 theta of its centre.
std::vector<float> amplitude(n_bands);
for (int band = 0; band < n_bands; band++) {
const double t = (band + 0.5) * HARMONIC_BAND_PX / distance_px; // tan 2theta
const double cos2 = 1.0 / (1.0 + t * t); // cos^2 2theta
amplitude[band] = static_cast<float>((1.0 - cos2) / (1.0 + cos2));
}
return PolarizationPlane(sector_median, amplitude);
}
// The stated polarization in the plane the background shows; as stated where it shows none. A negative
// coefficient is a vertically polarized source (CalcAzIntPolarizationCorr).
float PlaneApplied(float stated, float plane) {
return plane == 0.0f ? stated : std::fabs(stated) * plane;
}
} // namespace
ShadowFinder::ShadowFinder(const DiffractionExperiment &experiment, const PixelMask &mask)
@@ -407,7 +489,8 @@ ShadowFinder::ShadowFinder(const DiffractionExperiment &experiment, const PixelM
beam_y(experiment.GetBeamY_pxl()),
geometry(experiment.GetDiffractionGeometry()),
polarization(experiment.GetPolarizationFactor()),
pixel_mask(mask.GetMask(experiment)) {
pixel_mask(mask.GetMask(experiment)),
modules(experiment.GetModules()) {
if (pixel_mask.size() != static_cast<size_t>(width) * height)
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"ShadowFinder: pixel mask does not match the detector");
@@ -650,8 +733,9 @@ std::vector<uint32_t> ShadowFinder::GetMask(size_t nthreads) const {
if (nthreads == 0)
nthreads = AvailableCpus();
#ifdef JFJOCH_USE_CUDA
// Where every frame went to the device the mask is made there too, from the projection as it lies.
if (ShadowAccumulatorGPU *gpu = Gpu(); gpu && gpu->GetFrameCount() > 0 && host.frames == 0) {
// Where every frame went to the device the mask is made there too, from the projection as it lies -
// when it lies as the detector does (no panel table).
if (ShadowAccumulatorGPU *gpu = Gpu(); gpu && gpu->GetFrameCount() > 0 && host.frames == 0 && modules.empty()) {
const float diag = std::hypot(static_cast<float>(width), static_cast<float>(height));
if (!std::isfinite(beam_x) || !std::isfinite(beam_y)
|| std::fabs(beam_x - width * 0.5f) > 4.0f * diag || std::fabs(beam_y - height * 0.5f) > 4.0f * diag)
@@ -666,19 +750,43 @@ std::vector<uint32_t> ShadowFinder::GetMask(size_t nthreads) const {
setup.det_matrix[k] = rot[k];
setup.pixel_size_mm = geometry.GetPixelSize_mm();
setup.distance_mm = geometry.GetDetectorDistance_mm();
setup.has_polarization = polarization.has_value();
setup.polarization = polarization.value_or(0.0f);
ScopedGpuPin pin(gpu->GetDevice());
setup.has_polarization = polarization.has_value();
if (polarization)
setup.polarization = PlaneApplied(*polarization,
measured_plane(gpu->MeanProjection(pixel_mask), width, height, beam_x,
beam_y, setup.det_matrix,
setup.distance_mm / setup.pixel_size_mm, nthreads));
return gpu->Mask(setup, pixel_mask);
}
#endif
const Projection &p = Reduced();
if (modules.empty())
return MaskOn(p, pixel_mask, width, height, beam_x, beam_y, nthreads);
// Panels: the shadow and the gaps it crosses are on the detector plane, not in the image the panels are
// stored in, so the mask is made on the plane raster (the projection and the mask assembled to it, gaps
// counted as nothing and masked) and each stored pixel takes the answer of the raster pixel it lies on.
const PlaneRaster raster = PlaneRasterOf(modules, width, height);
Projection plane;
plane.max_value = AssembleToPlane(modules, p.max_value, width, height, raster, int64_t{0});
plane.sum_value = AssembleToPlane(modules, p.sum_value, width, height, raster, int64_t{0});
plane.valid_count = AssembleToPlane(modules, p.valid_count, width, height, raster, uint32_t{0});
plane.frames = p.frames;
const auto plane_mask = AssembleToPlane(modules, pixel_mask, width, height, raster,
uint32_t{1u << PixelMask::ModuleGapPixelBit});
const auto mask = MaskOn(plane, plane_mask, static_cast<int>(raster.width), static_cast<int>(raster.height),
beam_x - static_cast<float>(raster.x0), beam_y - static_cast<float>(raster.y0), nthreads);
return GatherFromPlane(modules, mask, raster, width, height, uint32_t{0});
}
std::vector<uint32_t> ShadowFinder::MaskOn(const Projection &p, const std::vector<uint32_t> &known_mask, int W, int H,
float centre_x, float centre_y, size_t nthreads) const {
const auto &max_value = p.max_value;
const auto &sum_value = p.sum_value;
const auto &valid_count = p.valid_count;
const uint32_t frames = p.frames;
const int W = width, H = height;
const int n_pixels = W * H;
std::vector<uint32_t> mask(n_pixels, 0);
@@ -690,8 +798,8 @@ std::vector<uint32_t> ShadowFinder::GetMask(size_t nthreads) const {
// makes max_radius, and every per-ring table sized by it, arbitrarily large. No centre, no
// shadow.
const float diag = std::hypot(static_cast<float>(W), static_cast<float>(H));
if (!std::isfinite(beam_x) || !std::isfinite(beam_y)
|| std::fabs(beam_x - W * 0.5f) > 4.0f * diag || std::fabs(beam_y - H * 0.5f) > 4.0f * diag)
if (!std::isfinite(centre_x) || !std::isfinite(centre_y)
|| std::fabs(centre_x - W * 0.5f) > 4.0f * diag || std::fabs(centre_y - H * 0.5f) > 4.0f * diag)
return mask;
// mean projection, usable pixels and the ring each pixel is on (ring_position). The mean is
@@ -702,10 +810,23 @@ std::vector<uint32_t> ShadowFinder::GetMask(size_t nthreads) const {
// in-plane rotation - about the centre the caller named.
// Following Kahn, Fourme, Gadet, Janin, Dumas & Andre (1982) J. Appl. Cryst. 15, 330-337
DiffractionGeometry pol_geometry = geometry;
pol_geometry.BeamX_pxl(beam_x).BeamY_pxl(beam_y);
pol_geometry.BeamX_pxl(centre_x).BeamY_pxl(centre_y);
const std::vector<float> det_matrix = geometry.GetDetectorMatrix().arr();
const float distance_px = geometry.GetDetectorDistance_mm() / geometry.GetPixelSize_mm();
// The stated degree, in the plane the background shows (measured_plane).
std::optional<float> polarization_applied;
if (polarization) {
std::vector<float> projection(n_pixels);
ParallelChunks(n_pixels, nthreads, [&](int lo, int hi) {
for (int i = lo; i < hi; i++)
projection[i] = valid_count[i] > 0 && known_mask[i] == 0
? static_cast<float>(static_cast<double>(sum_value[i]) / valid_count[i]) : NAN;
});
polarization_applied = PlaneApplied(*polarization, measured_plane(projection, W, H, centre_x, centre_y,
det_matrix.data(), distance_px, nthreads));
}
Plane<float> mean(n_pixels);
Plane<float> pol(n_pixels);
Plane<char> valid(n_pixels);
@@ -716,12 +837,12 @@ std::vector<uint32_t> ShadowFinder::GetMask(size_t nthreads) const {
for (int y = ylo; y < yhi; y++)
for (int x = 0; x < W; x++) {
const int i = y * W + x;
const RingPosition ring = ring_position(det_matrix.data(), distance_px, x - beam_x, y - beam_y);
const RingPosition ring = ring_position(det_matrix.data(), distance_px, x - centre_x, y - centre_y);
pol[i] = ring.obliquity
* (polarization.has_value()
* (polarization_applied.has_value()
? pol_geometry.CalcAzIntPolarizationCorr(static_cast<float>(x),
static_cast<float>(y),
polarization.value())
polarization_applied.value())
: 1.0f);
// pol > 0 also rejects a NaN factor. The correction is exactly zero only where
// the polarization fully suppresses the scattering, so such a pixel carries no
@@ -729,7 +850,7 @@ std::vector<uint32_t> ShadowFinder::GetMask(size_t nthreads) const {
// the pooled means, which the running box sums then turn into NaN for a whole row.
mean[i] = 0.0f;
valid[i] = 0;
if (valid_count[i] > 0 && pixel_mask[i] == 0 && pol[i] > 0.0f) {
if (valid_count[i] > 0 && known_mask[i] == 0 && pol[i] > 0.0f) {
mean[i] = static_cast<float>(static_cast<double>(sum_value[i])
/ valid_count[i] / pol[i]);
valid[i] = 1;
@@ -970,8 +1091,8 @@ std::vector<uint32_t> ShadowFinder::GetMask(size_t nthreads) const {
if (!valid[i] || region[i])
continue;
const RingPosition ring = ring_position(det_matrix.data(), distance_px,
static_cast<float>(i % W) - beam_x,
static_cast<float>(i / W) - beam_y);
static_cast<float>(i % W) - centre_x,
static_cast<float>(i / W) - centre_y);
const double phi = std::atan2(ring.ly, ring.lx) + std::numbers::pi;
const int sector = std::min(HARMONIC_SECTORS - 1, static_cast<int>(phi / (2.0 * std::numbers::pi) * HARMONIC_SECTORS));
values[static_cast<size_t>(radius[i] / HARMONIC_BAND_PX) * HARMONIC_SECTORS + sector].push_back(ratio[i]);
@@ -1002,8 +1123,8 @@ std::vector<uint32_t> ShadowFinder::GetMask(size_t nthreads) const {
continue;
// cos 2phi and sin 2phi from the offset to the beam.
const RingPosition ring = ring_position(det_matrix.data(), distance_px,
static_cast<float>(i % W) - beam_x,
static_cast<float>(i / W) - beam_y);
static_cast<float>(i % W) - centre_x,
static_cast<float>(i / W) - centre_y);
const float dx = ring.lx, dy = ring.ly;
const float r2 = std::max(dx * dx + dy * dy, 1e-6f);
const int band = radius[i] / HARMONIC_BAND_PX;
@@ -1122,4 +1243,47 @@ void HarmonicFit(const std::vector<double> &sector_median, int n_bands,
}
}
float PolarizationPlane(const std::vector<double> &sector_median, const std::vector<float> &amplitude) {
const int n_bands = static_cast<int>(amplitude.size());
// The modulation is the same at phi and at phi + 180 deg; what shadows the detector rarely is - an
// arm, a pin or a goniometer stands on one side of the beam - and shadows only darken. So each
// sector is taken as the brighter of itself and the sector opposite, and a band is fitted only where
// three quarters of the azimuth are seen that way.
constexpr int HALF = HARMONIC_SECTORS / 2;
std::vector<double> folded(sector_median);
std::vector<char> seen_enough(n_bands);
for (int band = 0; band < n_bands; band++) {
int seen = 0;
for (int k = 0; k < HALF; k++) {
const size_t a = static_cast<size_t>(band) * HARMONIC_SECTORS + k;
folded[a] = folded[a + HALF] = std::max(sector_median[a], sector_median[a + HALF]);
seen += folded[a] >= 0;
}
seen_enough[band] = seen >= HALF * 3 / 4;
}
std::vector<float> c, s;
HarmonicFit(folded, n_bands, c, s);
// A horizontally polarized source makes the background dim along lab x, c < 0, by more where the
// modulation it can give is larger; a vertically polarized one makes it dim along lab y, c > 0. A
// plane is taken only where the bands' harmonics follow its profile (PLANE_CORRELATION) and amount
// to a good part of what a fully polarized source gives (PLANE_MODULATION): a background with
// little modulation of its own decides nothing. With no modulation at all both are NaN, which
// decides nothing too.
double ca = 0.0, cc = 0.0, aa = 0.0;
for (int band = 0; band < n_bands; band++) {
if (!seen_enough[band])
continue;
ca += c[band] * amplitude[band];
cc += c[band] * c[band];
aa += amplitude[band] * amplitude[band];
}
const double correlation = ca / std::sqrt(cc * aa);
const double modulation = ca / aa;
if (correlation > PLANE_CORRELATION && modulation > PLANE_MODULATION)
return -1.0f;
if (correlation < -PLANE_CORRELATION && modulation < -PLANE_MODULATION)
return 1.0f;
return 0.0f;
}
} // namespace shadow_finder
+7
View File
@@ -63,6 +63,8 @@ class ShadowFinder {
const std::optional<float> polarization; // unset leaves the background as it was measured
std::vector<uint32_t> pixel_mask; // pixels already masked carry no background to test
// The panels the image is made of. With any, the mask is made on the detector plane (GetMask).
const DetectorModules modules;
// Per-pixel projection over the frames added so far (converted geometry). The sums and counts are
// integers and the maximum is a maximum, so the result does not depend on the order the frames
@@ -120,6 +122,11 @@ class ShadowFinder {
// took frames. Called with `m` held.
[[nodiscard]] const Projection &Reduced() const;
// The mask of a W x H projection, its known-masked pixels and the centre the rings are drawn about -
// the image's own, or the plane raster's where the image is made of panels.
[[nodiscard]] std::vector<uint32_t> MaskOn(const Projection &p, const std::vector<uint32_t> &known_mask,
int W, int H, float centre_x, float centre_y, size_t nthreads) const;
public:
static constexpr uint32_t SHADOW = 1;
static constexpr uint32_t TRANSMITTING = 2;
@@ -120,4 +120,22 @@ int BlockedOutTo(const std::vector<float> &baseline, const std::vector<int> &rin
void HarmonicFit(const std::vector<double> &sector_median, int n_bands,
std::vector<float> &harm_c, std::vector<float> &harm_s);
// How closely, over the radial bands, the background's cos 2phi harmonic must follow the profile a
// polarized source gives it (the correlation), and how large it must be against the profile of a fully
// polarized source (the least-squares scale), before the plane is taken from the background rather
// than as stated. On 46 rotation sweeps and 11 stills runs whose plane is horizontal, the largest values
// towards the vertical plane are 0.48 and 0.18, the latter on a background with almost no modulation;
// on a stills run whose plane lies along the image's y axis they are 0.998 and 0.47 - the scale reduced
// there by the placeholder distance the pre-scan reads it at.
inline constexpr double PLANE_CORRELATION = 0.5;
inline constexpr double PLANE_MODULATION = 0.3;
// The plane the source is polarized in, as the background shows it: +1 for the plane containing lab x
// (a horizontally polarized source), -1 for the plane turned by 90 degrees, 0 where the background does
// not show one clearly. `sector_median` is laid
// out as for HarmonicFit, each band's background relative to its rings; `amplitude[band]` is the
// relative modulation a fully polarized source gives the band, sin^2 2theta / (1 + cos^2 2theta). See
// GetMask.
float PolarizationPlane(const std::vector<double> &sector_median, const std::vector<float> &amplitude);
} // namespace shadow_finder
@@ -0,0 +1,181 @@
// SPDX-FileCopyrightText: 2026 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
// SPDX-License-Identifier: GPL-3.0-only
#include "BackgroundAperture.h"
#include <algorithm>
#include <cmath>
#include "../../common/JFJochMath.h"
std::vector<float> background_aperture::CandidateR3(float r2, float max_r3) {
std::vector<float> out;
for (float r3 = r2 + 2.0f; r3 <= max_r3 + 1e-3f; r3 += 1.0f)
out.push_back(r3);
return out;
}
void background_aperture::MeasureFrame(ImagePreprocessorBuffer &image, int width, int height,
const std::vector<DiffractionSpot> &spots, float r1, float r2,
const std::vector<float> &r3, float clip_nsigma, float gain,
const RingBackground &rings, const DiffractionGeometry &geometry,
const DetectorModules &modules, Tally &tally) {
if (r3.empty())
return;
tally.sum_d2.resize(r3.size(), 0.0);
tally.sum_d2_radial.resize(r3.size(), 0.0);
tally.sum_dd2.resize(r3.size(), 0.0);
const float r_max = r3.back();
const int half = static_cast<int>(std::ceil(r_max));
const int side = 2 * half + 1;
// A grid of centres, at least one aperture apart, kept clear of every found spot.
const double area = static_cast<double>(width) * height;
const int step = std::max(side, static_cast<int>(std::ceil(std::sqrt(area / MAX_APERTURES_PER_FRAME))));
const float clear = r_max + SPOT_CLEARANCE_PX;
std::vector<int32_t> cx, cy;
for (int y = half; y + half < height; y += step)
for (int x = half; x + half < width; x += step) {
bool near_spot = false;
for (const auto &s : spots) {
const Coord c = s.RawCoord();
if ((c.x - x) * (c.x - x) + (c.y - y) * (c.y - y) < clear * clear) {
near_spot = true;
break;
}
}
if (!near_spot) {
cx.push_back(x);
cy.push_back(y);
}
}
if (cx.empty())
return;
const int32_t *tiles = image.GatherTiles(cx, cy, width, half);
struct Pixel {
int32_t v;
float d2; // squared distance from the aperture centre
double b; // the ring background at this pixel's resolution
};
std::vector<Pixel> disk, ring;
for (size_t a = 0; a < cx.size(); ++a) {
const int32_t *t = tiles + a * static_cast<size_t>(side) * side;
const int64_t panel = modules.ModuleOfImagePixel(cx[a], cy[a]);
bool readable = true;
disk.clear();
ring.clear();
for (int dy = -half; dy <= half && readable; ++dy)
for (int dx = -half; dx <= half; ++dx) {
const float d2 = static_cast<float>(dx * dx + dy * dy);
if (d2 >= r_max * r_max || (d2 >= r1 * r1 && d2 < r2 * r2))
continue;
const int32_t v = t[(dy + half) * side + dx + half];
if (v == INT32_MIN || v == INT32_MAX) {
readable = false;
break;
}
double b = 0.0;
if (!rings.empty()) {
const auto [px, py] = modules.ImageToPlane(panel, cx[a] + dx, cy[a] + dy);
b = rings.At(2.0 * PI / geometry.PxlToRes(static_cast<float>(px), static_cast<float>(py)));
}
(d2 < r1 * r1 ? disk : ring).push_back({v, d2, b});
}
if (!readable || disk.empty())
continue;
double disk_v = 0.0, disk_b = 0.0;
for (const auto &p : disk) {
disk_v += p.v;
disk_b += p.b;
}
disk_v /= static_cast<double>(disk.size());
disk_b /= static_cast<double>(disk.size());
// Every candidate ring as the integrator reads it: the mean, then one high-side clip pass. The
// radial correction is taken over the ring's geometry, as the integrator's kernel is.
std::vector<double> d_plain(r3.size()), d_radial(r3.size());
bool measured = true;
for (size_t k = 0; k < r3.size() && measured; ++k) {
const float r3_sq = r3[k] * r3[k];
double sum = 0.0, sum_b = 0.0;
int n = 0;
for (const auto &p : ring)
if (p.d2 < r3_sq) {
sum += p.v;
sum_b += p.b;
++n;
}
if (n == 0) {
measured = false;
break;
}
const double mean = sum / n;
const double thr = mean + clip_nsigma * std::sqrt(gain * std::max(mean, 1.0));
double kept = 0.0;
int n_kept = 0;
for (const auto &p : ring)
if (p.d2 < r3_sq && (clip_nsigma <= 0.0f || p.v <= thr)) {
kept += p.v;
++n_kept;
}
measured = n_kept > 0;
if (measured) {
d_plain[k] = disk_v - kept / n_kept;
d_radial[k] = d_plain[k] - (disk_b - sum_b / n);
}
}
if (!measured)
continue;
for (size_t k = 0; k < r3.size(); ++k) {
tally.sum_d2[k] += d_plain[k] * d_plain[k];
if (!rings.empty()) {
tally.sum_d2_radial[k] += d_radial[k] * d_radial[k];
const double dd = d_radial[k] * d_radial[k] - d_plain[k] * d_plain[k];
tally.sum_dd2[k] += dd * dd;
}
}
++tally.apertures;
if (!rings.empty())
++tally.apertures_radial;
}
}
void background_aperture::Tally::Add(const Tally &other) {
sum_d2.resize(std::max(sum_d2.size(), other.sum_d2.size()), 0.0);
sum_d2_radial.resize(std::max(sum_d2_radial.size(), other.sum_d2_radial.size()), 0.0);
for (size_t k = 0; k < other.sum_d2.size(); ++k)
sum_d2[k] += other.sum_d2[k];
for (size_t k = 0; k < other.sum_d2_radial.size(); ++k)
sum_d2_radial[k] += other.sum_d2_radial[k];
sum_dd2.resize(std::max(sum_dd2.size(), other.sum_dd2.size()), 0.0);
for (size_t k = 0; k < other.sum_dd2.size(); ++k)
sum_dd2[k] += other.sum_dd2[k];
apertures += other.apertures;
apertures_radial += other.apertures_radial;
}
std::vector<double> background_aperture::Tally::MeanSquare(bool radial) const {
const size_t n = radial ? apertures_radial : apertures;
std::vector<double> out;
if (n == 0)
return out;
for (const double v : radial ? sum_d2_radial : sum_d2)
out.push_back(v / static_cast<double>(n));
return out;
}
double background_aperture::Tally::RadialZ(size_t k) const {
if (apertures_radial < 2 || apertures_radial != apertures || k >= sum_dd2.size())
return 0.0;
const double n = static_cast<double>(apertures_radial);
const double mean = (sum_d2_radial[k] - sum_d2[k]) / n;
const double var = std::max(sum_dd2[k] / n - mean * mean, 0.0);
return var > 0.0 ? -mean / std::sqrt(var / n) : 0.0;
}
int background_aperture::Best(const std::vector<double> &mean_square) {
if (mean_square.empty())
return -1;
return static_cast<int>(std::min_element(mean_square.begin(), mean_square.end()) - mean_square.begin());
}
@@ -0,0 +1,79 @@
// SPDX-FileCopyrightText: 2026 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
// SPDX-License-Identifier: GPL-3.0-only
#pragma once
#include <cstddef>
#include <cstdint>
#include <vector>
#include "../../common/DetectorModules.h"
#include "../../common/DiffractionGeometry.h"
#include "../../common/DiffractionSpot.h"
#include "../image_preprocessing/ImagePreprocessorBuffer.h"
#include "RingBackground.h"
// How far out the background ring should reach, measured on apertures with nothing in them.
//
// The ring mean stands in for the background under the signal disk. A wider ring averages more pixels,
// so its own noise falls; but it also reaches further from the reflection, so whatever the background
// does between the disk and the ring - a curved solvent ring, the tile structure of a fibre-optic CCD,
// the tails of reflections nobody predicted - enters the intensity as a bias. Which of the two wins is
// a property of the detector and the sample, not a constant: on a pixel detector counting a fraction of
// a photon per pixel the noise wins and the widest ring is best, on a binned CCD reading hundreds of
// ADU a pixel the structure wins and the narrowest is.
//
// So it is measured. Apertures are laid on a grid over pre-scan frames, away from every spot found; on
// each, the mean of the r1 disk and the mean of the r2..r3 ring are taken for every candidate r3, and
// the run keeps the r3 whose ring predicts the disk best - the smallest mean square of the difference.
// With nothing in the aperture the difference is exactly the error the ring makes in the background of
// a reflection: its noise plus its bias. The disk's own noise is the same for every candidate, so it
// does not move the choice. The ring is clipped as the integrator clips it (high side, at
// mean + nsigma * sqrt(gain * mean)).
//
// The same apertures also say whether the radial background-curvature correction helps: each difference
// is taken a second time with the correction applied - the frame's own ring background (RingBackground)
// averaged over the ring's pixels minus over the disk's, which is what the integrator's kernel takes off a
// reflection. Where the background really is a function of the radius the corrected ring predicts the
// disk better; where it is not - a strongly polarised beam, panels of different response - it predicts it
// worse, and the run measures which. The ring is chosen on the plain differences first, so its reach does
// not rest on the radial model; the correction is then kept where it improves that ring.
namespace background_aperture {
// The squared disk-minus-ring differences, summed per candidate r3 over every aperture measured: plain,
// and with the radial correction (counted separately: a frame without a ring background adds none).
struct Tally {
std::vector<double> sum_d2, sum_d2_radial;
// Sum of the squared per-aperture change the correction makes to d^2, for the standard error of
// the paired comparison (RadialZ).
std::vector<double> sum_dd2;
size_t apertures = 0, apertures_radial = 0;
void Add(const Tally &other);
// The mean square difference of each candidate, plain or corrected; empty where nothing was measured.
[[nodiscard]] std::vector<double> MeanSquare(bool radial) const;
// How many standard errors the correction lowers candidate k's mean square by, over the apertures
// measured both ways (positive: the correction helps).
[[nodiscard]] double RadialZ(size_t k) const;
};
// The candidate outer radii: from r2 + 2 up to max_r3, one pixel apart.
[[nodiscard]] std::vector<float> CandidateR3(float r2, float max_r3);
// The apertures of one frame, appended to `tally`. Centres lie on a grid over the frame, and an aperture
// is used only where every pixel out to the largest candidate is readable and no found spot is within
// that radius plus SPOT_CLEARANCE_PX of its centre. `rings` is this frame's ring background, or empty;
// `geometry` and `modules` place the pixels on the plane to read it at their resolution.
void MeasureFrame(ImagePreprocessorBuffer &image, int width, int height,
const std::vector<DiffractionSpot> &spots, float r1, float r2,
const std::vector<float> &r3, float clip_nsigma, float gain,
const RingBackground &rings, const DiffractionGeometry &geometry,
const DetectorModules &modules, Tally &tally);
// The candidate with the smallest mean square difference, or -1 where nothing was measured.
[[nodiscard]] int Best(const std::vector<double> &mean_square);
constexpr float SPOT_CLEARANCE_PX = 4.0f;
// At most this many apertures a frame: a 16 Mpx detector would otherwise lay twenty thousand.
constexpr size_t MAX_APERTURES_PER_FRAME = 2000;
} // namespace background_aperture
@@ -6,6 +6,7 @@
#include <algorithm>
#include <cmath>
#include <limits>
#include <numeric>
#include <utility>
namespace background_gain {
@@ -92,4 +93,74 @@ std::optional<float> Gain(const std::vector<Levels> &frames) {
return static_cast<float>(ratio.back().first);
}
void AddToHistogram(const std::vector<int32_t> &image, const std::vector<uint32_t> &mask, int64_t saturation,
std::vector<uint64_t> &histogram) {
const int64_t end = std::min<int64_t>(saturation, PEAK_HISTOGRAM_BINS);
for (size_t i = 0; i < image.size(); i++)
if (mask[i] == 0 && image[i] >= 0 && image[i] < end)
histogram[image[i]]++;
}
std::optional<GainEstimate> PhotonPeak(const std::vector<uint64_t> &histogram) {
// A float file that holds whole numbers, read at a fraction of its unit, fills only every q-th bin:
// the histogram is read at that step.
size_t q = 0;
for (size_t i = 1; i < histogram.size(); i++)
if (histogram[i] > 0)
q = std::gcd(q, i);
q = std::max<size_t>(q, 1);
std::vector<uint64_t> h;
for (size_t i = 0; i < histogram.size(); i += q)
h.push_back(histogram[i]);
// A peak stands out of a valley where it is higher by five times its own counting noise.
const auto stands = [&](size_t valley, size_t peak) {
return static_cast<double>(h[peak]) - static_cast<double>(h[valley])
> 5.0 * std::sqrt(static_cast<double>(h[peak]));
};
// Most pixels hold no photon. Down the zero peak to the first valley.
const size_t p0 = std::max_element(h.begin(), h.end()) - h.begin();
size_t v0 = p0;
while (v0 + 1 < h.size() && h[v0 + 1] <= h[v0])
v0++;
if (v0 + 1 >= h.size())
return std::nullopt;
const size_t p1 = std::max_element(h.begin() + v0, h.end()) - h.begin();
const size_t g = p1 - p0;
// The zero-photon peak is the detector's noise, so it has a width: a single bin with nothing beside it is
// a CCD's pixels outside the active area, all at zero, and what follows is its background, not a photon.
if (h[p0 + 1] == 0 || !stands(v0, p1) || p1 + 3 * g / 2 >= h.size())
return std::nullopt;
// A photon is a peak narrower than the spacing: it falls below half its height before the midpoint to
// the next. A CCD's background is a hump as wide as where it lies.
if (2 * h[p1 + g / 2] >= h[p1])
return std::nullopt;
// The two-photon peak: the histogram rises again, near one more gain on, past the valley after p1.
const size_t v2 = std::min_element(h.begin() + p1, h.begin() + p1 + g + 1) - h.begin();
const size_t p2 = std::max_element(h.begin() + v2, h.begin() + p1 + 3 * g / 2 + 1) - h.begin();
if (!stands(v2, p2) || 4 * (p2 - p1) < 3 * g || 4 * (p2 - p1) > 5 * g)
return std::nullopt;
// Within the bin: the vertex of a parabola through the log counts of the peak and its neighbours. A
// zero peak in the first bin is a subtracted baseline, cut where the values turn negative: zero.
const auto vertex = [&](size_t p) {
if (p == 0)
return 0.0;
const double a = std::log(std::max<double>(1.0, h[p - 1]));
const double b = std::log(std::max<double>(1.0, h[p]));
const double c = std::log(std::max<double>(1.0, h[p + 1]));
const double curvature = a - 2.0 * b + c;
return static_cast<double>(p) + (curvature < 0.0 ? 0.5 * (a - c) / curvature : 0.0);
};
const double pedestal = vertex(p0);
return GainEstimate{static_cast<float>(q * (vertex(p1) - pedestal)), static_cast<float>(q * pedestal)};
}
std::optional<GainEstimate> Estimate(const std::vector<Levels> &frames, const std::vector<uint64_t> &histogram) {
if (const auto peaks = PhotonPeak(histogram))
return peaks;
if (const auto g = Gain(frames))
return GainEstimate{*g, 0.0f};
return std::nullopt;
}
} // namespace background_gain
@@ -47,4 +47,32 @@ Levels MeasureFrame(const std::vector<int32_t> &image, size_t width, size_t heig
// fewer than MIN_BINS levels holding MIN_PAIRS_PER_BIN pairs.
std::optional<float> Gain(const std::vector<Levels> &frames);
// The gain of a detector whose background resolves single photons (a JUNGFRAU with its pedestal
// subtracted): the histogram of pixel values has a peak at zero photons, one at a single photon and
// another at two, a gain apart. The variance per unit mean above does not see it on a sparse background -
// the empty pixels it leaves out are most of it - so the quantum is read off the histogram instead. The
// gain is the spacing of the peaks, not the single photon's value, so a frame whose baseline was never
// subtracted - its zero-photon peak well above zero - reads the same gain, and its baseline besides.
constexpr size_t PEAK_HISTOGRAM_BINS = 16384;
// Adds the frame's unmasked pixels with 0 <= value < min(saturation, PEAK_HISTOGRAM_BINS) to histogram
// (PEAK_HISTOGRAM_BINS long, one bin per value).
void AddToHistogram(const std::vector<int32_t> &image, const std::vector<uint32_t> &mask, int64_t saturation,
std::vector<uint64_t> &histogram);
struct GainEstimate {
float gain; // detector units per photon (photon peaks: from the zero-photon to the single-photon peak)
float pedestal; // where the zero-photon peak sits; 0 where the baseline was subtracted or no peak shows
};
// The zero-photon peak is the highest bin; the single-photon peak the highest past its descent, standing out
// of the valley before it, falling to half its height before the midpoint to the next, and repeated by a
// two-photon peak near one more gain on. Nothing where the histogram shows no such pair - integer photon
// counts, whose single photon is the bin next to the zero peak, or a detector whose noise hides the photons.
std::optional<GainEstimate> PhotonPeak(const std::vector<uint64_t> &histogram);
// The gain of any input that reports detector units, rotation or stills, from the same frames: the photon
// peaks where the histogram shows them, else the variance per unit mean of the levels.
std::optional<GainEstimate> Estimate(const std::vector<Levels> &frames, const std::vector<uint64_t> &histogram);
} // namespace background_gain
@@ -13,6 +13,7 @@
#include "../../common/JFJochMath.h" // PI (M_PI is not standard, and MSVC does not define it)
#include "../SensorAbsorption.h"
#include "RingBackground.h"
namespace {
@@ -51,7 +52,8 @@ std::map<RadialKernelKey, std::vector<float>> radial_kernel_cache;
} // namespace
BraggIntegrationEngine::BraggIntegrationEngine(const DiffractionExperiment &experiment)
: geom(experiment.GetDiffractionGeometry()) {
: geom(experiment.GetDiffractionGeometry()), modules(experiment.GetModules()),
plane_bounds(modules.PlaneBounds(experiment.GetXPixelsNum(), experiment.GetYPixelsNum())) {
const auto settings = experiment.GetBraggIntegrationSettings();
const auto &det = experiment.GetDetectorSetup();
@@ -116,6 +118,7 @@ BraggIntegrationEngine::BraggIntegrationEngine(const DiffractionExperiment &expe
// longer overrides it for broadband data.
bkg_clip_nsigma = settings.GetBackgroundClipNSigma();
bkg_pixel_gain = settings.GetBackgroundPixelGain();
pixel_gain = settings.GetPixelGain();
bkg_trim = bkg_clip_nsigma > 0.0f ? 0.0f : settings.GetBackgroundTrimFraction();
// Overlap treatment. Ownership is decided out to the fit grid's half size, which is where the
@@ -126,6 +129,8 @@ BraggIntegrationEngine::BraggIntegrationEngine(const DiffractionExperiment &expe
if (overlap == OverlapMode::Exclude && mode == IntegratorMode::BoxSum)
overlap = OverlapMode::Off;
overlap_min_peak = settings.GetOverlapMinPeak();
keep_overloads = !experiment.IsRotationIndexing();
saturation_limit = static_cast<double>(experiment.GetSaturationLimit());
claim = static_cast<float>(R);
inv_claim = 1.0f / claim;
@@ -148,8 +153,8 @@ BraggIntegrationEngine::BraggIntegrationEngine(const DiffractionExperiment &expe
// bkg_radial is raised after construction only by the auto mode (MXAnalysisWithoutFPGA), which
// requires bkg_radial_auto, and the GPU allocates its curve buffers under the same condition.
// n_kern is the largest row BraggStencilKernelIndex can select, plus one.
r_max = std::hypot(std::max<double>(beam_x, static_cast<double>(xpixel) - beam_x),
std::max<double>(beam_y, static_cast<double>(ypixel) - beam_y));
r_max = std::hypot(std::max<double>(beam_x - plane_bounds.x0, plane_bounds.x1 - beam_x),
std::max<double>(beam_y - plane_bounds.y0, plane_bounds.y1 - beam_y));
bkg_radial_built = bkg_radial || bkg_radial_auto;
const float grow_max = bkg_radial_built ? BraggStencilMaxGrow_px(static_cast<float>(r_max), stencil)
: 0.0f;
@@ -217,10 +222,37 @@ void BraggIntegrationEngine::BuildRadialKernel(float grow) {
k_diff.push_back(static_cast<float>(hist_ann[k] / sa - hist_disk[k] / sd));
}
void BraggIntegrationEngine::RadialBackgroundFromRings(const std::vector<float> &ring_bkg, int32_t q_bins,
float low_q, float dq) {
radial_curve.clear();
const RingBackground rings(ring_bkg, q_bins, low_q, dq);
if (rings.empty())
return;
// The same bins as the engines' own curve: one per pixel of distance from the beam, out to the far
// corner.
const int n = static_cast<int>(std::ceil(r_max)) + 2;
const double two_k = 4.0 * PI / geom.GetWavelength_A();
radial_curve.resize(n);
for (int r = 0; r < n; ++r)
radial_curve[r] = static_cast<float>(rings.At(two_k * std::sin(0.5 * std::atan(r / F_px))));
}
std::vector<BraggPanel> BraggIntegrationEngine::Panels(const std::vector<Reflection> &predicted,
size_t npredicted) const {
std::vector<BraggPanel> out(npredicted);
for (size_t i = 0; i < npredicted; ++i) {
const float x = predicted[i].predicted_x, y = predicted[i].predicted_y;
out[i] = MakeBraggPanel(modules, modules.ModuleOfImagePixel(x, y), static_cast<int64_t>(xpixel),
static_cast<int64_t>(ypixel), x, y);
}
return out;
}
std::vector<Reflection> BraggIntegrationEngine::Finalize(const std::vector<Reflection> &predicted,
size_t npredicted,
const std::vector<BraggPanel> &panels,
const std::vector<BraggFitResult> &results,
int64_t image_number) const {
int64_t image_number) {
// Sized to what is kept, not to what was predicted: this vector is the one every image holds to the
// end of the pass, and a background ring lost to the neighbours drops a reflection here - on a
// dense pattern more than half of them, which a reserve of npredicted would carry as dead capacity.
@@ -234,10 +266,11 @@ std::vector<Reflection> BraggIntegrationEngine::Finalize(const std::vector<Refle
if (!fr.ok)
continue;
Reflection refl = predicted[i];
refl.I = fr.I;
refl.sigma = fr.sigma;
refl.bkg = fr.bkg;
refl.var_bkg = fr.var_bkg;
// In photons: the engine measured in ADU, with variances already taken at the gain.
refl.I = fr.I / pixel_gain;
refl.sigma = fr.sigma / pixel_gain;
refl.bkg = fr.bkg / pixel_gain;
refl.var_bkg = fr.var_bkg / (pixel_gain * pixel_gain);
if (fr.has_observed) {
refl.observed_x = fr.observed_x;
refl.observed_y = fr.observed_y;
@@ -245,9 +278,28 @@ std::vector<Reflection> BraggIntegrationEngine::Finalize(const std::vector<Refle
// has_observed is set only for a signal disk every pixel of which was readable.
refl.clipped = !fr.has_observed;
refl.overloaded = fr.overloaded;
// A rotation merge drops the whole rocking event of an overloaded reflection. A still has no
// rocking event: its overloaded observations are the fully recorded ones of the strongest
// reflections, so dropping them leaves those reflections to their partial observations, whose
// partiality correction then sets the merged intensity - and it reads low. Measured on clipped
// CCD stills, the merged low-resolution intensities came out at 0.4-0.6x of the deposited ones.
// So a still keeps the observation as a lower bound: each saturated pixel counted at the
// saturation limit. (A fit to the unsaturated wings was tried and read lower still: the
// profile learned from unsaturated spots does not describe the wings of a clipped one.)
// That takes a pixel AT the limit: an observation overloaded only by pixels unreadable on
// this frame has nothing to count at the limit, and counting those pixels as zero is no
// lower bound of anything - it stays overloaded and is dropped. (A pixel stuck at the limit
// is no clipped spot either; the pre-scan masks it, HotPixelFinder.)
if (fr.overloaded && keep_overloads && fr.saturated > 0) {
refl.I = fr.I + static_cast<float>(fr.saturated * (saturation_limit - fr.bkg));
refl.sigma = std::sqrt(fr.var_bkg + std::max(refl.I, 1.0f));
refl.overloaded = false;
++counts.overloads_kept;
}
refl.observed = true;
if (polarization)
refl.prescaling_corr /= geom.CalcAzIntPolarizationCorr(refl.predicted_x, refl.predicted_y, polarization.value());
refl.prescaling_corr /= geom.CalcAzIntPolarizationCorr(panels[i].plane_x, panels[i].plane_y,
polarization.value());
refl.image_scale_corr = refl.prescaling_corr * refl.qe_corr * refl.flight_corr / refl.partiality;
refl.image_number = static_cast<float>(image_number);
out.push_back(refl);
@@ -31,6 +31,7 @@
// that the downstream scaling/merge consumes unchanged.
// =============================================================================
#include <algorithm>
#include <cmath>
#include <cstddef>
#include <cstdint>
@@ -42,6 +43,7 @@
#include "../../common/DiffractionGeometry.h"
#include "../../common/Reflection.h"
#include "../image_preprocessing/ImagePreprocessorBuffer.h"
#include "BraggPanel.h"
#include "BraggStencil.h"
namespace bragg_engine {
@@ -140,6 +142,8 @@ struct BraggIntegrationCounts {
// only (the crowding of the pattern); nothing reads them.
uint64_t overlapped = 0;
uint64_t overlapped_major = 0;
// Overloaded reflections of stills, kept in the merge as a lower bound (BraggIntegrationEngine::Finalize).
uint64_t overloads_kept = 0;
};
// One reflection's extracted intensity, produced by the derived engine and turned into a
@@ -158,6 +162,7 @@ struct BraggFitResult {
bool ok = false;
bool has_observed = false;
bool overloaded = false; // a signal-disk pixel was saturated (Reflection::overloaded)
int saturated = 0; // signal-disk pixels at the saturation limit, left out of I
};
class BraggIntegrationEngine {
@@ -176,6 +181,9 @@ protected:
double bw_sigma; // bandwidth sigma [dimensionless, * Rpx -> px]
float bkg_clip_nsigma; // high-outlier background sigma-clip multiplier (0 = no clip)
float bkg_pixel_gain = 1.0f; // background pixel variance per unit mean the clip scales by
// ADU per photon (BraggIntegrationSettings::pixel_gain): every variance the engine forms is taken
// at it, and Finalize converts the reflections to photons with it. 1 changes nothing, bit for bit.
float pixel_gain = 1.0f;
bool use_ellipse; // radially elongate the per-reflection Gaussian
double c_radial; // radial variance coefficient of tan^2(2theta): parallax + capture
@@ -201,6 +209,11 @@ protected:
float overlap_min_peak = 0.0f; // Reject: least clean profile fraction that is kept
float claim = 0.0f, inv_claim = 0.0f;
// Overloaded reflections of stills are kept as a lower bound (Finalize), with every saturated pixel
// counted at the saturation limit, in the units of the preprocessed image.
bool keep_overloads = false;
double saturation_limit = 0.0;
// --- radial background curvature correction (BraggIntegrationSettings) ---
// The disk and the annulus are concentric, so any background LINEAR in position cancels between
// them; what survives is the curvature of the radial background. mean_annulus(B) - mean_disk(B)
@@ -228,6 +241,10 @@ protected:
int k_len = 0; // entries per kernel
int n_kern = 1; // kernels in the table (1 = circular stencil)
std::vector<float> k_diff; // n_kern * k_len, annulus-minus-disk weight per radial offset
// The radial background B the kernels are applied to, one value per pixel of distance from the
// beam, where the caller handed one over (RadialBackgroundFromRings). Empty: the curve is
// accumulated from the clipped ring pixels of the predicted reflections themselves.
std::vector<float> radial_curve;
// One radial-offset kernel for a ring grown by `grow` px, appended to k_diff. Kept out of line
// so the circular and elongated cases cannot drift apart. The signal disk does not change with
@@ -239,21 +256,30 @@ protected:
DiffractionGeometry geom; // kept for the per-reflection polarization correction
std::optional<float> polarization;
// The panels of the image (DetectorModules), empty for a flat detector, and the box on the plane
// they span - where the far corner is, for anything sized by the largest radius on the detector.
DetectorModules modules;
PlaneBox plane_bounds;
// The panel of each prediction, found from its position in the image (BraggPanel).
std::vector<BraggPanel> Panels(const std::vector<Reflection> &predicted, size_t npredicted) const;
// Accumulated over every image this engine has run. An engine belongs to one worker thread, so
// these are plain counters and the caller sums over the engines it made.
BraggIntegrationCounts counts;
// Assemble output reflections from the per-reflection fit results (polarization + scale corr).
std::vector<Reflection> Finalize(const std::vector<Reflection> &predicted, size_t npredicted,
const std::vector<BraggPanel> &panels,
const std::vector<BraggFitResult> &results,
int64_t image_number) const;
int64_t image_number);
public:
explicit BraggIntegrationEngine(const DiffractionExperiment &experiment);
virtual ~BraggIntegrationEngine() = default;
// predicted[0..npredicted) are the reflections to extract; image is the preprocessed int32
// frame (image.size() == npixel). Returns only the observed reflections.
// frame (image.size() == npixel). Returns only the observed reflections. Positions in and out are
// the image's: a reflection is on the panel whose box holds its predicted position.
virtual std::vector<Reflection> Run(const ImagePreprocessorBuffer &image,
const std::vector<Reflection> &predicted, size_t npredicted,
int64_t image_number) = 0;
@@ -267,6 +293,29 @@ public:
void BackgroundRadial(bool on) { bkg_radial = on && bkg_radial_built; }
[[nodiscard]] bool IsBackgroundRadialAuto() const { return bkg_radial_auto; }
// The radial background curve for the images that follow, from a peak-excluded background per
// resolution ring of the whole detector (the adaptive spot finder's GetRingBackground): q bin i
// holds the ring at low_q + (i + 0.5) * dq, entries past the first q_bins are further azimuthal
// bins and are averaged in, and a ring with no value (NAN) is bridged by its neighbours. On a
// serial frame the predicted reflections' own ring pixels are a sparse sample of the same curve -
// a few dozen reflections, against every pixel of the frame here. An empty profile goes back to
// accumulating the curve from the reflections.
void RadialBackgroundFromRings(const std::vector<float> &ring_bkg, int32_t q_bins, float low_q, float dq);
// Where that curve is in use (the correction on), the ring's high-side clip follows it as well: a ring
// pixel at radial offset `rad` from a reflection at radius r0 is clipped against the threshold plus
// the curve's rise from r0 to it, rounded to whole counts so that every engine keeps the same pixels.
// On a background falling steeply away from the beam the flat threshold otherwise cuts the beam-side
// half of the ring as outliers, and the background reads low. 0 where no curve is in use.
[[nodiscard]] int32_t RadialClipOffset(float r0, float rad) const {
if (!bkg_radial || radial_curve.empty())
return 0;
const int n = static_cast<int>(radial_curve.size());
const int b = std::clamp(static_cast<int>(std::lround(r0 + rad)), 0, n - 1);
const int b0 = std::clamp(static_cast<int>(std::lround(r0)), 0, n - 1);
return static_cast<int32_t>(std::lround(radial_curve[b] - radial_curve[b0]));
}
[[nodiscard]] const std::vector<float> &GetRadialBackground() const { return radial_curve; }
// What this engine has counted since it was built (BraggIntegrationCounts). The GPU engine keeps
// its counts on the device and brings them back here, so this is a synchronising call - ask for it
// once a pass, not once an image.
@@ -7,6 +7,8 @@
#include <cmath>
#include <cstdint>
#include <limits>
#include <tuple>
#include <utility>
#include <vector>
#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86))
@@ -23,6 +25,11 @@ namespace {
// The engine reads pixels in the INT32_MIN(masked)/INT32_MAX(saturated) convention.
inline bool valid(int32_t v) { return v != INT32_MIN && v != INT32_MAX; }
// A direction on the plane in a panel's pixel axes (MakeBraggStencil). Unchanged without panels.
inline std::pair<double, double> to_panel_axes(const BraggPanel &pn, double ux, double uy) {
return {ux * pn.fx + uy * pn.fy, ux * pn.sx + uy * pn.sy};
}
// Ask for the cache lines from first to last ahead of their use. Only a hint: it changes no result.
inline void prefetch(const void *p) {
#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86))
@@ -78,27 +85,33 @@ BraggIntegrationEngineCPU::BraggIntegrationEngineCPU(const DiffractionExperiment
: BraggIntegrationEngine(experiment),
refl_mask(static_cast<int>(xpixel), static_cast<int>(ypixel), 0),
owner(static_cast<int>(xpixel), static_cast<int>(ypixel), BRAGG_OWNER_NONE),
static_mask(mask.GetPackedMask()) {}
static_mask(mask.GetPackedMask()) {
if (mask.GetMask().size() != npixel)
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"Pixel mask size doesn't match the image");
}
void BraggIntegrationEngineCPU::MarkNeighbours(const std::vector<Reflection> &predicted,
const std::vector<BraggPanel> &panels,
const std::vector<uint32_t> &order) {
const int W = static_cast<int>(xpixel), H = static_cast<int>(ypixel);
// --- Reflection mask: mark the r2 signal region of every predicted reflection, so a neighbour's
// signal is excluded from this reflection's r2..r3 background ring. MASK_FLUX where the
// neighbour puts flux on this frame (NEIGHBOUR_MASK_MIN_PARTIALITY) - only those are excluded
// - and MASK_TAIL where only the tail of a rocking curve does, which is counted for the density
// guard but read as background. The region is the INNER stencil ellipse, taken in each
// neighbour's OWN frame - an elongated neighbour whose streak is still marked as a disk would
// leak its tails into this reflection's ring. ---
// leak its tails into this reflection's ring. Only on the neighbour's own panel: beyond it the
// image holds pixels that are elsewhere on the detector. ---
refl_mask.Clear();
for (const uint32_t i : order) {
const auto &r = predicted[i];
const BraggPanel &pn = panels[i];
const uint8_t level = r.partiality >= NEIGHBOUR_MASK_MIN_PARTIALITY ? MASK_FLUX : MASK_TAIL;
const BraggStencil st = MakeBraggStencil(r.predicted_x, r.predicted_y, stencil);
const int x0 = std::max(0, static_cast<int>(std::floor(r.predicted_x - st.ex_in - 1.0f)));
const int x1 = std::min(W - 1, static_cast<int>(std::ceil(r.predicted_x + st.ex_in + 1.0f)));
const int y0 = std::max(0, static_cast<int>(std::floor(r.predicted_y - st.ey_in - 1.0f)));
const int y1 = std::min(H - 1, static_cast<int>(std::ceil(r.predicted_y + st.ey_in + 1.0f)));
const BraggStencil st = MakeBraggStencil(pn, stencil);
const int x0 = std::max(pn.x0, static_cast<int>(std::floor(r.predicted_x - st.ex_in - 1.0f)));
const int x1 = std::min(pn.x1, static_cast<int>(std::ceil(r.predicted_x + st.ex_in + 1.0f)));
const int y0 = std::max(pn.y0, static_cast<int>(std::floor(r.predicted_y - st.ey_in - 1.0f)));
const int y1 = std::min(pn.y1, static_cast<int>(std::ceil(r.predicted_y + st.ey_in + 1.0f)));
for (int y = y0; y <= y1; ++y)
for (int x = x0; x <= x1; ++x) {
const auto d = BraggStencilDistances(st, x - r.predicted_x, y - r.predicted_y);
@@ -115,10 +128,12 @@ void BraggIntegrationEngineCPU::CountNeighbourCrowding(const std::vector<Reflect
const int W = static_cast<int>(xpixel), H = static_cast<int>(ypixel);
counts.predicted += npredicted;
const std::vector<uint32_t> order = FrameOrder(predicted, npredicted);
MarkNeighbours(predicted, order);
const std::vector<BraggPanel> panels = Panels(predicted, npredicted);
MarkNeighbours(predicted, panels, order);
for (const uint32_t i : order) {
const auto &r = predicted[i];
const BraggStencil st = MakeBraggStencil(r.predicted_x, r.predicted_y, stencil);
const BraggPanel &pn = panels[i];
const BraggStencil st = MakeBraggStencil(pn, stencil);
const int x0 = std::max(0, static_cast<int>(std::floor(r.predicted_x - st.ex_out - 1.0f)));
const int x1 = std::min(W - 1, static_cast<int>(std::ceil(r.predicted_x + st.ex_out + 1.0f)));
const int y0 = std::max(0, static_cast<int>(std::floor(r.predicted_y - st.ey_out - 1.0f)));
@@ -131,7 +146,8 @@ void BraggIntegrationEngineCPU::CountNeighbourCrowding(const std::vector<Reflect
|| d.inner < r2_sq || d.outer >= r3_sq)
continue;
const size_t idx = static_cast<size_t>(y) * W + x;
if (idx / 32 < static_mask.size() && ((static_mask[idx / 32] >> (idx % 32)) & 1U))
if (!BraggPanelHolds(pn, x, y)
|| (idx / 32 < static_mask.size() && ((static_mask[idx / 32] >> (idx % 32)) & 1U)))
continue;
++n_ring;
if (refl_mask.Get(x, y) == 0)
@@ -147,7 +163,7 @@ std::vector<Reflection> BraggIntegrationEngineCPU::RunImpl(const Sampler &img,
const std::vector<Reflection> &predicted,
size_t npredicted, int64_t image_number) {
if (npredicted == 0)
return Finalize(predicted, npredicted, std::vector<BraggFitResult>(npredicted), image_number);
return Finalize(predicted, npredicted, {}, std::vector<BraggFitResult>(npredicted), image_number);
counts.predicted += npredicted;
const int W = static_cast<int>(xpixel), H = static_cast<int>(ypixel);
@@ -155,7 +171,8 @@ std::vector<Reflection> BraggIntegrationEngineCPU::RunImpl(const Sampler &img,
// Every loop below whose results do not depend on the order walks the reflections in this one.
const std::vector<uint32_t> order = FrameOrder(predicted, npredicted);
MarkNeighbours(predicted, order);
const std::vector<BraggPanel> panels = Panels(predicted, npredicted);
MarkNeighbours(predicted, panels, order);
owner.Clear();
// --- Signal-region ownership: a pixel inside two reflections' signal regions belongs to the
@@ -169,10 +186,11 @@ std::vector<Reflection> BraggIntegrationEngineCPU::RunImpl(const Sampler &img,
const float claim_sq = claim * claim;
for (const uint32_t i : order) {
const auto &r = predicted[i];
const int x0 = std::max(0, static_cast<int>(std::floor(r.predicted_x - claim)));
const int x1 = std::min(W - 1, static_cast<int>(std::ceil(r.predicted_x + claim)));
const int y0 = std::max(0, static_cast<int>(std::floor(r.predicted_y - claim)));
const int y1 = std::min(H - 1, static_cast<int>(std::ceil(r.predicted_y + claim)));
const BraggPanel &pn = panels[i];
const int x0 = std::max(pn.x0, static_cast<int>(std::floor(r.predicted_x - claim)));
const int x1 = std::min(pn.x1, static_cast<int>(std::ceil(r.predicted_x + claim)));
const int y0 = std::max(pn.y0, static_cast<int>(std::floor(r.predicted_y - claim)));
const int y1 = std::min(pn.y1, static_cast<int>(std::ceil(r.predicted_y + claim)));
for (int y = y0; y <= y1; ++y)
for (int x = x0; x <= x1; ++x) {
const float dx = x - r.predicted_x, dy = y - r.predicted_y;
@@ -220,15 +238,16 @@ std::vector<Reflection> BraggIntegrationEngineCPU::RunImpl(const Sampler &img,
// prefetch.)
if (k + 1 < npredicted) {
const Reflection &n = predicted[order[k + 1]];
const Box b = box_of(n, MakeBraggStencil(n.predicted_x, n.predicted_y, stencil));
const Box b = box_of(n, MakeBraggStencil(panels[order[k + 1]], stencil));
for (int y = b.y0; y <= b.y1 && b.x0 <= b.x1; ++y)
prefetch_row(img.address(static_cast<size_t>(y) * W + b.x0),
img.address(static_cast<size_t>(y) * W + b.x1));
}
const auto &r = predicted[i];
const BraggPanel &pn = panels[i];
// This reflection's stencil: the r1 signal disk, and the r2..r3 ring elongated radially by
// the analytic smear.
const BraggStencil st = MakeBraggStencil(r.predicted_x, r.predicted_y, stencil);
const BraggStencil st = MakeBraggStencil(pn, stencil);
const Box box = box_of(r, st);
const int x0 = box.x0, x1 = box.x1, y0 = box.y0, y1 = box.y1;
@@ -243,7 +262,9 @@ std::vector<Reflection> BraggIntegrationEngineCPU::RunImpl(const Sampler &img,
for (int y = y0; y <= y1; ++y)
for (int x = x0; x <= x1; ++x) {
const auto d = BraggStencilDistances(st, x - r.predicted_x, y - r.predicted_y);
const int32_t px = img[y * W + x];
// Off the reflection's panel is a gap: unreadable, and not lost to the flux.
const bool on = BraggPanelHolds(pn, x, y);
const int32_t px = on ? img[y * W + x] : INT32_MIN;
if (do_clip && d.inner >= r2_sq && d.outer < r3_sq && valid(px) && refl_mask.Get(x, y) != MASK_FLUX)
clip_ring.push_back({px, d.rad});
if (BraggStencilInSignal(st, x - r.predicted_x, y - r.predicted_y, d.signal, r1_sq)) {
@@ -258,8 +279,10 @@ std::vector<Reflection> BraggIntegrationEngineCPU::RunImpl(const Sampler &img,
}
++s.n_inner;
if (px == INT32_MAX
|| (px == INT32_MIN && !static_masked(static_cast<size_t>(y) * W + x)))
|| (px == INT32_MIN && on && !static_masked(static_cast<size_t>(y) * W + x)))
s.overloaded = 1;
if (px == INT32_MAX)
++s.n_saturated;
if (!valid(px)) continue;
s.I_sum += px;
s.I_sum_x += static_cast<int64_t>(x) * px;
@@ -287,10 +310,10 @@ std::vector<Reflection> BraggIntegrationEngineCPU::RunImpl(const Sampler &img,
if (ClipsRing(s)) {
const int32_t thr = ClipThreshold(s);
for (const auto &[px, rad] : clip_ring)
if (px <= thr) {
if (static_cast<int64_t>(px) <= static_cast<int64_t>(thr) + RadialClipOffset(st.r0, rad)) {
clip.sum += px;
++clip.n;
if (bkg_radial) {
if (bkg_radial && radial_curve.empty()) {
// The radial curve is binned on the TRUE detector radius, so the
// offset here is the unshrunk radial projection.
const int b = std::clamp(static_cast<int>(std::lround(st.r0 + rad)), 0, a.n_rad - 1);
@@ -302,18 +325,19 @@ std::vector<Reflection> BraggIntegrationEngineCPU::RunImpl(const Sampler &img,
FinishPassA(a, i, r, st, s, clip, bkg_vals);
}
return ProfilePasses(img, owner, predicted, npredicted, a, image_number);
return ProfilePasses(img, owner, predicted, npredicted, panels, a, image_number);
}
BraggIntegrationEngineCPU::PassA BraggIntegrationEngineCPU::StartPassA(size_t npredicted) const {
const int W = static_cast<int>(xpixel), H = static_cast<int>(ypixel);
PassA a;
a.rough.resize(npredicted);
// A pixel's radius is the reflection's radius plus the pixel's projection on the beam->reflection
// direction, so no per-pixel sqrt is needed.
a.n_rad = static_cast<int>(std::ceil(std::hypot(std::max<double>(beam_x, W - beam_x),
std::max<double>(beam_y, H - beam_y)))) + 2;
if (bkg_radial) {
// direction, so no per-pixel sqrt is needed. Out to the far corner of the plane the panels span.
const float bx0 = static_cast<float>(plane_bounds.x0), bx1 = static_cast<float>(plane_bounds.x1);
const float by0 = static_cast<float>(plane_bounds.y0), by1 = static_cast<float>(plane_bounds.y1);
a.n_rad = static_cast<int>(std::ceil(std::hypot(std::max<double>(beam_x - bx0, bx1 - beam_x),
std::max<double>(beam_y - by0, by1 - beam_y)))) + 2;
if (bkg_radial && radial_curve.empty()) {
a.rad_sum.assign(a.n_rad, 0);
a.rad_cnt.assign(a.n_rad, 0);
}
@@ -346,6 +370,7 @@ void BraggIntegrationEngineCPU::FinishPassA(PassA &a, size_t i, const Reflection
out.r_bin = std::clamp(static_cast<int>(std::lround(st.r0)), 0, a.n_rad - 1);
out.k_bin = BraggStencilKernelIndex(st, n_kern);
out.overloaded = s.overloaded != 0;
out.saturated = s.n_saturated;
if (overlap != OverlapMode::Off && s.n_own < s.n_disk) {
++counts.overlapped;
@@ -403,9 +428,13 @@ void BraggIntegrationEngineCPU::FinishPassA(PassA &a, size_t i, const Reflection
// error enters n_inner times over: var(I) = I_sum + n_inner^2 * bkg/n_bkg_used. Leaving
// the second term out understates sigma by sqrt(1 + n_inner/n_bkg) - 1.109x at the
// default r1=4/r2=6/r3=10 stencil, on every reflection of every dataset.
// bkg_var is in counted units, as the profile fit reads it; every variance formed from it is
// taken at the gain, so a CCD's sigma - and the strong flag and the guard read from it - is in
// photons rather than in ADU counted as photons.
const double g = pixel_gain;
out.bkg_var = out.bkg / n_bkg_used;
out.var_bkg = static_cast<double>(s.n_inner_valid) * out.bkg
+ static_cast<double>(s.n_inner_valid) * s.n_inner_valid * out.bkg_var;
out.var_bkg = g * (static_cast<double>(s.n_inner_valid) * out.bkg
+ static_cast<double>(s.n_inner_valid) * s.n_inner_valid * out.bkg_var);
out.I_sum = s.I_sum;
out.n_inner = static_cast<int>(s.n_inner_valid);
out.n_disk = s.n_disk;
@@ -413,7 +442,7 @@ void BraggIntegrationEngineCPU::FinishPassA(PassA &a, size_t i, const Reflection
const double var_bkg_term = static_cast<double>(s.n_inner_valid) * s.n_inner_valid * out.bkg_var;
out.sigma = 1.0;
if (s.I_sum > 0) {
out.sigma = std::max(out.sigma, std::sqrt(static_cast<double>(s.I_sum) + var_bkg_term));
out.sigma = std::max(out.sigma, std::sqrt(g * (static_cast<double>(s.I_sum) + var_bkg_term)));
// The centroid of the SIGNAL, not of the disk. Weighting by the raw counts weights by
// signal plus background, and the background is flat over a disk centred on the
// PREDICTION - so its own centroid is the prediction exactly, and it pulls the answer
@@ -465,7 +494,7 @@ bool BraggIntegrationEngineCPU::FitKept(const BraggFitOut &o) const {
template <class Sampler, class OwnerMap>
BraggFitOut BraggIntegrationEngineCPU::FitProfile(const Sampler &img, const OwnerMap &owner_map,
const BraggFitSetup &s, size_t i,
const BraggFitSetup &s, const BraggPanel &pn, size_t i,
const std::vector<float> &shell_profiles,
std::vector<float> &cells,
std::vector<FitPixel> &fit_pixels) const {
@@ -476,9 +505,15 @@ BraggFitOut BraggIntegrationEngineCPU::FitProfile(const Sampler &img, const Owne
BraggFitOut o{};
const float *P;
if (s.shell >= 0)
P = shell_profiles.data() + static_cast<size_t>(s.shell) * GG;
else {
if (s.shell >= 0) {
// The shell's learned profile is in the plane's axes; laid out here in the panel's.
const float *learned = shell_profiles.data() + static_cast<size_t>(s.shell) * GG;
cells.resize(GG);
for (int dy = -R; dy <= R; ++dy)
for (int dx = -R; dx <= R; ++dx)
cells[(dy + R) * G + (dx + R)] = learned[BraggProfileCell(pn, dx, dy, R)];
P = cells.data();
} else {
// The grid's image rows, asked for now (as in pass A): building the profile below takes long
// enough for them to arrive before the fit reads them.
const int gx0 = std::max(0, s.cx - Rf), gx1 = std::min(W - 1, s.cx + Rf);
@@ -506,7 +541,7 @@ BraggFitOut BraggIntegrationEngineCPU::FitProfile(const Sampler &img, const Owne
// pixels, what Reject cuts on. m_read / m_all is the fraction of the r1 disk the
// summation seed the runaway guard compares against actually summed; with nothing missing
// and nothing excluded it is 1 and the guard is untouched. ---
const BraggStencil st = MakeBraggStencil(s.px, s.py, stencil);
const BraggStencil st = MakeBraggStencil(pn, stencil);
fit_pixels.clear();
for (int dy = -Rf; dy <= Rf; ++dy)
for (int dx = -Rf; dx <= Rf; ++dx) {
@@ -523,7 +558,7 @@ BraggFitOut BraggIntegrationEngineCPU::FitProfile(const Sampler &img, const Owne
o.p_grid += Pp;
o.p_peak = std::max(o.p_peak, Pp);
if (in_disk) o.m_all += Pp;
const int32_t v = img[y * W + x];
const int32_t v = BraggPanelHolds(pn, x, y) ? img[y * W + x] : INT32_MIN;
if (!valid(v)) {
o.p_lost_peak = std::max(o.p_lost_peak, Pp);
continue;
@@ -557,7 +592,8 @@ BraggFitOut BraggIntegrationEngineCPU::FitProfile(const Sampler &img, const Owne
template <class Sampler, class OwnerMap>
std::vector<Reflection> BraggIntegrationEngineCPU::ProfilePasses(const Sampler &img, const OwnerMap &owner_map,
const std::vector<Reflection> &predicted,
size_t npredicted, PassA &a,
size_t npredicted,
const std::vector<BraggPanel> &panels, PassA &a,
int64_t image_number) {
const int W = static_cast<int>(xpixel), H = static_cast<int>(ypixel);
std::vector<BraggFitResult> results(npredicted);
@@ -568,7 +604,6 @@ std::vector<Reflection> BraggIntegrationEngineCPU::ProfilePasses(const Sampler &
return !use_owner
|| BraggOwnedBy(owner_map.Get(x, y), static_cast<int>(i));
};
auto grid_idx = [this](int dx, int dy) { return (dy + R) * G + (dx + R); };
// --- Radial background curvature correction. The annulus mean is blind to the curvature of the
// radial background (a linear background cancels between the concentric disk and annulus), so
@@ -584,7 +619,11 @@ std::vector<Reflection> BraggIntegrationEngineCPU::ProfilePasses(const Sampler &
double corr = 0.0;
for (int k = 0; k < k_len; ++k) {
const int b = std::clamp(rh.r_bin + k - k_off, 0, a.n_rad - 1);
const double v = a.rad_cnt[b] > 0 ? static_cast<double>(a.rad_sum[b]) / a.rad_cnt[b] : rh.bkg;
double v;
if (!radial_curve.empty())
v = radial_curve[b];
else
v = a.rad_cnt[b] > 0 ? static_cast<double>(a.rad_sum[b]) / a.rad_cnt[b] : rh.bkg;
corr += static_cast<double>(kern[k]) * v;
}
rh.bkg -= corr; // annulus mean -> mean over the signal disk
@@ -607,9 +646,9 @@ std::vector<Reflection> BraggIntegrationEngineCPU::ProfilePasses(const Sampler &
if (overlap == OverlapMode::Reject && rh.n_own < overlap_min_peak * rh.n_disk) continue;
results[i] = {static_cast<float>(rh.I), static_cast<float>(rh.sigma), static_cast<float>(rh.bkg),
static_cast<float>(rh.obs_x), static_cast<float>(rh.obs_y),
static_cast<float>(rh.var_bkg), true, rh.has_obs, rh.overloaded};
static_cast<float>(rh.var_bkg), true, rh.has_obs, rh.overloaded, rh.saturated};
}
return Finalize(predicted, npredicted, results, image_number);
return Finalize(predicted, npredicted, panels, results, image_number);
}
auto shell_of = [&](float d) {
@@ -622,7 +661,7 @@ std::vector<Reflection> BraggIntegrationEngineCPU::ProfilePasses(const Sampler &
// --- Learn the profile per shell (+ global) from the strong spots. ---
// Two things are learned. The empirical profile is the average grid in the DETECTOR frame, which is
// where it is applied. The width is a pair of second moments taken in each spot's OWN radial /
// where it is applied - in the plane's axes, which a turned panel's pixels are mapped onto. The width is a pair of second moments taken in each spot's OWN radial /
// tangential frame: a grid stacked in the detector frame is azimuthally averaged, so its <r^2> is
// sigma_r^2 + sigma_t^2 with no way back, and a radially smeared spot reads as a wide TANGENTIAL
// one. Rotating each contribution into the spot's frame keeps the two apart.
@@ -637,19 +676,22 @@ std::vector<Reflection> BraggIntegrationEngineCPU::ProfilePasses(const Sampler &
for (size_t i = 0; i < npredicted; ++i) {
const auto &rh = rough[i];
if (!rh.ok || !rh.strong || rh.I <= 0.0) continue;
const double rx = predicted[i].predicted_x - beam_x, ry = predicted[i].predicted_y - beam_y;
const BraggPanel &pn = panels[i];
const double rx = pn.plane_x - beam_x, ry = pn.plane_y - beam_y;
const double Rpx = std::hypot(rx, ry);
const double ux = Rpx > 1e-6 ? rx / Rpx : 1.0, uy = Rpx > 1e-6 ? ry / Rpx : 0.0;
for (int dy = -R; dy <= R; ++dy)
const auto [ux, uy] = to_panel_axes(pn, Rpx > 1e-6 ? rx / Rpx : 1.0, Rpx > 1e-6 ? ry / Rpx : 0.0);
for (int dy = -R; dy <= R; ++dy)
for (int dx = -R; dx <= R; ++dx) {
const int x = rh.cx + dx, y = rh.cy + dy;
if (x < 0 || y < 0 || x >= W || y >= H) continue;
if (x < 0 || y < 0 || x >= W || y >= H || !BraggPanelHolds(pn, x, y)) continue;
const int32_t px = img[y * W + x];
if (!valid(px)) continue;
if (exclude && !clean(x, y, i)) continue;
const double v = (static_cast<double>(px) - rh.bkg) / rh.I;
shell_grid[rh.shell][grid_idx(dx, dy)] += v;
global_grid[grid_idx(dx, dy)] += v;
// The grid in the plane's axes (BraggProfileCell); the moments below are axis-free.
const int cell = BraggProfileCell(pn, dx, dy, R);
shell_grid[rh.shell][cell] += v;
global_grid[cell] += v;
if (dx * dx + dy * dy >= r1_sq) continue;
const double rad = dx * ux + dy * uy, tn = -dx * uy + dy * ux;
shell_mom[rh.shell].rad += v * rad * rad;
@@ -720,17 +762,19 @@ std::vector<Reflection> BraggIntegrationEngineCPU::ProfilePasses(const Sampler &
fs = {};
if (!rh.ok) continue;
// An overloaded reflection is not measured by any fit - its brightest pixels are what is
// missing. It is passed on with its box sum and the flag, for the merge to drop its rocking
// event (Reflection::overloaded); the missing-peak cut below would otherwise drop just this
// frame and leave the event to be extrapolated from its flanks.
// missing. It is passed on with its box sum and the flag, for a rotation merge to drop its
// rocking event (Reflection::overloaded) and for a still to be kept as a lower bound
// (Finalize); the missing-peak cut below would otherwise drop just this frame and leave the
// event to be extrapolated from its flanks.
if (rh.overloaded) {
results[i] = {static_cast<float>(rh.I), static_cast<float>(rh.sigma), static_cast<float>(rh.bkg),
static_cast<float>(rh.obs_x), static_cast<float>(rh.obs_y),
static_cast<float>(rh.var_bkg), true, false, true};
static_cast<float>(rh.var_bkg), true, false, true, rh.saturated};
continue;
}
const int sh = rh.shell < 0 ? 0 : rh.shell;
const BraggStencil st = MakeBraggStencil(predicted[i].predicted_x, predicted[i].predicted_y, stencil);
const BraggPanel &pn = panels[i];
const BraggStencil st = MakeBraggStencil(pn, stencil);
fs.fit = 1;
fs.px = predicted[i].predicted_x;
fs.py = predicted[i].predicted_y;
@@ -740,7 +784,7 @@ std::vector<Reflection> BraggIntegrationEngineCPU::ProfilePasses(const Sampler &
fs.shell = sh;
fs.footprint = st.fp_s2t > 0.0f;
if (!empirical) {
const double rx = predicted[i].predicted_x - beam_x, ry = predicted[i].predicted_y - beam_y;
const double rx = pn.plane_x - beam_x, ry = pn.plane_y - beam_y;
const double Rpx = std::hypot(rx, ry);
const double tan2t = Rpx / F_px;
double s2t = shell_sigma2[sh].tan;
@@ -754,7 +798,7 @@ std::vector<Reflection> BraggIntegrationEngineCPU::ProfilePasses(const Sampler &
const double radial_extra = std::max(shell_sigma2[sh].rad - s2t,
sbw * sbw + c_radial * tan2t * tan2t);
if (Rpx > 1e-6 && radial_extra > 0.25) {
ux = rx / Rpx; uy = ry / Rpx;
std::tie(ux, uy) = to_panel_axes(pn, rx / Rpx, ry / Rpx);
s2r = s2t + radial_extra;
elong = true;
}
@@ -792,7 +836,7 @@ std::vector<Reflection> BraggIntegrationEngineCPU::ProfilePasses(const Sampler &
std::vector<FitPixel> fit_pixels;
for (const uint32_t i : FrameOrder(predicted, npredicted))
if (setups[i].fit)
fits[i] = FitProfile(img, owner_map, setups[i], i, shell_profiles, cells_buf, fit_pixels);
fits[i] = FitProfile(img, owner_map, setups[i], panels[i], i, shell_profiles, cells_buf, fit_pixels);
}
for (size_t i = 0; i < npredicted; ++i) {
@@ -810,15 +854,17 @@ std::vector<Reflection> BraggIntegrationEngineCPU::ProfilePasses(const Sampler &
// 1/den is the profile-fit variance with the background taken as exact. The fit is
// I = sum(P*(px-bkg)/v) / sum(P^2/v), so dI/dbkg = -wsum/den and the background estimate's
// own error adds (wsum/den)^2 * var(bkg) - the same term the box sum was missing.
double sigma = std::sqrt(1.0 / den + (wsum / den) * (wsum / den) * rh.bkg_var);
// Both variances at the gain (FinishPassA), so the guard below compares like with like.
const double g = pixel_gain;
double sigma = std::sqrt(g * (1.0 / den + (wsum / den) * (wsum / den) * rh.bkg_var));
// var_bkg is the NON-SIGNAL part of that variance, and 1/den is the fit's variance taken at the
// fitted intensity, so the signal part to remove is I itself - not max(0, I). Clamping it leaves
// a down-fluctuated reflection's own (deflated) variance standing as its background variance,
// which is 2-3x too small; the merge then weights exactly the down-fluctuated observations up.
// The whole point of a separate var_bkg is that it does not move with the observation's own
// fluctuation, and 1/den - I is what does not (1/den grows with I one for one).
double var_bkg = std::max(0.0, 1.0 / den - I
+ (wsum / den) * (wsum / den) * rh.bkg_var);
double var_bkg = g * std::max(0.0, 1.0 / den - I
+ (wsum / den) * (wsum / den) * rh.bkg_var);
// The seed is a sum over the disk the box sum actually read, so when pixels are missing from
// both - excluded to a neighbour, or unreadable - the fit's full-profile intensity has to be
// scaled down to that same disk before the two are comparable. Nothing dropped gives 1.
@@ -834,21 +880,22 @@ std::vector<Reflection> BraggIntegrationEngineCPU::ProfilePasses(const Sampler &
results[i] = {static_cast<float>(I), static_cast<float>(sigma),
static_cast<float>(rh.bkg),
static_cast<float>(rh.obs_x), static_cast<float>(rh.obs_y),
static_cast<float>(var_bkg), true, rh.has_obs, rh.overloaded};
static_cast<float>(var_bkg), true, rh.has_obs, rh.overloaded, rh.saturated};
}
return Finalize(predicted, npredicted, results, image_number);
return Finalize(predicted, npredicted, panels, results, image_number);
}
template std::vector<Reflection> BraggIntegrationEngineCPU::ProfilePasses(
const BraggIntegrationEngineCPU::BufferSampler &, const BraggIntegrationEngineCPU::FlatOwnerMap &,
const std::vector<Reflection> &, size_t, BraggIntegrationEngineCPU::PassA &, int64_t);
const std::vector<Reflection> &, size_t, const std::vector<BraggPanel> &,
BraggIntegrationEngineCPU::PassA &, int64_t);
std::vector<Reflection> BraggIntegrationEngineCPU::Run(const ImagePreprocessorBuffer &image,
const std::vector<Reflection> &predicted,
size_t npredicted, int64_t image_number) {
if (image.size() != npixel)
return Finalize(predicted, npredicted, std::vector<BraggFitResult>(npredicted), image_number);
return Finalize(predicted, npredicted, {}, std::vector<BraggFitResult>(npredicted), image_number);
return RunImpl(BufferSampler{image.data()}, predicted, npredicted, image_number);
}
@@ -856,7 +903,7 @@ std::vector<Reflection> BraggIntegrationEngineCPU::Run(const CompressedImage &im
const std::vector<Reflection> &predicted,
size_t npredicted, int64_t image_number) {
if (image.GetWidth() * image.GetHeight() != npixel)
return Finalize(predicted, npredicted, std::vector<BraggFitResult>(npredicted), image_number);
return Finalize(predicted, npredicted, {}, std::vector<BraggFitResult>(npredicted), image_number);
std::vector<uint8_t> scratch;
const auto *ptr = image.GetUncompressedPtr(scratch);
@@ -56,9 +56,10 @@ class BraggIntegrationEngineCPU : public BraggIntegrationEngine {
TiledFrame<uint8_t> refl_mask;
TiledFrame<uint32_t> owner;
// Marks every predicted reflection's r2 region in refl_mask (MASK_FLUX / MASK_TAIL), visiting them in
// `order` (any order gives the same mask).
void MarkNeighbours(const std::vector<Reflection> &predicted, const std::vector<uint32_t> &order);
// Marks every predicted reflection's r2 region in refl_mask (MASK_FLUX / MASK_TAIL), on its own panel,
// visiting them in `order` (any order gives the same mask).
void MarkNeighbours(const std::vector<Reflection> &predicted, const std::vector<BraggPanel> &panels,
const std::vector<uint32_t> &order);
template <class Sampler>
std::vector<Reflection> RunImpl(const Sampler &img, const std::vector<Reflection> &predicted,
@@ -69,7 +70,8 @@ class BraggIntegrationEngineCPU : public BraggIntegrationEngine {
// fit. fit_pixels is scratch: the pixels the fit reads, gathered once.
struct FitPixel { float Pp, signal; };
template <class Sampler, class OwnerMap>
BraggFitOut FitProfile(const Sampler &img, const OwnerMap &owner_map, const BraggFitSetup &s, size_t i,
BraggFitOut FitProfile(const Sampler &img, const OwnerMap &owner_map, const BraggFitSetup &s,
const BraggPanel &pn, size_t i,
const std::vector<float> &shell_profiles, std::vector<float> &cells,
std::vector<FitPixel> &fit_pixels) const;
// Whether enough of a reflection's profile is readable, and its own, for the fit to be kept.
@@ -107,6 +109,7 @@ protected:
bool ok = false, strong = false, has_obs = false;
bool full = false; // every pixel of the signal disk was readable
bool overloaded = false; // a pixel of the signal disk was saturated
int saturated = 0; // signal-disk pixels at the saturation limit
};
// Everything pass A hands the profile passes.
struct PassA {
@@ -140,7 +143,8 @@ protected:
template <class Sampler, class OwnerMap>
std::vector<Reflection> ProfilePasses(const Sampler &img, const OwnerMap &owner_map,
const std::vector<Reflection> &predicted, size_t npredicted,
PassA &a, int64_t image_number);
const std::vector<BraggPanel> &panels, PassA &a,
int64_t image_number);
public:
BraggIntegrationEngineCPU(const DiffractionExperiment &experiment, const PixelMask &mask);
@@ -20,6 +20,7 @@ struct BraggGpuParams {
int R, G, GG;
float bkg_clip_nsigma; // high-side background sigma-clip multiplier (0 = no clip)
float bkg_pixel_gain; // background pixel variance per unit mean (1 = counted photons)
float pixel_gain; // ADU per photon every variance is taken at (see the CPU engine)
int empirical; // ProfileEmpirical vs ProfileGaussian
int use_ellipse;
float bw_sigma;
@@ -67,18 +68,20 @@ constexpr int COUNT_SLOTS = 5;
// `value` is what the launch writes: MASK_TAIL from every reflection, which also claims the owner map;
// then MASK_FLUX from the ones that put flux on this frame (`marks`), a later launch so that it wins
// over the first where two regions meet, as the CPU engine's maximum does; and 0 to clear.
__global__ void mark_mask(const float *px_x, const float *px_y, const uint8_t *marks, uint8_t *mask,
uint32_t *owner, BraggGpuParams p, int n, int value) {
__global__ void mark_mask(const float *px_x, const float *px_y, const BraggPanel *panel, const uint8_t *marks,
uint8_t *mask, uint32_t *owner, BraggGpuParams p, int n, int value) {
const int i = blockIdx.x;
if (i >= n) return;
if (value == MASK_FLUX && !marks[i]) return;
const bool clear = value == 0;
const float cx = px_x[i], cy = px_y[i];
const BraggStencil st = MakeBraggStencil(cx, cy, p.stencil);
const int x0 = max(0, (int) floorf(cx - st.ex_in - 1.0f));
const int x1 = min(p.W - 1, (int) ceilf(cx + st.ex_in + 1.0f));
const int y0 = max(0, (int) floorf(cy - st.ey_in - 1.0f));
const int y1 = min(p.H - 1, (int) ceilf(cy + st.ey_in + 1.0f));
// Only on the reflection's own panel (see the CPU engine).
const BraggPanel pn = panel[i];
const BraggStencil st = MakeBraggStencil(pn, p.stencil);
const int x0 = max(pn.x0, (int) floorf(cx - st.ex_in - 1.0f));
const int x1 = min(pn.x1, (int) ceilf(cx + st.ex_in + 1.0f));
const int y0 = max(pn.y0, (int) floorf(cy - st.ey_in - 1.0f));
const int y1 = min(pn.y1, (int) ceilf(cy + st.ey_in + 1.0f));
const int bw = x1 - x0 + 1, bh = y1 - y0 + 1;
if (bw <= 0 || bh <= 0) return;
for (int t = threadIdx.x; t < bw * bh; t += blockDim.x) {
@@ -159,21 +162,21 @@ __device__ __forceinline__ float profile_float(unsigned long long v) {
}
// --- Pass A box-sum: rough I / background / centroid / strong flag, one block per reflection. ---
__global__ void boxsum(const float *px_x, const float *px_y, const float *dd,
__global__ void boxsum(const float *px_x, const float *px_y, const BraggPanel *panel, const float *dd,
const int32_t *img, const uint8_t *mask, const uint32_t *owner, const uint8_t *static_mask,
BraggGpuParams p, int n,
int *cx_o, int *cy_o, float *I_o, float *sigma_o, float *bkg_o,
float *bkgvar_o, float *varbkg_o, float *obsx_o, float *obsy_o, uint8_t *ok_o, uint8_t *strong_o,
uint8_t *hasobs_o, uint8_t *overloaded_o, unsigned long long *invd2mm,
uint8_t *hasobs_o, uint8_t *overloaded_o, int *saturated_o, unsigned long long *invd2mm,
float *isum_o, int *ninner_o, int *rbin_o, int *kbin_o,
unsigned long long *rad_sum, int *rad_cnt, int n_rad,
unsigned long long *counts) {
unsigned long long *rad_sum, int *rad_cnt, int n_rad, int accumulate_rad,
const float *rad_curve, unsigned long long *counts) {
const int i = blockIdx.x;
if (i >= n) return;
__shared__ unsigned long long s_Isum, s_Ix, s_Iy;
__shared__ unsigned long long s_x, s_y; // positions behind s_Isum, to take the background out of the centroid
__shared__ int s_ninner, s_ninner_valid, s_nbkg, s_ndisk, s_nown, s_nsat;
__shared__ int s_ninner, s_ninner_valid, s_nbkg, s_ndisk, s_nown, s_nsat, s_nmax;
__shared__ int s_nring, s_nclean; // readable ring pixels, and those no neighbour covers; see the CPU engine
__shared__ unsigned long long s_bkgsum;
__shared__ int s_accept, s_full;
@@ -194,19 +197,20 @@ __global__ void boxsum(const float *px_x, const float *px_y, const float *dd,
unsigned long long *s_radv = s_rad; // signed value carried as two's complement
int *s_radn = (int *) (s_rad + p.rad_w);
__shared__ int s_radbase;
const BraggPanel pn = panel[i];
if (threadIdx.x == 0) {
const float rx = px_x[i] - p.beam_x, ry = px_y[i] - p.beam_y;
const float rx = pn.plane_x - p.beam_x, ry = pn.plane_y - p.beam_y;
s_r0 = sqrtf(rx * rx + ry * ry);
s_Isum = 0; s_Ix = 0; s_Iy = 0; s_x = 0; s_y = 0;
s_ninner = 0; s_ninner_valid = 0; s_nbkg = 0; s_bkgsum = 0;
s_ndisk = 0; s_nown = 0; s_nring = 0; s_nclean = 0; s_nsat = 0;
s_ndisk = 0; s_nown = 0; s_nring = 0; s_nclean = 0; s_nsat = 0; s_nmax = 0;
}
__syncthreads();
const float cx = px_x[i], cy = px_y[i];
// Every thread builds the same stencil from the same inputs; it is a few flops against a whole
// bounding box of pixel reads, so it costs less than staging it through shared memory.
const BraggStencil st = MakeBraggStencil(cx, cy, p.stencil);
const BraggStencil st = MakeBraggStencil(pn, p.stencil);
const int x0 = max(0, (int) floorf(cx - st.ex_out - 1.0f));
const int x1 = min(p.W - 1, (int) ceilf(cx + st.ex_out + 1.0f));
const int y0 = max(0, (int) floorf(cy - st.ey_out - 1.0f));
@@ -216,7 +220,7 @@ __global__ void boxsum(const float *px_x, const float *px_y, const float *dd,
long long l_Isum = 0, l_Ix = 0, l_Iy = 0;
long long l_x = 0, l_y = 0; // positions behind l_Isum, for the background-free centroid
int l_ni = 0, l_niv = 0, l_nb = 0, l_nd = 0, l_no = 0, l_nring = 0, l_nclean = 0, l_nsat = 0;
int l_ni = 0, l_niv = 0, l_nb = 0, l_nd = 0, l_no = 0, l_nring = 0, l_nclean = 0, l_nsat = 0, l_nmax = 0;
long long l_bkg = 0;
for (int t = threadIdx.x; t < area; t += blockDim.x) {
const int x = x0 + t % bw, y = y0 + t / bw;
@@ -232,12 +236,16 @@ __global__ void boxsum(const float *px_x, const float *px_y, const float *dd,
else if (p.exclude_px) continue;
}
++l_ni;
const int32_t px = img[y * p.W + x];
// Off the reflection's panel is a gap: unreadable, and not lost to the flux (see the CPU engine).
const bool on = BraggPanelHolds(pn, x, y);
const int32_t px = on ? img[y * p.W + x] : INT32_MIN;
// Saturated, or unreadable on this frame beyond the run's mask: an overload (see the CPU engine).
if (px == INT32_MAX || (px == INT32_MIN && !static_mask[y * p.W + x])) ++l_nsat;
if (px == INT32_MAX || (px == INT32_MIN && on && !static_mask[y * p.W + x])) ++l_nsat;
if (px == INT32_MAX) ++l_nmax;
if (valid(px)) { l_Isum += px; l_Ix += (long long) x * px; l_Iy += (long long) y * px;
l_x += x; l_y += y; ++l_niv; }
} else if (d.inner >= p.r2_sq && d.outer < p.r3_sq) {
if (!BraggPanelHolds(pn, x, y)) continue;
const int32_t px = img[y * p.W + x];
if (!valid(px)) continue;
++l_nring;
@@ -261,6 +269,7 @@ __global__ void boxsum(const float *px_x, const float *px_y, const float *dd,
WARP_ATOMIC_ADD(s_nring, l_nring);
WARP_ATOMIC_ADD(s_nclean, l_nclean);
WARP_ATOMIC_ADD(s_nsat, l_nsat);
WARP_ATOMIC_ADD(s_nmax, l_nmax);
__syncthreads();
for (int t = threadIdx.x; t < p.rad_w; t += blockDim.x) { s_radv[t] = 0; s_radn[t] = 0; }
@@ -307,7 +316,7 @@ __global__ void boxsum(const float *px_x, const float *px_y, const float *dd,
const int x = x0 + t % bw, y = y0 + t / bw;
const BraggStencilDist d = BraggStencilDistances(st, (float) x - cx, (float) y - cy);
if (!(d.inner >= p.r2_sq && d.outer < p.r3_sq)) continue;
if (mask[y * p.W + x] == MASK_FLUX) continue;
if (!BraggPanelHolds(pn, x, y) || mask[y * p.W + x] == MASK_FLUX) continue;
const int32_t px = img[y * p.W + x];
if (!valid(px)) continue;
const int slot = atomicAdd(&s_bn, 1);
@@ -349,12 +358,19 @@ __global__ void boxsum(const float *px_x, const float *px_y, const float *dd,
const int x = x0 + t % bw, y = y0 + t / bw;
const BraggStencilDist d = BraggStencilDistances(st, (float) x - cx, (float) y - cy);
if (!(d.inner >= p.r2_sq && d.outer < p.r3_sq)) continue;
if (mask[y * p.W + x] == MASK_FLUX) continue;
if (!BraggPanelHolds(pn, x, y) || mask[y * p.W + x] == MASK_FLUX) continue;
const int32_t px = img[y * p.W + x];
if (!valid(px)) continue;
if ((long long) px <= s_thr_i) {
// Where the frame's radial curve is in use the clip follows it (RadialClipOffset).
long long lim = s_thr_i;
if (rad_curve) {
const int b = min(max((int) lroundf(s_r0 + d.rad), 0), n_rad - 1);
const int b0 = min(max((int) lroundf(s_r0), 0), n_rad - 1);
lim += lroundf(rad_curve[b] - rad_curve[b0]);
}
if ((long long) px <= lim) {
c_l += px; ++cn_l;
if (n_rad > 0) {
if (accumulate_rad) {
// The radial curve is binned on the TRUE detector radius, so this is the
// unshrunk radial projection - no per-pixel sqrt.
const int idx = (int) lroundf(s_r0 + d.rad) - s_radbase;
@@ -369,7 +385,7 @@ __global__ void boxsum(const float *px_x, const float *px_y, const float *dd,
}
__syncthreads();
if (n_rad > 0) {
if (accumulate_rad) {
for (int t = threadIdx.x; t < p.rad_w; t += blockDim.x) {
if (s_radn[t] == 0) continue;
const int b = min(max(s_radbase + t, 0), n_rad - 1);
@@ -406,7 +422,7 @@ __global__ void boxsum(const float *px_x, const float *px_y, const float *dd,
double sigma = 1.0;
uint8_t hasobs = 0; double ox = 0.0, oy = 0.0;
if (Isum > 0) {
sigma = fmax(sigma, sqrt((double) Isum + var_bkg_term));
sigma = fmax(sigma, sqrt((double) p.pixel_gain * ((double) Isum + var_bkg_term)));
// The centroid of the SIGNAL. Weighting by raw counts weights by signal plus background,
// and the background is flat over a disk centred on the PREDICTION, so its centroid is the
// prediction and it pulls the answer there - the displacement comes out shrunk by
@@ -426,13 +442,14 @@ __global__ void boxsum(const float *px_x, const float *px_y, const float *dd,
cy_o[i] = (int) lroundf(cy);
I_o[i] = (float) I; sigma_o[i] = (float) sigma; bkg_o[i] = (float) bkg;
bkgvar_o[i] = (float) bkg_var;
varbkg_o[i] = (float) ((double) s_ninner_valid * bkg + var_bkg_term);
varbkg_o[i] = (float) ((double) p.pixel_gain * ((double) s_ninner_valid * bkg + var_bkg_term));
isum_o[i] = (float) Isum;
ninner_o[i] = s_ninner_valid;
rbin_o[i] = min(max((int) lroundf(s_r0), 0), n_rad > 0 ? n_rad - 1 : 0);
kbin_o[i] = BraggStencilKernelIndex(st, p.n_kern);
obsx_o[i] = (float) ox; obsy_o[i] = (float) oy; hasobs_o[i] = hasobs;
overloaded_o[i] = s_nsat > 0 ? 1 : 0;
saturated_o[i] = s_nmax;
ok_o[i] = 1;
// The profile and its resolution shells are learned from COMPLETE reflections only; see the CPU
// engine.
@@ -482,8 +499,7 @@ __global__ void reset(unsigned long long *shell_grid, unsigned long long *global
// the spot's own radial/tangential frame, because a detector-frame stack is azimuthally averaged
// and cannot tell a radially smeared spot from a tangentially wide one (see the CPU engine).
// One block per reflection. ---
__global__ void learn_profile(const int32_t *img, const uint32_t *owner,
const float *px_x, const float *px_y,
__global__ void learn_profile(const int32_t *img, const uint32_t *owner, const BraggPanel *panel,
const int *cx_a, const int *cy_a, const float *dd,
const unsigned long long *invd2mm,
const float *I_a, const float *bkg_a, const uint8_t *ok_a, const uint8_t *strong_a,
@@ -502,9 +518,12 @@ __global__ void learn_profile(const int32_t *img, const uint32_t *owner,
__syncthreads();
const int sh = s_sh;
const float bkg = bkg_a[i];
const float rx = px_x[i] - p.beam_x, ry = px_y[i] - p.beam_y;
const BraggPanel pn = panel[i];
const float rx = pn.plane_x - p.beam_x, ry = pn.plane_y - p.beam_y;
const float Rpx = sqrtf(rx * rx + ry * ry);
const float ux = Rpx > 1e-6f ? rx / Rpx : 1.0f, uy = Rpx > 1e-6f ? ry / Rpx : 0.0f;
// The radial direction on the plane, in the panel's pixel axes (see the CPU engine).
const float pux = Rpx > 1e-6f ? rx / Rpx : 1.0f, puy = Rpx > 1e-6f ? ry / Rpx : 0.0f;
const float ux = pux * pn.fx + puy * pn.fy, uy = pux * pn.sx + puy * pn.sy;
unsigned long long *sg = shell_grid + (size_t) sh * p.GG;
__shared__ unsigned long long s_rad, s_tan, s_w;
if (threadIdx.x == 0) { s_rad = 0; s_tan = 0; s_w = 0; }
@@ -513,14 +532,16 @@ __global__ void learn_profile(const int32_t *img, const uint32_t *owner,
for (int k = threadIdx.x; k < p.GG; k += blockDim.x) {
const int dx = k % p.G - p.R, dy = k / p.G - p.R;
const int x = cx + dx, y = cy + dy;
if (x < 0 || y < 0 || x >= p.W || y >= p.H) continue;
if (x < 0 || y < 0 || x >= p.W || y >= p.H || !BraggPanelHolds(pn, x, y)) continue;
const int32_t px = img[y * p.W + x];
if (!valid(px)) continue;
if (p.overlap == 2 && !BraggOwnedBy(owner[y * p.W + x], i)) continue;
const float v = ((float) px - bkg) / I;
const unsigned long long vq = profile_fixed(v);
atomicAdd(&sg[k], vq);
atomicAdd(&global_grid[k], vq);
// The grid in the plane's axes (BraggProfileCell, see the CPU engine).
const int cell = BraggProfileCell(pn, dx, dy, p.R);
atomicAdd(&sg[cell], vq);
atomicAdd(&global_grid[cell], vq);
if ((float) (dx * dx + dy * dy) >= p.r1_sq) continue;
const float rad = dx * ux + dy * uy, tn = -dx * uy + dy * ux;
l_rad += v * rad * rad; l_tan += v * tn * tn; l_w += v;
@@ -592,7 +613,7 @@ __global__ void build_profiles(const unsigned long long *shell_grid, const unsig
// correction because the kernel weights sum to zero. The kernel depends on how far this
// reflection's ring was elongated, so k_diff is a table and kbin_a picks the row.
// Mirrors BraggIntegrationEngineCPU. ---
__global__ void radial_correct(const unsigned long long *rad_sum, const int *rad_cnt, int n_rad,
__global__ void radial_correct(const unsigned long long *rad_sum, const int *rad_cnt, const float *curve, int n_rad,
const float *k_diff, int k_len, int k_off,
const float *isum_a, const int *ninner_a, const int *rbin_a,
const int *kbin_a,
@@ -605,7 +626,8 @@ __global__ void radial_correct(const unsigned long long *rad_sum, const int *rad
for (int k = 0; k < k_len; ++k) {
int b = rbin_a[i] + k - k_off;
b = min(max(b, 0), n_rad - 1);
const float v = rad_cnt[b] > 0 ? (float) (long long) rad_sum[b] / (float) rad_cnt[b] : bkg;
const float v = curve ? curve[b]
: rad_cnt[b] > 0 ? (float) (long long) rad_sum[b] / (float) rad_cnt[b] : bkg;
corr += kern[k] * v;
}
const float bkg_new = bkg - corr;
@@ -618,6 +640,7 @@ __global__ void radial_correct(const unsigned long long *rad_sum, const int *rad
// Otwinowski & Minor, Methods Enzymol 276, 307-326 (1997).
// One block per reflection; the (possibly elongated) profile is built in shared memory. ---
__global__ void fit(const int32_t *img, const uint32_t *owner, const float *px_x, const float *px_y,
const BraggPanel *panel,
const int *cx_a, const int *cy_a, const float *dd, const unsigned long long *invd2mm,
const float *I_seed, const float *sigma_seed, const float *bkg_a,
const float *bkgvar_a, const float *varbkg_seed, const uint8_t *ok_a, const uint8_t *overloaded_a,
@@ -640,7 +663,8 @@ __global__ void fit(const int32_t *img, const uint32_t *owner, const float *px_x
if (overloaded_a[i]) return;
const int cx = cx_a[i], cy = cy_a[i];
const BraggStencil st = MakeBraggStencil(px_x[i], px_y[i], p.stencil);
const BraggPanel pn = panel[i];
const BraggStencil st = MakeBraggStencil(pn, p.stencil);
// As in learn_profile: one thread per block, not one per thread. Two double-precision divisions
// on a card whose double throughput is a sixty-fourth of its single is worth doing once.
__shared__ int s_sh;
@@ -654,12 +678,14 @@ __global__ void fit(const int32_t *img, const uint32_t *owner, const float *px_x
const float *Psrc = use_shell ? (shell_P + (size_t) sh * p.GG) : global_P;
if (threadIdx.x == 0) { s_Rf = p.R; s_Gf = p.G; }
__syncthreads();
for (int k = threadIdx.x; k < p.GG; k += blockDim.x) Pbuf[k] = Psrc[k];
// The learned profile is in the plane's axes; laid out here in the panel's.
for (int k = threadIdx.x; k < p.GG; k += blockDim.x)
Pbuf[k] = Psrc[BraggProfileCell(pn, k % p.G - p.R, k / p.G - p.R, p.R)];
__syncthreads();
} else {
const int si = use_shell ? sh : N_SHELL; // N_SHELL is the global slot
float s2t = sigma2_t[si];
const float rx = px_x[i] - p.beam_x, ry = px_y[i] - p.beam_y;
const float rx = pn.plane_x - p.beam_x, ry = pn.plane_y - p.beam_y;
const float Rpx = sqrtf(rx * rx + ry * ry);
const float tan2t = Rpx / p.F_px;
float s2r = s2t, ux = 1.0f, uy = 0.0f;
@@ -669,7 +695,14 @@ __global__ void fit(const int32_t *img, const uint32_t *owner, const float *px_x
// parallax/capture term (see the CPU engine).
const float sbw = p.bw_sigma * Rpx;
const float radial_extra = fmaxf(sigma2_r[si] - s2t, sbw * sbw + p.c_radial * tan2t * tan2t);
if (Rpx > 1e-6f && radial_extra > 0.25f) { ux = rx / Rpx; uy = ry / Rpx; s2r = s2t + radial_extra; elong = true; }
if (Rpx > 1e-6f && radial_extra > 0.25f) {
// On the plane, in the panel's pixel axes (see the CPU engine).
const float pux = rx / Rpx, puy = ry / Rpx;
ux = pux * pn.fx + puy * pn.fy;
uy = pux * pn.sx + puy * pn.sy;
s2r = s2t + radial_extra;
elong = true;
}
}
// A spot that outgrows the r1 disk takes the measured footprint's widths (see the CPU engine).
if (st.fp_s2t > 0.0f) {
@@ -728,7 +761,7 @@ __global__ void fit(const int32_t *img, const uint32_t *owner, const float *px_x
l_pgrid += Pp;
l_ppeak = fmaxf(l_ppeak, Pp);
if (in_disk) l_mall += Pp;
if (!valid(img[y * p.W + x])) {
if (!BraggPanelHolds(pn, x, y) || !valid(img[y * p.W + x])) {
l_plost = fmaxf(l_plost, Pp);
continue;
}
@@ -772,7 +805,7 @@ __global__ void fit(const int32_t *img, const uint32_t *owner, const float *px_x
const float Pp = Pbuf[k];
if (Pp <= 0.0f) continue;
const int x = cx + (k % Gf - Rf), y = cy + (k / Gf - Rf);
if (x < 0 || y < 0 || x >= p.W || y >= p.H) continue;
if (x < 0 || y < 0 || x >= p.W || y >= p.H || !BraggPanelHolds(pn, x, y)) continue;
const int32_t px = img[y * p.W + x];
if (!valid(px)) continue;
const float v = fmaxf(B + Ihere * Pp, (float) WEIGHT_VARIANCE_MIN_FRACTION * B);
@@ -796,9 +829,10 @@ __global__ void fit(const int32_t *img, const uint32_t *owner, const float *px_x
// 1/s_den takes the background as exact; dI/dbkg = -s_wsum/s_den adds the background
// estimate's own error (see the CPU engine).
const float wr = s_wsum / s_den;
float I = s_I, sigma = sqrtf(1.0f / s_den + wr * wr * bkgvar_a[i]);
// Both at the gain, as the seed's (see the CPU engine).
float I = s_I, sigma = sqrtf(p.pixel_gain * (1.0f / s_den + wr * wr * bkgvar_a[i]));
// The signal part to remove is I itself, not max(0, I) - see the CPU engine.
float var_bkg = fmaxf(0.0f, 1.0f / s_den - I + wr * wr * bkgvar_a[i]);
float var_bkg = p.pixel_gain * fmaxf(0.0f, 1.0f / s_den - I + wr * wr * bkgvar_a[i]);
// Guard against profile-fit runaways (see the CPU engine): fall back to the summation seed
// when the profile result diverges from it. Pixels missing from both - excluded to a
// neighbour, or unreadable - scale the full-profile intensity back to the disk the seed
@@ -834,6 +868,9 @@ BraggIntegrationEngineGPU::BraggIntegrationEngineGPU(const DiffractionExperiment
d_global_n(1),
d_invd2(2),
d_counts(COUNT_SLOTS) {
if (mask.GetMask().size() != npixel)
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"Pixel mask size doesn't match the image");
threads = 128;
// On the engine's stream (the member: the parameter was moved from), where the kernels counting
// into it run - the NULL stream is not ordered before those.
@@ -882,6 +919,7 @@ BraggIntegrationEngineGPU::BraggIntegrationEngineGPU(const DiffractionExperiment
n_rad = static_cast<int>(std::ceil(r_max)) + 2;
d_rad_sum = CudaDevicePtr<unsigned long long>(n_rad);
d_rad_cnt = CudaDevicePtr<int>(n_rad);
d_rad_curve = CudaDevicePtr<float>(n_rad);
d_k_diff = CudaDevicePtr<float>(k_diff.size());
cuda_err(cudaMemcpyAsync(d_k_diff, k_diff.data(), sizeof(float) * k_diff.size(),
cudaMemcpyHostToDevice, *this->stream));
@@ -902,6 +940,7 @@ void BraggIntegrationEngineGPU::EnsureCapacity(size_t n) {
d_px_x = CudaDevicePtr<float>(new_capacity);
d_px_y = CudaDevicePtr<float>(new_capacity);
d_d = CudaDevicePtr<float>(new_capacity);
d_panel = CudaDevicePtr<BraggPanel>(new_capacity);
d_mark = CudaDevicePtr<uint8_t>(new_capacity);
d_cx = CudaDevicePtr<int>(new_capacity);
d_cy = CudaDevicePtr<int>(new_capacity);
@@ -920,10 +959,12 @@ void BraggIntegrationEngineGPU::EnsureCapacity(size_t n) {
d_strong = CudaDevicePtr<uint8_t>(new_capacity);
d_has_obs = CudaDevicePtr<uint8_t>(new_capacity);
d_overloaded = CudaDevicePtr<uint8_t>(new_capacity);
d_saturated = CudaDevicePtr<int>(new_capacity);
h_px_x = CudaHostPtr<float>(new_capacity);
h_px_y = CudaHostPtr<float>(new_capacity);
h_d = CudaHostPtr<float>(new_capacity);
h_panel = CudaHostPtr<BraggPanel>(new_capacity);
h_mark = CudaHostPtr<uint8_t>(new_capacity);
h_I = CudaHostPtr<float>(new_capacity);
h_sigma = CudaHostPtr<float>(new_capacity);
@@ -934,6 +975,7 @@ void BraggIntegrationEngineGPU::EnsureCapacity(size_t n) {
h_ok = CudaHostPtr<uint8_t>(new_capacity);
h_has_obs = CudaHostPtr<uint8_t>(new_capacity);
h_overloaded = CudaHostPtr<uint8_t>(new_capacity);
h_saturated = CudaHostPtr<int>(new_capacity);
capacity = new_capacity;
}
@@ -942,7 +984,7 @@ std::vector<Reflection> BraggIntegrationEngineGPU::Run(const ImagePreprocessorBu
size_t npredicted, int64_t image_number) {
std::vector<BraggFitResult> results(npredicted);
if (image.size() != npixel || npredicted == 0)
return Finalize(predicted, npredicted, results, image_number);
return Finalize(predicted, npredicted, {}, results, image_number);
counts.predicted += npredicted;
const int32_t *img = image.getGPUBuffer();
@@ -952,7 +994,9 @@ std::vector<Reflection> BraggIntegrationEngineGPU::Run(const ImagePreprocessorBu
EnsureCapacity(npredicted);
const int n = static_cast<int>(npredicted);
const std::vector<BraggPanel> panels = Panels(predicted, npredicted);
for (size_t i = 0; i < npredicted; ++i) {
h_panel[i] = panels[i];
h_px_x[i] = predicted[i].predicted_x;
h_px_y[i] = predicted[i].predicted_y;
h_d[i] = predicted[i].d;
@@ -961,6 +1005,7 @@ std::vector<Reflection> BraggIntegrationEngineGPU::Run(const ImagePreprocessorBu
cuda_err(cudaMemcpyAsync(d_px_x, h_px_x.get(), sizeof(float) * npredicted, cudaMemcpyHostToDevice, *stream));
cuda_err(cudaMemcpyAsync(d_px_y, h_px_y.get(), sizeof(float) * npredicted, cudaMemcpyHostToDevice, *stream));
cuda_err(cudaMemcpyAsync(d_d, h_d.get(), sizeof(float) * npredicted, cudaMemcpyHostToDevice, *stream));
cuda_err(cudaMemcpyAsync(d_panel, h_panel.get(), sizeof(BraggPanel) * npredicted, cudaMemcpyHostToDevice, *stream));
cuda_err(cudaMemcpyAsync(d_mark, h_mark.get(), sizeof(uint8_t) * npredicted, cudaMemcpyHostToDevice, *stream));
BraggGpuParams p{
@@ -969,6 +1014,7 @@ std::vector<Reflection> BraggIntegrationEngineGPU::Run(const ImagePreprocessorBu
.R = R, .G = G, .GG = GG,
.bkg_clip_nsigma = mode != IntegratorMode::BoxSum ? bkg_clip_nsigma : 0.0f,
.bkg_pixel_gain = bkg_pixel_gain,
.pixel_gain = pixel_gain,
.empirical = empirical ? 1 : 0,
.use_ellipse = use_ellipse ? 1 : 0,
.bw_sigma = static_cast<float>(bw_sigma), .c_radial = static_cast<float>(c_radial),
@@ -986,7 +1032,11 @@ std::vector<Reflection> BraggIntegrationEngineGPU::Run(const ImagePreprocessorBu
// Whether the radial correction runs for THIS image. n_rad only says the buffers exist - under
// the auto mode they are allocated for every image and used for the ones the ice score selects.
const int rad_n = bkg_radial ? n_rad : 0;
// Where the caller handed over a curve (RadialBackgroundFromRings) it is read instead, and the
// box sums accumulate nothing.
const bool radial_on = bkg_radial && n_rad > 0;
const bool radial_given = radial_on && !radial_curve.empty();
const int rad_n = radial_on ? n_rad : 0;
// The mask and the owner map can be taken back either by clearing the whole frame or by revisiting
// the boxes that were marked, and which is cheaper depends on the detector: on 18 Mpx the marks are
@@ -1005,37 +1055,41 @@ std::vector<Reflection> BraggIntegrationEngineGPU::Run(const ImagePreprocessorBu
if (p.overlap)
cuda_err(cudaMemsetAsync(d_owner, 0xff, sizeof(uint32_t) * npixel, *stream)); // BRAGG_OWNER_NONE
}
if (rad_n > 0) {
if (rad_n > 0 && !radial_given) {
cuda_err(cudaMemsetAsync(d_rad_sum, 0, sizeof(unsigned long long) * n_rad, *stream));
cuda_err(cudaMemsetAsync(d_rad_cnt, 0, sizeof(int) * n_rad, *stream));
}
if (radial_given)
cuda_err(cudaMemcpyAsync(d_rad_curve, radial_curve.data(), sizeof(float) * n_rad,
cudaMemcpyHostToDevice, *stream));
reset<<<32, 256, 0, *stream>>>(d_shell_grid, d_global_grid, d_mom, d_shell_n, d_global_n, d_invd2, GG);
cuda_err(cudaGetLastError());
dirty = true;
mark_mask<<<n, threads, 0, *stream>>>(d_px_x, d_px_y, d_mark, d_mask, d_owner, p, n, MASK_TAIL);
mark_mask<<<n, threads, 0, *stream>>>(d_px_x, d_px_y, d_panel, d_mark, d_mask, d_owner, p, n, MASK_TAIL);
cuda_err(cudaGetLastError());
mark_mask<<<n, threads, 0, *stream>>>(d_px_x, d_px_y, d_mark, d_mask, d_owner, p, n, MASK_FLUX);
mark_mask<<<n, threads, 0, *stream>>>(d_px_x, d_px_y, d_panel, d_mark, d_mask, d_owner, p, n, MASK_FLUX);
cuda_err(cudaGetLastError());
boxsum<<<n, threads, boxsum_shared_bytes, *stream>>>(d_px_x, d_px_y, d_d, img, d_mask, d_owner,
boxsum<<<n, threads, boxsum_shared_bytes, *stream>>>(d_px_x, d_px_y, d_panel, d_d, img, d_mask, d_owner,
d_static_mask->get(), p, n,
d_cx, d_cy, d_I, d_sigma, d_bkg, d_bkg_var, d_var_bkg, d_obs_x, d_obs_y,
d_ok, d_strong, d_has_obs, d_overloaded, d_invd2,
d_ok, d_strong, d_has_obs, d_overloaded, d_saturated, d_invd2,
d_isum, d_ninner, d_rbin, d_kbin,
d_rad_sum, d_rad_cnt, rad_n, d_counts);
d_rad_sum, d_rad_cnt, rad_n, rad_n > 0 && !radial_given,
radial_given ? d_rad_curve.get() : nullptr, d_counts);
cuda_err(cudaGetLastError());
// Correct the flat annulus background for the curvature of the radial background before anything
// downstream (profile fit, variance) reads it.
if (rad_n > 0) {
if (radial_on) {
radial_correct<<<(n + threads - 1) / threads, threads, 0, *stream>>>(
d_rad_sum, d_rad_cnt, rad_n, d_k_diff, k_len, k_off,
d_rad_sum, d_rad_cnt, radial_given ? d_rad_curve.get() : nullptr, n_rad, d_k_diff, k_len, k_off,
d_isum, d_ninner, d_rbin, d_kbin, d_ok, d_bkg, d_I, n);
cuda_err(cudaGetLastError());
}
if (mode != IntegratorMode::BoxSum) {
// Pass B: learn (shell computed inline) -> build -> fit.
learn_profile<<<n, threads, 0, *stream>>>(img, d_owner, d_px_x, d_px_y, d_cx, d_cy, d_d, d_invd2,
learn_profile<<<n, threads, 0, *stream>>>(img, d_owner, d_panel, d_cx, d_cy, d_d, d_invd2,
d_I, d_bkg, d_ok, d_strong,
d_shell_grid, d_global_grid, d_mom, d_shell_n, d_global_n, p, n);
cuda_err(cudaGetLastError());
@@ -1043,7 +1097,7 @@ std::vector<Reflection> BraggIntegrationEngineGPU::Run(const ImagePreprocessorBu
d_shell_grid, d_global_grid, d_mom, d_shell_n, d_global_n,
d_shell_P, d_global_P, d_sigma2_r, d_sigma2_t, p);
cuda_err(cudaGetLastError());
fit<<<n, threads, fit_shared_bytes, *stream>>>(img, d_owner, d_px_x, d_px_y, d_cx, d_cy, d_d, d_invd2,
fit<<<n, threads, fit_shared_bytes, *stream>>>(img, d_owner, d_px_x, d_px_y, d_panel, d_cx, d_cy, d_d, d_invd2,
d_I, d_sigma, d_bkg, d_bkg_var, d_var_bkg, d_ok, d_overloaded,
d_shell_P, d_global_P,
d_sigma2_r, d_sigma2_t, d_shell_n,
@@ -1054,7 +1108,7 @@ std::vector<Reflection> BraggIntegrationEngineGPU::Run(const ImagePreprocessorBu
// Nothing below reads the mask or the owner map, so put them back now, over the boxes that were
// marked rather than over the frame - where that is the cheaper of the two.
if (clear_by_box) {
mark_mask<<<n, threads, 0, *stream>>>(d_px_x, d_px_y, d_mark, d_mask, d_owner, p, n, 0);
mark_mask<<<n, threads, 0, *stream>>>(d_px_x, d_px_y, d_panel, d_mark, d_mask, d_owner, p, n, 0);
cuda_err(cudaGetLastError());
}
@@ -1069,6 +1123,7 @@ std::vector<Reflection> BraggIntegrationEngineGPU::Run(const ImagePreprocessorBu
cuda_err(cudaMemcpyAsync(h_obs_y.get(), d_obs_y, sizeof(float) * npredicted, cudaMemcpyDeviceToHost, *stream));
cuda_err(cudaMemcpyAsync(h_has_obs.get(), d_has_obs, sizeof(uint8_t) * npredicted, cudaMemcpyDeviceToHost, *stream));
cuda_err(cudaMemcpyAsync(h_overloaded.get(), d_overloaded, sizeof(uint8_t) * npredicted, cudaMemcpyDeviceToHost, *stream));
cuda_err(cudaMemcpyAsync(h_saturated.get(), d_saturated, sizeof(int) * npredicted, cudaMemcpyDeviceToHost, *stream));
cuda_err(cudaStreamSynchronize(*stream));
// The clearing pass has run, so the buffers are clean again for the next image.
if (clear_by_box)
@@ -1082,13 +1137,14 @@ std::vector<Reflection> BraggIntegrationEngineGPU::Run(const ImagePreprocessorBu
results[i].var_bkg = h_var_bkg[i];
results[i].ok = true;
results[i].overloaded = h_overloaded[i] != 0;
results[i].saturated = h_saturated[i];
if (h_has_obs[i]) {
results[i].observed_x = h_obs_x[i];
results[i].observed_y = h_obs_y[i];
results[i].has_observed = true;
}
}
return Finalize(predicted, npredicted, results, image_number);
return Finalize(predicted, npredicted, panels, results, image_number);
}
BraggIntegrationCounts BraggIntegrationEngineGPU::Counts() const {
@@ -38,6 +38,7 @@ class BraggIntegrationEngineGPU : public BraggIntegrationEngine {
// --- per-reflection device arrays (grown by EnsureCapacity) ---
CudaDevicePtr<float> d_px_x, d_px_y, d_d;
CudaDevicePtr<BraggPanel> d_panel; // the panel of each reflection (BraggStencil.h)
CudaDevicePtr<uint8_t> d_mark; // the reflection marks its signal region in d_mask
CudaDevicePtr<int> d_cx, d_cy;
CudaDevicePtr<float> d_I, d_sigma, d_bkg, d_bkg_var, d_var_bkg, d_obs_x, d_obs_y;
@@ -47,12 +48,14 @@ class BraggIntegrationEngineGPU : public BraggIntegrationEngine {
// preprocessor's copy. See BraggIntegrationEngineCPU::static_mask.
std::shared_ptr<CudaDevicePtr<uint8_t>> d_static_mask;
CudaDevicePtr<uint8_t> d_ok, d_strong, d_has_obs, d_overloaded;
CudaDevicePtr<int> d_saturated; // signal-disk pixels at the saturation limit
// --- radial background curvature correction (see BraggIntegrationEngine) ---
int n_rad = 0; // radial bins, 0 when the correction is off
CudaDevicePtr<unsigned long long> d_rad_sum; // integer pixel sums, see boxsum
CudaDevicePtr<float> d_k_diff;
CudaDevicePtr<int> d_rad_cnt;
CudaDevicePtr<float> d_rad_curve; // the curve handed over (RadialBackgroundFromRings)
// --- fixed-size device arrays ---
// The learning/fit math is single precision: FP64 is heavily throttled on consumer GPUs and the
@@ -78,9 +81,11 @@ class BraggIntegrationEngineGPU : public BraggIntegrationEngine {
// driver has staged it through a bounce buffer, so eight of them in a row are eight serialised
// round-trips rather than eight queued transfers.
CudaHostPtr<float> h_px_x, h_px_y, h_d;
CudaHostPtr<BraggPanel> h_panel;
CudaHostPtr<uint8_t> h_mark;
CudaHostPtr<float> h_I, h_sigma, h_bkg, h_var_bkg, h_obs_x, h_obs_y;
CudaHostPtr<uint8_t> h_ok, h_has_obs, h_overloaded;
CudaHostPtr<int> h_saturated;
void EnsureCapacity(size_t n);
@@ -31,16 +31,19 @@ kernel void mark_neighbours(device const float2 *xy [[buffer(0)]],
constant char *stencil_raw [[buffer(3)]],
constant BraggPassAFrame &f [[buffer(4)]],
constant uint8_t &want [[buffer(5)]],
device const BraggPanel *panels [[buffer(6)]],
uint i [[thread_position_in_grid]]) {
if (i >= f.n || (want != 0 && level[i] != want))
return;
const BraggStencilParams sp = stencil_params(stencil_raw);
const float px = xy[i].x, py = xy[i].y;
const BraggStencil st = MakeBraggStencil(px, py, sp);
const int x0 = max(0, (int) floor(px - st.ex_in - 1.0f));
const int x1 = min(f.width - 1, (int) ceil(px + st.ex_in + 1.0f));
const int y0 = max(0, (int) floor(py - st.ey_in - 1.0f));
const int y1 = min(f.height - 1, (int) ceil(py + st.ey_in + 1.0f));
// Only on the reflection's own panel, as the CPU engine marks.
const BraggPanel pn = panels[i];
const BraggStencil st = MakeBraggStencil(pn, sp);
const int x0 = max(pn.x0, (int) floor(px - st.ex_in - 1.0f));
const int x1 = min(pn.x1, (int) ceil(px + st.ex_in + 1.0f));
const int y0 = max(pn.y0, (int) floor(py - st.ey_in - 1.0f));
const int y1 = min(pn.y1, (int) ceil(py + st.ey_in + 1.0f));
for (int y = y0; y <= y1; ++y)
for (int x = x0; x <= x1; ++x) {
const BraggStencilDist d = BraggStencilDistances(st, x - px, y - py);
@@ -56,15 +59,17 @@ kernel void claim_owner(device const float2 *xy [[buffer(0)]],
device atomic_uint *owner [[buffer(1)]],
constant BraggPassAFrame &f [[buffer(2)]],
constant uint &release [[buffer(3)]],
device const BraggPanel *panels [[buffer(4)]],
uint i [[thread_position_in_grid]]) {
if (i >= f.n)
return;
const float px = xy[i].x, py = xy[i].y;
const float claim_sq = f.claim * f.claim;
const int x0 = max(0, (int) floor(px - f.claim));
const int x1 = min(f.width - 1, (int) ceil(px + f.claim));
const int y0 = max(0, (int) floor(py - f.claim));
const int y1 = min(f.height - 1, (int) ceil(py + f.claim));
const BraggPanel pn = panels[i];
const int x0 = max(pn.x0, (int) floor(px - f.claim));
const int x1 = min(pn.x1, (int) ceil(px + f.claim));
const int y0 = max(pn.y0, (int) floor(py - f.claim));
const int y1 = min(pn.y1, (int) ceil(py + f.claim));
for (int y = y0; y <= y1; ++y)
for (int x = x0; x <= x1; ++x) {
const float dx = x - px, dy = y - py;
@@ -88,12 +93,14 @@ kernel void box_sums(device const float2 *xy [[buffer(0)]],
constant char *stencil_raw [[buffer(5)]],
constant BraggPassAFrame &f [[buffer(6)]],
device BraggBoxSums *sums [[buffer(7)]],
device const BraggPanel *panels [[buffer(8)]],
uint i [[thread_position_in_grid]]) {
if (i >= f.n)
return;
const BraggStencilParams sp = stencil_params(stencil_raw);
const float px = xy[i].x, py = xy[i].y;
const BraggStencil st = MakeBraggStencil(px, py, sp);
const BraggPanel pn = panels[i];
const BraggStencil st = MakeBraggStencil(pn, sp);
const int x0 = max(0, (int) floor(px - st.ex_out - 1.0f));
const int x1 = min(f.width - 1, (int) ceil(px + st.ex_out + 1.0f));
const int y0 = max(0, (int) floor(py - st.ey_out - 1.0f));
@@ -103,7 +110,9 @@ kernel void box_sums(device const float2 *xy [[buffer(0)]],
for (int x = x0; x <= x1; ++x) {
const BraggStencilDist d = BraggStencilDistances(st, x - px, y - py);
const int idx = y * f.width + x;
const int32_t v = img[idx];
// Off the reflection's panel is a gap: unreadable, and not lost to the flux.
const bool on = BraggPanelHolds(pn, x, y);
const int32_t v = on ? img[idx] : PX_MASKED;
if (BraggStencilInSignal(st, x - px, y - py, d.signal, f.r1_sq)) {
++s.n_disk;
if (f.use_owner) {
@@ -114,7 +123,7 @@ kernel void box_sums(device const float2 *xy [[buffer(0)]],
// Unreadable here but not in the run's mask: lost to the flux on this frame.
const bool masked = (uint) idx / 32 < f.static_mask_words
&& ((static_mask[(uint) idx / 32] >> ((uint) idx % 32)) & 1u);
if (v == PX_SATURATED || (v == PX_MASKED && !masked))
if (v == PX_SATURATED || (v == PX_MASKED && on && !masked))
s.overloaded = 1;
if (!valid_px(v)) continue;
s.I_sum += v;
@@ -157,12 +166,14 @@ kernel void clip_sums(device const float2 *xy [[buffer(0)]],
device BraggClipSums *out [[buffer(7)]],
device atomic_uint *rad_sum [[buffer(8)]],
device atomic_int *rad_cnt [[buffer(9)]],
device const BraggPanel *panels [[buffer(10)]],
uint i [[thread_position_in_grid]]) {
if (i >= f.n || !clips[i])
return;
const BraggStencilParams sp = stencil_params(stencil_raw);
const float px = xy[i].x, py = xy[i].y;
const BraggStencil st = MakeBraggStencil(px, py, sp);
const BraggPanel pn = panels[i];
const BraggStencil st = MakeBraggStencil(pn, sp);
const int x0 = max(0, (int) floor(px - st.ex_out - 1.0f));
const int x1 = min(f.width - 1, (int) ceil(px + st.ex_out + 1.0f));
const int y0 = max(0, (int) floor(py - st.ey_out - 1.0f));
@@ -173,7 +184,7 @@ kernel void clip_sums(device const float2 *xy [[buffer(0)]],
for (int x = x0; x <= x1; ++x) {
const BraggStencilDist d = BraggStencilDistances(st, x - px, y - py);
const int idx = y * f.width + x;
const int32_t v = img[idx];
const int32_t v = BraggPanelHolds(pn, x, y) ? img[idx] : PX_MASKED;
if (!(d.inner >= f.r2_sq && d.outer < f.r3_sq && valid_px(v) && mask[idx] != MASK_FLUX && v <= t))
continue;
c.sum += v;
@@ -198,6 +209,7 @@ kernel void profile_fit(device const BraggFitSetup *setups [[buffer(0)]],
constant char *stencil_raw [[buffer(5)]],
constant BraggPassBFrame &f [[buffer(6)]],
device BraggFitOut *out [[buffer(7)]],
device const BraggPanel *panels [[buffer(8)]],
uint i [[thread_position_in_grid]]) {
if (i >= f.n || !setups[i].fit)
return;
@@ -205,8 +217,11 @@ kernel void profile_fit(device const BraggFitSetup *setups [[buffer(0)]],
const int Rf = s.Rf, Gf = 2 * Rf + 1;
BraggFitOut o = {};
// A learned profile is in the plane's axes (BraggProfileCell); a Gaussian is built in the panel's.
const BraggPanel pn = panels[i];
const bool learned = s.shell >= 0;
device const float *P;
if (s.shell >= 0)
if (learned)
P = shell_profiles + s.shell * (2 * f.R + 1) * (2 * f.R + 1);
else {
device float *g = cells + s.cells;
@@ -222,10 +237,10 @@ kernel void profile_fit(device const BraggFitSetup *setups [[buffer(0)]],
P = g;
}
const BraggStencil st = MakeBraggStencil(s.px, s.py, stencil_params(stencil_raw));
const BraggStencil st = MakeBraggStencil(pn, stencil_params(stencil_raw));
for (int dy = -Rf; dy <= Rf; ++dy)
for (int dx = -Rf; dx <= Rf; ++dx) {
const float Pp = P[(dy + Rf) * Gf + (dx + Rf)];
const float Pp = P[learned ? BraggProfileCell(pn, dx, dy, Rf) : (dy + Rf) * Gf + (dx + Rf)];
if (Pp <= 0.0f) continue;
const int x = s.cx + dx, y = s.cy + dy;
if (x < 0 || y < 0 || x >= f.width || y >= f.height) continue;
@@ -236,7 +251,7 @@ kernel void profile_fit(device const BraggFitSetup *setups [[buffer(0)]],
o.p_grid += Pp;
o.p_peak = o.p_peak < Pp ? Pp : o.p_peak; // std::max
if (in_disk) o.m_all += Pp;
if (!valid_px(img[y * f.width + x])) {
if (!BraggPanelHolds(pn, x, y) || !valid_px(img[y * f.width + x])) {
o.p_lost_peak = o.p_lost_peak < Pp ? Pp : o.p_lost_peak;
continue;
}
@@ -254,10 +269,10 @@ kernel void profile_fit(device const BraggFitSetup *setups [[buffer(0)]],
o.wsum = 0.0f;
for (int dy = -Rf; dy <= Rf; ++dy)
for (int dx = -Rf; dx <= Rf; ++dx) {
const float Pp = P[(dy + Rf) * Gf + (dx + Rf)];
const float Pp = P[learned ? BraggProfileCell(pn, dx, dy, Rf) : (dy + Rf) * Gf + (dx + Rf)];
if (Pp <= 0.0f) continue;
const int x = s.cx + dx, y = s.cy + dy;
if (x < 0 || y < 0 || x >= f.width || y >= f.height) continue;
if (x < 0 || y < 0 || x >= f.width || y >= f.height || !BraggPanelHolds(pn, x, y)) continue;
const int32_t v = img[y * f.width + x];
if (!valid_px(v)) continue;
if (f.exclude && f.use_owner && !BraggOwnedBy(owner[y * f.width + x], (int) i)) continue;
@@ -109,7 +109,7 @@ struct BraggIntegrationEngineMetal::Device {
id<MTLBuffer> rad_sum = nil, rad_cnt = nil; // the radial background curve, as the clip kernel adds it up
// Per reflection, grown with the frames.
size_t capacity = 0;
id<MTLBuffer> xy = nil, level = nil, sums = nil, clips = nil, thr = nil, clip_out = nil;
id<MTLBuffer> xy = nil, panels = nil, level = nil, sums = nil, clips = nil, thr = nil, clip_out = nil;
id<MTLBuffer> fit_setups = nil, fit_out = nil;
// Pass B's Gaussians, grown with the frames, and the learned profiles.
size_t cells_capacity = 0, profiles_capacity = 0;
@@ -168,7 +168,7 @@ std::vector<Reflection> BraggIntegrationEngineMetal::Run(const ImagePreprocessor
counts.predicted += npredicted;
const bool use_owner = overlap != OverlapMode::Off;
if (dev->unmark != nil) { // it reads xy, which is overwritten below
if (dev->unmark != nil) { // it reads xy and the panels, which are overwritten below
id<MTLCommandBuffer> unmark = dev->unmark;
dev->unmark = nil;
dev->clear = false; // unless it completed
@@ -188,6 +188,7 @@ std::vector<Reflection> BraggIntegrationEngineMetal::Run(const ImagePreprocessor
if (dev->capacity < npredicted) {
const size_t n = npredicted + npredicted / 2;
dev->xy = buffer(n * 2 * sizeof(float));
dev->panels = buffer(n * sizeof(BraggPanel));
dev->level = buffer(n);
dev->sums = buffer(n * sizeof(BraggBoxSums));
dev->clips = buffer(n);
@@ -200,6 +201,8 @@ std::vector<Reflection> BraggIntegrationEngineMetal::Run(const ImagePreprocessor
auto *xy = static_cast<float *>(dev->xy.contents);
auto *level = static_cast<uint8_t *>(dev->level.contents);
const std::vector<BraggPanel> panels = Panels(predicted, npredicted);
std::copy(panels.begin(), panels.end(), static_cast<BraggPanel *>(dev->panels.contents));
for (size_t i = 0; i < npredicted; ++i) {
xy[2 * i] = predicted[i].predicted_x;
xy[2 * i + 1] = predicted[i].predicted_y;
@@ -217,7 +220,10 @@ std::vector<Reflection> BraggIntegrationEngineMetal::Run(const ImagePreprocessor
f.inv_claim = inv_claim;
f.use_owner = use_owner;
f.exclude = overlap == OverlapMode::Exclude && mode != IntegratorMode::BoxSum;
f.n_rad = bkg_radial ? a.n_rad : 0;
// The curve is added up on the GPU only where none was handed over (RadialBackgroundFromRings):
// StartPassA sizes its sums for that case alone. The clip does not follow a handed-over curve here.
const bool accumulate_radial = bkg_radial && radial_curve.empty();
f.n_rad = accumulate_radial ? a.n_rad : 0;
f.static_mask_words = static_cast<uint32_t>(static_mask.size());
f.n = static_cast<uint32_t>(npredicted);
@@ -243,6 +249,7 @@ std::vector<Reflection> BraggIntegrationEngineMetal::Run(const ImagePreprocessor
[enc setBytes:&stencil length:sizeof(stencil) atIndex:3];
[enc setBytes:&f length:sizeof(f) atIndex:4];
[enc setBytes:&want length:sizeof(want) atIndex:5];
[enc setBuffer:dev->panels offset:0 atIndex:6];
[enc dispatchThreads:grid threadsPerThreadgroup:group];
}
if (use_owner) {
@@ -251,6 +258,7 @@ std::vector<Reflection> BraggIntegrationEngineMetal::Run(const ImagePreprocessor
[enc setBuffer:dev->owner offset:0 atIndex:1];
[enc setBytes:&f length:sizeof(f) atIndex:2];
[enc setBytes:&claim_not_release length:sizeof(claim_not_release) atIndex:3];
[enc setBuffer:dev->panels offset:0 atIndex:4];
[enc dispatchThreads:grid threadsPerThreadgroup:group];
}
[enc setComputePipelineState:k.box];
@@ -262,6 +270,7 @@ std::vector<Reflection> BraggIntegrationEngineMetal::Run(const ImagePreprocessor
[enc setBytes:&stencil length:sizeof(stencil) atIndex:5];
[enc setBytes:&f length:sizeof(f) atIndex:6];
[enc setBuffer:dev->sums offset:0 atIndex:7];
[enc setBuffer:dev->panels offset:0 atIndex:8];
[enc dispatchThreads:grid threadsPerThreadgroup:group];
[enc endEncoding];
Wait(cb);
@@ -279,12 +288,12 @@ std::vector<Reflection> BraggIntegrationEngineMetal::Run(const ImagePreprocessor
}
}
if (any_clip) {
if (bkg_radial && dev->rad_sum == nil) {
if (accumulate_radial && dev->rad_sum == nil) {
dev->rad_sum = buffer(a.n_rad * 2 * sizeof(uint32_t));
dev->rad_cnt = buffer(a.n_rad * sizeof(int32_t));
}
cb = [dev->queue commandBuffer];
if (bkg_radial) {
if (accumulate_radial) {
blit = [cb blitCommandEncoder];
[blit fillBuffer:dev->rad_sum range:NSMakeRange(0, a.n_rad * 2 * sizeof(uint32_t)) value:0];
[blit fillBuffer:dev->rad_cnt range:NSMakeRange(0, a.n_rad * sizeof(int32_t)) value:0];
@@ -300,12 +309,13 @@ std::vector<Reflection> BraggIntegrationEngineMetal::Run(const ImagePreprocessor
[enc setBuffer:dev->clips offset:0 atIndex:5];
[enc setBuffer:dev->thr offset:0 atIndex:6];
[enc setBuffer:dev->clip_out offset:0 atIndex:7];
[enc setBuffer:(bkg_radial ? dev->rad_sum : dev->clips) offset:0 atIndex:8]; // not written without the curve
[enc setBuffer:(bkg_radial ? dev->rad_cnt : dev->clips) offset:0 atIndex:9];
[enc setBuffer:(accumulate_radial ? dev->rad_sum : dev->clips) offset:0 atIndex:8]; // not written without the curve
[enc setBuffer:(accumulate_radial ? dev->rad_cnt : dev->clips) offset:0 atIndex:9];
[enc setBuffer:dev->panels offset:0 atIndex:10];
[enc dispatchThreads:grid threadsPerThreadgroup:group];
[enc endEncoding];
Wait(cb);
if (bkg_radial) {
if (accumulate_radial) {
const auto *w = static_cast<const uint32_t *>(dev->rad_sum.contents);
const auto *c = static_cast<const int32_t *>(dev->rad_cnt.contents);
for (int b = 0; b < a.n_rad; ++b) {
@@ -322,12 +332,13 @@ std::vector<Reflection> BraggIntegrationEngineMetal::Run(const ImagePreprocessor
std::vector<int32_t> no_trim; // the trimmed mean is the CPU engine's alone (Available)
for (size_t i = 0; i < npredicted; ++i) {
const Reflection &r = predicted[i];
FinishPassA(a, i, r, MakeBraggStencil(r.predicted_x, r.predicted_y, stencil), sums[i],
FinishPassA(a, i, r, MakeBraggStencil(panels[i], stencil), sums[i],
clips[i] ? clip_out[i] : BraggClipSums{}, no_trim);
}
const FlatOwnerMap owner_map{use_owner ? static_cast<const uint32_t *>(dev->owner.contents) : nullptr, xpixel};
dev->img = img;
auto ret = ProfilePasses(BufferSampler{image.data()}, owner_map, predicted, npredicted, a, image_number);
auto ret = ProfilePasses(BufferSampler{image.data()}, owner_map, predicted, npredicted, panels, a,
image_number);
dev->img = nil;
// --- Unmark this frame's regions and give back its claims, while the CPU goes on ---
@@ -341,6 +352,7 @@ std::vector<Reflection> BraggIntegrationEngineMetal::Run(const ImagePreprocessor
[enc setBytes:&stencil length:sizeof(stencil) atIndex:3];
[enc setBytes:&f length:sizeof(f) atIndex:4];
[enc setBytes:&unmark length:sizeof(unmark) atIndex:5];
[enc setBuffer:dev->panels offset:0 atIndex:6];
[enc dispatchThreads:grid threadsPerThreadgroup:group];
if (use_owner) {
const uint32_t release = 1;
@@ -349,6 +361,7 @@ std::vector<Reflection> BraggIntegrationEngineMetal::Run(const ImagePreprocessor
[enc setBuffer:dev->owner offset:0 atIndex:1];
[enc setBytes:&f length:sizeof(f) atIndex:2];
[enc setBytes:&release length:sizeof(release) atIndex:3];
[enc setBuffer:dev->panels offset:0 atIndex:4];
[enc dispatchThreads:grid threadsPerThreadgroup:group];
}
[enc endEncoding];
@@ -395,6 +408,7 @@ bool BraggIntegrationEngineMetal::FitOnDevice(const std::vector<BraggFitSetup> &
[enc setBytes:&stencil length:sizeof(stencil) atIndex:5];
[enc setBytes:&f length:sizeof(f) atIndex:6];
[enc setBuffer:dev->fit_out offset:0 atIndex:7];
[enc setBuffer:dev->panels offset:0 atIndex:8];
[enc dispatchThreads:MTLSizeMake(n, 1, 1) threadsPerThreadgroup:MTLSizeMake(64, 1, 1)];
[enc endEncoding];
Wait(cb);
@@ -0,0 +1,18 @@
// SPDX-FileCopyrightText: 2026 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
// SPDX-License-Identifier: GPL-3.0-only
#include "BraggPanel.h"
BraggPanel MakeBraggPanel(const DetectorModules &modules, int64_t panel, int64_t width, int64_t height,
float x, float y) {
if (modules.empty())
return {x, y, 1.0f, 0.0f, 0.0f, 1.0f, 0, 0, static_cast<int32_t>(width - 1), static_cast<int32_t>(height - 1)};
if (panel < 0)
return {x, y, 1.0f, 0.0f, 0.0f, 1.0f, 0, 0, -1, -1};
const DetectorModule &m = modules[panel];
const auto [px, py] = m.ImageToPlane(x, y);
return {static_cast<float>(px), static_cast<float>(py),
static_cast<float>(m.fx), static_cast<float>(m.fy), static_cast<float>(m.sx), static_cast<float>(m.sy),
static_cast<int32_t>(m.x0), static_cast<int32_t>(m.y0),
static_cast<int32_t>(m.x0 + m.width - 1), static_cast<int32_t>(m.y0 + m.height - 1)};
}
@@ -0,0 +1,16 @@
// SPDX-FileCopyrightText: 2026 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
// SPDX-License-Identifier: GPL-3.0-only
#pragma once
#include <cstdint>
#include "../../common/DetectorModules.h"
#include "BraggStencil.h"
// Panel `panel` of the module table, for a point at (x, y) of the image (width x height): its plane
// position, the panel's pixel axes on the plane and its box in the image (BraggPanel). With an empty
// table the image is one flat panel, the plane the image itself. Panel -1 of a table that has panels -
// a point in no panel's box - is a panel with no pixels.
BraggPanel MakeBraggPanel(const DetectorModules &modules, int64_t panel, int64_t width, int64_t height,
float x, float y);
@@ -23,6 +23,8 @@ struct BraggBoxSums {
int32_t n_bkg; // ring pixels behind bkg_sum
int32_t n_ring, n_clean; // readable ring pixels, and those no predicted neighbour covers
int32_t overloaded; // a signal-disk pixel was saturated, or unreadable on this frame only
int32_t n_saturated; // signal-disk pixels at the saturation limit
int32_t unused;
};
// The ring pixels at or below a reflection's clip threshold (BraggIntegrationEngineCPU::ClipThreshold).
@@ -40,6 +42,7 @@ struct BraggPassAFrame {
int32_t use_owner; // an overlap treatment is on, so the owner map is built and read
int32_t exclude; // ... and a pixel a neighbour owns leaves the signal disk
int32_t n_rad; // radial background bins; 0 when the curve is not accumulated
int32_t n_curve; // bins of the handed-over curve the clip follows (RadialClipOffset); 0: none
uint32_t static_mask_words; // length of the run's packed pixel mask
uint32_t n; // reflections
};
@@ -171,15 +171,40 @@ BRAGG_STENCIL_HD float BraggStencilMaxGrow_px(float r_max, const BRAGG_STENCIL_T
return g;
}
BRAGG_STENCIL_HD BraggStencil MakeBraggStencil(float px_x, float px_y, const BRAGG_STENCIL_THREAD BraggStencilParams &p) {
// The panel a reflection is on (DetectorModules), as the stencil needs it. Everything radial about a
// reflection - its distance from the beam, the direction the ring is elongated in, the radial
// background - is a property of the detector PLANE, while the pixels it is walked over are the image's.
// A panel's image pixels lie on the plane at a fixed turn (and maybe mirror), so the radial direction is
// taken on the plane and expressed in the panel's own pixel axes; a panel is rigid, so a distance in its
// pixels is the same distance on the plane. A pixel outside the panel's box is not the reflection's
// neighbour on the plane, whatever is stored there: the engines read it as a gap.
// Without panels the image is the plane: the whole image, plane == image, and every expression below
// is the one it always was.
struct BraggPanel {
float plane_x, plane_y; // the reflection on the plane
float fx, fy, sx, sy; // the plane step of one image pixel along x, and of one along y
int32_t x0, y0, x1, y1; // the panel's pixels in the image, inclusive
};
BRAGG_STENCIL_HD bool BraggPanelHolds(const BRAGG_STENCIL_THREAD BraggPanel &pn, int x, int y) {
return x >= pn.x0 && x <= pn.x1 && y >= pn.y0 && y <= pn.y1;
}
BRAGG_STENCIL_HD BraggStencil MakeBraggStencil(const BRAGG_STENCIL_THREAD BraggPanel &pn,
const BRAGG_STENCIL_THREAD BraggStencilParams &p) {
BraggStencil s;
const float rx = px_x - p.beam_x, ry = px_y - p.beam_y;
const float rx = pn.plane_x - p.beam_x, ry = pn.plane_y - p.beam_y;
const float r0 = sqrtf(rx * rx + ry * ry);
s.r0 = r0;
if (r0 > 1e-6f) {
s.ux = rx / r0;
s.uy = ry / r0;
}
// The radial direction in the panel's pixel axes. A pixel step (dx, dy) is f dx + s dy on the plane,
// so its radial part is dx (u.f) + dy (u.s). The identity of a flat detector leaves u as it is.
const float ux = s.ux, uy = s.uy;
s.ux = ux * pn.fx + uy * pn.fy;
s.uy = ux * pn.sx + uy * pn.sy;
s.grow = BraggStencilGrow_px(r0, p);
// A spot wider than the r1 disk can resolve keeps its background ring clear of itself: the ring
@@ -223,6 +248,26 @@ BRAGG_STENCIL_HD BraggStencil MakeBraggStencil(float px_x, float px_y, const BRA
return s;
}
// The cell of a learned profile (ProfileEmpirical) for grid offset (dx, dy) in a panel's pixels, on a grid
// of half-size R. The learned profile is kept in the plane's axes, so that reflections on panels turned
// against each other pool one shape rather than four orientations of it. A grid of whole pixels can only
// follow a quarter turn (and a mirror), so each panel axis is taken as the plane axis nearest to it; the
// small tilt of a placed panel is left out. Without panels, the cell of (dx, dy) itself.
BRAGG_STENCIL_HD int BraggProfileCell(const BRAGG_STENCIL_THREAD BraggPanel &pn, int dx, int dy, int R) {
const bool f_on_x = pn.fx * pn.fx >= pn.fy * pn.fy, s_on_x = pn.sx * pn.sx > pn.sy * pn.sy;
const int f = f_on_x ? (pn.fx > 0.0f ? 1 : -1) : (pn.fy > 0.0f ? 1 : -1);
const int s = s_on_x ? (pn.sx > 0.0f ? 1 : -1) : (pn.sy > 0.0f ? 1 : -1);
const int px = (f_on_x ? f * dx : 0) + (s_on_x ? s * dy : 0);
const int py = (f_on_x ? 0 : f * dx) + (s_on_x ? 0 : s * dy);
return (py + R) * (2 * R + 1) + (px + R);
}
// A reflection at (x, y) of a flat detector, where the image is the plane.
BRAGG_STENCIL_HD BraggStencil MakeBraggStencil(float x, float y, const BRAGG_STENCIL_THREAD BraggStencilParams &p) {
const BraggPanel pn = {x, y, 1.0f, 0.0f, 0.0f, 1.0f, 0, 0, 0, 0};
return MakeBraggStencil(pn, p);
}
// Which of the n_kern radial-background kernels this reflection uses: one per whole pixel of growth.
// Taken from the stencil, so the kernel and the ring it corrects are built from the same radius -
// deriving it from a separately computed r0 let the two engines round differently and pick
@@ -3,6 +3,8 @@ ADD_LIBRARY(JFJochBraggIntegration STATIC
BraggIntegrationEngine.h
BraggIntegrationEngineCPU.cpp
BraggIntegrationEngineCPU.h
BraggPanel.cpp
BraggPanel.h
BraggPassA.h
BraggPassB.h
BraggExp.h
@@ -16,6 +18,10 @@ ADD_LIBRARY(JFJochBraggIntegration STATIC
SpotWidth.h
BackgroundGain.cpp
BackgroundGain.h
BackgroundAperture.cpp
BackgroundAperture.h
RingBackground.cpp
RingBackground.h
)
TARGET_LINK_LIBRARIES(JFJochBraggIntegration JFJochImagePreprocessing JFJochCommon)
@@ -0,0 +1,33 @@
// SPDX-FileCopyrightText: 2026 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
// SPDX-License-Identifier: GPL-3.0-only
#include "RingBackground.h"
#include <algorithm>
#include <cmath>
RingBackground::RingBackground(const std::vector<float> &ring_bkg, int32_t q_bins, float low_q, float dq) {
if (q_bins <= 0 || !(dq > 0.0f))
return;
std::vector<double> sum(q_bins, 0.0);
std::vector<int> cnt(q_bins, 0);
for (size_t i = 0; i < ring_bkg.size(); ++i)
if (std::isfinite(ring_bkg[i])) {
sum[i % q_bins] += ring_bkg[i];
++cnt[i % q_bins];
}
for (int i = 0; i < q_bins; ++i)
if (cnt[i] > 0) {
q.push_back(low_q + (i + 0.5) * dq);
b.push_back(sum[i] / cnt[i]);
}
}
double RingBackground::At(double q_recipA) const {
if (q_recipA <= q.front())
return b.front();
if (q_recipA >= q.back())
return b.back();
const size_t j = std::upper_bound(q.begin(), q.end(), q_recipA) - q.begin() - 1;
return b[j] + (b[j + 1] - b[j]) * (q_recipA - q[j]) / (q[j + 1] - q[j]);
}
@@ -0,0 +1,20 @@
// SPDX-FileCopyrightText: 2026 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
// SPDX-License-Identifier: GPL-3.0-only
#pragma once
#include <cstdint>
#include <vector>
// A frame's background as a function of q, from a peak-excluded background per resolution ring of the
// whole detector (the adaptive spot finder's GetRingBackground): ring i holds low_q + (i + 0.5) * dq,
// entries past the first q_bins are further azimuthal bins and are averaged in, and a ring with no
// value (NAN) is bridged by its neighbours. Between rings the value is interpolated linearly; beyond
// the first and the last ring the end value is held, which has no curvature.
struct RingBackground {
std::vector<double> q, b;
RingBackground(const std::vector<float> &ring_bkg, int32_t q_bins, float low_q, float dq);
[[nodiscard]] bool empty() const { return q.size() < 2; }
[[nodiscard]] double At(double q_recipA) const;
};
@@ -30,16 +30,18 @@ float median_of(std::vector<float> &v) {
} // namespace
FootprintOutcome MeasureFootprintSpot(const FootprintTile &tile, int width, int height, float beam_x, float beam_y,
FootprintOutcome MeasureFootprintSpot(const FootprintTile &tile, const BraggPanel &pn, float beam_x, float beam_y,
float x, float y, FootprintSpot &spot) {
const int half = static_cast<int>(std::ceil(BKG_OUTER * WINDOW_MAX_PX)) + 1;
std::vector<float> ring;
const float rx = x - beam_x, ry = y - beam_y;
// The distance from the beam on the plane, and the radial direction in the panel's pixel axes.
const float rx = pn.plane_x - beam_x, ry = pn.plane_y - beam_y;
const float r = std::sqrt(rx * rx + ry * ry);
if (!(r > 1.0f)) return FootprintOutcome::LeftOut;
const float ux = rx / r, uy = ry / r;
const float ux = rx / r * pn.fx + ry / r * pn.fy, uy = rx / r * pn.sx + ry / r * pn.sy;
const int ix = static_cast<int>(std::lround(x)), iy = static_cast<int>(std::lround(y));
if (ix - half < 0 || iy - half < 0 || ix + half >= width || iy + half >= height) return FootprintOutcome::LeftOut;
if (ix - half < pn.x0 || iy - half < pn.y0 || ix + half > pn.x1 || iy + half > pn.y1)
return FootprintOutcome::LeftOut;
// Start from a compact spot at the prediction; each round re-centres on the signal and takes
// the window to three of the widths just measured.
@@ -51,7 +53,7 @@ FootprintOutcome MeasureFootprintSpot(const FootprintTile &tile, int width, int
const float reach = BKG_OUTER * std::max(wr, wt);
const int x0 = static_cast<int>(std::floor(cx - reach)), x1 = static_cast<int>(std::ceil(cx + reach));
const int y0 = static_cast<int>(std::floor(cy - reach)), y1 = static_cast<int>(std::ceil(cy + reach));
if (x0 < 0 || y0 < 0 || x1 >= width || y1 >= height) return FootprintOutcome::LeftOut;
if (x0 < pn.x0 || y0 < pn.y0 || x1 > pn.x1 || y1 > pn.y1) return FootprintOutcome::LeftOut;
// The re-centring is not bounded, so the window can walk off a tile the frame still holds.
if (x0 < tile.x0 || y0 < tile.y0 || x1 >= tile.x0 + tile.w || y1 >= tile.y0 + tile.h)
return FootprintOutcome::OffTile;
@@ -104,7 +106,8 @@ void MeasureFootprintSpots(const int32_t *img, int width, int height, float beam
const FootprintTile frame{img, 0, 0, width, height};
for (size_t s = 0; s < x.size(); ++s) {
FootprintSpot spot;
if (MeasureFootprintSpot(frame, width, height, beam_x, beam_y, x[s], y[s], spot) == FootprintOutcome::Measured)
const BraggPanel pn = {x[s], y[s], 1.0f, 0.0f, 0.0f, 1.0f, 0, 0, width - 1, height - 1};
if (MeasureFootprintSpot(frame, pn, beam_x, beam_y, x[s], y[s], spot) == FootprintOutcome::Measured)
out.push_back(spot);
}
}
@@ -42,6 +42,7 @@
#include "../../common/BraggIntegrationSettings.h"
#include "../../common/Reflection.h"
#include "../../common/SpotToSave.h"
#include "BraggStencil.h"
// One spot's measured widths, and its distance from the beam centre [px].
struct FootprintSpot {
@@ -51,7 +52,7 @@ struct FootprintSpot {
};
// Measure the spots at the given (sub-pixel) positions on one preprocessed frame (INT32_MIN masked,
// INT32_MAX saturated). A spot whose window holds an unreadable pixel, or no signal above its
// INT32_MAX saturated) of a flat detector. A spot whose window holds an unreadable pixel, or no signal above its
// background, is left out. Results are appended in the order of the positions.
void MeasureFootprintSpots(const int32_t *img, int width, int height, float beam_x, float beam_y,
const std::vector<float> &x, const std::vector<float> &y,
@@ -65,10 +66,11 @@ struct FootprintTile {
};
enum class FootprintOutcome { Measured, LeftOut, OffTile };
// One spot of MeasureFootprintSpots, reading the frame (width x height) through `tile`. OffTile: the
// window walked off the tile while still on the frame, so the spot has to be measured again, from
// the start, on a tile that holds more of the frame - the answer is then the one the whole frame gives.
FootprintOutcome MeasureFootprintSpot(const FootprintTile &tile, int width, int height, float beam_x, float beam_y,
// One spot at (x, y) of the image, on panel `pn` (BraggPanel: its plane position, the panel's pixel axes
// and its box), reading the frame through `tile`. The window stays on the panel; OffTile: it walked off
// the tile while still on the panel, so the spot has to be measured again, from the start, on a tile
// that holds more of the frame - the answer is then the one the whole frame gives.
FootprintOutcome MeasureFootprintSpot(const FootprintTile &tile, const BraggPanel &pn, float beam_x, float beam_y,
float x, float y, FootprintSpot &spot);
// Tabulate the spots: the median widths in bins of distance from the beam centre out to r_max. A bin
+32 -19
View File
@@ -14,6 +14,7 @@
#include "../../common/JFJochMath.h"
#include "../SensorAbsorption.h"
#include "BraggPanel.h"
using namespace spot_width;
@@ -109,7 +110,8 @@ constexpr int R_MOMENT = 9;
// every radius of the disk - an extra second moment that does not cancel between the two directions
// once they are weighted by the obliquity.
SpotShape shape_of(const int32_t *centre_px, int stride, int cx, int cy, double mx, double my,
const std::vector<int32_t> &ring, const DiffractionGeometry &geometry) {
const std::vector<int32_t> &ring, const DiffractionGeometry &geometry,
const DetectorModules &modules, int64_t panel, const BraggPanel &pn) {
SpotShape shape;
double sum = 0.0;
for (const int32_t v : ring) sum += v;
@@ -157,8 +159,10 @@ SpotShape shape_of(const int32_t *centre_px, int stride, int cx, int cy, double
}
if (!(flux > 0.0)) return shape;
// Where one radian of 2theta, and of the angle across the scattering plane, moves the spot.
const float x = static_cast<float>(cx + mx), y = static_cast<float>(cy + my);
// Where one radian of 2theta, and of the angle across the scattering plane, moves the spot - on
// the plane, where the geometry is.
const auto [plane_x, plane_y] = modules.ImageToPlane(panel, cx + mx, cy + my);
const float x = static_cast<float>(plane_x), y = static_cast<float>(plane_y);
const Coord s0(0, 0, 1);
const Coord s1 = geometry.LabCoord(x, y).Normalize();
const float two_theta = std::acos(std::clamp(s1 * s0, -1.0f, 1.0f));
@@ -198,8 +202,11 @@ SpotShape shape_of(const int32_t *centre_px, int stride, int cx, int cy, double
shape.two_theta = two_theta;
shape.jr = static_cast<float>(jr);
shape.jt = static_cast<float>(jt);
shape.m_rad = static_cast<float>(ux * ux * sxx + 2.0 * ux * uy * sxy + uy * uy * syy);
shape.m_tan = static_cast<float>(vx * vx * sxx + 2.0 * vx * vy * sxy + vy * vy * syy);
// The moments were taken in the panel's pixel axes, so the two directions are read there.
const double iux = ux * pn.fx + uy * pn.fy, iuy = ux * pn.sx + uy * pn.sy;
const double ivx = vx * pn.fx + vy * pn.fy, ivy = vx * pn.sx + vy * pn.sy;
shape.m_rad = static_cast<float>(iux * iux * sxx + 2.0 * iux * iuy * sxy + iuy * iuy * syy);
shape.m_tan = static_cast<float>(ivx * ivx * sxx + 2.0 * ivx * ivy * sxy + ivy * ivy * syy);
shape.cos_psi = cos_psi;
shape.par_u = static_cast<float>(par_u);
shape.par_v = static_cast<float>(par_v);
@@ -219,7 +226,7 @@ double median_of(std::vector<T> &v) {
} // namespace
void MeasureSpotFluxCurves(const ImagePreprocessorBuffer &image, int width, int height,
const DiffractionGeometry &geometry,
const DiffractionGeometry &geometry, const DetectorModules &modules,
const std::vector<DiffractionSpot> &spots,
std::vector<FluxCurve> &out) {
const int32_t *pixels = image.data();
@@ -228,11 +235,11 @@ void MeasureSpotFluxCurves(const ImagePreprocessorBuffer &image, int width, int
const Coord c = spots[i].RawCoord();
return pixels + static_cast<size_t>(std::lround(c.y)) * width + std::lround(c.x);
};
MeasureSpotFluxCurves(centre_px, width, width, height, geometry, spots, out);
MeasureSpotFluxCurves(centre_px, width, width, height, geometry, modules, spots, out);
}
void MeasureSpotFluxCurves(const std::function<const int32_t *(size_t)> &centre_px, int stride, int width, int height,
const DiffractionGeometry &geometry,
const DiffractionGeometry &geometry, const DetectorModules &modules,
const std::vector<DiffractionSpot> &spots,
std::vector<FluxCurve> &out) {
if (spots.empty()) return;
@@ -284,23 +291,26 @@ void MeasureSpotFluxCurves(const std::function<const int32_t *(size_t)> &centre_
return true;
};
// Candidates that pass the geometric gates, by band, strongest first.
struct Candidate { size_t index; int64_t count; float d_A; };
// Candidates that pass the geometric gates, by band, strongest first. The aperture has to lie on the
// spot's own panel; distances from the beam and the resolution are taken on the plane.
struct Candidate { size_t index; int64_t count; float d_A; int64_t panel; BraggPanel pn; };
std::array<std::vector<Candidate>, N_BAND> candidates;
constexpr double MIN_BEAM_DISTANCE_PX2 = static_cast<double>(MIN_BEAM_DISTANCE_PX)
* MIN_BEAM_DISTANCE_PX;
for (size_t i = 0; i < spots.size(); i++) {
const Coord &c = centre[i];
const int cx = static_cast<int>(std::lround(c.x)), cy = static_cast<int>(std::lround(c.y));
if (cx < R_BKG_OUT || cy < R_BKG_OUT || cx >= width - R_BKG_OUT || cy >= height - R_BKG_OUT)
const int64_t panel = modules.ModuleOfImagePixel(c.x, c.y);
const BraggPanel pn = MakeBraggPanel(modules, panel, width, height, c.x, c.y);
if (cx - R_BKG_OUT < pn.x0 || cy - R_BKG_OUT < pn.y0 || cx + R_BKG_OUT > pn.x1 || cy + R_BKG_OUT > pn.y1)
continue;
const double bx = c.x - beam_x, by = c.y - beam_y;
const double bx = pn.plane_x - beam_x, by = pn.plane_y - beam_y;
if (bx * bx + by * by < MIN_BEAM_DISTANCE_PX2) continue;
const float d_A = geometry.PxlToRes(c.x, c.y);
const float d_A = geometry.PxlToRes(pn.plane_x, pn.plane_y);
const int band = band_of(d_A);
if (band < 0) continue;
if (!isolated(i)) continue;
candidates[band].push_back({i, spots[i].Count(), d_A});
candidates[band].push_back({i, spots[i].Count(), d_A, panel, pn});
}
// The ring is gathered as the counts it is - the median of an int list is the same number, and
@@ -390,14 +400,15 @@ void MeasureSpotFluxCurves(const std::function<const int32_t *(size_t)> &centre_
if (!(curve.c[R_NORM - 1] > 0.0f) || !(curve.c[R_MAX - 1] > 0.0f)) continue;
const float norm = curve.c[R_NORM - 1];
for (float &v : curve.c) v /= norm;
curve.shape = shape_of(centre, stride, cx, cy, mx, my, ring, geometry);
curve.shape = shape_of(centre, stride, cx, cy, mx, my, ring, geometry, modules, cand[k].panel, cand[k].pn);
out.push_back(curve);
}
}
}
SpotTileMisses MeasureSpotsOnTiles(ImagePreprocessorBuffer &image, int width, int height,
const DiffractionGeometry &geometry, const std::vector<DiffractionSpot> &spots,
const DiffractionGeometry &geometry, const DetectorModules &modules,
const std::vector<DiffractionSpot> &spots,
std::vector<FluxCurve> &curves, std::vector<FootprintSpot> &footprint,
int half, int footprint_half) {
SpotTileMisses misses;
@@ -417,7 +428,7 @@ SpotTileMisses MeasureSpotsOnTiles(ImagePreprocessorBuffer &image, int width, in
MeasureSpotFluxCurves([&](size_t s) {
return tiled ? tiles + s * square(half) + static_cast<size_t>(half) * (side + 1)
: whole + static_cast<size_t>(ty[s]) * width + tx[s];
}, tiled ? side : width, width, height, geometry, spots, curves);
}, tiled ? side : width, width, height, geometry, modules, spots, curves);
const float beam_x = geometry.GetBeamX_pxl(), beam_y = geometry.GetBeamY_pxl();
const auto tile_of = [&](const int32_t *t, size_t k, size_t s, int h) {
@@ -425,11 +436,13 @@ SpotTileMisses MeasureSpotsOnTiles(ImagePreprocessorBuffer &image, int width, in
};
std::vector<FootprintSpot> measured(spots.size());
std::vector<FootprintOutcome> outcome(spots.size());
std::vector<BraggPanel> panel(spots.size());
std::vector<size_t> off_tile;
for (size_t s = 0; s < spots.size(); s++) {
const Coord c = spots[s].RawCoord();
panel[s] = MakeBraggPanel(modules, modules.ModuleOfImagePixel(c.x, c.y), width, height, c.x, c.y);
outcome[s] = MeasureFootprintSpot(tiled ? tile_of(tiles, s, s, half) : FootprintTile{whole, 0, 0, width, height},
width, height, beam_x, beam_y, c.x, c.y, measured[s]);
panel[s], beam_x, beam_y, c.x, c.y, measured[s]);
if (outcome[s] == FootprintOutcome::OffTile)
off_tile.push_back(s);
}
@@ -453,7 +466,7 @@ SpotTileMisses MeasureSpotsOnTiles(ImagePreprocessorBuffer &image, int width, in
const size_t s = off_tile[k];
const Coord c = spots[s].RawCoord();
outcome[s] = MeasureFootprintSpot(larger ? tile_of(again, k, s, h) : FootprintTile{whole, 0, 0, width, height},
width, height, beam_x, beam_y, c.x, c.y, measured[s]);
panel[s], beam_x, beam_y, c.x, c.y, measured[s]);
if (outcome[s] == FootprintOutcome::OffTile)
still.push_back(s);
}
+7 -4
View File
@@ -30,6 +30,7 @@
#include <optional>
#include <vector>
#include "../../common/DetectorModules.h"
#include "../../common/DiffractionGeometry.h"
#include "../../common/DiffractionSpot.h"
#include "../image_preprocessing/ImagePreprocessorBuffer.h"
@@ -186,9 +187,10 @@ struct BandwidthEstimate {
// Every isolated, strong, fully readable spot of one image, as a normalised encircled-flux curve
// with its shape, appended to `out`. Called on one worker's own vector, so the pool is independent of the order the
// workers finish in.
// workers finish in. The spots are in the image; `modules` places its panels on the plane the geometry
// describes (empty: the image is the plane), and a spot's aperture has to lie on its own panel.
void MeasureSpotFluxCurves(const ImagePreprocessorBuffer &image, int width, int height,
const DiffractionGeometry &geometry,
const DiffractionGeometry &geometry, const DetectorModules &modules,
const std::vector<DiffractionSpot> &spots,
std::vector<spot_width::FluxCurve> &out);
@@ -196,7 +198,7 @@ void MeasureSpotFluxCurves(const ImagePreprocessorBuffer &image, int width, int
// rows `stride` apart: R_BKG_OUT pixels of them every way that the image itself has. The frame is
// width x height.
void MeasureSpotFluxCurves(const std::function<const int32_t *(size_t)> &centre_px, int stride, int width, int height,
const DiffractionGeometry &geometry,
const DiffractionGeometry &geometry, const DetectorModules &modules,
const std::vector<DiffractionSpot> &spots,
std::vector<spot_width::FluxCurve> &out);
@@ -219,6 +221,7 @@ struct SpotTileMisses {
// back to the host. The answers are the whole frame's to the bit: each measurement reads the same
// pixels in the same order. The whole frame is read where the squares would be more pixels than it.
SpotTileMisses MeasureSpotsOnTiles(ImagePreprocessorBuffer &image, int width, int height,
const DiffractionGeometry &geometry, const std::vector<DiffractionSpot> &spots,
const DiffractionGeometry &geometry, const DetectorModules &modules,
const std::vector<DiffractionSpot> &spots,
std::vector<spot_width::FluxCurve> &curves, std::vector<FootprintSpot> &footprint,
int half = SPOT_TILE_HALF, int footprint_half = FOOTPRINT_TILE_HALF);
@@ -71,8 +71,11 @@ int BraggPrediction::Calc(const DiffractionExperiment &experiment, const Crystal
const BraggPredictionSettings &settings) {
const auto geom = experiment.GetDiffractionGeometry();
const auto det_width_pxl = static_cast<float>(experiment.GetXPixelsNum());
const auto det_height_pxl = static_cast<float>(experiment.GetYPixelsNum());
// The plane the panels span (without panels, the image): a quick reject, a reflection in a gap
// between panels is dropped when it is integrated.
const PlaneBox bounds = experiment.GetModules().PlaneBounds(experiment.GetXPixelsNum(), experiment.GetYPixelsNum());
const auto det_x0 = static_cast<float>(bounds.x0), det_x1 = static_cast<float>(bounds.x1);
const auto det_y0 = static_cast<float>(bounds.y0), det_y1 = static_cast<float>(bounds.y1);
const float one_over_dmax = 1.0f / settings.high_res_A;
const float one_over_dmax_sq = one_over_dmax * one_over_dmax;
@@ -192,7 +195,7 @@ int BraggPrediction::Calc(const DiffractionExperiment &experiment, const Crystal
float x = beam_x + F * S_rot_x / S_rot_z;
float y = beam_y + F * S_rot_y / S_rot_z;
if ((x < 0) || (x >= det_width_pxl) || (y < 0) || (y >= det_height_pxl))
if ((x < det_x0) || (x >= det_x1) || (y < det_y0) || (y >= det_y1))
continue;
// Sensor quantum efficiency at this reflection's angle of incidence on the
@@ -122,7 +122,7 @@ namespace {
float coeff = C.coeff_const / Srz;
float x = C.beam_x + Srx * coeff;
float y = C.beam_y + Sry * coeff;
if (x < 0.0f || x >= C.det_width_pxl || y < 0.0f || y >= C.det_height_pxl) return false;
if (x < C.det_x0 || x >= C.det_x1 || y < C.det_y0 || y >= C.det_y1) return false;
// Sensor quantum efficiency and the air flight path at this reflection's angle of incidence
// on the detector. Sr is the diffracted direction in the detector's own frame, so Srz over
@@ -189,8 +189,11 @@ namespace {
float bandwidth_sigma) {
KernelConsts kc{};
auto geom = experiment.GetDiffractionGeometry();
kc.det_width_pxl = static_cast<float>(experiment.GetXPixelsNum());
kc.det_height_pxl = static_cast<float>(experiment.GetYPixelsNum());
const PlaneBox bounds = experiment.GetModules().PlaneBounds(experiment.GetXPixelsNum(), experiment.GetYPixelsNum());
kc.det_x0 = static_cast<float>(bounds.x0);
kc.det_y0 = static_cast<float>(bounds.y0);
kc.det_x1 = static_cast<float>(bounds.x1);
kc.det_y1 = static_cast<float>(bounds.y1);
kc.beam_x = geom.GetBeamX_pxl();
kc.beam_y = geom.GetBeamY_pxl();
kc.coeff_const = geom.GetDetectorDistance_mm() / geom.GetPixelSize_mm();
@@ -10,8 +10,7 @@
#include "../indexing/CUDAMemHelpers.h"
struct KernelConsts {
float det_width_pxl;
float det_height_pxl;
float det_x0, det_y0, det_x1, det_y1; // the plane the panels span (DetectorModules::PlaneBounds)
float beam_x;
float beam_y;
float coeff_const;
@@ -16,8 +16,11 @@ int BraggPredictionRot::Calc(const DiffractionExperiment &experiment, const Crys
const BraggPredictionSettings &settings) {
const auto geom = experiment.GetDiffractionGeometry();
const auto det_width_pxl = static_cast<float>(experiment.GetXPixelsNum());
const auto det_height_pxl = static_cast<float>(experiment.GetYPixelsNum());
// The plane the panels span (without panels, the image): a quick reject, a reflection in a gap
// between panels is dropped when it is integrated.
const PlaneBox bounds = experiment.GetModules().PlaneBounds(experiment.GetXPixelsNum(), experiment.GetYPixelsNum());
const auto det_x0 = static_cast<float>(bounds.x0), det_x1 = static_cast<float>(bounds.x1);
const auto det_y0 = static_cast<float>(bounds.y0), det_y1 = static_cast<float>(bounds.y1);
const float one_over_dmax = 1.0f / settings.high_res_A;
const float one_over_dmax_sq = one_over_dmax * one_over_dmax;
@@ -238,7 +241,7 @@ int BraggPredictionRot::Calc(const DiffractionExperiment &experiment, const Crys
float x = beam_x + F * S_rot_x / S_rot_z;
float y = beam_y + F * S_rot_y / S_rot_z;
if ((x < 0) || (x >= det_width_pxl) || (y < 0) || (y >= det_height_pxl))
if ((x < det_x0) || (x >= det_x1) || (y < det_y0) || (y >= det_y1))
continue;
float dist_ewald_sphere = std::fabs(S.Length() - one_over_wavelength);
@@ -186,7 +186,7 @@ namespace {
float x = C.beam_x + Srx * coeff;
float y = C.beam_y + Sry * coeff;
if (x < 0.0f || x >= C.det_width_pxl || y < 0.0f || y >= C.det_height_pxl)
if (x < C.det_x0 || x >= C.det_x1 || y < C.det_y0 || y >= C.det_y1)
continue;
float dist_ewald = fabsf(sqrtf(Sx * Sx + Sy * Sy + Sz * Sz) - C.one_over_wavelength);
@@ -350,8 +350,11 @@ namespace {
KernelConstsRot kc{};
auto geom = experiment.GetDiffractionGeometry();
kc.det_width_pxl = static_cast<float>(experiment.GetXPixelsNum());
kc.det_height_pxl = static_cast<float>(experiment.GetYPixelsNum());
const PlaneBox bounds = experiment.GetModules().PlaneBounds(experiment.GetXPixelsNum(), experiment.GetYPixelsNum());
kc.det_x0 = static_cast<float>(bounds.x0);
kc.det_y0 = static_cast<float>(bounds.y0);
kc.det_x1 = static_cast<float>(bounds.x1);
kc.det_y1 = static_cast<float>(bounds.y1);
kc.beam_x = geom.GetBeamX_pxl();
kc.beam_y = geom.GetBeamY_pxl();
kc.coeff_const = geom.GetDetectorDistance_mm() / geom.GetPixelSize_mm();
@@ -10,8 +10,7 @@
#include "../indexing/CUDAMemHelpers.h"
struct KernelConstsRot {
float det_width_pxl;
float det_height_pxl;
float det_x0, det_y0, det_x1, det_y1; // the plane the panels span (DetectorModules::PlaneBounds)
float beam_x;
float beam_y;
float coeff_const;
@@ -40,6 +40,20 @@ struct BackgroundBand {
double tan_lo, tan_hi; // the band in tan(2theta), widened for the quick rejection
};
// A panel of the image and its place on the plane (DetectorModule), in a form the device can hold.
struct BackgroundPanel {
int x0, y0, width, height;
double ox, oy, fx, fy, sx, sy;
};
// Plane position of image pixel (x, y) of panel p - DetectorModule::ImageToPlane, written here so that the
// host and the device evaluate it the same way.
BACKGROUND_BAND_HD void BackgroundPlanePoint(const BackgroundPanel &p, int x, int y, float &px, float &py) {
const double u = x - p.x0, v = y - p.y0;
px = static_cast<float>(p.ox + u * p.fx + v * p.sx);
py = static_cast<float>(p.oy + u * p.fy + v * p.sy);
}
// atan2(y, x) from IEEE operations alone - add, multiply, divide, square root, all correctly rounded on
// the host and on the device - so that, compiled without contraction (see CMakeLists.txt), the host
// and the device return the same bits. The library atan2f does not: glibc's and CUDA's differ in the
@@ -63,9 +77,9 @@ BACKGROUND_BAND_HD double BackgroundAtan2(double y, double x) {
return y < 0 ? -a : a;
}
// The cell of pixel (x, y) about (beam_x, beam_y), or -1 when it is outside the band; for a pixel in
// it, also the two components of the derivative of its 2theta with respect to the centre.
BACKGROUND_BAND_HD int BackgroundBandCell(const BackgroundBand &b, int x, int y, float beam_x, float beam_y,
// The cell of the pixel at (x, y) on the plane about (beam_x, beam_y), or -1 when it is outside the band;
// for a pixel in it, also the two components of the derivative of its 2theta with respect to the centre.
BACKGROUND_BAND_HD int BackgroundBandCell(const BackgroundBand &b, float x, float y, float beam_x, float beam_y,
float &jac_x, float &jac_y) {
const float *rot = b.rot;
const float u = (x - beam_x) * b.pixel_size;
@@ -19,7 +19,9 @@ void check(cudaError_t err, const char *what) {
// Every pixel's cell (BackgroundBand::CELLS where it is outside the band or unusable), its index,
// and its derivatives.
// A pixel on no panel is outside the band.
__global__ void bin_kernel(BackgroundBand band, int width, size_t npixels, float beam_x, float beam_y,
const BackgroundPanel *__restrict__ panels, int npanels,
const char *__restrict__ usable, int32_t *__restrict__ key,
int32_t *__restrict__ index, float *__restrict__ jac_x,
float *__restrict__ jac_y) {
@@ -29,10 +31,21 @@ __global__ void bin_kernel(BackgroundBand band, int width, size_t npixels, float
int cell = BackgroundBand::CELLS;
float jx = 0.0f, jy = 0.0f;
if (usable[i]) {
const int c = BackgroundBandCell(band, static_cast<int>(i % width), static_cast<int>(i / width),
beam_x, beam_y, jx, jy);
if (c >= 0)
cell = c;
const int x = static_cast<int>(i % width), y = static_cast<int>(i / width);
float px = static_cast<float>(x), py = static_cast<float>(y);
bool on_panel = npanels == 0;
for (int p = 0; p < npanels && !on_panel; p++) {
const BackgroundPanel &m = panels[p];
if (x >= m.x0 && x < m.x0 + m.width && y >= m.y0 && y < m.y0 + m.height) {
BackgroundPlanePoint(m, x, y, px, py);
on_panel = true;
}
}
if (on_panel) {
const int c = BackgroundBandCell(band, px, py, beam_x, beam_y, jx, jy);
if (c >= 0)
cell = c;
}
}
key[i] = cell;
index[i] = static_cast<int32_t>(i);
@@ -112,6 +125,8 @@ struct BeamCenterBackgroundGPU::Impl {
CudaDevicePtr<char> usable;
CudaDevicePtr<float> mean;
CudaDevicePtr<int32_t> row_block;
CudaDevicePtr<BackgroundPanel> panels;
int npanels = 0;
CudaDevicePtr<int32_t> key, sorted_key, index, sorted_index;
CudaDevicePtr<float> jac_x, jac_y;
CudaDevicePtr<int32_t> offset;
@@ -159,8 +174,15 @@ struct BeamCenterBackgroundGPU::Impl {
};
BeamCenterBackgroundGPU::BeamCenterBackgroundGPU(int width, int height, const std::vector<int> &block_row,
const std::vector<BackgroundPanel> &panels,
const char *usable, const float *mean)
: impl(std::make_unique<Impl>(width, height)) {
impl->npanels = static_cast<int>(panels.size());
if (!panels.empty()) {
impl->panels = CudaDevicePtr<BackgroundPanel>(panels.size());
check(cudaMemcpyAsync(impl->panels.get(), panels.data(), panels.size() * sizeof(BackgroundPanel),
cudaMemcpyHostToDevice, impl->stream), "upload");
}
std::vector<int32_t> row_block(height);
for (size_t b = 0; b + 1 < block_row.size(); b++)
for (int y = block_row[b]; y < block_row[b + 1]; y++)
@@ -181,7 +203,8 @@ void BeamCenterBackgroundGPU::Bin(const BackgroundBand &band, float beam_x, floa
std::vector<int32_t> &count) {
Impl &d = *impl;
const auto blocks = static_cast<unsigned>((d.npixels + THREADS - 1) / THREADS);
bin_kernel<<<blocks, THREADS, 0, d.stream>>>(band, d.width, d.npixels, beam_x, beam_y, d.usable,
bin_kernel<<<blocks, THREADS, 0, d.stream>>>(band, d.width, d.npixels, beam_x, beam_y, d.panels.get(),
d.npanels, d.usable,
d.key, d.index, d.jac_x, d.jac_y);
check(cudaGetLastError(), "bin");
// A radix sort is stable, so each cell's pixels come out in pixel order.
@@ -23,8 +23,9 @@ class BeamCenterBackgroundGPU {
std::unique_ptr<Impl> impl;
public:
// block_row: the first row of each of the host's row blocks, and one past the last row at the end.
// panels: where the image's panels are on the plane; empty when the image is the plane.
BeamCenterBackgroundGPU(int width, int height, const std::vector<int> &block_row,
const char *usable, const float *mean);
const std::vector<BackgroundPanel> &panels, const char *usable, const float *mean);
~BeamCenterBackgroundGPU();
// Bin the band about (beam_x, beam_y) and sum each cell: the values, their squares, the two
@@ -12,6 +12,7 @@
#include "BeamCenterFFTCPU.h"
#include "BeamCenterFFTEngine.h"
#include "../../common/AssembleToPlane.h"
#include "../../common/CUDAWrapper.h"
#include <spdlog/spdlog.h>
#ifdef JFJOCH_USE_CUDA
@@ -241,6 +242,20 @@ BeamCenterFFTResult FindBeamCenterFFT(const DiffractionExperiment &experiment,
const std::vector<float> &mean,
const BeamCenterFFTSettings &settings) {
// The pre-scan projection is in converted geometry (ShadowFinder's frame).
return BeamCenterFFTScore(experiment.GetXPixelsNumConv(), experiment.GetYPixelsNumConv(),
mean, settings);
const DetectorModules &modules = experiment.GetModules();
const int64_t width = experiment.GetXPixelsNumConv(), height = experiment.GetYPixelsNumConv();
if (modules.empty())
return BeamCenterFFTScore(width, height, mean, settings);
// Panels: the point symmetry is about the beam on the detector plane, so the projection is scored as
// the plane raster (gaps hold nothing), and the centres come back in plane coordinates.
const PlaneRaster raster = PlaneRasterOf(modules, width, height);
BeamCenterFFTResult result = BeamCenterFFTScore(raster.width, raster.height,
AssembleToPlane(modules, mean, width, height, raster, NAN),
settings);
for (auto &c: result.point) {
c.beam_x_pxl += static_cast<float>(raster.x0);
c.beam_y_pxl += static_cast<float>(raster.y0);
}
return result;
}
@@ -11,6 +11,7 @@
#include "../../common/CompressedImage.h"
#include "../../common/JFJochMath.h"
#include "../../common/ParallelFor.h"
#include "../../common/PanelRows.h"
#ifdef JFJOCH_USE_CUDA
#include "../../common/CUDAWrapper.h"
#include "BeamCenterBackgroundGPU.h"
@@ -181,13 +182,20 @@ FindBeamCenterFromBackground(const DiffractionExperiment &experiment, const Pixe
band.tan_lo = tan_lo;
band.tan_hi = tan_hi;
// The pixels are binned at their place on the plane.
const DetectorModules &modules = experiment.GetModules();
std::vector<BackgroundPanel> panels;
for (const auto &m: modules.Get())
panels.push_back({static_cast<int>(m.x0), static_cast<int>(m.y0), static_cast<int>(m.width),
static_cast<int>(m.height), m.ox, m.oy, m.fx, m.fy, m.sx, m.sy});
#ifndef JFJOCH_USE_CUDA
(void) allow_device;
#else
// With a GPU the two passes over the pixels run there, and only the cells come back.
std::unique_ptr<BeamCenterBackgroundGPU> gpu;
if (allow_device && get_gpu_count() > 0)
gpu = std::make_unique<BeamCenterBackgroundGPU>(W, H, block_row, usable.data(), mean.data());
gpu = std::make_unique<BeamCenterBackgroundGPU>(W, H, block_row, panels, usable.data(), mean.data());
#endif
float step_x = 0.0f, step_y = 0.0f, sigma_x = 0.0f, sigma_y = 0.0f;
@@ -209,25 +217,25 @@ FindBeamCenterFromBackground(const DiffractionExperiment &experiment, const Pixe
int32_t *cells = band_cell.data() + static_cast<size_t>(block_row[b]) * W;
float *values = band_value.data() + static_cast<size_t>(block_row[b]) * W;
size_t n_band = 0;
for (int y = block_row[b]; y < block_row[b + 1]; y++) {
for (int x = 0; x < W; x++) {
const size_t i = static_cast<size_t>(y) * W + x;
if (!usable[i])
continue;
float jac_x, jac_y;
const int cell = BackgroundBandCell(band, x, y, beam_x, beam_y, jac_x, jac_y);
if (cell < 0)
continue;
cells[n_band] = cell;
values[n_band] = mean[i];
n_band++;
b_count[cell]++;
b_sum[cell] += mean[i];
b_sum_sq[cell] += static_cast<double>(mean[i]) * mean[i];
b_jx[cell] += jac_x;
b_jy[cell] += jac_y;
}
}
ForEachPixelInRows(modules, W, block_row[b], block_row[b + 1], [&](int64_t p, size_t i, double px, double py) {
if (!usable[i])
return;
auto x = static_cast<float>(px), y = static_cast<float>(py);
if (p >= 0) // as the device has it
BackgroundPlanePoint(panels[p], static_cast<int>(i % W), static_cast<int>(i / W), x, y);
float jac_x, jac_y;
const int cell = BackgroundBandCell(band, x, y, beam_x, beam_y, jac_x, jac_y);
if (cell < 0)
return;
cells[n_band] = cell;
values[n_band] = mean[i];
n_band++;
b_count[cell]++;
b_sum[cell] += mean[i];
b_sum_sq[cell] += static_cast<double>(mean[i]) * mean[i];
b_jx[cell] += jac_x;
b_jy[cell] += jac_y;
});
band_pixels[b] = n_band;
});
fold(true);
Loaded 100 of 219 files, more files were not shown because too many files have changed in this diff. Show more