The pre-scan sample (beam-stop shadow, defective pixels, spot width, the background beam centre)
and the first pass's frames (the spread and wedge schemes, the validation frames, the prefetch) now
come from [start, PrepassEnd) - the part of the sweep the geometry pre-pass integrates - instead of
the whole sweep. Rugnux::PrepassEnd is the one place that range is defined, for the pre-pass and for
these decisions alike, so any change to the pre-pass range (such as a minimum rotation) moves both.
Stills keep the whole range.
With rugnux following a collection while it is written, nothing before pass 2 then waits for the
second part of the sweep: the pre-scan, both first passes and the pre-pass run while it is
collected, and pass 2 starts reading as soon as they are done. An offline run takes the same
decisions from the same frames, so the streamed result still equals the offline one by md5 (in-house
JUNGFRAU 4M thaumatin replayed at one data file per second, also at -N 8 and with the replay paused
and resumed): 2.4 s from the last data file to the result, against 8.0 s for the offline run.
Result-changing. p.mtz md5 at af3ea9cca -> here (with the 120 deg minimum of the previous commit),
GPU: myob de2ab820 -> 9bdd6916, cytc 3e5d2f91 -> 62e744a1, thau bc5e3de3 -> 3ec88c34,
kdp cf83ee5d -> cdc2c068, 8a1a 50ab659e -> 309ea9a8, 8qaw d3287922 -> c2849d52; CPU: myob 3f9d12d8 ->
18c7ac2f, cytc d30c9969 -> 40e17d97, thau 4cdbdd94 -> f14e52da, kdp f1d801f3 -> eb930714. Sweeps of
120 deg or less are unchanged by this commit (their early range is the whole sweep). Needs the
battery before it is merged.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SVmAWnzCmRKAXVUCdc4iNi
5.2 KiB
What Rugnux does
The map of a run, in the order it happens — one paragraph per stage, each linking into the data-analysis reference where the algorithm lives. The walk-through is a rotation run with the defaults; stills differences are at the end.
Open the dataset. The geometry, wavelength and goniometer come from the file (What Rugnux reads). A goniometer axis makes it a rotation run, none makes it serial stills — nothing is asked of the user.
Pre-scan. A projection of frames (60 by default) spread over the first part of the sweep, the part the geometry pre-pass integrates, finds the beam-stop shadow and masks it (§1.5), masks pixels its frames show to be defective (§1.6), measures the beam centre from the isotropy of the scattered background and compares it with the file's (§1.4), and reads how wide this crystal's spots are, which sets the integration radius (§9.5), and how much longer they are along their radius than across it, which is the beam's bandwidth where the file does not state one (§9.6), and how much wider still they grow away from the beam, which sets the integration footprint (§9.1). In a GPU build the pre-scan runs on the card.
Spots. Every image is decoded — on the GPU straight from the compressed chunk (§0) — and one fused pass computes the azimuthal profile and finds the spots against each image's own per-resolution-ring noise (§2–§3). The ice-ring score is read off the same profile.
Indexing. The spots of a sample of frames are rotated back to a common crystal frame and the FFT search looks for periodicity over thousands of directions; candidate cells are Niggli-reduced, classified by Bravais lattice, refined both constrained and triclinic, and decided on how many validation frames each actually indexes (§4–§7). A de-novo run also tries a second hypothesis with the shortest accepted axis lowered from 10 to 5 Å, for small-molecule cells. The first pass is indexed a second time at the beam centre the pre-scan measured; the file's centre is kept unless it indexes nothing, gives an axis harmonic of the measured centre's lattice, or loses to it when both first passes are merged (§1.4). A failed pass triggers the discrete rescues — the rotation-axis sign, the first-pass depth ladder, the long-axis rescue — before anything is given up on.
First integration pass. At the geometry in the file, every frame of the first half of the sweep, at least 120° of it
(--prepass-fraction) is predicted
(§8) and profile-fit integrated
(§9); partials are combined into fulls, scaled and merged
(§10).
Geometry post-refinement. From those reflections the detector distance, beam centre and the cell scale / rotation axis are refined over all those frames at once, each step committed only if it improves a held-out residual (§7.5).
Second pass. The sweep is re-indexed de novo and re-integrated at the refined geometry; this
pass is the canonical output, and a guard compares the two passes and keeps the better one
(reported as PASS= / PASS_DECISION= in the report).
Space group. On the P1 merge of the final pass, the point group is scored operator by operator
on resolution-normalised intensities and the screw axes, glide planes and centring are read from the
systematic absences, with the centre of symmetry from the intensity distribution where the absences
leave it open (§13.1); twinning and translational
pseudo-symmetry are checked beside it (§13.2). CANNOT_DETERMINE and an enantiomorphic pair are real
answers here, not evasions.
Scale and merge. In the determined group: per-frame scales, the cross-validated correction surfaces (decay, absorption, modulation), the error model and ISa, outlier rejection, the CC1/2-based resolution cut, the anisotropy description, French–Wilson amplitudes and the R-free flags (§10, §13.3–§13.5).
Write. The merged .mtz / .cif / .hkl, the unmerged MTZ and the
results report land next to each other (Output files); with
--model, validation runs first and the maps and the placed model are written too
(§14).
Stills instead. Serial data skip the two-pass machinery: each image is indexed independently
(with the known-cell ffbidx indexer where a cell is given), partiality comes from a per-crystal
orientation-tilt post-refinement rather than a rocking curve, and a merohedral indexing ambiguity
has to be broken per image, at integration time, against a reference or a model
(Advanced ▸ the indexing ambiguity).