v1.0.0-rc.173 (#83)
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
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>
This commit was merged in pull request #83.
This commit is contained in:
1 parent
6dfe065365
commit
84228bf8be
452 files changed
+23762
-3779
No files matched your search
@@ -816,11 +816,30 @@ TEST_CASE("ResultReport_TranslationalNCS", "[Diagnostics]") {
|
||||
result.tncs.detected = false;
|
||||
result.tncs.near_extinct_class = false;
|
||||
result.tncs.undeclared_lattice_translations.push_back({0.5, 0.5, 0.0});
|
||||
result.tncs.undeclared_lattice_translation_pct.push_back(98.0);
|
||||
const auto lat = RenderResultReport("prefix", "in.h5", x, result);
|
||||
CHECK(lat.find("\nTNCS_DETECTED= FALSE\n") != std::string::npos);
|
||||
CHECK(lat.find("\nUNDECLARED_LATTICE_TRANSLATION= 0.500 0.500 0.000\n") != std::string::npos);
|
||||
CHECK(lat.find("\nUNDECLARED_LATTICE_TRANSLATION_PCT= 98.0\n") != std::string::npos);
|
||||
CHECK(lat.find("\nPATHOLOGY_FLAGS= LATTICE_TRANSLATION\n") != std::string::npos);
|
||||
CHECK(lat.find("\nTNCS_SUBLATTICE=") == std::string::npos);
|
||||
|
||||
// Admitted at 75% but short of a lattice translation's height: still a prompt to check, and the
|
||||
// wording names the very strong pseudo-translation as the other reading.
|
||||
result.tncs.undeclared_lattice_translation_pct = {80.0};
|
||||
const auto strong = RenderResultReport("prefix", "in.h5", x, result);
|
||||
CHECK(strong.find("\nPATHOLOGY_FLAGS= LATTICE_TRANSLATION\n") != std::string::npos);
|
||||
CHECK(strong.find("or a very strong pseudo-translation") != std::string::npos);
|
||||
|
||||
// Significant but weak: warned about, and worded as a check.
|
||||
result.tncs.undeclared_lattice_translations.clear();
|
||||
result.tncs.undeclared_lattice_translation_pct.clear();
|
||||
result.tncs.detected = true;
|
||||
result.tncs.peak_percent = 8.1;
|
||||
const auto weak = RenderResultReport("prefix", "in.h5", x, result);
|
||||
CHECK(weak.find("\nTNCS_DETECTED= TRUE\n") != std::string::npos);
|
||||
CHECK(weak.find("\nPATHOLOGY_FLAGS= PSEUDO_TRANSLATION\n") != std::string::npos);
|
||||
CHECK(weak.find("significant but weak; check whether molecular replacement needs it declared") != std::string::npos);
|
||||
}
|
||||
|
||||
TEST_CASE("ResultReport_GeometryNotConverged", "[Diagnostics]") {
|
||||
@@ -841,3 +860,308 @@ TEST_CASE("ResultReport_GeometryNotConverged", "[Diagnostics]") {
|
||||
CHECK(text.substr(flags, text.find('\n', flags + 1) - flags).find("GEOMETRY_NOT_CONVERGED")
|
||||
!= std::string::npos);
|
||||
}
|
||||
|
||||
TEST_CASE("ResultReport_RotationScale", "[Diagnostics]") {
|
||||
// A run that adopted a goniometer rotation scale integrated at the scaled oscillation, so that
|
||||
// is the oscillation the report gives; the starting angle is the stage's own and stays.
|
||||
DiffractionExperiment x(DetJF(1));
|
||||
x.Goniometer(GoniometerAxis("omega", 10.0f, 0.1f, Coord(1, 0, 0), {}));
|
||||
ProcessResult result;
|
||||
result.post_refine = PostRefineResult{};
|
||||
result.post_refine->rotation_scale = 0.97;
|
||||
result.post_refine->rotation_scale_suspect = true;
|
||||
|
||||
RunProvenance dev;
|
||||
dev.developer = true;
|
||||
const auto text = RenderResultReport("prefix", "in.h5", x, result, dev);
|
||||
CHECK(text.find("\nOSCILLATION_RANGE= 0.0970\n") != std::string::npos);
|
||||
CHECK(text.find("\nSTARTING_ANGLE= 10.000\n") != std::string::npos);
|
||||
CHECK(text.find("\nGONIOMETER_ROTATION_SCALE= 0.97000\n") != std::string::npos);
|
||||
CHECK(text.find("\nGONIOMETER_ROTATION_SCALE_SUSPECT= TRUE\n") != std::string::npos);
|
||||
|
||||
// A fit the run did not act on is reported as a fit, and the file's oscillation stands.
|
||||
result.post_refine->rotation_scale_suspect = false;
|
||||
const auto kept = RenderResultReport("prefix", "in.h5", x, result, dev);
|
||||
CHECK(kept.find("\nOSCILLATION_RANGE= 0.1000\n") != std::string::npos);
|
||||
CHECK(kept.find("\nGONIOMETER_ROTATION_SCALE_SUSPECT= FALSE\n") != std::string::npos);
|
||||
}
|
||||
|
||||
TEST_CASE("LeftoverLattice_Misorientation", "[Diagnostics]") {
|
||||
const CrystalLattice triclinic(52.0f, 61.0f, 73.0f, 81.0f, 76.0f, 69.0f);
|
||||
const auto rotated = [](const CrystalLattice &l, float deg, const Coord &axis) {
|
||||
const RotMatrix r(deg * static_cast<float>(PI) / 180.0f, axis);
|
||||
return CrystalLattice(r * l.Vec0(), r * l.Vec1(), r * l.Vec2());
|
||||
};
|
||||
const CrystalLattice turned = rotated(triclinic, 3.0f, Coord(0.3f, -0.5f, 0.8f));
|
||||
CHECK(LatticeMisorientationDeg(triclinic, turned) == Catch::Approx(3.0).margin(0.01));
|
||||
// The same lattice in another basis of the same metric (a cyclic relabelling written back) is
|
||||
// still 3 deg away.
|
||||
const CrystalLattice relabelled(turned.Vec1(), turned.Vec2(), turned.Vec0());
|
||||
CHECK(LatticeMisorientationDeg(triclinic, relabelled) == Catch::Approx(3.0).margin(0.01));
|
||||
// Turned by 180 deg about an axis that is no symmetry of a triclinic lattice: a twin domain.
|
||||
CHECK(LatticeMisorientationDeg(triclinic, rotated(triclinic, 180.0f, Coord(0.2f, 0.9f, 0.1f)))
|
||||
== Catch::Approx(180.0).margin(0.01));
|
||||
// A lattice symmetry is not a misorientation: tetragonal turned 90 deg about c.
|
||||
const CrystalLattice tetragonal(40.0f, 40.0f, 90.0f, 90.0f, 90.0f, 90.0f);
|
||||
CHECK(LatticeMisorientationDeg(tetragonal, rotated(tetragonal, 90.0f, tetragonal.Vec2())) < 0.01);
|
||||
// An unrelated cell has no matching basis.
|
||||
CHECK(std::isnan(LatticeMisorientationDeg(triclinic, CrystalLattice(45.0f, 45.0f, 120.0f, 90.0f, 90.0f, 90.0f))));
|
||||
}
|
||||
|
||||
TEST_CASE("LeftoverLattice_Classify", "[Diagnostics]") {
|
||||
CHECK(ClassifyLeftoverLattice(0.4, 1.0, 0.3) == LeftoverLatticeKind::Self);
|
||||
CHECK(ClassifyLeftoverLattice(2.7, 1.0, 0.3) == LeftoverLatticeKind::Domain);
|
||||
CHECK(ClassifyLeftoverLattice(179.9, 1.0, 0.3) == LeftoverLatticeKind::TwinDomain);
|
||||
CHECK(ClassifyLeftoverLattice(71.0, 1.0, 0.8) == LeftoverLatticeKind::Segmented);
|
||||
CHECK(ClassifyLeftoverLattice(NAN, 0.5, 0.3) == LeftoverLatticeKind::RelatedCell);
|
||||
CHECK(ClassifyLeftoverLattice(NAN, 3.02, 0.3) == LeftoverLatticeKind::RelatedCell);
|
||||
CHECK(ClassifyLeftoverLattice(NAN, 1.34, 0.3) == LeftoverLatticeKind::Foreign);
|
||||
}
|
||||
|
||||
TEST_CASE("ResultReport_LeftoverLattices", "[Diagnostics]") {
|
||||
DiffractionExperiment x(DetJF(1));
|
||||
ProcessResult result;
|
||||
result.consensus_cell = UnitCell{.a = 50.0f, .b = 60.0f, .c = 70.0f,
|
||||
.alpha = 90.0f, .beta = 100.0f, .gamma = 90.0f};
|
||||
LeftoverLatticeCensus census;
|
||||
census.primary_spots_pct = 60.0;
|
||||
census.primary_intensity_pct = 70.0;
|
||||
result.leftover_lattices = census;
|
||||
|
||||
auto text = RenderResultReport("p", "in.h5", x, result);
|
||||
CHECK(text.find("EXTRA_LATTICE_COUNT= 0") != std::string::npos);
|
||||
CHECK(text.find("Multiple lattices none found") != std::string::npos);
|
||||
CHECK(text.find("MULTIPLE_LATTICES= FALSE") != std::string::npos);
|
||||
|
||||
// A related cell carries intensity but is a question about the main cell, not a second crystal.
|
||||
LeftoverLattice related{.kind = LeftoverLatticeKind::RelatedCell, .cell = *result.consensus_cell,
|
||||
.volume_ratio = 0.5, .misorientation_deg = NAN, .z = 40.0,
|
||||
.spots_pct = 15.0, .intensity_pct = 12.0, .sweep_concentration = 0.3};
|
||||
result.leftover_lattices->lattices = {related};
|
||||
text = RenderResultReport("p", "in.h5", x, result);
|
||||
CHECK(text.find("EXTRA_LATTICE_1_KIND= RELATED_CELL") != std::string::npos);
|
||||
CHECK(text.find("EXTRA_LATTICE_1_MISORIENTATION_DEG") == std::string::npos);
|
||||
CHECK(text.find("MULTIPLE_LATTICES= FALSE") != std::string::npos);
|
||||
|
||||
// An unrelated cell is listed but not warned about: it is as often a wrong main lattice or tNCS.
|
||||
LeftoverLattice foreign{.kind = LeftoverLatticeKind::Foreign, .cell = *result.consensus_cell,
|
||||
.volume_ratio = 1.34, .misorientation_deg = NAN, .z = 40.0,
|
||||
.spots_pct = 20.0, .intensity_pct = 30.0, .sweep_concentration = 0.3};
|
||||
result.leftover_lattices->lattices = {foreign};
|
||||
text = RenderResultReport("p", "in.h5", x, result);
|
||||
CHECK(text.find("EXTRA_LATTICE_1_KIND= FOREIGN") != std::string::npos);
|
||||
CHECK(text.find("MULTIPLE_LATTICES= FALSE") != std::string::npos);
|
||||
|
||||
LeftoverLattice domain{.kind = LeftoverLatticeKind::Domain, .cell = *result.consensus_cell,
|
||||
.volume_ratio = 1.0, .misorientation_deg = 2.7, .z = 250.0,
|
||||
.spots_pct = 20.0, .intensity_pct = 25.0, .sweep_concentration = 0.3};
|
||||
result.leftover_lattices->lattices = {domain, related};
|
||||
text = RenderResultReport("p", "in.h5", x, result);
|
||||
CHECK(text.find("EXTRA_LATTICE_COUNT= 2") != std::string::npos);
|
||||
CHECK(text.find("EXTRA_LATTICE_1_MISORIENTATION_DEG= 2.70") != std::string::npos);
|
||||
CHECK(text.find("EXTRA_LATTICE_INTENSITY_PCT= 25.0") != std::string::npos);
|
||||
CHECK(text.find("MULTIPLE_LATTICES= TRUE") != std::string::npos);
|
||||
CHECK(text.find("split crystal, 2.7 deg from the main lattice") != std::string::npos);
|
||||
const auto flags = text.find("\nPATHOLOGY_FLAGS= ");
|
||||
REQUIRE(flags != std::string::npos);
|
||||
CHECK(text.substr(flags, text.find('\n', flags + 1) - flags).find("MULTIPLE_LATTICES") != std::string::npos);
|
||||
}
|
||||
|
||||
TEST_CASE("ResultReport_Mosaicity", "[Diagnostics]") {
|
||||
DiffractionExperiment x(DetJF(1));
|
||||
ProcessResult result;
|
||||
CHECK(RenderResultReport("p", "in.h5", x, result).find("MOSAICITY_DEG") == std::string::npos);
|
||||
result.mosaicity_deg = 0.091;
|
||||
result.mosaicity_deg_p10 = 0.080;
|
||||
result.mosaicity_deg_p90 = 0.105;
|
||||
const auto text = RenderResultReport("p", "in.h5", x, result);
|
||||
CHECK(text.find("MOSAICITY_DEG= 0.091") != std::string::npos);
|
||||
CHECK(text.find("MOSAICITY_DEG_P10= 0.080") != std::string::npos);
|
||||
CHECK(text.find("MOSAICITY_DEG_P90= 0.105") != std::string::npos);
|
||||
CHECK(text.find("Mosaicity 0.091 deg") != std::string::npos);
|
||||
}
|
||||
|
||||
TEST_CASE("ResultReport_SupercellCheck", "[Diagnostics]") {
|
||||
DiffractionExperiment x(DetJF(1));
|
||||
ProcessResult result;
|
||||
result.consensus_cell = UnitCell{.a = 50.0f, .b = 60.0f, .c = 70.0f,
|
||||
.alpha = 90.0f, .beta = 90.0f, .gamma = 90.0f};
|
||||
result.has_merge_statistics = true;
|
||||
ProcessResult::SupercellClass sc;
|
||||
sc.h = 0; sc.k = 0; sc.l = 1;
|
||||
sc.occupancy_pct = 18.0;
|
||||
sc.rock_pct = 5.0;
|
||||
sc.rock_se_pct = 0.4;
|
||||
sc.i_over_sigma = 1.2;
|
||||
sc.doubled_cell = UnitCell{.a = 50.0f, .b = 60.0f, .c = 140.0f, .alpha = 90.0f, .beta = 90.0f, .gamma = 90.0f};
|
||||
result.supercell = sc;
|
||||
|
||||
// A weak rocking part, as a real doubled cell can show: a prompt to check, worded as one.
|
||||
auto text = RenderResultReport("p", "in.h5", x, result);
|
||||
CHECK(text.find("\nSUPERCELL_POSSIBLE= TRUE\n") != std::string::npos);
|
||||
CHECK(text.find("\nPATHOLOGY_FLAGS= SUPERCELL_POSSIBLE\n") != std::string::npos);
|
||||
CHECK(text.find("POSSIBLE, check - class 0 0 1") != std::string::npos);
|
||||
CHECK(text.find("WARNING: Check the cell") != std::string::npos);
|
||||
CHECK(text.find("may put spots there") == std::string::npos);
|
||||
|
||||
// Further domains of the crystal can put spots on the half-integer nodes, and the line says so.
|
||||
LeftoverLatticeCensus census;
|
||||
census.primary_intensity_pct = 70.0;
|
||||
census.lattices.push_back(LeftoverLattice{.kind = LeftoverLatticeKind::TwinDomain, .cell = *result.consensus_cell,
|
||||
.volume_ratio = 1.0, .misorientation_deg = 179.5, .z = 50.0,
|
||||
.spots_pct = 8.0, .intensity_pct = 7.0, .sweep_concentration = 0.3});
|
||||
result.leftover_lattices = census;
|
||||
text = RenderResultReport("p", "in.h5", x, result);
|
||||
CHECK(text.find("the further lattice domains found may put spots there") != std::string::npos);
|
||||
CHECK(text.find("spots of the further lattice domains found landing on those positions") != std::string::npos);
|
||||
|
||||
// Not measured to rock: no indication.
|
||||
result.supercell->rock_pct = 1.0;
|
||||
text = RenderResultReport("p", "in.h5", x, result);
|
||||
CHECK(text.find("Supercell no indication") != std::string::npos);
|
||||
CHECK(text.find("\nPATHOLOGY_FLAGS= NONE\n") != std::string::npos);
|
||||
}
|
||||
|
||||
TEST_CASE("ResultReport_TwinningOutsidePhysicalRange", "[Diagnostics]") {
|
||||
DiffractionExperiment x(DetJF(1));
|
||||
ProcessResult result;
|
||||
result.consensus_cell = UnitCell{.a = 70.0f, .b = 70.0f, .c = 70.0f,
|
||||
.alpha = 90.0f, .beta = 90.0f, .gamma = 90.0f};
|
||||
result.has_merge_statistics = true;
|
||||
result.twinning.l_test_pairs = 5000;
|
||||
result.twinning.mean_abs_l = 0.355;
|
||||
result.twinning.second_moment = 1.60;
|
||||
result.twinning.twinning_suspected = true;
|
||||
result.twinning.adopted_operators_suspect = true;
|
||||
|
||||
// Below the 0.375 of a perfect twin: no twin fraction can give it, so neither a twin nor a false
|
||||
// operator is read from it.
|
||||
auto text = RenderResultReport("p", "in.h5", x, result);
|
||||
CHECK(text.find("\nTWINNING_VERDICT= NOT_READABLE\n") != std::string::npos);
|
||||
CHECK(text.find("TWINNING ") == std::string::npos);
|
||||
CHECK(text.find("\nPATHOLOGY_FLAGS= NONE\n") != std::string::npos);
|
||||
CHECK(text.find("Twinning not readable (<|L|> 0.355") != std::string::npos);
|
||||
CHECK(text.find("SYMMETRY SUSPECT") == std::string::npos);
|
||||
|
||||
// Inside the range on the adopted merge but far above 0.5 on the merge before the search: the
|
||||
// statistic is distorted on these data, and the low adopted reading is not evidence either.
|
||||
result.twinning.mean_abs_l = 0.395;
|
||||
TwinningAnalysisResult pre;
|
||||
pre.l_test_pairs = 5000;
|
||||
pre.mean_abs_l = 0.590;
|
||||
result.pre_promotion_twinning = pre;
|
||||
text = RenderResultReport("p", "in.h5", x, result);
|
||||
CHECK(text.find("\nTWINNING_VERDICT= NOT_READABLE\n") != std::string::npos);
|
||||
CHECK(text.find("0.590 before the space-group search") != std::string::npos);
|
||||
|
||||
// An ordinary reading keeps its verdict.
|
||||
result.pre_promotion_twinning.reset();
|
||||
result.twinning.adopted_operators_suspect = false;
|
||||
result.twinning.mean_abs_l = 0.419;
|
||||
text = RenderResultReport("p", "in.h5", x, result);
|
||||
CHECK(text.find("\nTWINNING_VERDICT= INDICATED\n") != std::string::npos);
|
||||
CHECK(text.find("\nPATHOLOGY_FLAGS= TWINNING\n") != std::string::npos);
|
||||
}
|
||||
|
||||
TEST_CASE("ResultReport_RotationLatticeWithoutIndexedFrames", "[Diagnostics]") {
|
||||
DiffractionExperiment x(DetJF(1));
|
||||
// A rotation run that indexed the sweep as a whole while no frame indexed on its own.
|
||||
ProcessResult result;
|
||||
result.images_processed = 1800;
|
||||
result.indexing_rate = 0.0f;
|
||||
result.rotation_lattice_found = true;
|
||||
result.consensus_cell = UnitCell{.a = 50.0f, .b = 60.0f, .c = 70.0f,
|
||||
.alpha = 90.0f, .beta = 100.0f, .gamma = 90.0f};
|
||||
const auto text = RenderResultReport("p", "in.h5", x, result);
|
||||
CHECK(text.find("NO_LATTICE") == std::string::npos);
|
||||
CHECK(text.find("No image indexed") == std::string::npos);
|
||||
CHECK(text.find("\nLATTICE_FOUND= TRUE\n") != std::string::npos);
|
||||
|
||||
// The no-crystal exit: the CLI hands over only the reason. The verdict has no image count to quote.
|
||||
ProcessResult none;
|
||||
none.warnings.push_back({PathologyCode::NO_LATTICE, "No crystal lattice was found: none"});
|
||||
const auto failed = RenderResultReport("p", "in.h5", x, none);
|
||||
CHECK(failed.find("\nVERDICT= FAILED\n") != std::string::npos);
|
||||
CHECK(failed.find("\nPATHOLOGY_FLAGS= NO_LATTICE\n") != std::string::npos);
|
||||
CHECK(failed.find("No crystal lattice was found in these frames") != std::string::npos);
|
||||
CHECK(failed.find("UNIT_CELL_CONSTANTS=") == std::string::npos);
|
||||
CHECK(failed.find("SPACE_GROUP_NUMBER=") == std::string::npos);
|
||||
}
|
||||
|
||||
TEST_CASE("ResultReport_PowderAndIce", "[Diagnostics]") {
|
||||
DiffractionExperiment x(DetJF(1));
|
||||
ProcessResult result;
|
||||
result.consensus_cell = UnitCell{.a = 79.0f, .b = 79.0f, .c = 38.0f,
|
||||
.alpha = 90.0f, .beta = 90.0f, .gamma = 90.0f};
|
||||
result.has_merge_statistics = true;
|
||||
|
||||
auto text = RenderResultReport("p", "in.h5", x, result);
|
||||
CHECK(text.find("Powder no rings detected") != std::string::npos);
|
||||
CHECK(text.find("ICE_RINGS_DETECTED") == std::string::npos);
|
||||
|
||||
result.powder.rings_q_recipA = {1.61f, 1.71f, 1.82f};
|
||||
result.powder.spot_fraction = 0.04f;
|
||||
result.powder.ice_ring_count = 2;
|
||||
result.powder.ice_spot_fraction = 0.03f;
|
||||
result.powder.non_ice_spot_fraction = 0.01f;
|
||||
result.ice_ring_score = 2.69f;
|
||||
result.ice_spot_ratio = 1.08f;
|
||||
result.ice_rings_detected = true;
|
||||
result.ice_flagged_fraction = 0.257;
|
||||
text = RenderResultReport("p", "in.h5", x, result);
|
||||
CHECK(text.find("Powder 3 rings holding 4% of the spots found - 2 ice (3%), 1 other (1%)") != std::string::npos);
|
||||
CHECK(text.find("\nICE_RINGS_DETECTED= TRUE\n") != std::string::npos);
|
||||
CHECK(text.find("\nICE_REFLECTIONS_ON_RINGS_PCT= 25.7\n") != std::string::npos);
|
||||
CHECK(text.find("Ice rings DETECTED: the 25.7% of the reflections") != std::string::npos);
|
||||
// The merge found ice: a prompt to check the ice shells, and not a powder warning.
|
||||
CHECK(text.find("\nPATHOLOGY_FLAGS= ICE_RINGS\n") != std::string::npos);
|
||||
|
||||
// Rings that are not ice are a separate prompt, in their own words.
|
||||
result.ice_rings_detected = false;
|
||||
result.powder.non_ice_spot_fraction = 0.20f;
|
||||
text = RenderResultReport("p", "in.h5", x, result);
|
||||
CHECK(text.find("\nPATHOLOGY_FLAGS= POWDER_RINGS\n") != std::string::npos);
|
||||
CHECK(text.find("Powder rings that are not ice: 1 rings hold 20%") != std::string::npos);
|
||||
result.powder.ice_spot_fraction = 0.30f;
|
||||
text = RenderResultReport("p", "in.h5", x, result);
|
||||
CHECK(text.find("\nPATHOLOGY_FLAGS= ICE_RINGS POWDER_RINGS\n") != std::string::npos);
|
||||
}
|
||||
|
||||
TEST_CASE("ResultReport_SweepGapsMaterial", "[Diagnostics]") {
|
||||
DiffractionExperiment x(DetJF(1));
|
||||
ProcessResult result;
|
||||
result.consensus_cell = UnitCell{.a = 79.0f, .b = 79.0f, .c = 38.0f,
|
||||
.alpha = 90.0f, .beta = 90.0f, .gamma = 90.0f};
|
||||
result.has_merge_statistics = true;
|
||||
result.merge_statistics.sweep_quality = TestSweepQuality();
|
||||
// Two frames of a long sweep: in the table and the summary, not a condition of the data set.
|
||||
result.merge_statistics.sweep_quality.sweep_deg = 360.0f;
|
||||
result.merge_statistics.sweep_quality.ranges.resize(1);
|
||||
result.merge_statistics.sweep_quality.ranges[0].rotation_deg = 1.0f;
|
||||
auto text = RenderResultReport("p", "in.h5", x, result);
|
||||
CHECK(text.find("SWEEP_GAPS") == std::string::npos);
|
||||
CHECK(text.find("Frames 100-149") == std::string::npos);
|
||||
RunProvenance dev;
|
||||
dev.developer = true;
|
||||
CHECK(RenderResultReport("p", "in.h5", x, result, dev).find("Frames 100-149") != std::string::npos);
|
||||
|
||||
result.merge_statistics.sweep_quality.ranges[0].rotation_deg = 40.0f;
|
||||
text = RenderResultReport("p", "in.h5", x, result);
|
||||
CHECK(text.find("\nPATHOLOGY_FLAGS= SWEEP_GAPS\n") != std::string::npos);
|
||||
}
|
||||
|
||||
TEST_CASE("ResultReport_SecondCrystal", "[Diagnostics]") {
|
||||
DiffractionExperiment x(DetJF(1));
|
||||
ProcessResult result;
|
||||
result.consensus_cell = UnitCell{.a = 79.0f, .b = 79.0f, .c = 38.0f,
|
||||
.alpha = 90.0f, .beta = 90.0f, .gamma = 90.0f};
|
||||
LeftoverLatticeCensus census;
|
||||
census.primary_intensity_pct = 80.0;
|
||||
census.lattices.push_back(LeftoverLattice{.kind = LeftoverLatticeKind::Domain, .cell = *result.consensus_cell,
|
||||
.volume_ratio = 1.0, .misorientation_deg = 38.9, .z = 50.0,
|
||||
.spots_pct = 12.0, .intensity_pct = 14.0, .sweep_concentration = 0.3});
|
||||
result.leftover_lattices = census;
|
||||
const auto text = RenderResultReport("p", "in.h5", x, result);
|
||||
CHECK(text.find("second crystal, 38.9 deg from the main lattice") != std::string::npos);
|
||||
CHECK(text.find("split crystal, ") == std::string::npos);
|
||||
}
|
||||
Reference in new issue
Block a user