rugnux: report what --model found, and attribute GEMMI's bundled headers
Two things left open by the previous commit. A model that was validated left nothing in the results report. R-work, R-free, the bulk-solvent parameters and the map filenames went to the log and nowhere else, so a run given --model was, in the file anyone reads afterwards, indistinguishable from one that was not - and the WARNING line added last commit was the only trace of a model that failed. Section 10. MODEL VALIDATION now carries it: MODEL_FILE, the space group the model is in, R_WORK / R_FREE with their reflection counts, the bulk-solvent k_sol / b_sol and overall scale, the mean 2Fo-Fc density at the atom centres, the hand and indexing operators the written reflections were brought into the model's frame with, and MAPS_PREFIX. A model that could not be used gets MODEL_VALIDATION= NOT_PERFORMED and the reason instead, in the shape the merging section already uses. A run that asked for no model has no section at all. That moves WARNINGS from 10 to 11, which is what REPORT_VERSION is for: it is now 4. No existing key was renamed and no table column moved, so a consumer that greps for what it needs is unaffected; one that keys on the section number of WARNINGS is not, hence the bump. The four third-party headers GEMMI has always bundled - fast_float, half, pocketfft and tinydir - were never listed in THIRD_PARTY_NOTICES.md, riding instead under GEMMI's single MPL-2.0 row. They are other authors' code under other licences (Apache-2.0 OR MIT OR BSL-1.0, MIT, BSD-3-Clause, BSD-2-Clause), and MPL-2.0 does not speak for them. Each now has its own row and its own licence text, alongside the PEGTL and sajson entries added with the CIF parser, and a note records why the six are listed separately from GEMMI. Their terms live in the headers rather than in LICENSE files, so five of the six texts are kept by hand; COLLECT.sh says so and copies the one - PEGTL - that ships a file. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WmryXe8ASbNi632sUMfsa
This commit is contained in:
@@ -69,7 +69,7 @@ TEST_CASE("ResultReport_Render", "[Diagnostics]") {
|
||||
const auto text = RenderResultReport("prefix", "in.h5", x, result);
|
||||
|
||||
// The stable keys a consumer greps for.
|
||||
CHECK(text.find("\nREPORT_VERSION= 3\n") != std::string::npos);
|
||||
CHECK(text.find("\nREPORT_VERSION= 4\n") != std::string::npos);
|
||||
CHECK(text.find("\nOUTPUT_PREFIX= prefix\n") != std::string::npos);
|
||||
CHECK(text.find("\nINDEXING_RATE= 0.8700\n") != std::string::npos);
|
||||
CHECK(text.find("\nSPACE_GROUP_NUMBER= 96\n") != std::string::npos);
|
||||
@@ -224,6 +224,48 @@ TEST_CASE("ResultReport_ProvenanceKeys", "[Diagnostics]") {
|
||||
CHECK(without.find("GPU_COUNT=") == std::string::npos);
|
||||
}
|
||||
|
||||
// A model that was asked for gets a section either way: the R-factors when it worked, and why it did
|
||||
// not when it did not. A run that never asked for one has no section at all.
|
||||
TEST_CASE("ResultReport_ModelValidationSection", "[Diagnostics]") {
|
||||
DiffractionExperiment x(DetJF(1));
|
||||
x.ImagesPerTrigger(600);
|
||||
|
||||
ProcessResult result;
|
||||
result.images_processed = 600;
|
||||
result.consensus_cell = UnitCell{.a = 79.0f, .b = 79.0f, .c = 38.0f,
|
||||
.alpha = 90.0f, .beta = 90.0f, .gamma = 90.0f};
|
||||
|
||||
CHECK(RenderResultReport("p", "in.h5", x, result).find("MODEL VALIDATION") == std::string::npos);
|
||||
|
||||
ModelValidationResult good;
|
||||
good.ok = true;
|
||||
good.model_path = "model.cif";
|
||||
good.model_space_group_number = 96;
|
||||
good.r_work = 0.1823;
|
||||
good.r_free = 0.2145;
|
||||
good.n_work = 16682;
|
||||
good.n_free = 928;
|
||||
good.mean_atom_density_sigma = 1.42;
|
||||
result.model_validation = good;
|
||||
|
||||
const auto text = RenderResultReport("p", "in.h5", x, result);
|
||||
CHECK(text.find("10. MODEL VALIDATION") != std::string::npos);
|
||||
CHECK(text.find("\nMODEL_FILE= model.cif\n") != std::string::npos);
|
||||
CHECK(text.find("\nR_FREE= 0.2145\n") != std::string::npos);
|
||||
CHECK(text.find("\nR_FREE_REFLECTIONS= 928\n") != std::string::npos);
|
||||
CHECK(text.find("MODEL_VALIDATION= NOT_PERFORMED") == std::string::npos);
|
||||
|
||||
ModelValidationResult failed;
|
||||
failed.model_path = "broken.pdb";
|
||||
failed.failure_reason = "model broken.pdb has no atoms or no unit cell";
|
||||
result.model_validation = failed;
|
||||
|
||||
const auto failed_text = RenderResultReport("p", "in.h5", x, result);
|
||||
CHECK(failed_text.find("\nMODEL_VALIDATION= NOT_PERFORMED\n") != std::string::npos);
|
||||
CHECK(failed_text.find("has no atoms") != std::string::npos);
|
||||
CHECK(failed_text.find("R_FREE=") == std::string::npos);
|
||||
}
|
||||
|
||||
// get_gpu_description collapses repeats, so a four-card machine reads as one line rather than the
|
||||
// same name four times. Build-independent: without CUDA there are no names and it is empty.
|
||||
TEST_CASE("ResultReport_GpuDescription", "[Diagnostics]") {
|
||||
|
||||
Reference in New Issue
Block a user