Pass 1 exists to choose the space group and post-refine the geometry. Its merged intensities are
discarded - pass 2 remakes them seconds later at the refined geometry, and that is the answer anyone
reads. It was nonetheless writing the full set of merged files at the end of every pass 1: a mmCIF
of every unique reflection (22 MB on an ordinary crystal, 48 MB on a crowded one), an .hkl, an .mtz
and the per-image scaling table, all through one thread.
Measured on an ordinary rotation set: 0.60 s of a 15 s run, and pass 2's identical block right
after it takes another 0.585 s to write the files that are kept.
The pass-2 quality guard is untouched, which is what disqualified an earlier attempt at this:
has_merge_statistics is set at the merge, well above the write, so pass 1 still reports the
completeness and CC1/2 the guard compares against. Nothing numeric moves - the same run measures
38.5 s before and 36.6 s after with a byte-identical .hkl.
Also hoist the pixel-mask accessor out of the preprocessor's per-pixel loop. It called .at() on
every pixel of the detector - 18 million bounds checks per engine, and an engine is built per worker
per pass - for a bound the loop already respects, which stopped it vectorising.
The <prefix>_01.mtz/.cif/.hkl are documented output, so this is a deliberate behaviour change: the
pre-pass result is no longer written. If it is wanted for comparison it should come back behind a
flag rather than by default.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011n8riB6X59oRjkrSHzNPAU