From 99617c549a305ddd566a874db77c3682a04a7fcf Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Sat, 18 Jul 2026 23:14:09 +0200 Subject: [PATCH] docs: rc.160 changelog + CPU_DATA_ANALYSIS/RUGNUX updates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- CLAUDE.md | 9 +++++++-- docs/CHANGELOG.md | 6 ++++++ docs/CPU_DATA_ANALYSIS.md | 16 ++++++++++++++-- docs/RUGNUX.md | 37 +++++++++++++++++++++++++++++++------ 4 files changed, 58 insertions(+), 10 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 3ea4eaaf..4a4086fc 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -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. diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 12ad4715..438d1723 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -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 `_*` output; the header-geometry pass is kept as `_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. diff --git a/docs/CPU_DATA_ANALYSIS.md b/docs/CPU_DATA_ANALYSIS.md index b38f3ef5..b0c721f7 100644 --- a/docs/CPU_DATA_ANALYSIS.md +++ b/docs/CPU_DATA_ANALYSIS.md @@ -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 `_*` output; the pass-1 (header-geometry) result is kept alongside as `_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 (Debye–Waller) 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 (Debye–Waller) 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 Debye–Waller $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 Padilla–Yeates $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. diff --git a/docs/RUGNUX.md b/docs/RUGNUX.md index 11503447..d7c49114 100644 --- a/docs/RUGNUX.md +++ b/docs/RUGNUX.md @@ -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 +`_*` output; the header-geometry pass is kept alongside as `_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 Debye–Waller 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*meas-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 ` | Noise sigma level for spot finding (default: 3.0) | | `--spot-threshold ` | Photon-count threshold for spot finding (default: 10) | | `--spot-high-resolution ` | High-resolution limit for spot finding, Å (default: 1.5) | +| `--spot-low-resolution ` | 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 ` | Minimum connected strong pixels per spot (default: 2; serial data can index better with 1 and a higher `--spot-threshold`) | | `--max-spots ` | 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 ` | `FFBIDX` \| `FFT` \| `FFTW` \| `Auto` \| `None` | | `-C, --unit-cell ` | Reference unit cell `"a,b,c,alpha,beta,gamma"` (required by `ffbidx`) | -| `-S, --space-group ` | Space group number (used for indexing and scaling) | -| `-r, --refine ` | Geometry refinement: `none` \| `orientation` \| `beam_and_lattice` (default) | +| `-S, --space-group ` | Space group number (`92`) or Hermann-Mauguin symbol (`P43212`) — for indexing and scaling | +| `-r, --refine ` | 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 ` | 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 ` | Stills: extra merge sigma ~num·(1−partiality)·⟨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 ` | rot3d: systematic sigma on under-captured fulls, ~num·(1−captured_fraction)·I (default: 1.0 for rotation, 0 otherwise) | | `--min-captured-fraction ` | 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 ` | High-resolution limit for scaling, Å — manual override (default: no limit; disables the automatic cutoff below) | @@ -230,6 +254,7 @@ Integration: | --- | --- | | `--integrator ` | Spot integrator: `gaussian` (profile-fit, default) \| `empirical` \| `boxsum` (classical fallback) | | `--integration-radius ` | Signal-box radius `r1`, or `r1,r2,r3` (px). One value ⇒ `r2=r1+2`, `r3=r1+4` | +| `--background-trim ` | 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 ` | 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):