diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 328b6a989..041ef7257 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -7,6 +7,7 @@ * `rugnux` measures the beam centre on every run, and indexes with it when the file's value indexes nothing. * `rugnux` places a detector swung out on a 2theta arm where the file says it stands. * `rugnux` writes the unmerged MTZ by default, with a P1 merge beside it, so a wrong space group can be re-merged without reprocessing. +* `rugnux` writes a batch header in the unmerged MTZ for every image the observations span, not only for the images that produced one, so a scaling program reads one run per sweep. * `rugnux` handles symmetry better: the lattice, the point group, the setting and the systematic absences. * `rugnux` fits the direction of the goniometer axis and not its length, so the cell chosen by the first pass is the one its own refinement scored. * `rugnux` reports the detector geometry it measured - the direct beam, the tilt and the beam centre - and what a single sweep can and cannot determine. diff --git a/image_analysis/WriteReflections.cpp b/image_analysis/WriteReflections.cpp index cb0a75a7f..e5a17a105 100644 --- a/image_analysis/WriteReflections.cpp +++ b/image_analysis/WriteReflections.cpp @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -748,7 +747,13 @@ void WriteUnmergedMtzReflections(const std::vector &outcomes // way to recover it. The partiality is NOT divided out - that is a scale, FRACTIONCALC carries // it, and every program this file is for wants to handle it its own way. gemmi::UnmergedHklMover hkl_mover(mtz.spacegroup); - std::set batch_numbers; + // The batch headers are written for every image the observations span, not only for the images + // that produced one. AIMLESS starts a new run wherever the phi series jumps, so an image that + // indexed nothing leaves a hole that cuts the sweep in two: measured on a 360 deg sweep with 67 + // unindexed images, AIMLESS made 23 runs of it and its scale model diverged - CC(1/2) 0.811, + // Rmeas overflowed to -1266, and the result no longer correlated with rugnux's own merge + // (Pearson 0.0018). Filling the gaps gives one run and the numbers the sweep deserves. + int first_batch = 0, last_batch = -1; // Lattice-centring absences are integrated on purpose - prediction runs in P so the space-group // search can confirm or disprove the centring - but they are not written here. POINTLESS reads @@ -766,7 +771,9 @@ void WriteUnmergedMtzReflections(const std::vector &outcomes // A summed full's image_number is its rocking-curve centroid, so this is the batch the // reflection is centred on - which is what a batch means for a full everywhere else. const int batch = 1 + static_cast(std::lround(r.image_number)); - batch_numbers.insert(batch); + if (last_batch < first_batch) { first_batch = batch; last_batch = batch; } + first_batch = std::min(first_batch, batch); + last_batch = std::max(last_batch, batch); mtz.data.push_back(static_cast(hkl[0])); mtz.data.push_back(static_cast(hkl[1])); mtz.data.push_back(static_cast(hkl[2])); @@ -861,7 +868,7 @@ void WriteUnmergedMtzReflections(const std::vector &outcomes batch.floats[115] = 1.0f; batch.floats[116] = static_cast(experiment.GetYPixelsNum()); - for (const int number : batch_numbers) { + for (int number = first_batch; number <= last_batch; number++) { batch.number = number; batch.floats[36] = phi_start_deg(static_cast(number - 1)); // phistt batch.floats[37] = batch.floats[36] + wedge_deg; // phiend