XtalOptimizer: ChatGPT fix to monoclinic extraction logic
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 14m17s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 15m19s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 15m54s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 17m35s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 17m37s
Build Packages / build:rpm (rocky8) (push) Successful in 17m37s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 18m40s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 9m39s
Build Packages / Generate python client (push) Successful in 33s
Build Packages / Build documentation (push) Successful in 54s
Build Packages / Create release (push) Skipped
Build Packages / build:rpm (rocky9) (push) Successful in 13m12s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 12m57s
Build Packages / XDS test (durin plugin) (push) Successful in 11m24s
Build Packages / XDS test (neggia plugin) (push) Successful in 10m26s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 11m54s
Build Packages / DIALS test (push) Successful in 13m12s
Build Packages / Unit tests (push) Successful in 1h1m23s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 14m17s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 15m19s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 15m54s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 17m35s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 17m37s
Build Packages / build:rpm (rocky8) (push) Successful in 17m37s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 18m40s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 9m39s
Build Packages / Generate python client (push) Successful in 33s
Build Packages / Build documentation (push) Successful in 54s
Build Packages / Create release (push) Skipped
Build Packages / build:rpm (rocky9) (push) Successful in 13m12s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 12m57s
Build Packages / XDS test (durin plugin) (push) Successful in 11m24s
Build Packages / XDS test (neggia plugin) (push) Successful in 10m26s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 11m54s
Build Packages / DIALS test (push) Successful in 13m12s
Build Packages / Unit tests (push) Successful in 1h1m23s
This commit is contained in:
@@ -355,17 +355,18 @@ void LatticeToRodriguesAndLengths_Hex(const CrystalLattice &latt, double rod[3],
|
||||
// Extract rotation (Rodrigues), lengths (a,b,c) and beta (rad) for monoclinic (unique axis b).
|
||||
// Frame choice: e2 aligned with b; e1 from a projected orthogonal to e2; e3 = e1 x e2.
|
||||
void LatticeToRodriguesLengthsBeta_Mono(const CrystalLattice &latt,
|
||||
double rod[3],
|
||||
double lengths[3],
|
||||
double &beta_rad) {
|
||||
double rod[3],
|
||||
double lengths[3],
|
||||
double &beta_rad) {
|
||||
const Coord a = latt.Vec0();
|
||||
const Coord b = latt.Vec1();
|
||||
const Coord c = latt.Vec2();
|
||||
|
||||
Eigen::Vector3d A(a[0], a[1], a[2]);
|
||||
Eigen::Vector3d Bv(b[0], b[1], b[2]);
|
||||
Eigen::Vector3d C(c[0], c[1], c[2]);
|
||||
const Eigen::Vector3d A(a[0], a[1], a[2]);
|
||||
const Eigen::Vector3d Bv(b[0], b[1], b[2]);
|
||||
const Eigen::Vector3d C(c[0], c[1], c[2]);
|
||||
|
||||
// Unit cell lengths
|
||||
const double a_len = A.norm();
|
||||
const double b_len = Bv.norm();
|
||||
const double c_len = C.norm();
|
||||
@@ -374,41 +375,63 @@ void LatticeToRodriguesLengthsBeta_Mono(const CrystalLattice &latt,
|
||||
lengths[1] = b_len;
|
||||
lengths[2] = c_len;
|
||||
|
||||
// beta = angle between a and c
|
||||
// Monoclinic beta = angle(a, c)
|
||||
double cos_beta = 0.0;
|
||||
if (a_len > 0.0 && c_len > 0.0)
|
||||
cos_beta = std::max(-1.0, std::min(1.0, A.dot(C) / (a_len * c_len)));
|
||||
if (a_len > 1e-15 && c_len > 1e-15) {
|
||||
cos_beta = A.dot(C) / (a_len * c_len);
|
||||
cos_beta = std::clamp(cos_beta, -1.0, 1.0);
|
||||
}
|
||||
|
||||
beta_rad = std::acos(cos_beta);
|
||||
|
||||
// Recover R from the same forward model used in refinement:
|
||||
// L ≈ R * B(beta) * D(a,b,c) => R ≈ L * (B*D)^-1
|
||||
// Protect against singular construction
|
||||
const double sin_beta = std::max(std::abs(std::sin(beta_rad)), 1e-12);
|
||||
|
||||
// Canonical monoclinic basis:
|
||||
//
|
||||
// B =
|
||||
// [ 1 0 cos(beta) ]
|
||||
// [ 0 1 0 ]
|
||||
// [ 0 0 sin(beta) ]
|
||||
//
|
||||
Eigen::Matrix3d Bmono = Eigen::Matrix3d::Zero();
|
||||
Bmono(0,0) = 1.0;
|
||||
Bmono(1,1) = 1.0;
|
||||
Bmono(0,2) = std::cos(beta_rad);
|
||||
Bmono(2,2) = sin_beta;
|
||||
|
||||
// Scale by lengths
|
||||
Eigen::DiagonalMatrix<double,3> D(a_len, b_len, c_len);
|
||||
|
||||
// Ideal body-frame lattice
|
||||
const Eigen::Matrix3d M = Bmono * D;
|
||||
|
||||
// Observed lattice
|
||||
Eigen::Matrix3d L;
|
||||
L.col(0) = A;
|
||||
L.col(1) = Bv;
|
||||
L.col(2) = C;
|
||||
|
||||
Eigen::Matrix3d Bmono = Eigen::Matrix3d::Identity();
|
||||
Bmono(0, 2) = std::cos(beta_rad);
|
||||
Bmono(2, 2) = std::sin(beta_rad);
|
||||
|
||||
Eigen::DiagonalMatrix<double, 3> D(lengths[0], lengths[1], lengths[2]);
|
||||
Eigen::Matrix3d M = Bmono * D;
|
||||
|
||||
Eigen::Matrix3d R_est = Eigen::Matrix3d::Identity();
|
||||
if (std::abs(M.determinant()) > 1e-15) {
|
||||
R_est = L * M.inverse();
|
||||
}
|
||||
// Estimate rotation:
|
||||
// R ≈ L * M^{-1}
|
||||
Eigen::Matrix3d R_est = L * M.inverse();
|
||||
|
||||
// Project to nearest proper rotation matrix
|
||||
Eigen::JacobiSVD<Eigen::Matrix3d> svd(R_est, Eigen::ComputeFullU | Eigen::ComputeFullV);
|
||||
|
||||
Eigen::Matrix3d R = svd.matrixU() * svd.matrixV().transpose();
|
||||
|
||||
// Enforce det(R)=+1
|
||||
if (R.determinant() < 0.0) {
|
||||
Eigen::Matrix3d U = svd.matrixU();
|
||||
U.col(2) *= -1.0;
|
||||
R = U * svd.matrixV().transpose();
|
||||
}
|
||||
|
||||
// Rodrigues vector
|
||||
Eigen::AngleAxisd aa(R);
|
||||
Eigen::Vector3d r = aa.angle() * aa.axis();
|
||||
const Eigen::Vector3d r = aa.angle() * aa.axis();
|
||||
|
||||
rod[0] = r.x();
|
||||
rod[1] = r.y();
|
||||
rod[2] = r.z();
|
||||
|
||||
Reference in New Issue
Block a user