diff --git a/image_analysis/scale_merge/TranslationalNCS.cpp b/image_analysis/scale_merge/TranslationalNCS.cpp index 7c0634f3b..fc7f6cd32 100644 --- a/image_analysis/scale_merge/TranslationalNCS.cpp +++ b/image_analysis/scale_merge/TranslationalNCS.cpp @@ -767,9 +767,12 @@ std::string TranslationalNCSToText(const TranslationalNCSResult &result) { os << "\n [z = " << std::setprecision(1) << result.peak_z << " against a permutation null of " << result.null_mean << " +- " << std::setprecision(2) << result.null_sd << "%]\n"; if (result.modulation_measured) - os << " Intensity modulation along that vector: " << std::setprecision(1) << result.modulation + os << " Intensity modulation: " << std::setprecision(1) << result.modulation << "x between the strongest and weakest phase class [random-vector control " - << result.modulation_null << "x]\n"; + << result.modulation_null << "x]\n" + << " [read on the search's own vector over d >= 4 A, which is what the control is drawn\n" + << " against; the vector reported above is that one re-refined on the whole data, so it\n" + << " points more accurately and this number is not re-read off it]\n"; if (!result.modulation_measured) { os << " The modulation test could not be run - too few acentric reflections beyond 4 A - so\n" << " the peak above stands alone.\n" diff --git a/rugnux/Rugnux.cpp b/rugnux/Rugnux.cpp index 84c7ba19a..f31b081d0 100644 --- a/rugnux/Rugnux.cpp +++ b/rugnux/Rugnux.cpp @@ -7502,9 +7502,21 @@ ProcessResult Rugnux::RunPipeline(RugnuxObserver *observer, bool write_output, b // because it is folded under no symmetry, at full resolution and production-scaled. // Report-only: nothing reads it back. if (determined != nullptr && determined->number > 1) { + // The pseudo-translation the zone is normalised by is measured on THIS merge, not + // taken from `result.tncs`. That one is fitted on the adopted group's merge, and + // where the pseudo-translation is not compatible with the adopted symmetry that + // merge has already averaged across its own phase classes, so the vector fitted + // there is poorly determined - measured on one crystal, the correlation between E^2 + // and cos(2 pi h.u) reads 0.04 on the group merge against 0.25 here, with the + // optimum elsewhere entirely, and a vector that names the wrong classes normalises + // the zone by noise. It is also the basis this merge is indexed on: a change of + // basis committed by the search leaves a vector measured before it pointing + // somewhere else. + const auto p1_tncs = AnalyzeTranslationalNCS( + p1.merged, gemmi::UnitCell(*result.consensus_cell)); result.twin_immune_zones = AnalyzeTwinImmuneZones( p1.merged, gemmi::UnitCell(*result.consensus_cell), *determined, - TranslationalNCSVectorForLTest(result.tncs)); + TranslationalNCSVectorForLTest(p1_tncs)); if (!result.twin_immune_zones->zones.empty()) logger.Info("{}", TwinImmuneZonesToText(*result.twin_immune_zones)); }