RESULT-CHANGING: the centred-lattice test asks only about a class the lattice metric hosts
The centred-lattice test (run after a triclinic indexing whose search arms could test no operator) takes its candidate from the Niggli character table, which names a class on 3 deg relative tolerances. Le Page, which measures each two-fold's obliquity on the lattice itself at the 1 deg bound every other metric question of the run uses, can find fewer rotations than that class carries. The test then adopted a group the lattice does not host: on a triclinic crystal whose C-monoclinic two-fold is 1.7 deg oblique (XDS refines the same angle), C2 was adopted at operator CC 0.46 and written on a cell the group cannot describe, and the Le Page re-ask that follows cannot demote. The test now runs only where Le Page carries the candidate's holohedry; otherwise it logs why and leaves the question to the Le Page re-ask. Over the rc181 open, in-house and private battery rows this was the one final point group with more rotations than the metric hosts; every other centred-test adoption is hosted and unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UqXYdL4qBGYRiSXSGXfCLu
This commit is contained in:
1 parent
48d895d715
commit
486c0b06d1
2 files changed
+40
-1
No files matched your search
@@ -2642,6 +2642,23 @@ bool Rugnux::ScaleMergeAndSymmetry(PipelineLocals &p) {
|
||||
// The metric only generates the candidate; the intensity CC gate below makes the decision
|
||||
// (a false pseudo-symmetry is rejected by the correlation).
|
||||
const auto cand = LatticeSearch(*end_msg.rotation_lattice);
|
||||
// The candidate comes from the Niggli character table, which names a class on relative
|
||||
// tolerances (3 deg). Le Page measures each two-fold's obliquity on the lattice itself, at
|
||||
// the bound every other metric question of the run is put at (LATTICE_MAX_OBLIQUITY_DEG).
|
||||
// Where it finds fewer rotations than the candidate's holohedry the lattice does not host
|
||||
// that class, and what the intensities could confirm is a pseudo-symmetry: measured on a
|
||||
// triclinic crystal whose C-monoclinic two-fold is 1.7 deg oblique (the angle XDS refines
|
||||
// as well), C2 was adopted at operator CC 0.46 and written on a cell the group cannot
|
||||
// describe. So it is not asked here; the metric re-ask below asks Le Page's own class.
|
||||
const auto metric = LePageLattice(*end_msg.rotation_lattice);
|
||||
const bool metric_hosts = metric
|
||||
&& static_cast<size_t>(metric->n_operators) >= HolohedryRotations(cand.system);
|
||||
if (!metric_hosts && cand.system != gemmi::CrystalSystem::Triclinic)
|
||||
logger.Info("Centred-lattice test: the cell's character names a {} lattice, but some of its two-folds "
|
||||
"are more than {:.1f} deg oblique (Le Page finds {} rotation(s)), so the lattice "
|
||||
"does not host it and it is not offered to the intensities",
|
||||
gemmi::crystal_system_str(cand.system), LATTICE_MAX_OBLIQUITY_DEG,
|
||||
metric ? metric->n_operators : 0);
|
||||
// Exact integer reindex from the indexed setting straight to the candidate conventional
|
||||
// setting: P[i][j] = conv_real[i] . rot_reciprocal[j]. Derived from the two lattices, so it
|
||||
// holds even if the refined indexed cell is not exactly LatticeSearch's Niggli cell (whose
|
||||
@@ -2657,7 +2674,7 @@ bool Rugnux::ScaleMergeAndSymmetry(PipelineLocals &p) {
|
||||
reindex.a[i][j] = std::round(v);
|
||||
reindex_res = std::max(reindex_res, std::fabs(v - reindex.a[i][j]));
|
||||
}
|
||||
if (cand.system != gemmi::CrystalSystem::Triclinic && reindex_res < 0.1) {
|
||||
if (metric_hosts && cand.system != gemmi::CrystalSystem::Triclinic && reindex_res < 0.1) {
|
||||
std::vector<MergedReflection> merged_c = sm.merged;
|
||||
for (auto &m : merged_c)
|
||||
reindex_hkl(m, reindex);
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "../common/Coord.h"
|
||||
#include "../common/UnitCell.h"
|
||||
#include "../image_analysis/lattice_search/LePageLattice.h"
|
||||
#include "../image_analysis/lattice_search/LatticeSearch.h"
|
||||
#include "gemmi/symmetry.hpp"
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
@@ -207,3 +208,24 @@ TEST_CASE("LePageLattice - a filtered group may not rest on an operator the filt
|
||||
});
|
||||
CHECK(!r.has_value());
|
||||
}
|
||||
|
||||
TEST_CASE("LePageLattice - a two-fold the character table admits but the metric does not host") {
|
||||
// A C-centred monoclinic description whose alpha is 1.7 deg off 90: the Niggli character table,
|
||||
// on its relative tolerances, still names the class, while the two-fold is more oblique than
|
||||
// Le Page's bound, so the lattice does not host it. The centred-lattice test in the rotation merge
|
||||
// asks the intensities about a class only where both agree. A lattice 0.3 deg off is hosted.
|
||||
const CrystalLattice oblique = CrystalLattice(120, 100, 70, 88.3, 115, 90).ToPrimitive('C');
|
||||
const auto named = LatticeSearch(oblique);
|
||||
CHECK(named.system == gemmi::CrystalSystem::Monoclinic);
|
||||
CHECK(named.centering == 'C');
|
||||
const auto metric = LePageLattice(oblique);
|
||||
REQUIRE(metric.has_value());
|
||||
CHECK(metric->n_operators == 1);
|
||||
CHECK(metric->system == gemmi::CrystalSystem::Triclinic);
|
||||
|
||||
const auto hosted = LePageLattice(CrystalLattice(120, 100, 70, 89.7, 115, 90).ToPrimitive('C'));
|
||||
REQUIRE(hosted.has_value());
|
||||
CHECK(hosted->n_operators == 2);
|
||||
CHECK(hosted->system == gemmi::CrystalSystem::Monoclinic);
|
||||
CHECK(hosted->centering == 'C');
|
||||
}
|
||||
Reference in new issue
Block a user