10 Commits
Author SHA1 Message Date
leonarski_fandClaude Opus 5 d275bbcae7 calibration: -C overrides the calibrant, with absences from -S
The five named standards are a convenience, not the limit of what a powder
calibration can be run against. A unit cell given with -C now IS the standard
in --mode calibration, and its rings are enumerated from that cell.

A cell alone does not give a ring list, though: the centring and any glide
decide which hkl the lattice actually diffracts into, and the fit pairs the
innermost OBSERVED ring with the innermost LISTED one - so a list opening with
a reflection that is not there scales the whole calibration by the ratio
between them. Where -S is given, the absences come from the space group itself
via gemmi, which covers centring, glides and screws in one mechanism rather
than the three hand-written conditions the built-in table uses. The two agree
exactly on LaB6 and CeO2, which is the cross-check that says the gemmi route is
safe to hand a user's cell.

They do NOT agree on silicon, and the test now pins that: Fd-3m's symmetry
absences are only the F centring, while silicon's 222 and its relatives are
extinguished by its two-atom basis - a structure-factor absence, not a symmetry
one, so no symmetry handler can know it. gemmi offers 24 rings where the
diamond condition gives 18. The extra rings do not move the first one, so the
distance is not scaled, but they are rings with no intensity offered to the
matcher - which is why --calibrant si stays, and why the usage text says -S
supplies symmetry absences only.

Without -S the cell is taken as primitive and the log says "assumed primitive".

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NfuDvf5ipV3Hi8TiCUKD27
2026-08-31 16:23:37 +02:00
leonarski_fandClaude Opus 5 5a80d2df53 calibration: fix four ways the powder fit quietly loses its input
None of these changes the answer on a well-separated cubic standard - the LaB6
distance series is bit-identical by both methods - but each one is a case where
input is dropped or mis-assigned without saying so.

The circumcentre vote grid was a fixed 4000x4000 box, and the caller never
passed anything else. That allocated 128 MB whatever the detector, and on a
detector larger than 4000 px in either direction it put the beam centre outside
the grid, so every vote was discarded and the guess failed with "Beam center
not found". Span the spots' own bounding box instead: a powder ring encloses
its centre, so that is where the answer has to be. uint32 votes while there -
the most any bin can take is C(500,3).

Spots were assigned to the FIRST calibrant ring within a fixed 0.1 1/A, not the
nearest. Silver behenate's orders sit 0.108 1/A apart and hexagonal ice has
three rings inside 0.06, so for those two standards the window reaches the
neighbour and every point lands on the lower-q ring of the pair, biasing the
distance. Take the nearest ring, and clamp the window to half the gap to the
neighbour - which is what the profile path already did inline, now shared as
RingMatchWindow and covered by a test that checks it actually narrows on the
crowded standards and not on LaB6.

A profile bin no pixel fell in is NaN. SectorPeakQ dropped such a sector by
accident, through NaN comparisons falling false; check the four background bins
and return explicitly.

Ice-ring handling is switched off in calibration mode. Flagged spots are sorted
last by the spot budget and so discarded first, which for --calibrant ice
throws away exactly what is being calibrated on.

The two per-ring std::cout lines in GuessGeometry are gone: a library has no
business writing to a terminal, and constructing a Logger to keep them would
emit a version banner from inside a fit. What matched belongs in the result
struct, which the quality gating still to come needs anyway.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NfuDvf5ipV3Hi8TiCUKD27
2026-08-31 16:18:27 +02:00
leonarski_fandClaude Opus 5 fba5435c38 calibration: report what the ring fit knows about its own answer
The ring fit reported the SCATTER of its measurements (rms, and the beam-centre
standard error that follows from it) but nothing about how well the fit pinned
each parameter. Those two part company exactly where a calibration is worth
doubting: as the rings run out, the tilt and the beam centre stop being
separable - both displace a ring's radius as cos(phi) and only the way that
amplitude scales with radius tells them apart - so the fit can sit tightly on
the few points it has while being free to spend tens of pixels of beam centre
on a tilt the data do not support.

Take the covariance of the converged problem from Ceres and report it. Measured
on a LaB6 distance series, the fitted tilt is 50 sigma at 110 mm and 0.1 sigma
at 500 mm, where only two rings reach the detector; at 500 mm the fit quotes its
own beam centre to +-180 px and its tilt to +-2.9 deg on a 0.35 deg value, and
the correlation between them is 1.000. Nothing acts on this yet - it is printed
so the next change can gate on it.

Ceres returns the bare (J'J)^-1 of an unweighted problem, so it is scaled by
chi2 per degree of freedom; that leaves the sigmas in pixels, mm and radians
whatever unit the residual is stated in. Cost is one 5x5 SVD per run, below the
noise of the surrounding I/O.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NfuDvf5ipV3Hi8TiCUKD27
2026-08-31 16:11:18 +02:00
leonarski_fandClaude Opus 5 03456dcddd calibration: an option to hold the detector tilt fixed
--mode calibration fits five parameters - beam centre, distance and the two
PONI tilts - and a program that cannot express a tilted detector has nowhere to
put the last two. Dropping them after the fact is worse than never fitting
them: the centre and the distance of a tilted fit have already absorbed the
tilt, so the flattened geometry is right nowhere.

rugnux --no-refine-tilt, the "Refine detector tilt" tick box on the viewer's
Calib page and RingOptimizer's refine_tilt argument hold rot1/rot2 at the value
the geometry came in with and fit the remaining three. That is the best
flat-detector answer, and the one such a program would refine to itself.

Measured on a five-distance calibrant series. At short distance the tilt is
real and reproducible - three independent fits agreeing to 0.01 deg, radial rms
1.4 -> 0.4 px - and its direct beam agrees with the background beam-centre
estimator to 0.05 px, so the tilted model is the physically right one. The
pinned fit then displaces the centre 2.6 px to absorb the tilt and lands within
0.03 px of the same place at every distance.

Past ~300 mm, where only two rings reach the detector, the tilt is instead
under-determined: it comes out with the opposite sign to every short-distance
fit and drags the PONI 28 px while the rms does not move (0.960 against 0.962).
The existing degeneracy guard only fires on a strictly single ring, so it does
not catch that; declining a tilt that does not pay for itself in rms is left
for a separate change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MxrrPcxodNiXzhNiECCVp5
2026-08-30 20:44:12 +02:00
leonarski_f 538f3504d3 v1.0.0.rc-161 (#71)
Build Packages / build:windows:nocuda (push) Successful in 20m4s
Build Packages / Unit tests (push) Skipped
Build Packages / build:viewer-tgz:cpu (push) Successful in 16m5s
Build Packages / build:viewer-tgz:cuda (push) Successful in 17m26s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 27m46s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 20m17s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 26m13s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 23m17s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 28m11s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 19m30s
Build Packages / build:rpm (rocky8) (push) Successful in 24m34s
Build Packages / build:rpm (rocky9) (push) Successful in 21m30s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 23m33s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 20m18s
Build Packages / DIALS test (push) Successful in 18m23s
Build Packages / XDS test (durin plugin) (push) Successful in 11m30s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 10m16s
Build Packages / XDS test (neggia plugin) (push) Successful in 8m2s
Build Packages / Generate python client (push) Successful in 49s
Build Packages / Build documentation (push) Successful in 1m21s
Build Packages / Create release (push) Skipped
Build Packages / build:windows:cuda (push) Successful in 29m45s
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: significantly better quality of results, and faster.** A large rework of integration, scaling, merging, geometry refinement and space-group determination, together with measurements the program previously made no attempt at - the direct beam before indexing, the beam stop, the goniometer rotation scale, and the stretches of a sweep the crystal did not deliver. A rotation dataset typically gains observations at better <I/sigma> and R_meas, and every `mx` and `scale` run writes a `<prefix>_report.txt` results report modelled on XDS's `CORRECT.LP`. Many defaults moved with it: spot detection is self-calibrating, beam-stop detection and rotation geometry post-refinement are on, resolution limits default to as far as the detector reaches, and ice-ring handling engages only where the crystal is measured to have ice.
* **jfjoch_viewer:** the beam-stop shadow, the detector calibration and the beam-centre measurement are reachable from "Analyze dataset"; the settings panel reports how the sample moved and how polarized the beam was; image rendering and interaction are faster.
* **Performance:** bitshuffle+LZ4 images are decoded on the GPU rather than on the host, with the bitshuffle inverse fused into preprocessing so the decompressed frame is never held in device memory.
* **Broker, writer, packaging and build:** image-slot lifetime and locking fixes, per-image datasets sized by the images actually written, the Debian/Ubuntu broker package renamed to `jfjoch`, and `image_analysis` compiling under MSVC again.

**Breaking change to the rugnux command line:**
* `--azint-only` and `--scale` are **removed**, replaced by `--mode azint` and `--mode scale`; the full pipeline is `--mode mx` and remains the default. A script passing the old flags now fails with the list of valid modes rather than silently running the wrong one.
* `-t`/`--stride` is **refused on rotation data**: skipping frames cuts every reflection's rocking curve, so the combined fulls and their partiality would be measured over frames the sweep never recorded. Select a contiguous range with `-s`/`-e` instead. `--mode azint` and `--force-still` still take a stride.

**Breaking changes to OpenAPI** - regenerate the client (`jfjoch-client` 1.0.0-rc.161, `frontend/src/client`) or read the affected fields as optional:
* `image_scale_b` is removed from the `plot_type` enum, so a client requesting that plot now gets an error rather than a curve.
* `azim_int_settings.high_q_recipA`, `spot_finding_settings.high_resolution_limit` and `spot_finding_settings.low_resolution_limit` are no longer `required`. All three mean "no limit at that end" when unset and are omitted from the response instead of carrying a placeholder value, which raises in a client generated from an rc.160-or-earlier spec. A value of 0 is still accepted and means the same thing.

**Breaking changes to the stored formats** - a consumer reading these fields must treat them as optional:
* The per-image image-scale B factor is no longer computed, so `/entry/MX/imageScaleBFactor` is absent from newly written HDF5 files and the corresponding key is absent from the CBOR DataMessage and END blocks. Files written by rc.160 and earlier still contain it and still open; nothing in the pipeline reads it any more.
* `_reflns.jfjoch_diffrn_ISa` now carries the whole-range `1/sqrt(a*b)` that XDS's ISa denotes, and the error-model `a` and `b` are reported in XDS's convention; the strong-reflection asymptote moves to `_reflns.jfjoch_diffrn_ISa_asymptotic`. **A file written by an earlier version carries the asymptote under the plain `ISa` name.**

Reviewed-on: #71
Co-authored-by: Filip Leonarski <filip.leonarski@psi.ch>
2026-08-13 17:03:10 +02:00
leonarski_f 75e401f0e5 v1.0.0-rc.153 (#63)
Build Packages / Unit tests (push) Successful in 1h31m59s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 8m43s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 10m5s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 9m27s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 8m56s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 9m24s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 10m27s
Build Packages / build:rpm (rocky8) (push) Successful in 9m20s
Build Packages / build:rpm (rocky9) (push) Successful in 10m50s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 9m54s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 8m38s
Build Packages / DIALS test (push) Successful in 12m13s
Build Packages / XDS test (durin plugin) (push) Successful in 7m8s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 7m8s
Build Packages / XDS test (neggia plugin) (push) Successful in 7m50s
Build Packages / Generate python client (push) Successful in 16s
Build Packages / Build documentation (push) Successful in 50s
Build Packages / Create release (push) Skipped
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.

* jfjoch_broker: Add EXPERIMENTAL pixelrefine mode for image processing
* jfjoch_broker: Allow to load user mask from 8-bit and 16-bit TIFF files
* jfjoch_broker: Add ROI calculation in non-FPGA workflow
* jfjoch_broker: Fixes to TCP image pusher
* jfjoch_broker: Remove NUMA bindings
* jfjoch_broker: Improvements to indexing
* jfjoch_broker: For PSI EIGER, trimming energies are taken from the detector configuration (now compulsory) instead of hardcoded values
* jfjoch_writer: Save ROI definitions and the per-pixel ROI bitmap in the master file; azimuthal ROIs support phi (angular) sectors
* jfjoch_viewer: Major redesign with dockable panels and saved layouts, plus on-canvas creation/move/resize of box, circle and azimuthal ROIs
* jfjoch_viewer: Run jfjoch_process reprocessing jobs from inside the GUI and overlay per-run results

Reviewed-on: #63
2026-06-23 20:29:49 +02:00
leonarski_f bb9f5c715f v1.0.0-rc.135 (#44)
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 9m55s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 10m28s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 8m56s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 11m47s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 13m7s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 12m31s
Build Packages / build:rpm (rocky8) (push) Successful in 12m59s
Build Packages / build:rpm (rocky9) (push) Successful in 14m5s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 15m30s
Build Packages / Generate python client (push) Successful in 1m18s
Build Packages / Build documentation (push) Successful in 1m3s
Build Packages / Create release (push) Has been skipped
Build Packages / build:rpm (ubuntu2404) (push) Successful in 10m8s
Build Packages / XDS test (durin plugin) (push) Successful in 9m16s
Build Packages / XDS test (neggia plugin) (push) Successful in 7m59s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 9m12s
Build Packages / DIALS test (push) Successful in 11m44s
Build Packages / Unit tests (push) Successful in 1h23m8s
This is an UNSTABLE release. The release has significant modifications and bug fixes, if things go wrong, it is better to revert to 1.0.0-rc.132.

* Multiple small bug fixes scattered across the whole code base. (detected with GPT-5.4)
* jfjoch_viewer: Improve image render performance

Reviewed-on: #44
Co-authored-by: Filip Leonarski <filip.leonarski@psi.ch>
Co-committed-by: Filip Leonarski <filip.leonarski@psi.ch>
2026-04-16 11:59:59 +02:00
leonarski_f 8b356a7001 v1.0.0-rc.96 (#1)
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 7m47s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 7m20s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 8m13s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 7m10s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 7m53s
Build Packages / build:rpm (rocky8) (push) Successful in 7m57s
Build Packages / Generate python client (push) Successful in 13s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 7m39s
Build Packages / Create release (push) Has been skipped
Build Packages / Build documentation (push) Successful in 36s
Build Packages / build:rpm (rocky9) (push) Successful in 9m0s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 6m55s
Build Packages / Unit tests (push) Successful in 1h10m44s
This is an UNSTABLE release.

* Fixes in CI pipeline
* jfjoch_broker: Remove PNG preview, no dependency on libpng
* jfjoch_writer: Fix UTC timestamp being generated wrong (mix between milli- and microseconds)
* jfjoch_viewer: Show data collection time in dataset tooltip
* jfjoch_viewer: Allow to choose the calibrant (presets for LaB6 and silver behenate)
* jfjoch_viewer: Auto foreground value
* Use external libjpeg-turbo and libtiff: simpler build stack, these are built and linked statically in automated Docker builds
* Remove OpenBLAS dependency

Reviewed-on: #1
Co-authored-by: Filip Leonarski <filip.leonarski@psi.ch>
Co-committed-by: Filip Leonarski <filip.leonarski@psi.ch>
2025-11-02 13:45:57 +01:00
leonarski_f c67337cfe1 v1.0.0-rc.72 2025-09-08 20:28:59 +02:00
leonarski_f bb32f27635 v1.0.0-rc.70 2025-08-27 06:21:10 +02:00