rugnux first pass: twin-composite test compares the class on neither with every other class

A crystal whose spots avoid one coset of an index-2 sub-lattice thins the overlap and the class on
neither alike, so comparing only the weaker domain's own class with the class on neither nearly
fired on a single long-axis hexagonal crystal (stopped by the congruence check alone). The class on
neither must now be four times emptier per node than the emptiest of the weaker domain's own class
and the overlap. On the evaluated private, inhouse and open sets the non-twins score at most 1.44;
the two known index-3 twins score 61 and more.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SVmAWnzCmRKAXVUCdc4iNi
This commit is contained in:
leonarski_fandClaude Opus 5.5 committed 2026-10-10 01:00:56 +02:00
1 parent 9f6bb00b61
commit 8362dc8563
1 file changed
+17 -13
+17 -13
View File
@@ -1423,11 +1423,14 @@ auto Rugnux::FirstPassRun::IndexSchemes() -> FirstPass {
// neither the frame count nor the occupancy of the classes it adds tells it from a superstructure.
// What does is the class of nodes on neither domain. Two domains put every reflection on the union of
// their own index-n sub-lattices K1 and K2 and leave the (1 - 1/n)^2 of the nodes on neither empty but
// for chance coincidences. One crystal cannot: whatever sub-lattice its reflections favour (a
// pseudo-translation), the nodes off K1 that lie on K2 and those that lie on neither are the same
// cosets of it, and as dense in spots per node. The two sub-lattices are the same lattice in two
// orientations, so their cells must also agree. Where all of this holds the stronger domain's own
// cell is adopted, and the other domain is left to the leftover-lattice census, which names it.
// for chance coincidences, while the nodes on both (the overlap) and on each alone are populated. One
// crystal cannot do that: whatever sub-lattice its reflections favour (a pseudo-translation), the
// nodes off K1 that lie on K2 and those that lie on neither are the same cosets of it and as dense in
// spots, and a crystal whose spots avoid one coset of a sub-lattice thins the overlap with the class
// on neither alike. So the class on neither must be far emptier than every other class. The two
// sub-lattices are the same lattice in two orientations, so their cells must also agree. Where all
// of this holds the stronger domain's own cell is adopted, and the other domain is left to the
// leftover-lattice census, which names it.
// Following Friedel's twin index (Friedel 1926, Lecons de cristallographie) and the obverse/reverse
// reflection classes of Herbst-Irmer & Sheldrick (2002) Acta Cryst. B58, 477-481
auto Rugnux::FirstPassRun::TwinCompositeHypothesis(FirstPass best) -> FirstPass {
@@ -1482,19 +1485,20 @@ auto Rugnux::FirstPassRun::TwinCompositeHypothesis(FirstPass best) -> FirstPass
const bool congruent = std::abs(u1.a - u2.a) < 0.02 * u1.a && std::abs(u1.b - u2.b) < 0.02 * u1.b
&& std::abs(u1.c - u2.c) < 0.02 * u1.c && std::abs(u1.alpha - u2.alpha) < 2.0
&& std::abs(u1.beta - u2.beta) < 2.0 && std::abs(u1.gamma - u2.gamma) < 2.0;
// Spots per node: each domain alone holds 1/n - 1/n^2 of the nodes, neither (1 - 1/n)^2. One
// crystal reads the two densities alike, up to the scatter of the pair picked as the emptiest
// out of 7 or 13 forms (up to 1.6 where the run has a hundred spots); two domains read them
// tens of times apart.
const double weak_density = c.only2 / (1.0 / n - 1.0 / (n * n));
// Spots per node: each domain alone holds 1/n - 1/n^2 of the nodes, both 1/n^2, neither
// (1 - 1/n)^2. One crystal reads the emptiest of the first three about as dense as neither (up
// to 1.5 times, the scatter of picking the emptiest pair out of 7 or 13 forms); two domains read
// it tens of times denser.
const double other_density = std::min(c.only2 / (1.0 / n - 1.0 / (n * n)),
c.both * static_cast<double>(n * n));
const double neither_density = c.neither / ((1.0 - 1.0 / n) * (1.0 - 1.0 / n));
const bool composite = congruent && c.only2 >= 20 && weak_density > 4.0 * neither_density;
const bool composite = congruent && c.only2 >= 20 && other_density > 4.0 * neither_density;
logger.Info("Twin-composite hypothesis, index {}: of {} validation spots on the standing cell "
"({:.0f} A^3), the sub-lattices ({},{},{}) and ({},{},{}) hold {} and {} alone, {} "
"together and {} on neither - per node {:.1f} on the weaker one's own class against "
"together and {} on neither - per node {:.1f} on the emptiest of the other classes against "
"{:.1f} on neither{} => {}", n, hkl.size(), best.vol,
forms[bi][0], forms[bi][1], forms[bi][2], forms[bj][0], forms[bj][1], forms[bj][2],
c.only1, c.only2, c.both, c.neither, weak_density, neither_density,
c.only1, c.only2, c.both, c.neither, other_density, neither_density,
congruent ? "" : ", cells not congruent",
composite ? "two domains on their coincidence lattice" : "one lattice");
if (!composite)