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>
69 lines
2.9 KiB
C++
69 lines
2.9 KiB
C++
// SPDX-FileCopyrightText: 2026 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
#include "NXmxModules.h"
|
|
|
|
#include <cmath>
|
|
|
|
#include "../common/JFJochException.h"
|
|
|
|
namespace {
|
|
|
|
// A translation dataset as a vector in pixels of the internal frame (x = column, y = row, z = beam).
|
|
Coord ReadTranslation_px(HDF5Object &file, const std::string &path, double pixel_size_m, const RotMatrix &delta) {
|
|
HDF5DataSet ds(file, path);
|
|
std::vector<double> value;
|
|
ds.ReadVector(value);
|
|
const auto vec = ds.ReadAttrVec("vector");
|
|
if (value.empty() || vec.size() != 3)
|
|
throw JFJochException(JFJochExceptionCategory::HDF5, path + ": not a translation");
|
|
double scale = 1.0;
|
|
if (ds.AttrExists("units")) {
|
|
const std::string units = ds.ReadAttrStr("units");
|
|
if (units == "mm")
|
|
scale = 1e-3;
|
|
else if (units == "um" || units == "microns")
|
|
scale = 1e-6;
|
|
}
|
|
const double len_px = value[0] * scale / pixel_size_m;
|
|
// McStas -> internal is a half turn about z; the discrete image orientation is undone after it.
|
|
const Coord mcstas(static_cast<float>(-vec[0]), static_cast<float>(-vec[1]), static_cast<float>(vec[2]));
|
|
return delta.transpose() * (static_cast<float>(len_px) * mcstas);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
DetectorModules ReadNXmxModules(HDF5Object &file, double pixel_size_m, const DetectorOrientation &orientation) {
|
|
const RotMatrix delta = orientation.Matrix();
|
|
std::vector<DetectorModule> out;
|
|
for (size_t n = 0;; n++) {
|
|
const std::string base = "/entry/instrument/detector/module_" + std::to_string(n) + "/";
|
|
if (!file.Exists(base + "data_origin"))
|
|
break;
|
|
const auto origin = file.ReadVector<int64_t>(base + "data_origin");
|
|
const auto size = file.ReadVector<int64_t>(base + "data_size");
|
|
if (origin.size() != 2 || size.size() != 2)
|
|
throw JFJochException(JFJochExceptionCategory::HDF5, base + ": only two-dimensional modules are read");
|
|
const Coord o = ReadTranslation_px(file, base + "module_offset", pixel_size_m, delta);
|
|
const Coord f = ReadTranslation_px(file, base + "fast_pixel_direction", pixel_size_m, delta);
|
|
const Coord s = ReadTranslation_px(file, base + "slow_pixel_direction", pixel_size_m, delta);
|
|
if (std::fabs(o.z) > 1e-3 || std::fabs(f.z) > 1e-6 || std::fabs(s.z) > 1e-6)
|
|
throw JFJochException(JFJochExceptionCategory::HDF5, base + ": a module out of the detector plane is not read");
|
|
DetectorModule m;
|
|
m.y0 = origin[0];
|
|
m.x0 = origin[1];
|
|
m.height = size[0];
|
|
m.width = size[1];
|
|
m.ox = o.x;
|
|
m.oy = o.y;
|
|
m.fx = f.x;
|
|
m.fy = f.y;
|
|
m.sx = s.x;
|
|
m.sy = s.y;
|
|
out.push_back(m);
|
|
}
|
|
if (out.size() < 2)
|
|
return {};
|
|
return DetectorModules(out);
|
|
}
|