Combines the stills reader and module work (stills-readers, stills-modgeom, stills-euxfel) onto rc178 with the owner's decisions for this release: - Inputs are files, never a directory; several files of one format are one dataset (the multi-input CLI of the previous commit), so every reader takes an explicit list: JFJochXFELReader::ReadFiles, ReadCXI, ReadPanelTable and JFJochXTCReader::ReadFiles take std::vector<std::string>; ListFiles and xtc::CollectStreams are gone, CanRead* accept a regular file only. - One HDF5 frame reader (JFJochCrystFELReader -> JFJochXFELReader) parameterised by what the file holds: per-shot groups or a 3D stack, a /metadata panel table (posx/posy/angle, pixel size, nominal camera length, pixel mask: as SACLA writes), a Cheetah CXI single panel (square frame; a tiled slab is refused with a message). At most 8 files open; every file checked against the first. Signed 32-bit decode, per-frame 3D masks, panels at their own coffset (from the EuXFEL work). - Frames stored one chunk each are read the way the NXmx reader reads its images: only the chunk's place is asked of HDF5 under its lock (H5Dget_chunk_info_by_coord), the bytes are read through HDF5ImageSource::RawFile (positional, no lock) and decoded outside it - deflate(+shuffle) by zlib, bitshuffle/LZ4 (and zstd, plain LZ4) by CompressedImage's decoders. Bitshuffle/LZ4 used to go through HDF5's filter under the global lock, one frame at a time. - LCLS-I XTC (Rayonix): wavelength from the beam record, pixel size from the Rayonix model and binning, only --detector-distance needed; damaged/compressed frames skipped, a truncated last event dropped; std::ifstream, no POSIX calls: builds with MSVC. No DIALS .expt support at all. - CrystFEL .geom: module geometry only (panel ranges, fs/ss, corners, pixel size, coffset, data path) and optionally the camera length; everything else is ignored with a note in the log. - --mask-good / --mask-bad <file>:<dataset>: a mask array in another HDF5 file, in the frames' stored layout (what a .geom's mask_file used to give). - Gain measured on the background for panel-table and CXI input that states none (--gain overrides). - Detector modules from explicit geometry only (DetectorModules: the reader's panels, an NXmx file with one NXdetector_module per module, or --module-geometry); never from the image. Spots and predictions are mapped through the modules, the image is not re-assembled. - Module refinement in the stills bundle adjustment (Ceres; per-module shift and in-plane turn, gauge on mean shift/turn/scale and on the two tilt-like patterns when the tilt is refined; adopted only where it predicts held-out frames better). Applied for a foreign multi-panel detector (panel table, .geom panels); for a JUNGFRAU measured and reported only. Written to <prefix>_modules.h5 (NXmx NXdetector_module groups), read back with --module-geometry. - A panel-table file's camera length is nominal: with a reference cell it is refined from the cell. - Broker and writer output unchanged: masters keep the single NXdetector_module group, the start message carries no module list. Tests: [CrystFELGeometry], JFJochXFELReader_*, JFJochXTCReader, [JFJochMultiReader], [CellPopulation], SaturationCeiling_*, [DetectorModules], RefineGlobalGeometry_ModulePlacement, [reindex], Sublattice. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015CeEGgpKdfkCTJb3YNMJcu
227 lines
14 KiB
Markdown
227 lines
14 KiB
Markdown
# Rugnux
|
|
|
|
`rugnux` is the **offline** crystallographic data-analysis tool of Jungfraujoch — the
|
|
data-processing half of the system (see [Naming](NAMING.md) for where the name comes from).
|
|
It takes a stored dataset, runs the full analysis pipeline — spot finding, indexing, geometry
|
|
refinement, Bragg integration, scaling and merging — and writes the merged reflections
|
|
(`.mtz`/`.cif`/`.hkl`), the unmerged MTZ and the results report; the per-image `_process.h5` is
|
|
written only on request (`--write-process-h5`), or as the only output with `--no-merge`. A rotation run
|
|
that finds no lattice still spot-finds every image and writes their per-image analysis there, then exits
|
|
as failed.
|
|
|
|
It runs the *same* analysis code as the online and interactive tools, driven from the command line
|
|
over files.
|
|
|
|
```
|
|
rugnux {<options>} <input.h5> {<input.h5>} [<broker URL>]
|
|
```
|
|
|
|
Run it with no arguments to print the usage.
|
|
|
|
Several Jungfraujoch/NXmx masters of stills, given one after another, are read as one run: their
|
|
images are taken in the order given, indexed and merged together, and the log gives the indexing
|
|
rate of each input beside the run's. They must be one setup - the same detector, wavelength,
|
|
distance and beam centre (to 0.1%, 0.1 mm and 1 pixel), since stills geometry refinement refines
|
|
one geometry for all frames - and a pixel masked in any of them is masked for all. Stills in the
|
|
other formats are given the same way, as all their files: `rugnux run*.h5` (SACLA), `rugnux *.cxi`,
|
|
`rugnux *.xtc`. Inputs are always files, read in the order given (a shell glob gives them sorted by
|
|
name); a directory is refused. Rotation sweeps are not read together.
|
|
|
|
Given the URL of a `jfjoch_broker` (`http://host:port/`) and the path the master file *will* have,
|
|
`rugnux` follows the broker's current collection while it is being written: the data files are read
|
|
as the broker reports them closed, processing starts on the first images, and the run ends with the
|
|
images the collection delivered. A choice made early on a near tie is checked again on every frame
|
|
once all are in, and the run is made again where that check ends elsewhere, so the answer is the one
|
|
the whole sweep gives. This is for rotation data and `--mode mx`; the collection's token is read from
|
|
`JUNGFRAUJOCH_HTTP_TOKEN` and sent only to the broker. With the master file already on disk, the URL
|
|
is ignored.
|
|
|
|
> **Note.** `rugnux` is under very active development. This page describes the tool and
|
|
> its options at a high level; the authoritative, always-current list of options is the program's
|
|
> own usage message — run `rugnux` with no arguments.
|
|
|
|
```{contents} On this page
|
|
:local:
|
|
:depth: 2
|
|
```
|
|
|
|
## Quick start
|
|
|
|
Four commands cover most of what people ask of `rugnux`. Each takes the **master** file of the
|
|
dataset — one written by Jungfraujoch, a DECTRIS EIGER master, or an NXmx master written by another
|
|
facility's toolchain; a PILATUS miniCBF, marCCD or SMV sweep works too (see [What Rugnux reads](RUGNUX_FORMATS.md))
|
|
— and names its output files from `-o`:
|
|
|
|
```
|
|
# 1. everything from the data - index, integrate, scale and merge with the defaults
|
|
rugnux -o myrun dataset_master.h5
|
|
|
|
# 2. with a reference dataset of the same crystal form: it fixes the space group and the cell,
|
|
# resolves the indexing ambiguity, and hands over its R-free set
|
|
rugnux -o myrun -z reference.mtz dataset_master.h5
|
|
|
|
# 3. with a known structure: R-work / R-free and sigma_A-weighted 2mFo-DFc / mFo-DFc maps
|
|
# (a predicted model, or one the rigid body cannot place, goes to molecular replacement)
|
|
rugnux -o myrun --model model.pdb dataset_master.h5
|
|
|
|
# 4. with the space group and the cell pinned (-S takes either spelling: P43212 or 96)
|
|
rugnux -o myrun -S P43212 -C 79,79,38,90,90,90 dataset_master.h5
|
|
```
|
|
|
|
Parallelism needs no asking for: a run already uses the machine's threads. `-N` is there to *limit*
|
|
that, or to lift the per-image loop's default ceiling of 16 workers per GPU.
|
|
|
|
Nothing more is needed to pick the workflow: a dataset carrying a **goniometer axis** that turns is
|
|
processed as a rotation sweep, one without (or with an axis that stands still) as **independent
|
|
stills**, and scaling and merging run by default
|
|
in both. A rotation run that merges — the default — leaves eight files next to each other:
|
|
|
|
```
|
|
myrun.mtz merged intensities + French-Wilson amplitudes, for CCP4 / phenix
|
|
myrun.cif the same, as mmCIF - the self-describing format, and what to deposit
|
|
myrun.hkl the scaled observations unmerged, as SHELX HKLF 4 - for SHELXL, SHELXC / ANODE
|
|
myrun_unmerged.mtz every observation before scaling, for pointless / aimless / careless -
|
|
the largest file of the run (--no-export-unmerged skips it)
|
|
myrun_report.txt what the run determined: cell, space group, statistics, warnings
|
|
myrun_plot.txt one row per image, for plotting how the crystal behaved over the sweep
|
|
myrun_detector.jpg the detector with the pixel mask and the beam-stop shadow drawn on it
|
|
myrun_log.txt the full timestamped log of the run (debug level)
|
|
```
|
|
|
|
The two MTZ extras are most of the bytes a run writes — worth knowing when sizing a scratch
|
|
directory for a campaign, and both have off switches.
|
|
|
|
Read `myrun_report.txt` first: it says which space group was chosen and on what evidence, how far
|
|
the data go, and anything that needs attention.
|
|
|
|
### What the terminal shows
|
|
|
|
The terminal shows the run as numbered steps, each with one-line results and the time it took, the
|
|
warnings among them, and a summary at the end; everything else goes to `myrun_log.txt`. A note's
|
|
time is how long the step ran since the line above it, and the rule under a step gives its total, so
|
|
the steps add up to the wall time. Abridged:
|
|
|
|
```
|
|
Step 3 Indexing
|
|
... beam centre kept: measured 7.5 px off, same lattice 1.36 s
|
|
... lattice triclinic P: 28.56 35.34 63.56 106.0 90.3 90.3 0.00 s
|
|
... 52/60 validation frames, 24% of their spots on it 0.00 s
|
|
------------------------------------------------------- done in 1.36 s
|
|
Step 4 Integration (geometry pre-pass), 1800 images
|
|
... 1800 images, 836 per second 2.15 s
|
|
------------------------------------------------------- done in 2.16 s
|
|
...
|
|
Step 9 Scaling and merging
|
|
... merge in P1: 14464 unique 0.64 s
|
|
... space group P 1 21 1 (No. 4) 0.05 s
|
|
... merge in P21: 16847 unique 0.26 s
|
|
... resolution 1.57 A (CC1/2 fall-off at 1.64 A) 0.02 s
|
|
------------------------------------------------------- done in 1.89 s
|
|
...
|
|
==============================================================================
|
|
Result WARNINGS: Merged to 1.57 A in P 1 21 1. 3 conditions need
|
|
attention: SCALING_NOT_CONVERGED, MULTIPLE_LATTICES, ICE_RINGS.
|
|
Space group P 1 21 1
|
|
Unit cell 35.337 28.465 62.937 90.000 105.824 90.000
|
|
Resolution 1.57 A written; the CC1/2 fall-off is fitted at 1.64 A
|
|
Signal I/sigma 6.0 R_meas 17.2 % CC1/2 0.995 ISa 10.2
|
|
Wall time 11.78 s
|
|
==============================================================================
|
|
With any question about this run, send myrun_report.txt and myrun_log.txt.
|
|
```
|
|
|
|
On a terminal an integration pass draws a progress bar in place; written to a file or a pipe (a
|
|
batch job's log) every line starts with the time of day instead, there is no bar, and a long pass
|
|
says how far it has got once a quarter. Warnings are marked `!!` and errors `** ERROR:`; a warning
|
|
that comes back from a later merge is shown once more on one line and then only counted. `-v` puts
|
|
the whole log on the terminal in place of the steps. The log file carries what is needed to answer a
|
|
question about a run without the data: version, build, GPU, threads, the command line, the header
|
|
geometry, every decision with its numbers, and a timestamp on every line.
|
|
|
|
A few things worth knowing before reaching for more flags:
|
|
|
|
- **The written reflections stop where CC1/2 falls through 0.30.** Every reflection file is
|
|
resolution-trimmed automatically (`--resolution-cutoff cc-logistic`, one shell past the crossing);
|
|
`--resolution-cutoff off` keeps the full measured range, `--scaling-high-resolution` fixes the
|
|
limit by hand. A Rugnux file reaching less far than another program's on the same data is usually
|
|
this default at work, not lost data.
|
|
- **Rotation data are best left de novo.** Pinning the cell and space group (recipe 4) is the
|
|
normal thing to do for **serial stills**, where the `ffbidx` indexer needs a cell; on a rotation
|
|
sweep it tends to *degrade* low-symmetry cases, so prefer recipe 1 and let the run determine both
|
|
(see [Rotation data](RUGNUX_TUTORIAL.md#rotation-data)). `-S` takes a Hermann-Mauguin symbol (`P43212`) or a
|
|
space-group number (`96`), whichever is to hand.
|
|
- **Anomalous data are there without `-A`.** A rotation merge always keeps the Bijvoet split: a
|
|
default run's `.mtz` carries `I(+)`/`I(-)` beside `IMEAN`, and its `.hkl` every observation at the index it was measured at —
|
|
`FRIEDELS_LAW= TRUE` in the report says how the *statistics* were counted, not that the signal was
|
|
averaged away. What `-A` changes is the counting basis and the error model: each hand becomes a
|
|
merged observation of its own, so multiplicity, completeness and ⟨I/σ⟩ are counted anomalously and
|
|
the sigmas are refitted on the Bijvoet-separated merge. Reach for it for anomalous statistics; the
|
|
signal itself is in the file either way. (Stills merges carry no split by default — there `-A` is
|
|
what creates one.)
|
|
- **A model names the enantiomorph.** Where the data accept the model — it is tested against a
|
|
null of the same model in random orientations, and `MODEL_FIT=` in the report says the verdict —
|
|
`--model` settles which of P4<sub>1</sub>2<sub>1</sub>2 and P4<sub>3</sub>2<sub>1</sub>2 the merged
|
|
reflections are *labelled* with — a choice no merged intensity can make. It is a label and nothing
|
|
more: the two groups have the same rotation operations, so no reflection moves, and in particular
|
|
I(+) and I(-) are left exactly as measured. Whether the model agrees with the data about the hand
|
|
is then a real question, and the anomalous difference map answers it — a run says so when the
|
|
density at the model's atoms comes out inverted.
|
|
- **`-z` and `--model` overlap but are not the same.** A reference MTZ steers the processing from
|
|
the start; a model scores the merge and settles the frame it is written in — where the data
|
|
accept it; a model they reject changes nothing. Either resolves an
|
|
[indexing ambiguity](RUGNUX_ADVANCED.md#the-indexing-ambiguity), which on serial data decides whether the merged
|
|
intensities are usable at all.
|
|
- **Small molecules need no flag either.** Short axes, spots wider than the integration disk and
|
|
glide-plane space groups are handled by the default run, and `myrun.hkl` goes straight to SHELXT /
|
|
SHELXL ([Small-molecule data](RUGNUX_TUTORIAL.md#small-molecule-data)).
|
|
- **`--scaling-high-resolution <d>`**, where the resolution is already known, sharpens both the
|
|
space-group search and the error model.
|
|
- **A run wants memory in proportion to what it integrates**, not to the detector: 2.5-14 GB of
|
|
host RAM and 3-7 GB on the card over the datasets measured, both peaking in scaling and
|
|
merging. [Installing Rugnux ▸ Memory](RUGNUX_INSTALL.md#memory) has the table and the two
|
|
flags that lower it. A very large cell needs far more, and a CPU-only build most of all — tens of
|
|
GB of host RAM ([Very large unit cells](RUGNUX_INSTALL.md#very-large-unit-cells)).
|
|
- Everything else is in [Running Rugnux](RUGNUX_TUTORIAL.md#running-rugnux) and the full
|
|
[Command-line options](RUGNUX_ADVANCED.md#command-line-options).
|
|
|
|
|
|
## The rest of the manual
|
|
|
|
One page per job, so the answer needed is near the top of a short page:
|
|
|
|
- [What Rugnux does](RUGNUX_OVERVIEW.md) — the pipeline from images to merged reflections,
|
|
in order. Read this one first.
|
|
- [Installing Rugnux](RUGNUX_INSTALL.md) — packages, the release archive, GPU drivers, building
|
|
from source, hardware.
|
|
- [What Rugnux reads](RUGNUX_FORMATS.md) — will it open your data: NXmx / EIGER masters, PILATUS
|
|
miniCBF, marCCD and SMV (ADSC, Rigaku d\*TREK) sweeps, one sweep per input, and serial XFEL stills
|
|
from SACLA (Cheetah HDF5), Cheetah CXI single-panel files and LCLS-I XTC.
|
|
- [Running Rugnux](RUGNUX_TUTORIAL.md) — a first run in detail, rotation, serial and small-molecule
|
|
data, and every file a run writes.
|
|
- [Rugnux with other programs](RUGNUX_INTEGRATION.md) — the reflection-file conventions, the
|
|
unmerged export, and worked command lines for phenix, REFMAC, POINTLESS / AIMLESS, careless,
|
|
Phaser, SHELXC/D/E and, for small molecules, SHELXT / SHELXL.
|
|
- [The results report](RUGNUX_REPORT.md) — the `KEY= value` interface, sweep quality and the
|
|
anisotropy section.
|
|
- [Advanced usage](RUGNUX_ADVANCED.md) — reference data and the indexing ambiguity, model
|
|
validation, re-merging, and the full command-line option tables.
|
|
- [Models and reference data](RUGNUX_MODEL_AND_REFERENCE.md) — every model and reference option,
|
|
and decision by decision what a model can and cannot change.
|
|
- [Detector calibration](RUGNUX_CALIBRATION.md) — the geometry from a calibrant's powder rings
|
|
(`--mode calibration`).
|
|
- [Measuring Rugnux](RUGNUX_BENCHMARKING.md) — the validation battery, the REFMAC check, the timing
|
|
benchmark, and how to take timings on another machine that compare with ours.
|
|
- [CPU/GPU data analysis](CPU_DATA_ANALYSIS.md) — the algorithms behind all of it.
|
|
|
|
## Where it fits among the three analysis tools
|
|
|
|
| Tool | Mode | Driven by | Output |
|
|
| --- | --- | --- | --- |
|
|
| [`jfjoch_broker`](JFJOCH_BROKER.md) | Online, real-time streaming analysis on FPGA + GPU | HTTP/REST + ZeroMQ | Live results and statistics, images streamed to [`jfjoch_writer`](JFJOCH_WRITER.md) |
|
|
| [`jfjoch_viewer`](JFJOCH_VIEWER.md) | Interactive, on-screen exploration | Qt desktop application | On screen; a processing job can write the same files as `rugnux` |
|
|
| **`rugnux`** | **Offline batch processing of a stored dataset** | **Command-line interface** | **`_process.h5`, and `.mtz`/`.cif`/`.hkl` when merging** |
|
|
|
|
Use `rugnux` to re-analyse data after acquisition, to experiment with processing
|
|
parameters, or to produce merged intensities for downstream structure solution.
|
|
|