Stop making the first pass write the files the second pass replaces
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
This commit is contained in:
co-authored by
Claude Opus 5
parent
16639e9de2
commit
c9fc46e6e2
@@ -237,9 +237,14 @@ ImagePreprocessorGPU::ImagePreprocessorGPU(const DiffractionExperiment &experime
|
||||
cpu_stats_reg(cpu_stats) {
|
||||
// Setup mask. The same for every worker, so it is uploaded once per GPU and shared; keyed on the
|
||||
// PixelMask's own vector, which the derived table is a pure function of.
|
||||
// Hoist the accessor and index without the bounds check: this runs once per worker over every
|
||||
// pixel of the detector - 18 million times per engine on a 16 Mpx one, and an engine is built per
|
||||
// worker per pass - and .at() on each of them stops the loop vectorising for a bound the loop
|
||||
// itself already respects.
|
||||
const std::vector<uint32_t> &mask_raw = mask.GetMask();
|
||||
std::vector<uint8_t> mask_vec(npixels);
|
||||
for (int i = 0; i < npixels; i++)
|
||||
mask_vec[i] = (mask.GetMask().at(i) != 0);
|
||||
mask_vec[i] = (mask_raw[i] != 0);
|
||||
gpu_mask = SharedDeviceTable(mask.GetMask().data(), npixels, mask_vec.data(), *stream);
|
||||
|
||||
// Setup GPU settings. The current device, not device 0: workers are pinned round-robin across GPUs,
|
||||
|
||||
Reference in New Issue
Block a user