symmetry: the cell a group is adopted on is refined under that group
Build Packages / Create release (push) Successful in 15s
Build Packages / build:rugnux:aarch64 (cross) (push) Successful in 7m21s
Build Packages / build:rugnux-tgz (x86_64) (push) Successful in 8m28s
Build Packages / build:viewer-tgz:cpu (push) Successful in 9m53s
Build Packages / build:viewer-tgz:cuda (push) Successful in 11m57s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 15m12s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 15m50s
Build Packages / build:windows:nocuda (push) Successful in 17m15s
Build Packages / build:windows:cuda (push) Successful in 19m50s
Build Packages / HDF5 consumer tests (DIALS, XDS) (push) Successful in 23m14s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 19m9s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 19m12s
Build Packages / build:rugnux:windows (push) Successful in 10m50s
Build Packages / Generate python client (push) Successful in 44s
Build Packages / Build documentation (push) Successful in 1m23s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 20m10s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 19m23s
Build Packages / build:rpm (rocky8) (push) Successful in 18m2s
Build Packages / build:rpm (rocky9) (push) Successful in 18m22s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 13m46s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 12m25s
Build Packages / Unit tests (push) Successful in 1h12m4s
Build Packages / Create release (push) Successful in 15s
Build Packages / build:rugnux:aarch64 (cross) (push) Successful in 7m21s
Build Packages / build:rugnux-tgz (x86_64) (push) Successful in 8m28s
Build Packages / build:viewer-tgz:cpu (push) Successful in 9m53s
Build Packages / build:viewer-tgz:cuda (push) Successful in 11m57s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 15m12s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 15m50s
Build Packages / build:windows:nocuda (push) Successful in 17m15s
Build Packages / build:windows:cuda (push) Successful in 19m50s
Build Packages / HDF5 consumer tests (DIALS, XDS) (push) Successful in 23m14s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 19m9s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 19m12s
Build Packages / build:rugnux:windows (push) Successful in 10m50s
Build Packages / Generate python client (push) Successful in 44s
Build Packages / Build documentation (push) Successful in 1m23s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 20m10s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 19m23s
Build Packages / build:rpm (rocky8) (push) Successful in 18m2s
Build Packages / build:rpm (rocky9) (push) Successful in 18m22s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 13m46s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 12m25s
Build Packages / Unit tests (push) Successful in 1h12m4s
A space group confirmed from the intensities AFTER integration is one no constrained fit has produced. The Bravais class is decided on the unrefined indexing candidate, so a two-fold the spot positions never offered leaves the freely refined metric standing in the group's own setting - a C 1 2 1 whose alpha is 88.5 - and that cell goes to the report, the master file and the MTZ. At adoption, re-refine the lattice under the group's constraint against the accumulated rotation spots, at the geometry the images were integrated at, and keep it when the spots do - the bar the indexer's own pseudo-symmetry guard uses. Where they refuse it, report the nearest metric the group fixes and say that a deviation that size is not refinement noise. A cell whose violation is above MAX_METRIC_VIOLATION is the WRONG cell for its group rather than an unconstrained one, and nothing here touches it: a visible mismatch must not become a plausible-looking one. The projection is applied as a change of basis, not as three rebuilt vectors: the three-Coord constructor enforces a right-handed basis, and a left-handed lattice came back with an axis flipped and its free angle replaced by the supplement, which failed the merge outright. Battery over 151 datasets, base against this: 144 byte-identical, 7 cells moved onto their group's metric, no space group changed, no run gained or lost, open arm 94/99 both ways. Every merge statistic of the seven is unchanged except completeness, which rises on four and falls 0.1 % on one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KWkZ1o2aoQ9EimF2wtzBky
This commit is contained in:
1 parent
22b4700c1e
commit
0fccbe21b5
11 files changed
+380
-9
No files matched your search
@@ -596,3 +596,46 @@ TEST_CASE("CrystalLattice::ToPrimitive gives an R-centred lattice its rhombohedr
|
||||
CHECK(back.c == Catch::Approx(c).epsilon(1e-4));
|
||||
CHECK(back.gamma == Catch::Approx(120.0).epsilon(1e-4));
|
||||
}
|
||||
|
||||
// SymmetrizeMetric is what a run falls back on when it has adopted a group on a cell no fit under
|
||||
// that group produced. It has to do two things: leave the group's metric exactly satisfied, and move
|
||||
// the cell as little as that requires - which means the orientation it arrives in is kept.
|
||||
TEST_CASE("SymmetrizeMetric puts a cell onto the metric its group fixes") {
|
||||
const auto &c2 = *gemmi::find_spacegroup_by_name("C 1 2 1");
|
||||
|
||||
// A C-centred monoclinic setting whose alpha is 1.5 deg off, as a freely refined metric promoted
|
||||
// after integration arrives: the group cannot describe it.
|
||||
const CrystalLattice off(160.0, 140.0, 90.0, 88.5, 119.9, 90.1);
|
||||
const auto fixed = SymmetrizeMetric(off, c2).GetUnitCell();
|
||||
CHECK(fixed.alpha == Catch::Approx(90.0).margin(1e-3));
|
||||
CHECK(fixed.gamma == Catch::Approx(90.0).margin(1e-3));
|
||||
// The free angle and the lengths stay where they were, to well inside the move it had to make.
|
||||
CHECK(fixed.beta == Catch::Approx(119.9).margin(0.2));
|
||||
CHECK(fixed.a == Catch::Approx(160.0).epsilon(2e-3));
|
||||
CHECK(fixed.b == Catch::Approx(140.0).epsilon(2e-3));
|
||||
CHECK(fixed.c == Catch::Approx(90.0).epsilon(2e-3));
|
||||
|
||||
// A cell the group already describes is not moved at all, whatever orientation it is in.
|
||||
const CrystalLattice ok(80.0, 50.0, 60.0, 90.0, 105.0, 90.0);
|
||||
const auto same = SymmetrizeMetric(ok, c2).GetUnitCell();
|
||||
check_uc(same, 80.0, 50.0, 60.0, 90.0, 105.0, 90.0, 1e-3, 1e-3);
|
||||
|
||||
// ...including one that is not axis-aligned: the answer is a property of the lattice, not of the
|
||||
// frame it is written in, and the orientation it came in is the orientation it goes out in.
|
||||
const RotMatrix rot(0.7, Coord(1.0f, 2.0f, 3.0f).Normalize());
|
||||
const CrystalLattice turned = off.Multiply(rot);
|
||||
// A LEFT-handed basis keeps its hand and its angles: the three-Coord constructor would flip an
|
||||
// axis and hand back the supplement of beta, which is a different cell from the one the
|
||||
// reflections are indexed on - and a metric projection may not change the cell that much.
|
||||
const CrystalLattice flipped = off.Multiply(gemmi::Mat33(-1, 0, 0, 0, 1, 0, 0, 0, 1));
|
||||
REQUIRE(flipped.CalcVolume() < 0);
|
||||
const auto left = SymmetrizeMetric(flipped, c2);
|
||||
CHECK(left.CalcVolume() < 0);
|
||||
CHECK(left.GetUnitCell().beta == Catch::Approx(flipped.GetUnitCell().beta).margin(1e-3));
|
||||
CHECK(left.GetUnitCell().alpha == Catch::Approx(90.0).margin(1e-3));
|
||||
|
||||
const auto turned_fixed = SymmetrizeMetric(turned, c2);
|
||||
check_uc(turned_fixed.GetUnitCell(), fixed.a, fixed.b, fixed.c, 90.0, fixed.beta, 90.0, 1e-3, 1e-3);
|
||||
CHECK(turned_fixed.Vec0() * turned.Vec0()
|
||||
== Catch::Approx(turned_fixed.Vec0().Length() * turned.Vec0().Length()).epsilon(1e-4));
|
||||
}
|
||||
Reference in new issue
Block a user