MultiLatticeSearch: Explore all valid sign flips when comparing with reference cell
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 9m24s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 10m30s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 11m2s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 11m43s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 12m39s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 12m51s
Build Packages / build:rpm (rocky8) (push) Successful in 10m21s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 10m4s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 9m31s
Build Packages / Generate python client (push) Successful in 12s
Build Packages / XDS test (durin plugin) (push) Successful in 8m34s
Build Packages / Create release (push) Skipped
Build Packages / Build documentation (push) Successful in 38s
Build Packages / build:rpm (rocky9) (push) Successful in 11m47s
Build Packages / DIALS test (push) Successful in 12m35s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 6m15s
Build Packages / XDS test (neggia plugin) (push) Successful in 5m12s
Build Packages / Unit tests (push) Successful in 56m53s

This commit is contained in:
2026-06-05 11:36:23 +02:00
parent 64e6b32e1d
commit 02ecf5c32e
4 changed files with 73 additions and 20 deletions
+8 -1
View File
@@ -80,9 +80,16 @@ void CrystalLattice::Sort() {
std::swap(vec[0], vec[1]);
}
void CrystalLattice::FlipSign(size_t i1) {
if (i1 >= 3)
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"index out of range (0..2)");
vec[i1] *= -1;
}
void CrystalLattice::FixHandedness() {
if (CalcVolume() < 0)
vec[2] *= -1;
FlipSign(2);
}
+1
View File
@@ -39,6 +39,7 @@ public:
void Regularize(const gemmi::CrystalSystem &input);
[[nodiscard]] std::vector<float> GetUBMatrix() const;
CrystalLattice NiggliReduce() const;
void FlipSign(size_t i1);
};
inline std::ostream &operator<<( std::ostream &output, const CrystalLattice &in ) {
+49 -19
View File
@@ -35,6 +35,30 @@ namespace {
}
}
CrystalLattice Transform(const CrystalLattice &in_latt, int i) {
CrystalLattice latt = in_latt;
switch (i) {
case 0:
break;
case 1:
latt.FlipSign(0);
latt.FlipSign(1);
break;
case 2:
latt.FlipSign(0);
latt.FlipSign(2);
break;
case 3:
latt.FlipSign(1);
latt.FlipSign(2);
break;
default:
break;
}
return latt;
}
std::vector<MultiLatticeSearchResult> MultiLatticeSearch(const std::vector<CrystalLattice> &lattices,
float dist_tolerance,
float angle_tolerance_deg) {
@@ -48,29 +72,35 @@ std::vector<MultiLatticeSearchResult> MultiLatticeSearch(const std::vector<Cryst
ret.push_back({reference, reference, Coord(0, 0, 0)});
for (size_t i = 1; i < lattices.size(); i++) {
const CrystalLattice &latt = lattices[i];
bool found = false;
for (int flip = 0; flip < 4; flip++) {
if (found)
continue;
const CrystalLattice latt = Transform(lattices[i], flip);
if (!latt.GetUnitCell().is_close(ref_cell, dist_tolerance, angle_tolerance_deg))
continue;
if (!latt.GetUnitCell().is_close(ref_cell, dist_tolerance, angle_tolerance_deg))
continue;
const Eigen::Matrix3d R = RotationRefToTarget(reference, latt);
const Eigen::Matrix3d R = RotationRefToTarget(reference, latt);
const Eigen::AngleAxisd aa(R);
const Eigen::Vector3d rod = aa.angle() * aa.axis();
const Coord rotation_vector(static_cast<float>(rod.x()),
static_cast<float>(rod.y()),
static_cast<float>(rod.z()));
const Eigen::AngleAxisd aa(R);
const Eigen::Vector3d rod = aa.angle() * aa.axis();
const Coord rotation_vector(static_cast<float>(rod.x()),
static_cast<float>(rod.y()),
static_cast<float>(rod.z()));
// output_lattice = R * reference, built straight from the Eigen matrix
// so it is exactly a proper rotation of the reference (full double precision).
const Eigen::Matrix3d out = R * LatticeMatrix(reference);
ret.push_back({
latt,
CrystalLattice(Coord(out(0, 0), out(1, 0), out(2, 0)),
Coord(out(0, 1), out(1, 1), out(2, 1)),
Coord(out(0, 2), out(1, 2), out(2, 2))),
rotation_vector
});
// output_lattice = R * reference, built straight from the Eigen matrix
// so it is exactly a proper rotation of the reference (full double precision).
const Eigen::Matrix3d out = R * LatticeMatrix(reference);
ret.push_back({
latt,
CrystalLattice(Coord(out(0, 0), out(1, 0), out(2, 0)),
Coord(out(0, 1), out(1, 1), out(2, 1)),
Coord(out(0, 2), out(1, 2), out(2, 2))),
rotation_vector
});
found = true;
}
}
return ret;
+15
View File
@@ -65,4 +65,19 @@ TEST_CASE("MultiLatticeSearch_SkipsDifferentCell") {
TEST_CASE("MultiLatticeSearch_Empty") {
auto result = MultiLatticeSearch({});
CHECK(result.empty());
}
TEST_CASE("MultiLatticeSearch_EP") {
// Real EP case
CrystalLattice cell1(Coord(-13.2, -30.0, -29.6),
Coord(70.1, -12.16, -18.6),
Coord(7.6, -23.9, 44.8));
CrystalLattice cell2(Coord(-13.2, -29.9, -29.5),
Coord(-70.1, 12.15, 18.8),
Coord(1.8, 45.4, -23.7)
);
auto result = MultiLatticeSearch({cell1, cell2},
0.1, 5);
REQUIRE(result.size() == 2);
}