RESULT-CHANGING (owner approved): stills unmerged MTZ written only for the crystals on the run's cell

The unmerged MTZ took every integrated still. A still whose cell is not close to the run's - the same
test, with the same tolerances, the merge applies - was indexed in another lattice (on few spots,
typically an axis multiple), so its H K L do not name the reflections a reading program takes them
for: aimless or careless would scale them in as wrong reflections. On two 25k-frame XFEL runs such
frames carried 60% of the integrated reflections, and the 824 MB file was the largest single cost
after the merge (about 7 s in --mode scale). Rotation runs are unchanged (one lattice).

The orientation matrix in the batch headers is likewise taken from the first crystal on the run's cell.
Test: Unmerged MTZ: on stills, only the crystals on the run's cell.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-10-14 13:15:13 +02:00
co-authored by Claude Opus 5.5
parent 2d118f6df1
commit a574e97b10
2 changed files with 39 additions and 3 deletions
+26
View File
@@ -335,3 +335,29 @@ TEST_CASE("MTZ history: command line and input, in records of at most 80 charact
CHECK(joined.find("Input file: " + provenance.input_identity) != std::string::npos);
CHECK(mtz.history.size() <= 30);
}
TEST_CASE("Unmerged MTZ: on stills, only the crystals on the run's cell", "[write_reflections][portable]") {
// A still indexed with its c axis doubled names other reflections by the same indices, so its rows
// would be read as the wrong reflections; it is left out, the crystal on the run's cell is written.
const auto experiment = TestExperiment(); // no goniometer: stills
std::vector<IntegrationOutcome> outcomes(2);
outcomes[0].latt = CrystalLattice(TETRAGONAL_CELL);
outcomes[1].latt = CrystalLattice(UnitCell{47.0f, 47.0f, 126.0f, 90.0f, 90.0f, 90.0f});
for (int f = 0; f < 2; ++f)
for (int l = 1; l <= 5; ++l) {
Reflection r{};
r.h = 1; r.k = 2; r.l = l;
r.image_number = static_cast<float>(f);
r.I = 100.0f;
r.sigma = 10.0f;
r.prescaling_corr = 1.0f;
r.partiality = 1.0f;
outcomes[f].reflections.push_back(r);
}
const gemmi::Mtz mtz = UnmergedMtz(outcomes, TETRAGONAL_CELL, experiment, false, OutputProvenance{}, 1);
CHECK(mtz.nreflections == 5);
const auto batch = mtz.column_with_label("BATCH");
REQUIRE(batch != nullptr);
for (int i = 0; i < mtz.nreflections; ++i)
CHECK((*batch)[i] == 1.0f);
}