Build Packages / Create release (push) Successful in 24s
Build Packages / build:viewer:macos-arm64:nocuda (push) Successful in 3m29s
Build Packages / build:rugnux:macos-arm64:nocuda (push) Successful in 2m43s
Build Packages / build:rugnux:linux-aarch64:cuda (push) Successful in 8m27s
Build Packages / build:rugnux:linux-x86_64:cuda (push) Successful in 9m53s
Build Packages / build:viewer:linux-x86_64:nocuda (push) Successful in 9m58s
Build Packages / build:viewer:linux-x86_64:cuda (push) Successful in 11m22s
Build Packages / build:jfjoch:rocky8:nocuda (push) Successful in 13m39s
Build Packages / build:viewer:windows-x86_64:nocuda (push) Successful in 18m37s
Build Packages / build:jfjoch:rocky9:nocuda (push) Successful in 16m32s
Build Packages / build:viewer:windows-x86_64:cuda (push) Successful in 24m11s
Build Packages / HDF5 consumer tests (DIALS, XDS) (push) Successful in 25m30s
Build Packages / build:jfjoch:ubuntu2404:nocuda (push) Successful in 19m3s
Build Packages / build:jfjoch:ubuntu2204:nocuda (push) Successful in 20m23s
Build Packages / build:jfjoch:rocky8:cuda-sls9 (push) Successful in 19m41s
Build Packages / Generate python client (push) Successful in 50s
Build Packages / Build documentation (push) Successful in 1m16s
Build Packages / build:jfjoch:rocky9:cuda-sls9 (push) Successful in 21m0s
Build Packages / build:jfjoch:rocky8:cuda (push) Successful in 18m38s
Build Packages / build:rugnux:windows-x86_64:cuda (push) Successful in 14m33s
Build Packages / build:jfjoch:rocky9:cuda (push) Successful in 17m55s
Build Packages / build:jfjoch:ubuntu2204:cuda (push) Successful in 20m50s
Build Packages / build:jfjoch:ubuntu2404:cuda (push) Successful in 18m38s
Build Packages / Unit tests (push) Successful in 1h46m14s
* jfjoch_broker: Optional per-dataset authentication - statistics, images and plots can require a bearer token, which jfjoch_viewer supports. * jfjoch_viewer: Dark mode and a theme-matched colour scheme, a magnifier panel, and simpler contrast and background controls. * Rugnux: Multiple performance improvements on GPU and CPU (CPU-only processing up to 40% faster, faster image decoding on ARM), with unchanged results. * Rugnux: `--model` rigid-body refinement runs on the GPU, and the model-validation check is faster and more reliable. * Rugnux: Improved scaling and merging - error model, outlier rejection, absorption correction and French-Wilson amplitudes now agree more closely with XDS and ctruncate. * Rugnux: Improved integration - radial background on powder and ice rings, crowded rotation data keep their reflections, and CPU-only builds integrate large unit cells as GPU builds do. * Rugnux: More robust detector geometry - measured beam centre, X-ray bandwidth and goniometer rate, and geometry refinement accepted only on significant evidence. * Rugnux: Merged files are written in the standard setting, or in the setting of a reference MTZ, structure-factor mmCIF or model, with its free-R flags. * Rugnux: Richer report - ice and powder rings, further lattices, superstructure candidates and mosaicity, with warnings worded as prompts to check. * Rugnux: Clear error messages when a data set needs more GPU or host memory than is available. Reviewed-on: #83 Co-authored-by: Filip Leonarski <filip.leonarski@psi.ch>
76 lines
3.0 KiB
C++
76 lines
3.0 KiB
C++
// SPDX-FileCopyrightText: 2026 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
#include "LeftoverLattices.h"
|
|
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
#include <Eigen/Dense>
|
|
#include "../common/JFJochMath.h" // PI
|
|
|
|
const char *LeftoverLatticeKindName(LeftoverLatticeKind kind) {
|
|
switch (kind) {
|
|
case LeftoverLatticeKind::Self: return "SELF";
|
|
case LeftoverLatticeKind::Domain: return "DOMAIN";
|
|
case LeftoverLatticeKind::TwinDomain: return "TWIN_DOMAIN";
|
|
case LeftoverLatticeKind::Segmented: return "SEGMENTED";
|
|
case LeftoverLatticeKind::RelatedCell: return "RELATED_CELL";
|
|
case LeftoverLatticeKind::Foreign: return "FOREIGN";
|
|
}
|
|
return "FOREIGN";
|
|
}
|
|
|
|
double LatticeMisorientationDeg(const CrystalLattice &a, const CrystalLattice &b) {
|
|
auto mat = [](const CrystalLattice &l) {
|
|
Eigen::Matrix3d M;
|
|
const Coord v[3] = {l.Vec0(), l.Vec1(), l.Vec2()};
|
|
for (int c = 0; c < 3; c++)
|
|
M.col(c) = Eigen::Vector3d(v[c].x, v[c].y, v[c].z);
|
|
return M;
|
|
};
|
|
const Eigen::Matrix3d A = mat(a), B = mat(b);
|
|
const Eigen::Matrix3d GA = A.transpose() * A;
|
|
const double scale = GA.diagonal().mean();
|
|
// Every unimodular change of basis with entries -1..1: enough for two reduced cells.
|
|
double best = NAN;
|
|
for (int code = 0; code < 19683; code++) {
|
|
Eigen::Matrix3d M;
|
|
int c = code;
|
|
for (int e = 0; e < 9; e++) {
|
|
M(e / 3, e % 3) = c % 3 - 1;
|
|
c /= 3;
|
|
}
|
|
if (std::abs(M.determinant() - 1.0) > 1e-6)
|
|
continue;
|
|
const Eigen::Matrix3d BM = B * M;
|
|
if ((BM.transpose() * BM - GA).cwiseAbs().maxCoeff() > 0.06 * scale)
|
|
continue;
|
|
// The rotation nearest to the (slightly non-orthogonal) map from A to BM.
|
|
Eigen::JacobiSVD<Eigen::Matrix3d> svd(BM * A.inverse(), Eigen::ComputeFullU | Eigen::ComputeFullV);
|
|
const Eigen::Matrix3d R = svd.matrixU() * svd.matrixV().transpose();
|
|
if (R.determinant() < 0)
|
|
continue;
|
|
const double ang = std::acos(std::clamp((R.trace() - 1.0) / 2.0, -1.0, 1.0)) * 180.0 / PI;
|
|
if (std::isnan(best) || ang < best)
|
|
best = ang;
|
|
}
|
|
return best;
|
|
}
|
|
|
|
LeftoverLatticeKind ClassifyLeftoverLattice(double misorientation_deg, double volume_ratio,
|
|
double sweep_concentration) {
|
|
if (std::isfinite(misorientation_deg)) {
|
|
if (misorientation_deg <= 1.0)
|
|
return LeftoverLatticeKind::Self;
|
|
if (sweep_concentration >= 0.6)
|
|
return LeftoverLatticeKind::Segmented;
|
|
if (misorientation_deg >= 177.0)
|
|
return LeftoverLatticeKind::TwinDomain;
|
|
return LeftoverLatticeKind::Domain;
|
|
}
|
|
for (int n = 1; n <= 8; n++)
|
|
if (std::abs(volume_ratio / n - 1.0) < 0.06 || std::abs(volume_ratio * n - 1.0) < 0.06)
|
|
return LeftoverLatticeKind::RelatedCell;
|
|
return LeftoverLatticeKind::Foreign;
|
|
}
|