Build Packages / Create release (push) Successful in 17s
Build Packages / build:portable:macos-arm64:nocuda (push) Successful in 4m41s
Build Packages / HDF5 consumer tests (DIALS, XDS) (push) Successful in 20m49s
Build Packages / build:portable:windows-x86_64:nocuda (push) Successful in 13m6s
Build Packages / build:portable:windows-x86_64:cuda (push) Successful in 23m44s
Build Packages / build:rugnux:linux-aarch64:cuda (push) Successful in 7m28s
Build Packages / build:portable:linux-x86_64:nocuda (push) Successful in 11m50s
Build Packages / build:portable:linux-x86_64:cuda (push) Successful in 14m9s
Build Packages / build:jfjoch:rocky8:nocuda (push) Successful in 16m25s
Build Packages / build:jfjoch:ubuntu2204:nocuda (push) Successful in 15m42s
Build Packages / build:jfjoch:rocky9:nocuda (push) Successful in 20m50s
Build Packages / build:jfjoch:ubuntu2404:nocuda (push) Successful in 20m36s
Build Packages / build:jfjoch:rocky8:cuda-sls9 (push) Successful in 22m18s
Build Packages / build:jfjoch:rocky9:cuda-sls9 (push) Successful in 23m29s
Build Packages / Generate python client (push) Successful in 30s
Build Packages / Build documentation (push) Successful in 1m10s
Build Packages / build:jfjoch:rocky8:cuda (push) Successful in 21m38s
Build Packages / build:jfjoch:ubuntu2204:cuda (push) Successful in 17m8s
Build Packages / build:jfjoch:rocky9:cuda (push) Successful in 23m10s
Build Packages / build:jfjoch:ubuntu2404:cuda (push) Successful in 19m16s
Build Packages / Unit tests (push) Successful in 2h8m4s
Build Packages / Validation Battery (push) Successful in 40m53s
* 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: 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. Reviewed-on: #88 Co-authored-by: Filip Leonarski <filip.leonarski@psi.ch>
134 lines
4.2 KiB
C++
134 lines
4.2 KiB
C++
// SPDX-FileCopyrightText: 2026 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
#include "RugnuxLiveStatus.h"
|
|
|
|
double RugnuxLiveStatus::Since(std::chrono::steady_clock::time_point t) const {
|
|
return std::chrono::duration<double>(t - start).count();
|
|
}
|
|
|
|
double RugnuxLiveStatus::Now() const {
|
|
return Since(std::chrono::steady_clock::now());
|
|
}
|
|
|
|
void RugnuxLiveStatus::CloseStep() {
|
|
if (!s.steps.empty() && !s.steps.back().duration_s)
|
|
s.steps.back().duration_s = Now() - s.steps.back().started_s;
|
|
}
|
|
|
|
void RugnuxLiveStatus::Start(int64_t images_expected, std::optional<double> expected_collection_s,
|
|
std::chrono::steady_clock::time_point start_received) {
|
|
std::unique_lock ul(m);
|
|
s = RugnuxLiveSnapshot{};
|
|
s.state = RugnuxLiveState::Running;
|
|
s.images_expected = images_expected;
|
|
s.expected_collection_s = expected_collection_s;
|
|
start = start_received;
|
|
last_image.reset();
|
|
}
|
|
|
|
void RugnuxLiveStatus::ImageReceived(std::chrono::steady_clock::time_point received) {
|
|
std::unique_lock ul(m);
|
|
++s.images_received;
|
|
// Several forward threads report, so the images need not come here in the order they arrived.
|
|
const double t = Since(received);
|
|
if (!s.start_to_first_image_s || t < s.start_to_first_image_s.value())
|
|
s.start_to_first_image_s = t;
|
|
if (!last_image || received > last_image.value())
|
|
last_image = received;
|
|
}
|
|
|
|
void RugnuxLiveStatus::Step(const std::string &title) {
|
|
std::unique_lock ul(m);
|
|
CloseStep();
|
|
s.steps.push_back(RugnuxLiveStep{.title = title, .started_s = Now()});
|
|
s.step_progress.reset();
|
|
}
|
|
|
|
void RugnuxLiveStatus::Note(const std::string &text) {
|
|
std::unique_lock ul(m);
|
|
if (s.steps.empty())
|
|
s.steps.push_back(RugnuxLiveStep{.title = "", .started_s = Now()});
|
|
s.steps.back().notes.push_back(text);
|
|
}
|
|
|
|
void RugnuxLiveStatus::Progress(uint64_t done, uint64_t total) {
|
|
std::unique_lock ul(m);
|
|
if (total > 0)
|
|
s.step_progress = static_cast<float>(done) / static_cast<float>(total);
|
|
}
|
|
|
|
void RugnuxLiveStatus::Finish(RugnuxLiveState state, const std::string &message) {
|
|
std::unique_lock ul(m);
|
|
CloseStep();
|
|
s.elapsed_s = Now();
|
|
s.state = state;
|
|
s.message = message;
|
|
s.step_progress.reset();
|
|
}
|
|
|
|
void RugnuxLiveStatus::Result(const std::string &verdict, const std::string &verdict_text,
|
|
const std::vector<std::pair<std::string, std::string>> &summary,
|
|
const std::vector<std::string> &warnings) {
|
|
std::unique_lock ul(m);
|
|
s.verdict = verdict;
|
|
s.verdict_text = verdict_text;
|
|
s.summary = summary;
|
|
s.warnings = warnings;
|
|
}
|
|
|
|
void RugnuxLiveStatus::Latency(double last_image_to_written_s) {
|
|
std::unique_lock ul(m);
|
|
s.last_image_to_written_s = last_image_to_written_s;
|
|
}
|
|
|
|
std::optional<std::chrono::steady_clock::time_point> RugnuxLiveStatus::LastImage() {
|
|
std::unique_lock ul(m);
|
|
if (last_image)
|
|
s.last_image_s = Since(last_image.value());
|
|
return last_image;
|
|
}
|
|
|
|
void RugnuxLiveStatus::Cut(const std::string &reason) {
|
|
std::unique_lock ul(m);
|
|
s.cut = reason;
|
|
s.cut_s = Now();
|
|
}
|
|
|
|
void RugnuxLiveStatus::Probe(const std::string &text) {
|
|
std::unique_lock ul(m);
|
|
s.probe = text;
|
|
s.probe_s = Now();
|
|
}
|
|
|
|
void RugnuxLiveStatus::Warning(const std::string &text) {
|
|
std::unique_lock ul(m);
|
|
s.warnings.push_back(text);
|
|
}
|
|
|
|
void RugnuxLiveStatus::Clear() {
|
|
std::unique_lock ul(m);
|
|
s = RugnuxLiveSnapshot{};
|
|
last_image.reset();
|
|
}
|
|
|
|
RugnuxLiveSnapshot RugnuxLiveStatus::Get() const {
|
|
std::unique_lock ul(m);
|
|
RugnuxLiveSnapshot ret = s;
|
|
if (s.state == RugnuxLiveState::Running)
|
|
ret.elapsed_s = Now();
|
|
|
|
// Held since START, reported since the first image - or, before it has come, since now.
|
|
const double zero = s.start_to_first_image_s.value_or(s.state == RugnuxLiveState::Running ? ret.elapsed_s : 0.0);
|
|
ret.elapsed_s -= zero;
|
|
for (auto &step: ret.steps)
|
|
step.started_s -= zero;
|
|
if (ret.probe_s)
|
|
*ret.probe_s -= zero;
|
|
if (ret.last_image_s)
|
|
*ret.last_image_s -= zero;
|
|
if (ret.cut_s)
|
|
*ret.cut_s -= zero;
|
|
return ret;
|
|
}
|