v1.0.0-rc.156 #66

Open
leonarski_f wants to merge 64 commits from 2606-rc.156-fixes into main
Owner

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_process: Major rotation (rot3d) data processing overhaul - robust profile-fit integration, Cauchy-loss scaling with optional absorption surface, de-novo indexing and space-group/centering determination fixes, and merging statistics + ISa in the mmCIF output.
  • jfjoch_process: Add EXPERIMENTAL ice-ring detection (--detect-ice-rings) that excludes ice reflections from scaling.
  • Compression: Add BSHUF_ZSTD_RLE_HUFF, make compression size-aware (drop frames that don't fit rather than aborting), and add the jfjoch_recompress tool.
  • jfjoch_viewer: Report "Multiple lattices detected" and grey out "Analyze dataset" on a live connection.
  • jfjoch_broker: Write smargon chi/phi goniometer positions to NXmx; read sensor thickness/material from HDF5 metadata.
  • CI: Build Windows (CUDA and non-CUDA) installers.
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_process: Major rotation (rot3d) data processing overhaul - robust profile-fit integration, Cauchy-loss scaling with optional absorption surface, de-novo indexing and space-group/centering determination fixes, and merging statistics + ISa in the mmCIF output. * jfjoch_process: Add EXPERIMENTAL ice-ring detection (--detect-ice-rings) that excludes ice reflections from scaling. * Compression: Add BSHUF_ZSTD_RLE_HUFF, make compression size-aware (drop frames that don't fit rather than aborting), and add the jfjoch_recompress tool. * jfjoch_viewer: Report "Multiple lattices detected" and grey out "Analyze dataset" on a live connection. * jfjoch_broker: Write smargon chi/phi goniometer positions to NXmx; read sensor thickness/material from HDF5 metadata. * CI: Build Windows (CUDA and non-CUDA) installers.
leonarski_f added 64 commits 2026-07-01 22:00:16 +02:00
Dataset re-processing reads a stored HDF5 file, so it is unavailable for
the live HTTP stream. Disable the "Analyze dataset" hero button while a
source is connected (with an explanatory tooltip) instead of letting the
user click through to a "open a file first" dialog afterwards.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Space-group search (image_analysis/scale_merge/SearchSpaceGroup):
- Two-stage POINTLESS-style determination. Stage A scores each distinct rotation
  operator once (was once per candidate space group, ~34x faster on lysozyme:
  ~26s -> <1s) and picks the largest point group all of whose operators confirm.
  Stage B picks the maximal space group whose predicted absences are confirmed
  weak, fixing the prototype's default to the symmorphic group (it returned P422
  instead of P4(3)2(1)2). Enantiomorphic / origin-ambiguous pairs (P4(1) vs P4(3),
  I222 vs I2(1)2(1)2(1)) are reported as indistinguishable.
- Constrain candidates to subgroups of the lattice (metric) holohedry and weigh
  centering only P-vs-metric, fed from rotation indexing's LatticeSearch result.

Integration / pipeline:
- With no user-fixed space group, predict in P (IndexAndRefine) so the
  centering-absent reflections are integrated and the search can confirm/deny
  centering (catching pseudo-centering / a missed superstructure) instead of
  trusting the metric; a user-fixed group still rejects absences in integration.
- JFJochProcess: scale+merge in P1 -> determine the space group -> set it and
  re-scale+merge in it (statistics then come out in the right symmetry) -> write
  it to /entry/sample/space_group_number (new EndMessage.space_group_number,
  preferred by NXmx::Sample). jfjoch_scale no longer searches; it consumes the
  file's space group (and no longer clobbers it with an empty -S).

Twinning (new image_analysis/scale_merge/TwinningAnalysis): Padilla-Yeates L-test
(<|L|>, <L^2>; acentric-only, positive intensities so L is bounded) plus a
shell-normalised <I^2>/<I>^2 second moment and a twin-fraction estimate. Reported
after the final merge in jfjoch_process and jfjoch_scale, and surfaced in the
jfjoch_viewer merge-statistics window with a red outline when twinning is suspected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Drop oversized-metadata frames instead of aborting the collection
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 13m55s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 14m54s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 15m1s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 15m11s
Build Packages / build:rpm (rocky8) (push) Successful in 15m6s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 15m16s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 15m58s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 7m52s
Build Packages / XDS test (durin plugin) (push) Successful in 8m9s
Build Packages / Generate python client (push) Successful in 29s
Build Packages / Create release (push) Skipped
Build Packages / XDS test (neggia plugin) (push) Successful in 8m8s
Build Packages / Build documentation (push) Successful in 59s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 11m17s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 12m12s
Build Packages / DIALS test (push) Successful in 12m20s
Build Packages / build:rpm (rocky9) (push) Successful in 13m38s
Build Packages / Unit tests (push) Successful in 1h0m37s
2398330e52
A serial-crystallography run on a detector with a large converted geometry
(JF17T16, modules tiled vertically + horizontally) aborted with
"Array out of bounds (Not enough memory to save image)". An indexed still on
such a detector predicts/integrates close to the kMaxReflections (10000) cap;
at ~170 B per serialized Reflection that is ~1.7 MB of per-image CBOR metadata,
which overflowed the fixed 1 MB the buffer slot reserved on top of the image.
The serialization guard then threw and cancelled the whole run.

- Raise the per-image metadata headroom from 1 MB to 4 MB
  (GetImageBufferLocationSize). The worst case - 10000 reflections + 2000 spots
  (API max) + 65534 azimuthal bins - serializes to 2.78 MB, leaving margin while
  staying negligible next to the multi-MB image slot.
- When metadata still does not fit, drop just that frame (log metadata/image/slot
  sizes + recycle the slot) instead of aborting, in both the FPGA and Lite
  receivers.
- Add a regression test asserting the worst-case metadata fits the headroom.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
JFJochBitShuffleCompressor::Compress now takes a dest_size and returns a
negative value when the compressed output would not fit, instead of writing
past the destination buffer. The check is lazy: before each block it verifies
the remaining space still covers that block's worst case (mirrored by the new
MaxCompressedBlockSize helper, consistent with MaxCompressedSize so a dest
sized to MaxCompressedSize never fails). On overflow the dest content is
undefined - no rescue.

The receiver uses this to compress directly into the writer buffer slot and
drop just the oversized frame instead of pre-reserving the full worst-case
image size next to the per-image CBOR metadata.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Compressor: bump bitshuffle block size 4096 -> 16384 elements
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 14m4s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 14m42s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 14m52s
Build Packages / build:rpm (rocky8) (push) Successful in 14m50s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 15m0s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 15m34s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 15m42s
Build Packages / XDS test (durin plugin) (push) Successful in 8m25s
Build Packages / Generate python client (push) Successful in 31s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 8m32s
Build Packages / Create release (push) Skipped
Build Packages / XDS test (neggia plugin) (push) Successful in 8m17s
Build Packages / Build documentation (push) Successful in 59s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 11m12s
Build Packages / build:rpm (rocky9) (push) Successful in 12m52s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 12m22s
Build Packages / DIALS test (push) Successful in 13m0s
Build Packages / Unit tests (push) Successful in 59m47s
Build Packages / build:windows (push) Failing after 12m51s
aadba5b343
On sparse lyso frames the larger block improves compression ratio across all
bshuf algorithms (16-bit data): ZSTD 8.58 -> 9.30, LZ4 7.38 -> 7.58, RLE
6.82 -> 6.90. 16384 captures most of the gain available from even larger
blocks (ZSTD tops out ~9.55 at 65536) while staying close to the cache sweet
spot: the cheap codecs (LZ4, RLE) peak in throughput once a block's working
set fits L1d (~4096 elem here), so very large blocks trade real throughput for
diminishing ratio - and that penalty is worse on the Xeon Gold/Platinum
production hosts (smaller private L2, shared-L3 contention under many parallel
compression threads).

The block size is stored per-dataset in the bitshuffle HDF5 filter params, so
existing readers (XDS/Neggia/Durin/CrystFEL) stay compatible.

Move the per-block bitshuffle scratch off the inline member array onto a
lazily-sized heap vector, like tmp_space, so the block size no longer bloats
every stack-allocated compressor (incl. the transient ones in
CBORStream2Serializer).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the fixed-element DefaultBlockSize with a byte target divided by
elem_size to get the block element count, so the per-block working set (and
thus cache behaviour) stays constant across pixel bit depths instead of halving
from 8- to 16- to 32-bit. The target is per-algorithm, following the measured
sweet spots on sparse data: LZ4 wants a small, cache-resident block for
throughput (16 kB), ZSTD/RLE want a large block for ratio (128 kB). The gap is
widest on extreme-sparsity inputs such as the uint32 pixel_mask, where
large-block ZSTD reaches 100-1800x vs ~160x for LZ4.

The block size is read back per-dataset from the bitshuffle stream header
(block_size = header_bytes / elem_size) and the HDF5 filter params, so the
decompressor and external readers (XDS/Neggia/Durin/CrystFEL) need no change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Compress() and FrameTransformation::CompressImage() returned int64_t with a
negative value meaning "did not fit". That is a footgun: the negative result
silently converts to a huge size_t if a caller forgets to check it. Return
size_t and instead throw a named CompressionBufferTooSmallException (deriving
from JFJochException, Compression category) when the output would not fit the
destination buffer.

The receiver catches it explicitly and drops just that frame, as before; the
offline/GetCompressedImage path uses a worst-case buffer so it never throws.
Add a test that a too-small destination throws and a worst-case buffer does not.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
New CompressionAlgorithm that emits a standard Zstandard frame: zero/0xFF runs
become RLE_Blocks (like BSHUF_ZSTD_RLE) and literal regions become
Compressed_Blocks with per-block adaptive Huffman literals and no sequences
(Number_of_Sequences=0). Short runs are absorbed into the literal stream;
incompressible literals fall back to Raw_Blocks so the worst case stays within
ZSTD_compressBound.

The Huffman tree + bitstream are produced by zstd's own HUF_compress{1,4}X_repeat
(the same calls ZSTD_compressLiterals uses); only the frame/block/literals-section
framing is hand-written, with comments citing zstd_compression_format.md so it can
be checked clause by clause. Output decodes with stock ZSTD_decompress, so no
reader changes are needed (decode routes like BSHUF_ZSTD).

On sparse diffraction this gives ~12% smaller files than bitshuffle/LZ4 at about
the same end-to-end speed, sitting between LZ4 and full ZSTD; for maximum ratio
use BSHUF_ZSTD. Robust on any input: tests round-trip pure zeros, Poisson(10),
Mersenne-Twister noise (checked against the size bound), an extreme-sparsity mask,
and a real lyso image through stock ZSTD_decompress.

API: exposed as "bszstd_rlehuf"; regenerate the Python/TS clients (update_version.sh)
to surface the new value there.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Builds a single Compressed_Block (Huffman-coded Literals_Section, empty
Sequences_Section) and checks: the block type is Compressed, its trailing
Number_of_Sequences byte is 0, and stock ZSTD_decompress reconstructs the
literals exactly. This is the format guarantee from zstd_compression_format.md
("if Number_of_Sequences == 0 ... Block's decompressed content is defined solely
by the Literals Section content"), locked into the test suite.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Regenerate OpenAPI clients for bszstd_rlehuf compression value
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 13m54s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 14m31s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 14m51s
Build Packages / build:rpm (rocky8) (push) Successful in 14m49s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 15m5s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 15m5s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 15m48s
Build Packages / XDS test (durin plugin) (push) Successful in 7m55s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 7m50s
Build Packages / Generate python client (push) Successful in 34s
Build Packages / Create release (push) Skipped
Build Packages / Build documentation (push) Successful in 1m10s
Build Packages / XDS test (neggia plugin) (push) Successful in 8m36s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 11m7s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 12m1s
Build Packages / build:rpm (rocky9) (push) Successful in 13m7s
Build Packages / DIALS test (push) Successful in 12m45s
Build Packages / Unit tests (push) Successful in 1h14m59s
Build Packages / build:windows (push) Successful in 18m31s
809f6f92a3
update_version.sh regenerated the TypeScript client (types.gen.ts, zod.gen.ts)
and Redoc docs to include the new "bszstd_rlehuf" compression enum value added
to jfjoch_api.yaml; the package-lock version field follows VERSION. The C++
server model treats compression as a plain string, so it needed no change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
tools: add jfjoch_recompress (bitshuffle/LZ4 -> bitshuffle/zstd)
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 12m47s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 13m3s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 13m36s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 13m32s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 13m43s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 14m29s
Build Packages / XDS test (durin plugin) (push) Successful in 8m12s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 11m18s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 11m26s
Build Packages / Generate python client (push) Successful in 15s
Build Packages / build:rpm (rocky8) (push) Successful in 12m46s
Build Packages / Create release (push) Skipped
Build Packages / Build documentation (push) Successful in 45s
Build Packages / build:rpm (rocky9) (push) Successful in 13m24s
Build Packages / DIALS test (push) Successful in 13m10s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 6m58s
Build Packages / XDS test (neggia plugin) (push) Successful in 5m53s
Build Packages / Unit tests (push) Successful in 59m15s
Build Packages / build:windows (push) Successful in 18m58s
f261adf42a
New offline tool that re-compresses /entry/data/data of a _data_NNNNNN.h5 file
from bitshuffle/LZ4 to the standard bitshuffle/Zstd HDF5 filter. Every other
object (groups, datasets, attributes, the dataset's own attributes,
dims/dtype/chunking/block size) is reproduced unchanged.

It writes a fresh file - only /entry/data/data is re-encoded, every other object
is H5Ocopy'd verbatim - which then atomically replaces the original via rename().
This needs no h5repack (the new file has no leftover space) and is crash-safe
(the original is opened read-only until the rename). Frames are streamed one at a
time through the registered bitshuffle filter (decompress LZ4, compress Zstd), so
it is dtype-agnostic and never holds the whole dataset in memory.

Output is read by the standard bitshuffle+zstd HDF5 plugin (verified against the
hdf5plugin/DIALS libh5bshuf.so, which links libzstd and supports the zstd mode).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The rot3d combine over-extrapolates fulls reconstructed from only a fraction f
of their rocking curve (min_partiality admits f as low as 0.02). Against XDS on
HEWL these low-capture fulls are systematically biased HIGH (+15% at f=0.8 to
+100% at f=0.3), and the bias - not random scatter - is the strong-reflection
floor that hurts anomalous accuracy.

--capture-uncertainty <coeff> (default 0 = off, baseline bit-identical) adds a
systematic uncertainty ~coeff*(1-f)*I to each full's sigma, so the merge
down-weights the over-extrapolated fulls and the error model treats their
scatter as expected. Unlike outlier rejection (which trades accuracy for CC1/2),
this fixes a real bias, so accuracy improves: at coeff=1.0 the anomalous peak
height vs XDS rises CL_CL +16%, SD_MET/SG_CYS +5-6%, ISa 10.7->11.0. Rotation-
only (no-op for stills, which never combine).

Also expose the per-image scale offline: Combine3D now carries the first-pass
per-image scale metadata (G, B, mosaicity, wedge, CC) forward instead of
dropping it, and jfjoch_process -M writes <prefix>_image.dat from it (the
offline self-scaling result was otherwise unobservable - process.h5's per-image
arrays are only filled on the online path). This enabled the XDS DECAY
comparison (jfjoch G tracks XDS, r=0.93).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The rotation per-image mosaicity was ~3x too small (0.045 vs the true 0.13deg),
which crippled the partiality model and capped per-observation precision: it
predicted reflections on too few frames and over-peaked the rocking partiality,
so the rot3d-combined fulls were ~1.7x noisier than XDS's, the integration
bottleneck behind the jungfraujoch-vs-XDS ISa gap.

Two root causes, both fixed:
- CalcMosaicityXDS (Kabsch-2010 MLE) searched each spot's exact-Bragg phi only
  within +-wedge (the 0.2deg oscillation). Reflections recorded at larger rocking
  offset - the tail that defines the mosaic width - fell outside and were dropped,
  truncating the tau distribution so the MLE underestimated ~2x. Widen the search
  window to wedge+0.8deg; the MLE then converges to the true 0.13deg (and is
  insensitive to widening further, since it weights by the recorded fraction).
- ScaleOnTheFly then re-refined the mosaicity from the intensity residual, which
  is degenerate with the per-image scale G and collapses it toward its floor.
  Trust the (now correct) indexing mosaicity and keep it fixed during scaling.

With the correct mosaicity, --capture-uncertainty (which down-weights the
over-extrapolated under-captured fulls) now pays off strongly, so default it ON
(1.0) for the rot3d combine; it stays off for non-rot3d. Together on the HEWL
rotation crystal: ISa 10.7 -> 19.1, and anomalous peak height vs XDS goes from
52% to ~78% (CL_CL 1.92x -> 1.29x). This reaches XDS's own published-correction
ceiling (DECAY+ABSORP+MODPIX ~= 19.6); the remaining gap to its quoted ISa 28 is
the I->inf extrapolation. No effect on the stills path (rotation-only code).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The profile radius (intrinsic excitation-error width = mosaicity + divergence)
was the plain RMS of dist_ewald over indexed spots. With a finite energy
bandwidth that spread is broadened by the bandwidth's radial smear
sigma_bw = bandwidth_sigma*lambda/(2 d^2), which prediction then re-applies per
reflection - so bandwidth was counted twice and the radius was inflated (most at
high resolution, sigma_bw ~ 1/d^2). Subtract the bandwidth variance from the
measured spread so the radius is the intrinsic width. bandwidth = 0
(monochromatic / rotation) is unchanged. Small for narrow bandwidths (~6% of the
variance, ~4% radius on the 1% jet); matters for wide-bandwidth / pink beam.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Document the rot3d path that was missing: a new section on combining a
reflection's per-frame partials into one full (de-biased weighted combine,
captured fraction, capture-aware systematic uncertainty, XDS-order full
re-scaling) so the merge sees counting statistics instead of rocking-curve
slicing. Recast the profile-radius and mosaicity sections as what the system
does - profile radius as the intrinsic (bandwidth-deconvolved) width, mosaicity
by ML with a search window wide enough to capture the rocking tail and held
fixed during scaling - rather than the optimisation narrative.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The default 2D Bragg integrator is ProfileIntegrate2D (Kabsch profile fit with a
per-resolution-shell Gaussian profile and de-biased variance), with box summation
as the seed/fallback (--integrator boxsum|gaussian|empirical). Section 9 and the
section 13 note both still claimed integration was summation-only with no profile
fitting; rewrite them to describe the profile-fit default.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Weak high-resolution still reflections were systematically over-subtracted: a
bandwidth-streaked high-res spot (or a neighbour) leaks into the r2-r3 background
annulus and biases its mean high, so the subtracted background is too large and
the merged high-resolution intensities go negative (seen as reproducibly negative
<I/sig> at 100% completeness and high multiplicity past ~1.9 A).

Add one high-outlier sigma-clip pass to the box-sum background (reject ring pixels
above mean + 3*sqrt(mean), recompute) so the contamination no longer inflates it.
A clean Poisson background is essentially unchanged (~0.1% exceed the cut). On the
HEWL serial-stills jet this de-biases the high-res band - <I/sig> 2.03 A 0.9 -> 1.6,
1.79 A -0.1 -> +0.7 - extends the usable resolution ~2.2 -> ~2.0 A and improves
overall R-meas 130 -> 124%, with CC1/2 and CC-vs-reference neutral. The rotation
crystal is unchanged (ISa 19.1), its clean backgrounds being barely clipped.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
With a finite energy bandwidth each reflection is smeared RADIALLY by
sigma_bw = bandwidth_sigma * R_px (R_px = distance from the beam centre, so large
at high resolution): high-resolution spots become radial streaks. The isotropic
per-shell Gaussian both mis-weights them and clips the streak tail on the fixed
profile grid, losing intensity (biased low, noisy).

When a bandwidth is set, fit each reflection with a per-reflection Gaussian
elongated only along its radial direction - sigma^2_radial = sigma^2_intrinsic +
sigma_bw^2, sigma^2_tangential = sigma^2_intrinsic - on a grid grown to hold the
streak. Unlike an isotropic widening this adds no tangential background. It only
engages where the smear exceeds the intrinsic spot (high resolution); low/mid
resolution and monochromatic data (bandwidth 0, e.g. rotation) are untouched.

On the HEWL serial-stills jet (with the background sigma-clip) this lifts the
overall CC-vs-reference 52 -> 55% and the high-resolution I/sig (1.7 A 0.5 -> 1.4),
recovering the 2.0-2.5 A band, with CC1/2 preserved (the per-shot noise the wider
region adds is averaged out by the high serial multiplicity). Rotation ISa 19.1
unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
CI: Build Windows non-CUDA installer
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 13m10s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 14m42s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 14m58s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 15m12s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 15m15s
Build Packages / build:rpm (rocky8) (push) Successful in 15m11s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 15m30s
Build Packages / XDS test (neggia plugin) (push) Successful in 8m39s
Build Packages / Generate python client (push) Successful in 14s
Build Packages / XDS test (durin plugin) (push) Successful in 9m34s
Build Packages / Create release (push) Skipped
Build Packages / XDS test (JFJoch plugin) (push) Successful in 9m30s
Build Packages / Build documentation (push) Successful in 51s
Build Packages / build:rpm (rocky9) (push) Successful in 13m7s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 11m48s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 11m47s
Build Packages / DIALS test (push) Successful in 13m23s
Build Packages / Unit tests (push) Successful in 1h13m49s
Build Packages / build:windows:nocuda (push) Failing after 13m47s
Build Packages / build:windows:cuda (push) Failing after 13m47s
a0856e1042
merge: de-bias the error-model variance fit (chi^2 was ~2.2, now ~1) and report chi^2
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 12m52s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 13m8s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 13m26s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 13m34s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 13m59s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 14m17s
Build Packages / XDS test (durin plugin) (push) Successful in 7m40s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 10m46s
Build Packages / build:rpm (rocky8) (push) Successful in 12m32s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 12m11s
Build Packages / Generate python client (push) Successful in 16s
Build Packages / Create release (push) Skipped
Build Packages / build:rpm (rocky9) (push) Successful in 13m2s
Build Packages / Build documentation (push) Successful in 42s
Build Packages / DIALS test (push) Successful in 13m38s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 7m9s
Build Packages / XDS test (neggia plugin) (push) Successful in 5m44s
Build Packages / Unit tests (push) Successful in 57m53s
Build Packages / build:windows:nocuda (push) Successful in 16m26s
Build Packages / build:windows:cuda (push) Successful in 18m26s
107bcae0f0
RefineErrorModel fits the variance model a*sigma^2 + (b*<I>)^2 to the binned
*median* of the squared symmetry-mate deviations, chosen for robustness. But a
single deviation squared over its variance is chi-square(1)-distributed, whose
median is only 0.4549 of its mean, so the fit was calibrating the variances to
0.4549x their true value: the merged sigmas came out ~1.48x too small and the
achieved reduced chi^2 was 1/0.4549 = 2.2, not 1. The error model was internally
well-behaved (flat chi^2 across resolution) but globally over-confident, which
inflated ISa (=1/b) by ~1.48x and made the exported sigmas too optimistic for
downstream weighting / French-Wilson.

Divide the binned median by the chi-square(1) median (0.4549) to recover an
unbiased estimate of the mean E[dev^2]=sigma^2, keeping the robustness of the
median while targeting reduced chi^2 = 1. Also compute the achieved median
reduced chi^2 (same normalization) and report it on the "Error model" line so
mis-calibration can no longer drift silently.

Verified: HEWL rotation a 0.588->1.292, b 0.052->0.077, ISa 19.1->12.9, chi^2
2.17->1.06; serial Jet8 ISa 1.0->0.7, chi^2 0.92. Relative ISa comparisons and
all CC1/2/CCref/anomalous metrics are unchanged (sigma-independent or a common
constant); only the absolute sigma calibration is corrected.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
space group: determine centering from absences; jfjoch_process re-indexes from scratch
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 14m5s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 14m29s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 14m41s
Build Packages / build:rpm (rocky8) (push) Successful in 14m46s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 14m59s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 15m13s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 15m29s
Build Packages / XDS test (durin plugin) (push) Successful in 7m54s
Build Packages / Generate python client (push) Successful in 30s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 8m12s
Build Packages / Create release (push) Skipped
Build Packages / XDS test (neggia plugin) (push) Successful in 8m23s
Build Packages / Build documentation (push) Successful in 1m8s
Build Packages / build:windows:nocuda (push) Failing after 25m35s
Build Packages / build:windows:cuda (push) Failing after 25m35s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 11m12s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 12m2s
Build Packages / build:rpm (rocky9) (push) Successful in 12m45s
Build Packages / DIALS test (push) Successful in 12m52s
Build Packages / Unit tests (push) Successful in 59m5s
02477f1ce4
Fixes wrong space-group assignment on cubic insulin (true I2_13, a=77.6).

SearchSpaceGroup: drop the lattice-centering gate (and the now-unused
lattice_centering option). The indexer often returns the conventional cell,
whose geometry hides I/F/C centering - that information lives only in the
systematic absences. Stage B now tests every centering of the point group and
confirms it from the data, so an indexer-reported 'P' no longer excludes
I2_13/I23. (I23 and I2_13 remain indistinguishable by absences and are reported
as such.)

jfjoch_process: discard any unit cell stored in the input HDF5 by default so the
cell is re-determined from scratch. A stale/wrong stored cell otherwise resolves
the indexing algorithm to FFBIDX, which trusts that cell and locks onto the wrong
lattice (Ins_I_3 went from 2.7% -> 76% indexing). A user-supplied -C cell still
applies.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ScaleOnTheFly fits each frame's scale G independently with no neighbour
coupling, so the few partials of one rocking event are weight-summed in
combine3D on inconsistent scales - jitter that never enters the full's
counting sigma and instead surfaces as scatter between symmetry mates,
inflating the error-model b (low ISa). A centered moving average of
log(G) over a small frame window (default 9, on for rot3d) removes it,
mirroring XDS's smooth scaling. Complementary to --scale-fulls (which
rescales between fulls, after the combine): smoothing fixes within-event
scale, scale-fulls fixes between-full.

On the rotation lysozyme set (1.4A, merged, with --scale-fulls): ISa
11.7 -> 15.0, R_meas 10.0% -> 8.3%, CCref stable, chi2 ~0.97 (honest).
Anomalous (full-res): ANODE S-peak 0.61x -> 0.80x of XDS.

--smooth-g[=window] tunes/disables it (=0 off); --mosaicity <deg> is a
diagnostic that fixes the scaling mosaicity for sweeps.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
integration: gate the background-ring sigma-clip to stills (bandwidth>0)
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 13m41s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 15m4s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 15m5s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 15m5s
Build Packages / build:rpm (rocky8) (push) Successful in 15m12s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 15m22s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 15m58s
Build Packages / XDS test (neggia plugin) (push) Successful in 8m9s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 9m12s
Build Packages / Generate python client (push) Successful in 21s
Build Packages / Create release (push) Skipped
Build Packages / XDS test (durin plugin) (push) Successful in 9m17s
Build Packages / Build documentation (push) Successful in 48s
Build Packages / build:rpm (rocky9) (push) Successful in 12m57s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 11m39s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 12m20s
Build Packages / DIALS test (push) Successful in 13m15s
Build Packages / build:windows:nocuda (push) Successful in 16m12s
Build Packages / Unit tests (push) Successful in 1h0m33s
Build Packages / build:windows:cuda (push) Successful in 18m12s
bbd888dcc3
The 76e88b0f sigma-clip (reject ring pixels above mean+3*sqrt(mean))
de-biases bandwidth-streaked high-resolution stills, but it ran on all
data. On rotation (no streaks) it clips legitimate high background pixels
and biases the mean low, slightly inflating weak intensities and hurting
the anomalous signal. Gate it to bandwidth>0 (stills), matching how the
814dff34 radial-profile change is already gated.

Rotation lysozyme (self-scaled, smooth-g, -A): anomalous S-peak 0.84x ->
0.86x of XDS (SD_MET 11.71 -> 11.94, CL_CL 1.28x -> 1.25x), ISa unchanged.
Stills (bandwidth set) are byte-identical (clip still applies).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ProfileIntegrate2D::BoxSum now excludes every predicted reflection's r2 disk
from the r2..r3 background annulus (mirroring BraggIntegrate2D), so a neighbour
Bragg peak can no longer bias a reflection's background high and over-subtract.
With neighbours excluded the annulus can safely widen, so the default r_3 goes
8 -> 10 (more background pixels, lower-variance estimate).

Measured (rotation lyso @1.0 A, external CCref/CCxds vs XDS): 1.05 A CCref +1.3
/ CCxds +1.3, R-meas -5 pts, low-res R-meas unchanged. Serial (Jet8 @0.0002
bandwidth): 1.68 A CC1/2 +3.9 / CCref +1.1, 1.58 A +4.0 / +1.6.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Each partial subtracted its own independently-estimated per-frame background,
so a weak full assembled from N frames accumulated one background-estimation
variance per frame. The true background is flat over the few frames of one
rocking event, so replace each partial's background by the event mean and
correct its intensity by n_bkg*(bkg - pooled), where n_bkg = (sigma^2 - I)/bkg
is the effective background-pixel count -- correct for weak AND strong
reflections (sigma^2/bkg would over-count strong ones and over-correct them).
Single-frame events are a no-op.

Measured (rotation lyso @1.0 A): 1.05 A CC1/2 81.3 -> 83.0, R-meas 81.4 ->
77.2, CCref +0.2, CCxds +0.3; overall R-meas 10.0 -> 9.4%; ISa preserved (13.5).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
S.S0 = |S||S0| cos(2theta), so dividing the rocking rate |m2 . (S x S0)| by it
added a spurious 1/cos(2theta) factor (1.0 at low res, 1.8x at 1 A) to the
reciprocal Lorentz, hence to the absolute/Wilson scale. Divide by |S||S0| to get the correct zeta*sin(2theta) (times a constant 1/lambda^2 the overall scale
absorbs). The spurious factor depends on 2theta only, so it cancels within a
resolution shell and between symmetry mates -- CC1/2, CCref and R-meas are
metric-neutral -- but it corrupts the absolute scale and destabilises the
per-image B-factor and cross-resolution error model. CPU and GPU kernels.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
HDF5MetadataSource ignored /entry/instrument/detector/sensor_thickness and
sensor_material and left the DetectorSetup default (320 um, Si). Read them when
present (NXmx stores thickness in metres), so reprocessing honours the recorded
sensor -- which the parallax/absorption model needs. (The acquisition path still
records the 320 um default because DetDECTRIS sets no per-model thickness; that
is a separate, acquisition-side fix.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
broker: don't clobber sensor thickness/material with the API default
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 14m41s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 15m32s
Build Packages / build:rpm (rocky8) (push) Successful in 15m27s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 15m37s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 15m46s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 15m54s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 16m1s
Build Packages / XDS test (neggia plugin) (push) Successful in 7m38s
Build Packages / XDS test (durin plugin) (push) Successful in 8m7s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 8m7s
Build Packages / Create release (push) Skipped
Build Packages / Generate python client (push) Successful in 26s
Build Packages / Build documentation (push) Successful in 57s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 11m22s
Build Packages / build:rpm (rocky9) (push) Successful in 12m20s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 12m17s
Build Packages / DIALS test (push) Successful in 12m43s
Build Packages / Unit tests (push) Successful in 59m55s
Build Packages / build:windows:nocuda (push) Failing after 14m5s
Build Packages / build:windows:cuda (push) Failing after 14m5s
b51036ad30
JFJochBrokerParser set SensorThickness_um / SensorMaterial unconditionally from
the request's Detector model, but that model defaults them to 320 um / Si with
IsSet=false. So any start request that didn't explicitly carry the sensor
overwrote the detector-reported value (DECTRIS SIMPLON read) or the
detector-specific default with 320 um -- the "PILATUS4 ends up 320 um" symptom.
Guard both with the IsSet flag, mirroring highVoltageV just above. The
receiver -> FillMessage -> CBOR -> writer chain was already correct; the value
was simply wrong at the source.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
integration: de-contaminate the profile width, add a radial parallax ellipse
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 13m30s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 14m44s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 14m45s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 14m46s
Build Packages / build:rpm (rocky8) (push) Successful in 15m1s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 15m20s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 15m25s
Build Packages / XDS test (durin plugin) (push) Successful in 9m46s
Build Packages / XDS test (neggia plugin) (push) Successful in 9m25s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 9m44s
Build Packages / Create release (push) Skipped
Build Packages / Generate python client (push) Successful in 16s
Build Packages / build:rpm (rocky9) (push) Successful in 11m47s
Build Packages / Build documentation (push) Successful in 52s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 13m0s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 13m27s
Build Packages / DIALS test (push) Successful in 14m10s
Build Packages / Unit tests (push) Successful in 59m3s
Build Packages / build:windows:cuda (push) Successful in 16m54s
Build Packages / build:windows:nocuda (push) Successful in 15m18s
26901da42f
The profile-fit width came from the full 13x13 second moment, which runs 3-8x
wider than the true spot: neighbour reflections leak into the (unmasked) learning
grid -- catastrophic at low res where spots crowd the beam -- and the far corners
(lever arm dx^2+dy^2 up to 72) add rectified background noise. Splitting the spot
moment into radial vs tangential shows the tangential width is isotropic
(mosaicity/divergence) while the radial excess is pure sensor parallax ~tan^2(2th).

- Measure the width over the signal disk r1 on the monochromatic path (inherently
  excludes neighbours, caps the radial tail); keep the generous full-grid width on
  the broadband/stills path (sparse spots, the centroid-undersampling floor).
- Extend the (was bandwidth-only) radial ellipse with an analytic, material-aware
  parallax term c_par*tan^2(2theta), c_par = Var(z)/pixel^2 from sensor thickness +
  material + energy (parallax_var_px2; Si and CdTe), plus a fixed weak-spot capture
  term on the monochromatic path only.

HEWL rotation @1.0A: ISa 13.5->15.7, CC1/2 1.12A 91.3->95.9 / 1.05A 83.0->85.2,
external CCref band 88.1->89.9, CCxds 93.4->94.8, R-meas 9.4->8.7; low/mid flat.
Sharp serial stills gain slightly from parallax; broadband stills neutral.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
integration: centre the profile on the predicted sub-pixel position
Build Packages / Unit tests (push) Successful in 58m42s
Build Packages / build:windows:cuda (push) Successful in 18m14s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 13m7s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 14m4s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 13m30s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 12m44s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 13m26s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 14m25s
Build Packages / build:rpm (rocky8) (push) Successful in 21m46s
Build Packages / build:rpm (rocky9) (push) Successful in 13m20s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 12m15s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 11m20s
Build Packages / DIALS test (push) Successful in 12m40s
Build Packages / XDS test (durin plugin) (push) Successful in 8m12s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 9m37s
Build Packages / XDS test (neggia plugin) (push) Successful in 6m23s
Build Packages / Generate python client (push) Successful in 30s
Build Packages / Build documentation (push) Successful in 1m11s
Build Packages / Create release (push) Skipped
Build Packages / build:windows:nocuda (push) Successful in 9m59s
5ba5fe8ad1
The profile was learned and applied on the integer pixel round(predicted), so a
shared profile sits up to 0.5 px off the true spot (and stacking spots with random
sub-pixel offsets broadens the learned profile). Build the Gaussian per reflection
instead, centred on the predicted sub-pixel offset -- noise-free geometry, unlike the
observed centroid, which hurt -- and elongated radially as before.

HEWL rotation @1.0A: ISa 15.7->16.2, CCref band 89.9->90.0, CCxds 94.8->95.0 (high-res
1.00A CCref 66.0->66.9); sharp serial stills 1.68A CC1/2 61.6->62.5; anomalous S peak
0.92x XDS (no accuracy traded). De-broadening the learned width by the 1/12 px^2/axis
integer-binning floor was tested and rejected (it over-narrows).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
integration: add --reciprocal-profile dial (global reciprocal-space width)
Build Packages / Unit tests (push) Successful in 59m53s
Build Packages / build:windows:nocuda (push) Successful in 18m24s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 14m30s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 14m33s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 14m54s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 14m20s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 15m2s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 15m29s
Build Packages / build:rpm (rocky8) (push) Successful in 14m37s
Build Packages / build:rpm (rocky9) (push) Successful in 12m44s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 12m10s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 11m21s
Build Packages / DIALS test (push) Successful in 12m22s
Build Packages / XDS test (durin plugin) (push) Successful in 7m34s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 7m41s
Build Packages / XDS test (neggia plugin) (push) Successful in 7m52s
Build Packages / Generate python client (push) Successful in 24s
Build Packages / Build documentation (push) Successful in 1m0s
Build Packages / Create release (push) Skipped
Build Packages / build:windows:cuda (push) Successful in 16m53s
3aec235f67
The per-shell profile width is learned in pixels, so it varies ~4x with resolution
(mostly the geometric projection of a near-constant reciprocal-space relrod) and must
be binned per shell -> it starves at high resolution / on sparse data. The new
--reciprocal-profile flag instead learns ONE global width in reciprocal space,
sigma2_q,tan = A + B|q| + C|q|^2: the Jacobian g_tan=cos(2theta) removes the geometric
projection, and C|q|^2 is the crystal mosaicity relrod (variance ~(eta|q|)^2). Applied
per reflection as sigma2_tan,px = (A + B|q| + C|q|^2)/g_tan^2 (B,C clamped >=0;
quadratic->linear->constant fallback).

Off by default. On the sharp HEWL test crystal (mosaicity 0.091deg, so C fits to ~0 and
it reduces to the validated linear form) it is metric-neutral: ISa 16.2->16.3, anomalous
0.92x unchanged, CCref band 90.0->89.9, CC1/2 a touch lower (per-shell isn't starved at
23k spots/shell, and a global fit is less flexible). So: simpler + more transferable at a
small CC1/2 cost, ISa/anomalous held. Its payoff is on MOSAIC crystals (large C|q|^2),
where per-shell starves on the wide weak high-res spots and 6 shells are too coarse; both
lyso test crystals are sharp, so it ships as a dial to try on mosaic data elsewhere.
A separate radial relrod fit was tried and dropped (no gain). See NEXTGEN_INTEGRATOR.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
When a space group is supplied without a reference cell, de-novo two-pass
rotation indexing fed the FFT's Niggli-reduced primitive cell straight into
XtalOptimizer as if it were the conventional cell. For non-primitive lattices
(centered I/F/R/C, or hexagonal where the primitive pair sits at gamma=60) the
conventional-system model then refined to a wrong minimum and indexed 0% of
frames: cytC (P3121) gave 103.9/103.9/78 instead of 83.7/83.7/88.6, insulin
(I213) 66.7 instead of 77.65, insulin-R3 51/51/36 instead of 81.4/81.4/33.3.

Run LatticeSearch on the FFT primitive cell (it already yields the correct
conventional cell + reindex for I/F/R/C). For the one remaining gap - a
metrically hexagonal lattice that the geometry-keyed search lands on the
ortho-hexagonal C setting - re-express the reduced primitive cell in
conventional hexagonal axes (b -> b - a opens gamma 60 -> 120).

De-novo "-S" now indexes cytC/insu/Ins_H/lyso/MyoB/EP/lyso_ref at 100% with the
correct cell; the "-C -S" path is unchanged. The helper stays in this .cpp
(g++) rather than CrystalLattice.h to avoid recompiling CUDA units, which is
broken under the box's CUDA-13 nvcc; promote it to a method once that is fixed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Two offline-processing ergonomics changes.

scale-fulls is now ON by default for -P rot3d (it refits the per-frame scale on
the combined fulls and lifts ISa substantially, e.g. HEWL rot3d 7.0 -> 16.4).
--scale-fulls stays as the explicit opt-in for non-rot3d order; new
--no-scale-fulls disables it for rot3d. (scale_fulls is now an optional<bool>
defaulting to combine_3d.) Note: on low-completeness data the Unity-reference
refit can cost a little CC1/2 (endothiapepsin ~70% complete: -5% in a mid shell);
pair with --reject-outliers for the full low-symmetry benefit.

When merging (-M), the merged reflections (.mtz/.cif) are the wanted output, so
the large per-image _process.h5 is no longer written by default - it routinely
ran to hundreds of MB. Pass --write-process-h5 to also emit it. Without merging
the _process.h5 is the only output and is always written. Implemented with a
ProcessConfig.write_process_h5 flag gating the FileWriter; reflection and
image.dat writing are unaffected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
jfjoch_process: optional absorption surface for rot3d scaling (--absorption)
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 13m18s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 14m31s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 14m57s
Build Packages / build:rpm (rocky8) (push) Successful in 14m6s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 15m15s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 15m23s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 15m34s
Build Packages / XDS test (neggia plugin) (push) Successful in 8m55s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 9m17s
Build Packages / XDS test (durin plugin) (push) Successful in 9m25s
Build Packages / Create release (push) Skipped
Build Packages / Generate python client (push) Successful in 28s
Build Packages / Build documentation (push) Successful in 57s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 11m31s
Build Packages / build:rpm (rocky9) (push) Successful in 12m45s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 11m44s
Build Packages / DIALS test (push) Successful in 13m3s
Build Packages / Unit tests (push) Successful in 58m30s
Build Packages / build:windows:cuda (push) Successful in 20m21s
Build Packages / build:windows:nocuda (push) Successful in 10m30s
e45a1577d6
Adds an opt-in smooth absorption correction for rotation scaling. After the
rot3d fulls are scaled, --absorption[=num] fits a multiplicative surface
A(s1_crystal) - a degree<=4 monomial basis (real spherical harmonics up to l=4,
as XDS/DIALS) of the diffracted-beam direction in the crystal/goniometer frame,
by ridge-regularized log-linear least-squares of I_scaled/I_ref weighted by
(I/sigma)^2, over num iterations (default 3); the surface divides image_scale_corr
and the fulls are re-merged.

Off by default and a no-op without rot3d. On the test panel (~13 keV, thin
crystals) it is metric-neutral - fitted rms(log A) ~3-4%, ISa/CC1/2 unchanged -
because absorption is negligible there and the per-frame scale G(phi) already
absorbs the angular part. It is kept as a lever for low-energy data (e.g. 6 keV)
where absorption becomes significant. Stored as ScalingSettings::absorption_iter.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The per-image G/B/mosaicity fit used a plain L2 loss, so a few outlier
reflections occasionally dragged a frame into a bad optimum - a stochastic
(~15% of runs) per-frame mis-scaling that elevated R-meas and collapsed CC1/2
at low symmetry (the image-level CC1/2 half-split makes the damage look patchy
across shells, while the data is genuinely noisier). A Cauchy loss (3 sigma)
soft-downweights those outliers without a hard cut: MyoB 0/10 catastrophic
(was ~2/10), R-meas stable, and ISa improves on every test crystal
(EP0210 9.2->12.4, MyoB 12.5->14.6, lysoC 10.4->11.2, cytC 11.5->12.6),
most on low symmetry.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
--smooth-g now takes a rotation range in degrees (default 5) instead of a frame
count, converted to an odd frame window from the oscillation step inside
JFJochProcess. This makes the per-frame scale-G smoothing physical and
independent of the frame slicing. (Note: G-smoothing is not the cure for the
low-symmetry stochastic collapse - the per-image scale Cauchy loss is - but a
degree-based window is the correct parameterization regardless.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fit the reciprocal tangential-width model y(q)=a0+a1*t+a2*t^2 in a centered,
standardized variable t=(q-qbar)/qscale instead of the raw {1,q,q^2} monomials:
the raw normal matrix went near-singular when the strong spots span a narrow
q-range (small cell / sparse still), letting tiny per-frame jitter swing the
curvature into a wild over-wide profile. Adds IRLS (Huber) robustness, a ridge
on the curvature (sharp-crystal prior), and clamps the applied width to the
fitted q-range (no extrapolation). Stays strictly per-frame (no dataset pooling),
so it works online and for stills. Neutral on rotation data (cytC high-res CC1/2
win preserved 66.8 vs 65.6%).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Per-operator CC alone cannot separate a real weak symmetry operator from a false
moderate one: a noisy crystal's genuine cubic 2-folds (InsI2 I23, CC ~0.51) score
BELOW a pseudo-symmetric crystal's false 2-fold (InsH3, CC 0.64), so no CC threshold
works. Add a self-consistency test: a candidate point group is accepted only if
merging the intensities under it does not inflate R-meas past max_rmeas_ratio (1.5x)
the most-consistent candidate. A false operator forces non-equivalent reflections
together and blows R-meas up; a real one leaves it flat.

Fixes InsH3: was over-called R32 (ISa collapsed to 2.2 from the forced merge), now
correctly R3/H3 (ISa 10.2, matching XDS). InsI2 stays I23, and lysoC/InsI3/MyoB/
EP0210/cytC/lyso_ref are unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
jfjoch_process gains --detect-ice-rings, which (a) activates the existing spot-finder
ice flagging (ice spots de-prioritised in indexing) and (b) drops reflections sitting
on a hexagonal-ice powder ring from scaling/combine/merge/stats, via a new shared
IsOnIceRing() helper over ICE_RING_RES_A using the spot-finder's q half-width. Their
integrated intensity is contaminated by the strong, variable ice background, so leaving
them in mis-scales the whole frame and inflates the error model.

On EP0117 (ice-ring crystal): de-novo space-group determination recovers from P1 to P2
and CC1/2 improves (31->37%). Off by default; a no-op without the flag. This is the
first, non-controversial step - the residual gap needs ice-aware background/integration
(follow-up).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The hexagonal-ice ring FWHM measured on JUNGFRAU data (azimuthal radial background
profile) is ~0.06 q, so the exclusion half-width should be ~0.03; the previous 0.02
under-covered the strong low-res rings. On EP0117 with --detect-ice-rings this lifts
CC1/2 37->50%, and combined with --reject-outliers 3 (which down-weights the
radiation-damaged late frames) reaches ~94% (XDS 98.5%). Only active with
--detect-ice-rings, so default behaviour is unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
--min-image-cc <num> is documented in percent and the per-image CC is a fraction in
[0,1], but the value was passed straight to MinCCForImage (which requires [0,1]), so
the documented usage (e.g. --min-image-cc 30) threw an uncaught JFJochException and
aborted. Divide the percent argument by 100.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Records the validated z-score detector (on the azint radial background profile) and
position/width estimation, for a future --detect-ice-rings=auto. Not yet implemented.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The hexagonal lattice metric (two equal axes at 60/120 deg, both perpendicular to the
third) is also satisfied by its ortho-hexagonal C-centred supercell, so the
geometry-keyed LatticeSearch lands a metrically-hexagonal lattice on the C-orthorhombic
setting. The -S path already re-expresses it (HexagonalConventional) keyed on the
supplied space group; do the same de-novo, keyed on the metric of the reduced PRIMITIVE
cell (rhombohedral lattices have a rhombohedral primitive cell and are unaffected).

cytC (P3121) now indexes de-novo as hexagonal 83.8/83.8/88.6 gamma=120 and merges in
P3121 (CC1/2 99.7%, ISa 13.1), for both test crystals, instead of the orthohexagonal
C2/P1. lysoC/InsI3/InsH3 unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The R-meas-ratio over-symmetry guard (commit 7ade6d9) missed a near-perfect
pseudo-2-fold: InsH2 (XDS R3) has a false 2-fold at operator CC 0.85 whose merged
intensities still correlate well, so R-meas inflated only ~1.3x and R32 was accepted
(ISa collapsing to 3.9). The reduced chi^2 (within-orbit scatter / sigma^2) is the
right signal - false equivalents disagree by many sigma even when they correlate well.

Measured chi^2 ratio (candidate / best subgroup) across the test set: true point groups
<= 1.63 (a cubic merge of a noisy crystal, InsI3, is the worst real case), false >= 2.26
(InsH2) and 6.0 (InsH3); threshold 2.0 separates them. InsH2 now resolves to R3 (ISa 6.1
from the false R32's 3.9); InsH3/InsI2/InsI3/cytC/lysoC/MyoB/EP0210 unchanged and correct.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Per-observation merge outlier rejection at 6 sigma is neutral-or-better across every test
crystal (CC1/2 up or flat: lysoC 99.7->99.9, MyoB 98.9->99.6, EP0210 97.6->98.8,
cytC 99.7->100.0, InsI2 99.2->99.7; R-meas slightly lower everywhere; ISa unchanged), and
it is the lever for radiation-damaged / ice data (EP0117 reaches CC1/2 ~95% with it). Make
it the rot3d default, like scale-fulls and smooth-g; --reject-outliers 0 disables it. Off
for the non-rot3d partiality models, which were not benchmarked.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
WriteReflections: write merging statistics + ISa to the mmCIF output
Build Packages / build:windows:cuda (push) Failing after 2m40s
Build Packages / build:windows:nocuda (push) Failing after 2m40s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 13m47s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 14m42s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 14m46s
Build Packages / build:rpm (rocky8) (push) Successful in 14m52s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 15m10s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 15m5s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 15m47s
Build Packages / Unit tests (push) Failing after 19m1s
Build Packages / Generate python client (push) Successful in 32s
Build Packages / Build documentation (push) Successful in 1m0s
Build Packages / Create release (push) Skipped
Build Packages / XDS test (JFJoch plugin) (push) Successful in 7m54s
Build Packages / XDS test (durin plugin) (push) Successful in 8m7s
Build Packages / XDS test (neggia plugin) (push) Successful in 8m24s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 11m5s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 12m4s
Build Packages / build:rpm (rocky9) (push) Successful in 12m58s
Build Packages / DIALS test (push) Successful in 12m32s
a773aaa6a9
The .cif (--scaling-output cif) now carries the per-shell and overall merging
statistics in the standard _reflns / _reflns_shell categories (resolution, redundancy,
completeness, <I/sigma>, R-rim/R-meas, CC1/2) plus the Diederichs asymptotic I/sigma
(ISa) as a free-text _reflns.pdbx_diffrn_ISa item (no standard CIF tag exists). The
MergeStatistics and the ISa string are threaded through WriteReflections to the mmCIF
writer; jfjoch_process and jfjoch_scale pass them. Values match the text statistics table.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CC1/2 merge: assign half-sets by deterministic per-image hash
Build Packages / build:windows:cuda (push) Failing after 4m30s
Build Packages / build:windows:nocuda (push) Successful in 10m0s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 13m43s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 14m46s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 14m53s
Build Packages / build:rpm (rocky8) (push) Successful in 14m54s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 15m10s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 15m34s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 15m37s
Build Packages / XDS test (durin plugin) (push) Successful in 8m5s
Build Packages / Generate python client (push) Successful in 31s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 8m50s
Build Packages / Create release (push) Skipped
Build Packages / XDS test (neggia plugin) (push) Successful in 8m44s
Build Packages / Build documentation (push) Successful in 1m7s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 10m45s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 12m5s
Build Packages / build:rpm (rocky9) (push) Successful in 13m8s
Build Packages / DIALS test (push) Successful in 12m47s
Build Packages / Unit tests (push) Successful in 1h0m40s
35607057d9
MergeOnTheFly::AddImage picked each image's CC1/2 half from a shared
mt19937 drawn in call order (and before Mask), so the split depended on
iteration/thread order and on how many images were masked. The class is
mutex-guarded for concurrent "on-the-fly" use, so any parallel merge would
make CC1/2 non-reproducible - a latent race.

Assign the half as a splitmix64 hash of the image's stable index instead,
computed after Mask. The split is now reproducible run-to-run, independent
of AddImage order, parallel-safe, and decoupled from masking. Callers pass
the outcome's vector index as the image id.

Verified: lyso_ref two-pass -M -P rot3d gives identical CC1/2 across runs
(overall 99.6%, P41212); hash split is balanced ~50/50.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
smargon: write chi/phi goniometer position into NXmx transformations
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 14m15s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 15m13s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 15m9s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 15m11s
Build Packages / build:rpm (rocky8) (push) Successful in 15m14s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 15m30s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 15m52s
Build Packages / build:windows:nocuda (push) Successful in 15m54s
Build Packages / build:windows:cuda (push) Successful in 17m32s
Build Packages / XDS test (neggia plugin) (push) Successful in 7m30s
Build Packages / Generate python client (push) Successful in 30s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 8m31s
Build Packages / Create release (push) Skipped
Build Packages / XDS test (durin plugin) (push) Successful in 8m47s
Build Packages / Build documentation (push) Successful in 58s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 11m37s
Build Packages / build:rpm (rocky9) (push) Successful in 12m37s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 12m44s
Build Packages / DIALS test (push) Successful in 12m55s
Build Packages / Unit tests (push) Successful in 1h0m54s
b7613c559c
Add an optional Smargon static positioner (chi/phi angles + rotation axes)
that is reconstructed into the NXmx sample transformation chain. Chi/phi are
appended at the innermost end of the chain (closest to the sample) for both
the goniometer and grid-scan branches, with axes defaulting to chi {0,0,1}
and phi = omega default {1,0,0}.

- SmargonPosition gains chi_axis/phi_axis (common/JFJochMessages.h)
- OpenAPI: optional phi_axis/chi_axis arrays; clients regenerated
- OpenAPIConvert wires Dataset_settings.smargon -> DatasetSettings
- CBOR serializer/deserializer round-trip the axes
- tests: CBORSerialize_Start_Smargon

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
When per-image CBOR metadata comes within 32 bytes of the buffer slot
size, slot_size - (metadata_size + 32) wrapped around (size_t), passing a
huge output_size to CompressImage. That defeated the buffer-too-small
guard and let the compressor write the full image past the end of the
slot, corrupting adjacent memory; AppendImage then threw a plain
JFJochException that aborted the whole collection after the fact.

Detect metadata_size + 32 >= slot_size explicitly and throw
CompressionBufferTooSmallException, so the existing catch drops just this
frame gracefully - the case the change was meant to handle.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
SmoothImageScaleG rewrites the partials in place (image_scale_corr and
image_scale_g). On the no-reference path that is harmless: each scaling
pass recomputes G from scratch via ScaleAllImages, so smoothing always
runs on freshly-refined G. On the reference path the scaling loop is
skipped, so G is computed once and stays; running scale_and_merge twice
(P1 then the adopted space group) smoothed the already-smoothed G a
second time, compounding into a ~2x wider effective kernel than the
configured --smooth-g and biasing the merged intensities.

Smooth only on the first pass of the reference path (G is unchanged
afterwards, and the smoothed partials persist into the second pass's
combine3D). The no-reference path is unchanged.

Verified on lyso (600 frames, -P rot3d -z ref.mtz -M): the reference run
now logs the smoothing once instead of twice, and the merged MTZ changes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
rotation indexer: refine candidate cells and pick the best after refinement
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 14m24s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 14m32s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 14m40s
Build Packages / build:rpm (rocky8) (push) Successful in 15m8s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 15m12s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 15m25s
Build Packages / build:windows:nocuda (push) Successful in 15m47s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 15m50s
Build Packages / build:windows:cuda (push) Successful in 17m29s
Build Packages / XDS test (durin plugin) (push) Successful in 8m31s
Build Packages / Generate python client (push) Successful in 32s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 9m3s
Build Packages / Create release (push) Skipped
Build Packages / XDS test (neggia plugin) (push) Successful in 8m31s
Build Packages / Build documentation (push) Successful in 1m6s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 11m23s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 12m16s
Build Packages / build:rpm (rocky9) (push) Successful in 12m56s
Build Packages / DIALS test (push) Successful in 12m42s
Build Packages / Unit tests (push) Successful in 1h34m10s
00821e32ef
De-novo two-pass indexing failed on large-cell / superstructure / modulated
crystals (EcwtAL500 0%, EcwtCQ034 0%) and mis-handled a pseudo-symmetric one
(EcwtCQ066 14%). The common cause: the choice of unit cell was made too early,
on the raw pre-refinement spot fraction, which is an unreliable discriminator
(a correct hexagonal cell indexes only ~13% of the un-refined accumulated
spots, while a wrong larger cell can index more).

Move the decision to after geometry refinement, where it is reliable:

- FFTIndexer now OFFERS widened candidate cells instead of deciding. ReduceResults
  gains a `widen` flag: the standard path (9 shortest vectors) is unchanged; the
  widened path anchors the two short axes and lets the third range over all
  filtered vectors (+dedup) to reach the long axis of an elongated cell.
  FilterFFTResults takes the peak count as a parameter (30 standard, 60 widened).
  RunInternal appends widened candidates only when its standard best indexes
  poorly, so compact crystals are untouched.

- RotationIndexer fully refines the top few candidates and keeps the one that
  indexes the most spots under its own refined geometry (IndexedFraction). Each
  refine is length-bounded (1.2x the found cell) so a free triclinic refine cannot
  drift onto a pseudo-translation / modulation supercell (CQ034's satellites). The
  earlier (primary) candidate is preferred: a later one is adopted only if it
  indexes clearly more and reasonably well in absolute terms, so a twin's noisy
  near-tie cannot displace it. Extra/twin lattices are only searched when the
  chosen cell is the FFT primary (lattice[0]), since MultiLatticeSearch's
  rotations are derived from that primary.

- The pseudo-symmetry guard (de-novo only - a user-fixed space group is always
  honored) is a ratio of refined fractions: refine the primitive as triclinic and
  drop to P only if the constrained cell indexes less than half of it. A false
  promotion indexes badly under its constraint (CQ066 ratio ~0.1) while genuine
  higher symmetry, including R-centred, indexes comparably (Ins_H R3 ratio ~0.7)
  and is kept.

Validated on the full /data/rotation_test battery: AL500 0->89% (C2), CQ034
0->99%, CQ066 14->93% (ISa 7.2->13.7); the other 15 crystals keep their exact
cell, space group, indexing rate and ISa (no regressions).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a row after the Indexing solution that flags images with more than
one indexed lattice (indexing_lattice_count > 1).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The THIRD_PARTY_NOTICES.md manifest lived only at the repo root and was
referenced from docs/SOFTWARE.md via a ../ link that escapes the Sphinx
source tree, so it never rendered in the published docs and was absent
from the navigation.

Add docs/THIRD_PARTY_NOTICES.md to the General toctree and fix the
SOFTWARE.md link. The docs page is generated from the canonical root file
by update_version.sh (like the python-client docs): licenses/*.txt links
point at the repository, and the project-license links point at the
in-docs LICENSE / FPGA_LICENSE pages.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The two Windows jobs (build-windows / build-windows-nocuda) differed only in
-DJFJOCH_USE_CUDA=ON/OFF, so collapse them into one matrixed job (variant
cuda/nocuda), mirroring the build-rpm matrix.

On a tag, upload the NSIS installer (jfjoch-<version>-win64-{cuda<major>|cpu}.exe,
named in CMakeLists.txt) to the release via gitea_upload_file.py, the same helper
the RPM/DEB nocuda variants use to attach viewer/writer artifacts.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ci: drop requests dependency and use PowerShell for the Windows release upload
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 12m29s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 13m26s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 13m39s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 13m48s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 14m6s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 14m8s
Build Packages / build:windows:nocuda (push) Successful in 14m26s
Build Packages / build:windows:cuda (push) Successful in 17m26s
Build Packages / XDS test (durin plugin) (push) Successful in 7m20s
Build Packages / build:rpm (rocky8) (push) Successful in 11m40s
Build Packages / build:windows:nocuda (pull_request) Successful in 9m34s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 11m18s
Build Packages / Generate python client (push) Successful in 17s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 11m58s
Build Packages / Create release (push) Skipped
Build Packages / Build documentation (push) Successful in 1m8s
Build Packages / build:rpm (rocky9) (push) Successful in 13m19s
Build Packages / DIALS test (push) Successful in 13m23s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 7m32s
Build Packages / XDS test (neggia plugin) (push) Successful in 6m16s
Build Packages / build:windows:cuda (pull_request) Successful in 16m40s
Build Packages / build:rpm (ubuntu2204_nocuda) (pull_request) Successful in 9m55s
Build Packages / build:rpm (rocky8_nocuda) (pull_request) Successful in 10m55s
Build Packages / build:rpm (rocky9_nocuda) (pull_request) Successful in 11m12s
Build Packages / build:rpm (ubuntu2404_nocuda) (pull_request) Successful in 9m35s
Build Packages / build:rpm (rocky8_sls9) (pull_request) Successful in 10m36s
Build Packages / build:rpm (ubuntu2204) (pull_request) Successful in 9m58s
Build Packages / build:rpm (rocky8) (pull_request) Successful in 11m15s
Build Packages / build:rpm (rocky9_sls9) (pull_request) Successful in 12m7s
Build Packages / build:rpm (rocky9) (pull_request) Successful in 11m42s
Build Packages / build:rpm (ubuntu2404) (pull_request) Successful in 10m21s
Build Packages / Generate python client (pull_request) Successful in 25s
Build Packages / Build documentation (pull_request) Successful in 57s
Build Packages / Create release (pull_request) Skipped
Build Packages / XDS test (neggia plugin) (pull_request) Successful in 6m12s
Build Packages / XDS test (durin plugin) (pull_request) Successful in 7m24s
Build Packages / XDS test (JFJoch plugin) (pull_request) Successful in 6m58s
Build Packages / DIALS test (pull_request) Successful in 10m41s
Build Packages / Unit tests (push) Successful in 1h11m21s
Build Packages / Unit tests (pull_request) Successful in 58m33s
4b393082d4
The Windows viewer runner has Python but not the 'requests' package, and does
not necessarily have bash. So:
- rewrite gitea_upload_file.py to use only the Python stdlib (urllib), which
  works with a bare interpreter on both the Linux package runners and Windows;
  also drop the file's unused create_release() (gitea_create_release.py owns that);
- run the Windows 'Upload installer to release' step in PowerShell (always present)
  instead of bash, globbing the NSIS .exe with Get-ChildItem.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
All checks were successful
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 12m29s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 13m26s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 13m39s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 13m48s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 14m6s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 14m8s
Build Packages / build:windows:nocuda (push) Successful in 14m26s
Build Packages / build:windows:cuda (push) Successful in 17m26s
Build Packages / XDS test (durin plugin) (push) Successful in 7m20s
Build Packages / build:rpm (rocky8) (push) Successful in 11m40s
Build Packages / build:windows:nocuda (pull_request) Successful in 9m34s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 11m18s
Build Packages / Generate python client (push) Successful in 17s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 11m58s
Build Packages / Create release (push) Skipped
Build Packages / Build documentation (push) Successful in 1m8s
Build Packages / build:rpm (rocky9) (push) Successful in 13m19s
Build Packages / DIALS test (push) Successful in 13m23s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 7m32s
Build Packages / XDS test (neggia plugin) (push) Successful in 6m16s
Build Packages / build:windows:cuda (pull_request) Successful in 16m40s
Build Packages / build:rpm (ubuntu2204_nocuda) (pull_request) Successful in 9m55s
Build Packages / build:rpm (rocky8_nocuda) (pull_request) Successful in 10m55s
Build Packages / build:rpm (rocky9_nocuda) (pull_request) Successful in 11m12s
Build Packages / build:rpm (ubuntu2404_nocuda) (pull_request) Successful in 9m35s
Build Packages / build:rpm (rocky8_sls9) (pull_request) Successful in 10m36s
Build Packages / build:rpm (ubuntu2204) (pull_request) Successful in 9m58s
Build Packages / build:rpm (rocky8) (pull_request) Successful in 11m15s
Build Packages / build:rpm (rocky9_sls9) (pull_request) Successful in 12m7s
Build Packages / build:rpm (rocky9) (pull_request) Successful in 11m42s
Build Packages / build:rpm (ubuntu2404) (pull_request) Successful in 10m21s
Build Packages / Generate python client (pull_request) Successful in 25s
Build Packages / Build documentation (pull_request) Successful in 57s
Build Packages / Create release (pull_request) Skipped
Build Packages / XDS test (neggia plugin) (pull_request) Successful in 6m12s
Build Packages / XDS test (durin plugin) (pull_request) Successful in 7m24s
Build Packages / XDS test (JFJoch plugin) (pull_request) Successful in 6m58s
Build Packages / DIALS test (pull_request) Successful in 10m41s
Build Packages / Unit tests (push) Successful in 1h11m21s
Build Packages / Unit tests (pull_request) Successful in 58m33s
You are not authorized to merge this pull request.
This pull request can be merged automatically.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin 2606-rc.156-fixes:2606-rc.156-fixes
git checkout 2606-rc.156-fixes
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: mx/Jungfraujoch#66