Build Packages / Create release (push) Successful in 21s
Build Packages / build:portable:macos-arm64:nocuda (push) Successful in 5m0s
Build Packages / build:portable:linux-x86_64:nocuda (push) Successful in 16m46s
Build Packages / build:rugnux:linux-aarch64:cuda (push) Successful in 11m27s
Build Packages / build:portable:windows-x86_64:nocuda (push) Successful in 21m4s
Build Packages / build:portable:linux-x86_64:cuda (push) Successful in 18m54s
Build Packages / HDF5 consumer tests (DIALS, XDS) (push) Successful in 26m32s
Build Packages / build:portable:windows-x86_64:cuda (push) Successful in 25m50s
Build Packages / build:jfjoch:rocky8:nocuda (push) Successful in 20m11s
Build Packages / build:jfjoch:ubuntu2204:nocuda (push) Successful in 19m1s
Build Packages / build:jfjoch:rocky9:nocuda (push) Successful in 22m53s
Build Packages / build:jfjoch:ubuntu2404:nocuda (push) Successful in 23m43s
Build Packages / Generate python client (push) Successful in 32s
Build Packages / Build documentation (push) Successful in 1m46s
Build Packages / build:jfjoch:rocky8:cuda-sls9 (push) Successful in 28m24s
Build Packages / build:jfjoch:rocky8:cuda (push) Successful in 30m21s
Build Packages / build:jfjoch:rocky9:cuda-sls9 (push) Successful in 32m44s
Build Packages / build:jfjoch:ubuntu2204:cuda (push) Successful in 20m17s
Build Packages / build:jfjoch:rocky9:cuda (push) Successful in 25m4s
Build Packages / build:jfjoch:ubuntu2404:cuda (push) Successful in 21m58s
Build Packages / Unit tests (push) Successful in 1h41m55s
Build Packages / Validation Battery (push) Successful in 32m16s
* 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>
53 lines
2.0 KiB
C++
53 lines
2.0 KiB
C++
// SPDX-FileCopyrightText: 2026 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
#include <catch2/catch_all.hpp>
|
|
#include <cmath>
|
|
#include <random>
|
|
|
|
#include "../image_analysis/image_preprocessing/SaturationCeiling.h"
|
|
|
|
// A bright tail, P(> v) ~ 1/v, as the cores of Bragg peaks give.
|
|
static saturation_ceiling::Histogram Tail(int64_t clip_from, int64_t clip_to) {
|
|
saturation_ceiling::Histogram h{};
|
|
std::mt19937 rng(1);
|
|
std::uniform_real_distribution<double> u(0.0, 1.0);
|
|
for (int i = 0; i < 2000000; i++) {
|
|
auto v = static_cast<int64_t>(std::min(1e9, 100.0 / (1.0 - u(rng)))); // P(> v) ~ 1/v above 100
|
|
if (v >= clip_from) {
|
|
// Clipped at a ceiling of its own, somewhere in [clip_from, clip_to].
|
|
v = clip_from + static_cast<int64_t>(u(rng) * static_cast<double>(clip_to - clip_from));
|
|
}
|
|
saturation_ceiling::Add(h, v);
|
|
}
|
|
return h;
|
|
}
|
|
|
|
TEST_CASE("SaturationCeiling_NoClipping", "[portable]") {
|
|
CHECK(!saturation_ceiling::Ceiling(Tail(INT32_MAX, INT32_MAX)).has_value());
|
|
}
|
|
|
|
TEST_CASE("SaturationCeiling_OneLevel", "[portable]") {
|
|
const auto c = saturation_ceiling::Ceiling(Tail(12000, 12000));
|
|
REQUIRE(c.has_value());
|
|
CHECK(*c <= 12000);
|
|
CHECK(*c > 12000 * 0.98);
|
|
}
|
|
|
|
TEST_CASE("SaturationCeiling_BandPerPixel", "[portable]") {
|
|
// Each pixel stops at its own level - the ADC's limit less that pixel's dark.
|
|
const auto c = saturation_ceiling::Ceiling(Tail(12400, 15600));
|
|
REQUIRE(c.has_value());
|
|
CHECK(*c <= 12400);
|
|
CHECK(*c > 12400 * 0.98);
|
|
}
|
|
|
|
TEST_CASE("SaturationCeiling_MaskedPixelsLeftOut", "[portable]") {
|
|
saturation_ceiling::Histogram h{};
|
|
const std::vector<int32_t> values(1000, 5000);
|
|
saturation_ceiling::Add(h, values, std::vector<uint32_t>(1000, 1));
|
|
CHECK(!saturation_ceiling::Ceiling(h).has_value());
|
|
saturation_ceiling::Add(h, values, {});
|
|
CHECK(saturation_ceiling::Ceiling(h).has_value());
|
|
}
|