docs: rc.160 changelog + CPU_DATA_ANALYSIS/RUGNUX updates

Document the newest rc.160 work: rotation geometry post-refinement (now
default-on), the opt-in per-batch relative-B, the always-on radiation-damage
report, net-absence space-group centering ranking, and software/geometry
provenance in the merged mmCIF. Add a §7.5 for the two-pass post-refinement.
Drop the removed .hkl output from RUGNUX.md and add the new CLI options
(--rotation-no-postrefine, --relative-b, --refine-geometry, --background-trim,
--stills-modulation, --still-partiality, --spot-low-resolution,
--min-pix-per-spot, -S symbol, -r flex).

Add a plain-lysozyme (HEWL) carve-out to the no-sample-identity rule: the
field's universal standard specimen and its reference cell are allowed, while
named user datasets and every other sample stay forbidden.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-18 23:14:09 +02:00
co-authored by Claude Opus 4.8
parent fcafc61be6
commit 99617c549a
4 changed files with 58 additions and 10 deletions
+7 -2
View File
@@ -83,8 +83,13 @@ a hard rule, not a preference.
- **Fine**: general crystallographic descriptors — space group / Laue class ("a P2₁ crystal", "a
holohedral 422 case"), lattice centering, twinning, "a crystal whose true axis is reported as its
3× harmonic", pseudo-symmetry, etc. Describe the *crystallographic situation*, not the specimen.
- **Tests** must use neutral names (e.g. `tetragonal_uc`, not a specimen-named variable) and, where
a cell is needed, a synthetic cell chosen for the test — not a real dataset's parameters.
- **Exception — plain lysozyme.** Lysozyme (HEWL) is the field's universal standard test specimen,
not a user's confidential dataset, so naming it and using its well-known reference cell
(tetragonal ~79/79/38, P4₃2₁2) in tests, docs and comments is allowed. This carve-out is only for
generic lysozyme as a benchmark; a *named user dataset* that happens to be lysozyme is still off
limits, and every other real sample remains forbidden.
- **Tests** must otherwise use neutral names (e.g. `tetragonal_uc`, not a specimen-named variable)
and, where a cell is needed, a synthetic cell chosen for the test — not a real dataset's parameters.
When a bug was found on a specific dataset, commit the *behaviour* ("de-novo indexing adopted a
spurious axis-multiple supercell"), never the dataset.
+6
View File
@@ -3,6 +3,12 @@
### 1.0.0-rc.160
This is an UNSTABLE release. It includes many experimental features, as well as many AI generated fixes. We recommend using rc.152 for production use.
* rugnux: Rotation **geometry post-refinement** is now on by default (`--rotation-no-postrefine` to disable; also a viewer checkbox). A first pass integrates at the header geometry, then the shared detector distance + beam centre and the crystal cell/goniometer-axis are post-refined over all frames (cross-validated, committed only for a small < 1 % move, with the gauge-weak beam centre restrained toward the header); a second pass re-indexes de novo and re-integrates at the refined geometry. The refined pass is the canonical `<prefix>_*` output; the header-geometry pass is kept as `<prefix>_01_*`.
* rugnux: Optional per-batch **relative-B** correction for rotation (`--relative-b[=deg]`, default 10°-of-rotation batches when bare, off otherwise) - a cross-validated, curvature-smoothed resolution×dose correction beyond the single global decay slope.
* rugnux: Always-on **radiation-damage report** for rotation - the per-image scale correlation-to-merge and mosaicity versus dose, plus the relative B-factor change over the run (first→last) as a scalar and a per-batch relative-B curve, printed to the log and written to the merged mmCIF. Report-only; it never alters the merge.
* rugnux: De-novo space-group search ranks candidate lattice **centerings by net absences** (systematically-absent minus violating), not the gross absent count, fixing an over-centering of a genuinely C-centred lattice to F.
* rugnux: Record the **producing software** (name and version) and the refined **detector distance and beam centre** in the merged mmCIF (and the software in the MTZ history).
* Bragg integration: Carry the box-sum observed centroid through the profile-fit path, so the observed spot centroid is emitted in every integrator mode.
* rugnux: Report **ISa** as the counting-subtracted strong-reflection asymptote, not `1/b` of the whole-range fit; it also sets the merged-sigma floor. CC1/2, R-meas and per-obs sigmas unchanged.
* Frontend: Azimuthal-integration Q fields (Q spacing / Low Q / High Q) accept 5 decimals (was 3), matching the 1e-5 `q_spacing` minimum; number-field precision is now configurable.
* rugnux: Add a dataset-wide **Wilson B-factor** estimate to the merged output (mmCIF, stats table, log); the per-image viewer Wilson B emits NaN for implausible fits.
+14 -2
View File
@@ -352,6 +352,16 @@ with $R(\phi)$ constructed from the axis-angle representation of the goniometer
Refinement is performed in stages with decreasing acceptance tolerance for including reflections (three stages, indexing tolerance $0.3\to0.2\to0.1$), which stabilizes convergence when starting from imperfect indexing and approximate geometry.
### 7.5 Rotation geometry post-refinement (two-pass)
The refinement above (§7.2) runs per image against that image's spots. For rotation data an additional **post-refinement** (on by default; `--rotation-no-postrefine` disables it) improves the detector distance, beam centre and crystal cell/axis using **all** frames at once, then re-integrates:
1. **Pass 1** integrates, scales and merges at the header geometry.
2. Against the merged fulls, the shared detector distance and beam centre and the crystal cell / goniometer-axis are refined jointly over all frames (Ceres, robust loss). The fit is **cross-validated** on a deterministic frame split — refined on one half, gated on the held-out half — and the geometry is **committed only for a small move** (a distance/beam shift under ~1 %); a larger move is treated as a fit instability and rejected. The beam centre is gauge-weak in a rotation series (it trades off against the crystal orientation), so it is restrained toward the header value.
3. **Pass 2** re-indexes de novo and re-integrates at the committed geometry, reusing pass-1's space group for the merge only.
The refined pass is written as the canonical `<prefix>_*` output; the pass-1 (header-geometry) result is kept alongside as `<prefix>_01_*` for comparison.
---
## 8. Reflection prediction
@@ -566,12 +576,14 @@ The fulls are then re-scaled in the XDS sense — a per-image scale refit direct
After scale-fulls, three **correction surfaces** are fitted on the combined fulls (rotation path, **on by default**; disable all with `--no-scaling-corrections`), each an alternating multiplicative refinement of the per-full scale against the merged reference:
- **Decay.** Radiation damage weakens later frames more at higher resolution — a resolution×time (DebyeWaller) systematic the resolution-flat per-image scale cannot capture. A single global relative-$B$ rate is fitted, $\ln(I_\mathrm{ref}/I_\mathrm{obs}) = 2\,(\mathrm{d}B/\mathrm{d}n)\,(n-\bar n)\,s^2$ (frame $n$, $s^2 = 1/4d^2$), and folded into the scale. It engages only when the total relative-$B$ over the run exceeds a physical floor (2 Ų); below that the decay is negligible and "correcting" it only spreads symmetry equivalents (same $s^2$, different frames).
- **Decay.** Radiation damage weakens later frames more at higher resolution — a resolution×time (DebyeWaller) systematic the resolution-flat per-image scale cannot capture. A single global relative-$B$ rate is fitted, $\ln(I_\mathrm{ref}/I_\mathrm{obs}) = 2\,(\mathrm{d}B/\mathrm{d}n)\,(n-\bar n)\,s^2$ (frame $n$, $s^2 = 1/4d^2$), and folded into the scale. It engages only when the total relative-$B$ over the run exceeds a physical floor (2 Ų); below that the decay is negligible and "correcting" it only spreads symmetry equivalents (same $s^2$, different frames). An optional **per-batch relative-$B$** (`--relative-b[=deg]`, off unless requested; 10°-of-rotation batches by default) extends the single global rate to a smooth $B(n)$ curve — the same $s^2$-weighted decay fit solved independently over short frame batches, curvature-penalized so it cannot over-fit and cross-validated like the surfaces below — for crystals whose decay is non-linear in dose.
- **Absorption.** A smooth multiplicative factor over the diffracted-beam direction expressed in the goniometer (crystal) frame: each full's predicted detector position gives the lab diffracted direction, de-rotated by the spindle so a fixed crystal-frame direction is sampled at many rotation angles and its grid cell is well-determined. Negligible at hard X-rays / thin crystals; it matters at low photon energy.
- **Modulation** (detector-plane flat-field). A smooth multiplicative factor over where each reflection lands on the detector (predicted $x,y$): symmetry-equivalents land at different positions as the crystal rotates, over-determining the surface. It absorbs detector-response and geometric systematics that inflate $R_\mathrm{meas}$. The same 16×16 detector-frame surface is available for the stills path (`--stills-modulation`, off by default), where serial data repeatedly hammers the same detector regions.
Each surface is **cross-validated**: fitted on even-numbered frames and kept only if it improves the held-out odd-frame agreement by a clear margin (and vice versa), scored by a **σ-independent, $R_\mathrm{meas}$-like** fractional agreement $\sum|I_s-I_\mathrm{ref}|/\sum|I_\mathrm{ref}|$ rather than a studentized $\chi^2$ — so a surface cannot "pass" by reshaping the sigmas instead of tightening the intensities. A surface fitted to noise where its systematic is absent does not generalize and is discarded — a correction never adds scatter.
**Radiation-damage report (rotation, report-only).** Independently of whether any decay correction is applied, rugnux measures and reports the relative DebyeWaller $B$ across the sweep: the per-image scale's correlation to the merge and the per-image mosaicity versus frame (dose), together with a per-batch relative-$B$ curve whose first→last change is a single headline number (measured before any decay correction, against the least-damaged early wedge). It is written to the log and to the merged mmCIF as a data-quality-vs-dose diagnostic and **never** alters the merged intensities — distinct from the decay correction above, which does fold into the scale.
### 10.7 R-free test-set flags
A fraction of the unique reflections (`rfree_fraction`, default 0.05) is flagged as a **free (test) set**, written to the output (MTZ `FreeR_flag`, mmCIF `_refln.status_free`, a text-HKL column) for model validation (§14) and for downstream refinement. The flag is a pure function of the reflection's **Friedel-merged (Laue) ASU index**, which gives three properties:
@@ -662,7 +674,7 @@ A **dataset-wide** Wilson $B$ is also estimated over the merged reflections —
- **Space-group symmetry** beyond centering absences is not necessarily enforced during prediction/integration unless the space group is supplied and used downstream.
- **Resolution masking and ice rings** are controllable; including ice-ring spots in indexing can improve robustness for some samples but may bias refinement in others.
- **Rotation vs still modes** differ substantially in prediction and scaling: partiality is angle-driven in rotation data, while stills are predicted (within an excitation-error window) and scaled with unit partiality.
- **Space-group determination.** When no space group is supplied, a POINTLESS-like search scores Laue-group symmetry (CC of $I(h)$ vs $I(Rh)$ plus merge self-consistency) and detects screw/centering absences from the $P1$-merged intensities. The self-consistency test is calibrated so a merohedral twin — whose twin law forces non-equivalent reflections together and inflates the merged $\chi^2$ — stays in its true lower symmetry rather than being over-promoted to the holohedral group. Because a partial twin's within-orbit $\chi^2$ can nonetheless look self-consistent, a chi²-passing promotion is additionally **vetoed** when merging its extra operator balloons the error-model $b$ (the intensity-proportional systematic) relative to the confirmed subgroup: a genuine symmetry step gains multiplicity without inflating $b$, whereas a twin forces non-equivalent reflections together and $b$ balloons. **Centering** is accepted when the systematically-absent class is weak relative to the present one by *either* of two floor-independent tests — its mean signed $I/\sigma$ well below the present mean, *or* its rate of individually-significant reflections well below the present class's own significant rate. The second test matters on weak / low-energy data, where a positive intensity floor (background/profile leakage) lifts the absent class's mean $I/\sigma$ to $\sim1.5$$2.3$ instead of $\sim0$ and, when the present class is itself weak, inflates the plain mean ratio past its bound and hides a real centering (an $I$-centred cubic recorded at 5 keV was otherwise kept primitive); a false centering fails both tests because its absent class is as strong as the present one.
- **Space-group determination.** When no space group is supplied, a POINTLESS-like search scores Laue-group symmetry (CC of $I(h)$ vs $I(Rh)$ plus merge self-consistency) and detects screw/centering absences from the $P1$-merged intensities. The self-consistency test is calibrated so a merohedral twin — whose twin law forces non-equivalent reflections together and inflates the merged $\chi^2$ — stays in its true lower symmetry rather than being over-promoted to the holohedral group. Because a partial twin's within-orbit $\chi^2$ can nonetheless look self-consistent, a chi²-passing promotion is additionally **vetoed** when merging its extra operator balloons the error-model $b$ (the intensity-proportional systematic) relative to the confirmed subgroup: a genuine symmetry step gains multiplicity without inflating $b$, whereas a twin forces non-equivalent reflections together and $b$ balloons. **Centering** is accepted when the systematically-absent class is weak relative to the present one by *either* of two floor-independent tests — its mean signed $I/\sigma$ well below the present mean, *or* its rate of individually-significant reflections well below the present class's own significant rate. The second test matters on weak / low-energy data, where a positive intensity floor (background/profile leakage) lifts the absent class's mean $I/\sigma$ to $\sim1.5$$2.3$ instead of $\sim0$ and, when the present class is itself weak, inflates the plain mean ratio past its bound and hides a real centering (an $I$-centred cubic recorded at 5 keV was otherwise kept primitive); a false centering fails both tests because its absent class is as strong as the present one. When several centerings pass, they are ranked by their **net** systematic absences (absent minus violating), not the gross absent count, so a super-centering (e.g. $F$ over a true $C$) whose extra, only-half-populated absent class merely dilutes the strength ratio does not out-rank the correct lower centering.
- **Twinning check.** A PadillaYeates $L$-test ($\langle|L|\rangle$, $\langle L^2\rangle$) and the second moment $\langle I^2\rangle/\langle I\rangle^2$ (taken per resolution shell with noise-only shells skipped and Wilson outliers rejected, so a single strong reflection in a collapsed-mean shell cannot skew it) are written to the merged mmCIF as a twinning diagnostic. Twinning is only flagged in Laue classes where a merohedral twin law can exist; the holohedral high-symmetry classes ($4/mmm$, $6/mmm$, $m\bar{3}m$, and $\bar{3}m$ on a rhombohedral lattice) are exempt, so a low $\langle|L|\rangle$ there is reported as a statistical artefact rather than twinning.
- **Outlier rejection.** Merging applies an optional per-observation median-based $N\sigma$ cut (default 6σ for `rot3d`) and an optional per-crystal $\Delta\mathrm{CC}_{1/2}$ image rejection (`--reject-delta-cchalf`, CrystFEL-style, off by default). The same $N\sigma$ cut is fed back into the error model: after an initial $a,b$ fit the parameters are re-fit once on the reflections that survive rejection (dropping any whose squared deviation exceeds $N\sigma^2\,[a\,\sigma^2 + (b\,\langle I\rangle)^2]$), so the calibrated errors describe the reflections that actually enter the merge rather than the pre-rejection pool.
- **Automatic resolution cutoff.** By default the reported/written high-resolution limit is trimmed where $\mathrm{CC}_{1/2}$ falls off (logistic, target 0.30); `--scaling-high-resolution` overrides it and `--resolution-cutoff off` disables it.
+31 -6
View File
@@ -4,7 +4,7 @@
data-processing half of the system (see [Naming](NAMING.md) for where the name comes from).
It takes an existing HDF5 dataset, runs the full analysis pipeline — spot finding, indexing,
geometry refinement, Bragg integration and (optionally) scaling and merging — and writes the
results to a `_process.h5` file, plus reflection files (`.mtz`/`.cif`/`.hkl`) when merging is
results to a `_process.h5` file, plus reflection files (`.mtz`/`.cif`) when merging is
requested.
It runs the *same* analysis code as the online and interactive tools, just driven from the
@@ -20,7 +20,7 @@ command line over a file rather than a live detector stream.
| --- | --- | --- | --- |
| [`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 | Displayed on screen (results not saved to disk) |
| **`rugnux`** | **Offline batch processing of a stored dataset** | **Command-line interface** | **`_process.h5`, and `.mtz`/`.cif`/`.hkl` when merging** |
| **`rugnux`** | **Offline batch processing of a stored dataset** | **Command-line interface** | **`_process.h5`, and `.mtz`/`.cif` when merging** |
Use `rugnux` to re-analyse data after acquisition, to experiment with processing
parameters, or to produce merged intensities for downstream structure solution.
@@ -89,12 +89,23 @@ resolution) sharpens both the space-group search and the error model. To tune th
`--two-pass-rotation=100` (or `-R100` — the first-pass image count); to force the sweep to be
treated as independent stills use `--force-still`.
By default a rotation run also **post-refines the geometry** in a second pass: the first pass
integrates and merges at the header geometry, then the detector distance + beam centre and the crystal
cell / rotation-axis are refined against the merged fulls (cross-validated, and committed only for a
small < 1 % move, with the gauge-weak beam centre restrained toward the header), and the second pass
re-indexes de novo and re-integrates at the refined geometry. The refined pass is the canonical
`<prefix>_*` output; the header-geometry pass is kept alongside as `<prefix>_01_*` for comparison.
Disable it with `--rotation-no-postrefine`.
After the per-frame scale-fulls step, rotation scaling applies three **correction surfaces**, **on by
default** (`--no-scaling-corrections` disables all):
- **Decay** — a global DebyeWaller relative-*B* over the run, for the radiation damage that weakens
later frames more at high resolution (a resolution×time systematic the resolution-flat per-frame
scale cannot remove). It only engages when the total relative-*B* exceeds a physical floor (2 Ų).
scale cannot remove). It only engages when the total relative-*B* exceeds a physical floor (2 Ų). An
optional `--relative-b[=deg]` extends this single global rate to a smooth per-batch relative-*B* curve
(default 10°-of-rotation batches when bare, off otherwise), cross-validated like the surfaces here, for
crystals whose decay is non-linear in dose.
- **Absorption** — a smooth multiplicative factor over the diffracted-beam direction in the goniometer
frame (path length through the crystal). Negligible at hard X-rays / thin crystals; it matters at
low photon energy. Its benefit shows up most on model-based metrics: a smooth absorption error
@@ -114,6 +125,11 @@ scored as a σ-independent, *R*<sub>meas</sub>-like fractional deviation, so a s
cross-validation by merely reshaping the sigmas; where the systematic is absent the surface is a no-op
rather than a source of added noise, which is why they are safe to leave on.
Independently of any correction, a rotation run prints a **radiation-damage report** — the per-image
scale correlation-to-merge and mosaicity versus dose, and the relative *B*-factor change over the run
(first→last) together with a per-batch relative-*B* curve, also written to the merged mmCIF. It is a
data-quality-vs-dose diagnostic and never alters the merged intensities.
### Still / serial data
A dataset with **no goniometer axis** (e.g. a serial grid scan) is processed as **independent
@@ -161,6 +177,8 @@ Spot finding:
| `--spot-sigma <num>` | Noise sigma level for spot finding (default: 3.0) |
| `--spot-threshold <num>` | Photon-count threshold for spot finding (default: 10) |
| `--spot-high-resolution <num>` | High-resolution limit for spot finding, Å (default: 1.5) |
| `--spot-low-resolution <num>` | Low-resolution limit for spot finding, Å (default: 50; lower it, e.g. 24, to exclude the direct-beam halo on weak serial data) |
| `--min-pix-per-spot <num>` | Minimum connected strong pixels per spot (default: 2; serial data can index better with 1 and a higher `--spot-threshold`) |
| `--max-spots <num>` | Maximum spot count (default: 250) |
| `--detect-ice-rings[=on\|off]` | Flag ice-ring spots (de-prioritised in indexing) and exclude ice-ring reflections from scaling/merging; overrides the dataset/master-file setting (default: use the dataset value) |
@@ -187,12 +205,14 @@ rotation explicitly and pick the pass or lattice.
| `--force-still` | Treat a rotation (goniometer) dataset as independent stills instead of rotation |
| `-X, --indexing-algorithm <txt>` | `FFBIDX` \| `FFT` \| `FFTW` \| `Auto` \| `None` |
| `-C, --unit-cell <cell>` | Reference unit cell `"a,b,c,alpha,beta,gamma"` (required by `ffbidx`) |
| `-S, --space-group <num>` | Space group number (used for indexing and scaling) |
| `-r, --refine <txt>` | Geometry refinement: `none` \| `orientation` \| `beam_and_lattice` (default) |
| `-S, --space-group <num\|symbol>` | Space group number (`92`) or Hermann-Mauguin symbol (`P43212`) — for indexing and scaling |
| `-r, --refine <txt>` | Geometry refinement: `none` \| `orientation` \| `beam_and_lattice` (default) \| `flex` (try all three per image, keep whichever indexes the most spots; alias `multi`) |
| `-R, --two-pass-rotation[=num]` | Two-pass offline rotation indexing (default for goniometer data; optional first-pass image count, default 100) |
| `--single-pass-rotation[=num]` | Online-like single-pass rotation indexing (optional min angular range, deg) |
| `--redo-rotation-spots` | Redo spot finding for the two-pass rotation first pass |
| `--force-rotation-lattice <vec>` | Force rotation lattice (9 floats, Å), skipping the first pass |
| `--rotation-no-postrefine` | Rotation: disable the default-on two-pass geometry post-refine (see the rotation section) |
| `--refine-geometry[=N\|off]` | Stills: extra first pass that bundle-adjusts the shared beam/distance/cell from N strongly-indexed frames (default 200) then re-indexes; default ON for stills with a reference cell (`-C` / `-z`), `=off` disables |
Indexer choice in brief: `ffbidx` (GPU) refines toward a **known cell** and is best for sparse
serial stills; `fft` (GPU) / `fftw` (CPU) index **de novo** and suit strong rotation data. See the
@@ -207,7 +227,11 @@ Scaling and merging:
| `-B, --refine-bfactor` | Refine a per-image B-factor (stills only) |
| `--scale-fulls` / `--no-scale-fulls` | rot3d: refit a per-frame scale on the combined fulls (XDS order, Unity model); on by default for rotation data, off for stills |
| `--smooth-g[=deg]` | rot3d: smooth the per-frame scale *G* over a degree range before the 3D combine (XDS DELPHI-like; default 5° for rotation, 0 = off) |
| `--no-scaling-corrections` | rot3d: disable the default-on decay + absorption correction surfaces fitted on the fulls after scale-fulls (see below) |
| `--no-scaling-corrections` | rot3d: disable the default-on decay + absorption + modulation correction surfaces fitted on the fulls after scale-fulls (see below) |
| `--relative-b[=deg]` | rot3d: fit a per-batch relative-*B* beyond the single decay slope over deg-degree batches, cross-validated (default 10° when bare; off otherwise) |
| `--still-partiality` | Experimental (stills): weight reflections by a Gaussian excitation-error partiality instead of treating each as a full |
| `--partiality-uncertainty <num>` | Stills: extra merge sigma ~num·(1partiality)·⟨I⟩ on partials (use with `--still-partiality`; default 0, ~2.5 recommended) |
| `--stills-modulation` | Experimental (stills): fit a detector-plane modulation (flat-field) surface, cross-validated (default off) |
| `--capture-uncertainty <num>` | rot3d: systematic sigma on under-captured fulls, ~num·(1captured_fraction)·I (default: 1.0 for rotation, 0 otherwise) |
| `--min-captured-fraction <num>` | rot3d: drop a combined full whose rocking curve was captured below this fraction — edge-of-sweep truncated fulls (default: 0.7 for rotation, 0 otherwise; 0 = off) |
| `--scaling-high-resolution <num>` | High-resolution limit for scaling, Å — manual override (default: no limit; disables the automatic cutoff below) |
@@ -230,6 +254,7 @@ Integration:
| --- | --- |
| `--integrator <txt>` | Spot integrator: `gaussian` (profile-fit, default) \| `empirical` \| `boxsum` (classical fallback) |
| `--integration-radius <r>` | Signal-box radius `r1`, or `r1,r2,r3` (px). One value ⇒ `r2=r1+2`, `r3=r1+4` |
| `--background-trim <f>` | Monochromatic (rotation + still): symmetric trimmed-mean fraction for the background ring, 0≤f<0.5 (default 0.10; 0 = plain mean) — removes the high-side bias that over-subtracts weak high-angle spots |
| `--bandwidth <num>` | Relative X-ray bandwidth FWHM (e.g. `0.01` for a 1% DMM); default from file or 0 (monochromatic) |
Geometry overrides (defaults are taken from the input file; override them to reprocess with a corrected geometry):