diff --git a/image_analysis/scale_merge/SearchSpaceGroup.cpp b/image_analysis/scale_merge/SearchSpaceGroup.cpp index a355c281..4871cd5c 100644 --- a/image_analysis/scale_merge/SearchSpaceGroup.cpp +++ b/image_analysis/scale_merge/SearchSpaceGroup.cpp @@ -732,9 +732,16 @@ SearchSpaceGroupResult SearchSpaceGroup( // control rows, and on the same crystal one row can be 20x an average reflection while another // is half of one. Pooling them lets the weak rows set the threshold for the strong one and the // rescue never fires (that very crystal pooled to a row median of 0.7 and stayed at P42_12). + // A row needs more than a reflection or two behind its median before that median may set the + // threshold. The scale only ever RAISES the cut, so a row whose control class holds one strong + // reflection would license a screw claim the row does not support - a genuine 4_2 whose 00l are + // observed only at l=4n, strongly, would read its l=4n+2 reflections as absent and be reported as + // 4_1/4_3. Below this count the row falls back to the plain cut, i.e. no rescue. + constexpr size_t MIN_ROW_CONTROL_REFLECTIONS = 3; std::map row_median; for (auto& [row, esq] : row_present_esq) - row_median[row] = MedianOf(esq); + if (esq.size() >= MIN_ROW_CONTROL_REFLECTIONS) + row_median[row] = MedianOf(esq); const int screw_absent = static_cast(screw_absent_refl.size()); int screw_violations = 0;