From 18d3f553254e7703aed57add05cc8bc2550dbfae Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Thu, 27 Aug 2026 13:42:48 +0200 Subject: [PATCH] rugnux: read mmCIF models with --model, and say when a model could not be used --model called gemmi::read_pdb unconditionally, so a coordinate file in mmCIF - which is how the PDB serves coordinates by default - was refused outright: Model validation: cannot read model 6G8A.cif: Incorrect file format (perhaps it is cif not pdb?) Worse than the refusal was what followed it. ValidateAgainstModel logged, returned an empty result, and the run went on to finish with exit code 0, no R-free, no maps and nothing in the report - indistinguishable from a run that was never given --model at all. A script that passed a .cif, checked the exit code and grepped for R-free simply got nothing back. Both read sites now go through read_structure_gz with CoorFormat::Detect, so PDB, mmCIF and mmJSON are all read, gzipped or not, and the format comes from the file's content rather than from its name. Detect is passed explicitly: GEMMI otherwise takes the extension and only falls back to the content when it does not recognise one, and a model arrives named however whoever produced it named it. That needed a part of GEMMI the vendored subset had trimmed away. mmread.hpp was already here but its CIF parser was not, so this restores what upstream GEMMI ships: read_cif/mmcif/json/mmread_gz, plus GEMMI's own copies of PEGTL (MIT, Colin Hirsch and Daniel Frey; 155 headers, 672 kB) and sajson (MIT, Chad Austin; one header). Both are listed in THIRD_PARTY_NOTICES.md with their own licence texts, PEGTL's collected by COLLECT.sh and sajson's kept by hand, its terms being a comment block rather than a file. json.cpp carries a one-line change: upstream keeps sajson at the root of its repository, outside the include tree this subset copies, so the include points at where the other bundled headers live. ModelValidationResult gains failure_reason, and a model that was asked for and could not be used now reaches the results report as WARNING: Model validation did not run: model bogus.pdb has no atoms or no unit cell in --mode mx and --mode scale alike. The run still succeeds - a merge that is good is not made bad by a model that was not - but it no longer does so quietly. One log line was making a claim it could not support: the indexing-ambiguity message said the ambiguity was "resolved against the supplied model" while being printed before the model is read, so it announced a resolution that a failed model never performed. It now says the model will be used; the reference branch, where the work really has already happened, keeps the past tense. Verified on the rotation test dataset with a deposited mmCIF, the same file gzipped, an mmCIF under a .pdb name, a PDB, and an unreadable file. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_016WmryXe8ASbNi632sUMfsa --- THIRD_PARTY_NOTICES.md | 2 + docs/CHANGELOG.md | 2 + docs/RUGNUX.md | 11 +- gemmi_gph/CMakeLists.txt | 6 + gemmi_gph/gemmi/third_party/sajson.h | 2599 +++++++++++++++++ gemmi_gph/gemmi/third_party/tao/LICENSE | 21 + gemmi_gph/gemmi/third_party/tao/NOTES | 11 + gemmi_gph/gemmi/third_party/tao/pegtl.hpp | 53 + .../tao/pegtl/analysis/analyze_cycles.hpp | 135 + .../tao/pegtl/analysis/counted.hpp | 31 + .../tao/pegtl/analysis/generic.hpp | 43 + .../tao/pegtl/analysis/grammar_info.hpp | 40 + .../tao/pegtl/analysis/insert_guard.hpp | 68 + .../tao/pegtl/analysis/rule_info.hpp | 37 + .../tao/pegtl/analysis/rule_type.hpp | 35 + .../gemmi/third_party/tao/pegtl/analyze.hpp | 25 + .../third_party/tao/pegtl/apply_mode.hpp | 27 + .../third_party/tao/pegtl/argv_input.hpp | 57 + .../gemmi/third_party/tao/pegtl/ascii.hpp | 71 + .../third_party/tao/pegtl/buffer_input.hpp | 222 ++ .../third_party/tao/pegtl/change_action.hpp | 42 + .../tao/pegtl/change_action_and_state.hpp | 73 + .../tao/pegtl/change_action_and_states.hpp | 83 + .../third_party/tao/pegtl/change_control.hpp | 40 + .../third_party/tao/pegtl/change_state.hpp | 72 + .../third_party/tao/pegtl/change_states.hpp | 81 + .../gemmi/third_party/tao/pegtl/config.hpp | 20 + .../third_party/tao/pegtl/cstream_input.hpp | 39 + .../third_party/tao/pegtl/disable_action.hpp | 39 + .../third_party/tao/pegtl/discard_input.hpp | 41 + .../tao/pegtl/discard_input_on_failure.hpp | 43 + .../tao/pegtl/discard_input_on_success.hpp | 43 + .../third_party/tao/pegtl/enable_action.hpp | 39 + gemmi_gph/gemmi/third_party/tao/pegtl/eol.hpp | 41 + .../gemmi/third_party/tao/pegtl/eol_pair.hpp | 22 + .../third_party/tao/pegtl/file_input.hpp | 50 + .../third_party/tao/pegtl/input_error.hpp | 57 + .../third_party/tao/pegtl/internal/action.hpp | 59 + .../tao/pegtl/internal/action_input.hpp | 120 + .../third_party/tao/pegtl/internal/alnum.hpp | 26 + .../third_party/tao/pegtl/internal/alpha.hpp | 26 + .../tao/pegtl/internal/always_false.hpp | 29 + .../third_party/tao/pegtl/internal/any.hpp | 66 + .../third_party/tao/pegtl/internal/apply.hpp | 94 + .../third_party/tao/pegtl/internal/apply0.hpp | 92 + .../tao/pegtl/internal/apply0_single.hpp | 42 + .../tao/pegtl/internal/apply_single.hpp | 42 + .../third_party/tao/pegtl/internal/at.hpp | 67 + .../third_party/tao/pegtl/internal/bof.hpp | 41 + .../third_party/tao/pegtl/internal/bol.hpp | 41 + .../third_party/tao/pegtl/internal/bump.hpp | 53 + .../tao/pegtl/internal/bump_help.hpp | 63 + .../third_party/tao/pegtl/internal/bytes.hpp | 46 + .../tao/pegtl/internal/control.hpp | 59 + .../tao/pegtl/internal/cr_crlf_eol.hpp | 40 + .../third_party/tao/pegtl/internal/cr_eol.hpp | 40 + .../tao/pegtl/internal/crlf_eol.hpp | 40 + .../tao/pegtl/internal/cstream_reader.hpp | 50 + .../tao/pegtl/internal/cstring_reader.hpp | 49 + .../tao/pegtl/internal/demangle.hpp | 85 + .../tao/pegtl/internal/demangle_cxxabi.hpp | 41 + .../tao/pegtl/internal/demangle_nop.hpp | 28 + .../tao/pegtl/internal/demangle_sanitise.hpp | 48 + .../tao/pegtl/internal/disable.hpp | 59 + .../tao/pegtl/internal/discard.hpp | 43 + .../tao/pegtl/internal/dusel_mode.hpp | 31 + .../tao/pegtl/internal/duseltronik.hpp | 188 ++ .../third_party/tao/pegtl/internal/enable.hpp | 59 + .../third_party/tao/pegtl/internal/endian.hpp | 70 + .../tao/pegtl/internal/endian_gcc.hpp | 214 ++ .../tao/pegtl/internal/endian_win.hpp | 115 + .../third_party/tao/pegtl/internal/eof.hpp | 41 + .../third_party/tao/pegtl/internal/eol.hpp | 41 + .../third_party/tao/pegtl/internal/eolf.hpp | 42 + .../tao/pegtl/internal/file_mapper_posix.hpp | 95 + .../tao/pegtl/internal/file_opener.hpp | 78 + .../tao/pegtl/internal/file_reader.hpp | 109 + .../tao/pegtl/internal/has_apply.hpp | 33 + .../tao/pegtl/internal/has_apply0.hpp | 33 + .../tao/pegtl/internal/has_match.hpp | 53 + .../tao/pegtl/internal/identifier.hpp | 30 + .../tao/pegtl/internal/if_apply.hpp | 118 + .../tao/pegtl/internal/if_missing.hpp | 72 + .../tao/pegtl/internal/if_must.hpp | 58 + .../tao/pegtl/internal/if_must_else.hpp | 27 + .../tao/pegtl/internal/if_then_else.hpp | 61 + .../tao/pegtl/internal/input_pair.hpp | 37 + .../tao/pegtl/internal/integer_sequence.hpp | 86 + .../tao/pegtl/internal/istream_reader.hpp | 47 + .../tao/pegtl/internal/istring.hpp | 107 + .../tao/pegtl/internal/iterator.hpp | 60 + .../tao/pegtl/internal/lf_crlf_eol.hpp | 45 + .../third_party/tao/pegtl/internal/lf_eol.hpp | 40 + .../third_party/tao/pegtl/internal/list.hpp | 27 + .../tao/pegtl/internal/list_must.hpp | 28 + .../tao/pegtl/internal/list_tail.hpp | 28 + .../tao/pegtl/internal/list_tail_pad.hpp | 30 + .../third_party/tao/pegtl/internal/marker.hpp | 99 + .../third_party/tao/pegtl/internal/must.hpp | 70 + .../third_party/tao/pegtl/internal/not_at.hpp | 67 + .../third_party/tao/pegtl/internal/one.hpp | 77 + .../third_party/tao/pegtl/internal/opt.hpp | 69 + .../third_party/tao/pegtl/internal/pad.hpp | 27 + .../tao/pegtl/internal/pad_opt.hpp | 28 + .../tao/pegtl/internal/peek_char.hpp | 40 + .../tao/pegtl/internal/peek_mask_uint.hpp | 62 + .../tao/pegtl/internal/peek_mask_uint8.hpp | 42 + .../tao/pegtl/internal/peek_uint.hpp | 53 + .../tao/pegtl/internal/peek_uint8.hpp | 41 + .../tao/pegtl/internal/peek_utf16.hpp | 62 + .../tao/pegtl/internal/peek_utf32.hpp | 51 + .../tao/pegtl/internal/peek_utf8.hpp | 97 + .../tao/pegtl/internal/pegtl_string.hpp | 103 + .../third_party/tao/pegtl/internal/plus.hpp | 68 + .../third_party/tao/pegtl/internal/raise.hpp | 63 + .../third_party/tao/pegtl/internal/range.hpp | 58 + .../third_party/tao/pegtl/internal/ranges.hpp | 100 + .../tao/pegtl/internal/read_uint.hpp | 85 + .../tao/pegtl/internal/rematch.hpp | 86 + .../third_party/tao/pegtl/internal/rep.hpp | 80 + .../tao/pegtl/internal/rep_min.hpp | 28 + .../tao/pegtl/internal/rep_min_max.hpp | 91 + .../tao/pegtl/internal/rep_opt.hpp | 61 + .../tao/pegtl/internal/require.hpp | 52 + .../tao/pegtl/internal/result_on_found.hpp | 27 + .../third_party/tao/pegtl/internal/rules.hpp | 61 + .../third_party/tao/pegtl/internal/seq.hpp | 91 + .../tao/pegtl/internal/skip_control.hpp | 35 + .../third_party/tao/pegtl/internal/sor.hpp | 76 + .../third_party/tao/pegtl/internal/star.hpp | 62 + .../tao/pegtl/internal/star_must.hpp | 27 + .../third_party/tao/pegtl/internal/state.hpp | 96 + .../third_party/tao/pegtl/internal/string.hpp | 68 + .../tao/pegtl/internal/trivial.hpp | 42 + .../tao/pegtl/internal/try_catch_type.hpp | 76 + .../third_party/tao/pegtl/internal/until.hpp | 98 + .../third_party/tao/pegtl/istream_input.hpp | 39 + .../gemmi/third_party/tao/pegtl/match.hpp | 71 + .../third_party/tao/pegtl/memory_input.hpp | 378 +++ .../third_party/tao/pegtl/mmap_input.hpp | 85 + .../gemmi/third_party/tao/pegtl/normal.hpp | 96 + .../gemmi/third_party/tao/pegtl/nothing.hpp | 24 + .../gemmi/third_party/tao/pegtl/parse.hpp | 57 + .../third_party/tao/pegtl/parse_error.hpp | 51 + .../gemmi/third_party/tao/pegtl/position.hpp | 54 + .../third_party/tao/pegtl/read_input.hpp | 80 + .../third_party/tao/pegtl/require_apply.hpp | 20 + .../third_party/tao/pegtl/require_apply0.hpp | 20 + .../third_party/tao/pegtl/rewind_mode.hpp | 29 + .../gemmi/third_party/tao/pegtl/rules.hpp | 71 + .../third_party/tao/pegtl/string_input.hpp | 72 + .../third_party/tao/pegtl/tracking_mode.hpp | 27 + .../gemmi/third_party/tao/pegtl/uint16.hpp | 66 + .../gemmi/third_party/tao/pegtl/uint32.hpp | 66 + .../gemmi/third_party/tao/pegtl/uint64.hpp | 67 + .../gemmi/third_party/tao/pegtl/uint8.hpp | 44 + .../gemmi/third_party/tao/pegtl/utf16.hpp | 53 + .../gemmi/third_party/tao/pegtl/utf32.hpp | 53 + .../gemmi/third_party/tao/pegtl/utf8.hpp | 36 + .../gemmi/third_party/tao/pegtl/version.hpp | 19 + gemmi_gph/json.cpp | 132 + gemmi_gph/mmcif.cpp | 1147 ++++++++ gemmi_gph/mmread_gz.cpp | 29 + gemmi_gph/read_cif.cpp | 38 + licenses/COLLECT.sh | 4 + licenses/pegtl.txt | 21 + licenses/sajson.txt | 21 + rugnux/ModelValidation.cpp | 21 +- rugnux/ModelValidation.h | 7 +- rugnux/Rugnux.cpp | 16 +- rugnux/Rugnux.h | 5 +- rugnux/rugnux_cli.cpp | 9 +- tests/CMakeLists.txt | 1 + tests/ModelValidationTest.cpp | 104 + 174 files changed, 13550 insertions(+), 15 deletions(-) create mode 100644 gemmi_gph/gemmi/third_party/sajson.h create mode 100644 gemmi_gph/gemmi/third_party/tao/LICENSE create mode 100644 gemmi_gph/gemmi/third_party/tao/NOTES create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/analysis/analyze_cycles.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/analysis/counted.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/analysis/generic.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/analysis/grammar_info.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/analysis/insert_guard.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/analysis/rule_info.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/analysis/rule_type.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/analyze.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/apply_mode.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/argv_input.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/ascii.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/buffer_input.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/change_action.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/change_action_and_state.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/change_action_and_states.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/change_control.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/change_state.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/change_states.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/config.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/cstream_input.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/disable_action.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/discard_input.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/discard_input_on_failure.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/discard_input_on_success.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/enable_action.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/eol.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/eol_pair.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/file_input.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/input_error.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/action.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/action_input.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/alnum.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/alpha.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/always_false.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/any.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/apply.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/apply0.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/apply0_single.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/apply_single.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/at.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/bof.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/bol.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/bump.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/bump_help.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/bytes.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/control.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/cr_crlf_eol.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/cr_eol.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/crlf_eol.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/cstream_reader.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/cstring_reader.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/demangle.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/demangle_cxxabi.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/demangle_nop.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/demangle_sanitise.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/disable.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/discard.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/dusel_mode.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/duseltronik.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/enable.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/endian.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/endian_gcc.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/endian_win.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/eof.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/eol.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/eolf.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/file_mapper_posix.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/file_opener.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/file_reader.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/has_apply.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/has_apply0.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/has_match.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/identifier.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/if_apply.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/if_missing.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/if_must.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/if_must_else.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/if_then_else.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/input_pair.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/integer_sequence.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/istream_reader.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/istring.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/iterator.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/lf_crlf_eol.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/lf_eol.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/list.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/list_must.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/list_tail.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/list_tail_pad.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/marker.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/must.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/not_at.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/one.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/opt.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/pad.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/pad_opt.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/peek_char.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/peek_mask_uint.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/peek_mask_uint8.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/peek_uint.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/peek_uint8.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/peek_utf16.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/peek_utf32.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/peek_utf8.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/pegtl_string.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/plus.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/raise.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/range.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/ranges.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/read_uint.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/rematch.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/rep.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/rep_min.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/rep_min_max.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/rep_opt.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/require.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/result_on_found.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/rules.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/seq.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/skip_control.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/sor.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/star.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/star_must.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/state.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/string.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/trivial.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/try_catch_type.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/internal/until.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/istream_input.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/match.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/memory_input.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/mmap_input.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/normal.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/nothing.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/parse.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/parse_error.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/position.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/read_input.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/require_apply.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/require_apply0.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/rewind_mode.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/rules.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/string_input.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/tracking_mode.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/uint16.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/uint32.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/uint64.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/uint8.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/utf16.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/utf32.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/utf8.hpp create mode 100644 gemmi_gph/gemmi/third_party/tao/pegtl/version.hpp create mode 100644 gemmi_gph/json.cpp create mode 100644 gemmi_gph/mmcif.cpp create mode 100644 gemmi_gph/mmread_gz.cpp create mode 100644 gemmi_gph/read_cif.cpp create mode 100644 licenses/pegtl.txt create mode 100644 licenses/sajson.txt create mode 100644 tests/ModelValidationTest.cpp diff --git a/THIRD_PARTY_NOTICES.md b/THIRD_PARTY_NOTICES.md index 21385345..b0141f9d 100644 --- a/THIRD_PARTY_NOTICES.md +++ b/THIRD_PARTY_NOTICES.md @@ -48,6 +48,8 @@ These are copied into the source tree (see the path) rather than fetched. | [LZ4](https://github.com/lz4/lz4) | `compression/lz4/` | Yann Collet | BSD-2-Clause | [lz4.txt](licenses/lz4.txt) | | [HLS arbitrary-precision types](https://github.com/Xilinx/HLS_arbitrary_Precision_Types) | `fpga/include/` | Xilinx, Inc. | Apache-2.0 | [xilinx-hls-headers.txt](licenses/xilinx-hls-headers.txt) | | [GEMMI](https://github.com/project-gemmi/gemmi) | `gemmi_gph/` | Global Phasing Ltd. | MPL-2.0 | [gemmi.txt](licenses/gemmi.txt) | +| [PEGTL](https://github.com/taocpp/PEGTL) | `gemmi_gph/gemmi/third_party/tao/` | Dr. Colin Hirsch and Daniel Frey | MIT | [pegtl.txt](licenses/pegtl.txt) | +| [sajson](https://github.com/chadaustin/sajson) | `gemmi_gph/gemmi/third_party/sajson.h` | Chad Austin | MIT | [sajson.txt](licenses/sajson.txt) | | [traccc (ACTS)](https://github.com/acts-project/traccc) | `image_analysis/spot_finding/StrongPixelSet.cpp`, `SpotExtractorGPU.cu` | CERN, for the benefit of the ACTS project | MPL-2.0 | [traccc.txt](licenses/traccc.txt) | | [xbflash.qspi](https://github.com/Xilinx/XRT) | `tools/xbflash.qspi/` | Xilinx / AMD | Apache-2.0 | [xbflash-qspi.txt](licenses/xbflash-qspi.txt) | | [wingetopt](https://github.com/alex85k/wingetopt) | `tools/wingetopt/` | Todd C. Miller; The NetBSD Foundation | ISC AND BSD-2-Clause | [wingetopt.txt](licenses/wingetopt.txt) | diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 3666d5ca..b1bbe899 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -4,6 +4,8 @@ This is an UNSTABLE release. It includes many experimental features, as well as many AI generated fixes. We recommend using rc.152 for production use. * The rugnux results report records how the run was invoked, what it cost and what it ran on: `COMMAND_LINE=` is the command line as one shell-ready line, `WALL_TIME=` the whole invocation in seconds, and `GPU_COUNT=` / `GPU=` how many GPUs were visible and which ones. The total wall time is also printed on stdout, next to the processing time it is slightly larger than. +* `rugnux --model` reads an mmCIF coordinate file as well as a PDB one, gzipped or not, taking the format from the file's content rather than its name. A `.cif` model was rejected before, and the run then finished successfully with no R-free and no maps. +* A model `rugnux --model` cannot use - unreadable, or without atoms, a unit cell or a usable space group - is reported as a `WARNING:` line in the results report instead of only in the log, so a run that was asked to validate and could not is no longer indistinguishable from one that was never asked. * rugnux says which GPUs it can see before it starts processing, so a machine that turns out to have none - a driver mismatch, a leftover `CUDA_VISIBLE_DEVICES` - is noticed while there is still time to stop rather than after a run that took far longer than it should have. * rugnux writes `_unmerged.mtz` on every run that produces an output prefix, instead of only when asked for it with `--export-unmerged`. It is written in `--mode mx` and `--mode scale` and with `--no-merge`, alongside the merged files and replacing none of them. `--no-export-unmerged` turns it off. * `/start` asks the writer whether the run can be written before the detector is armed, so a run whose output file already exists, or whose output directory cannot be created, is refused up front with the writer's own message instead of failing once the detector is running. This needs the TCP image stream or the built-in HDF5 writer; the ZeroMQ stream has no way to answer and is unchanged. diff --git a/docs/RUGNUX.md b/docs/RUGNUX.md index 2e9e4fa9..38ed78d0 100644 --- a/docs/RUGNUX.md +++ b/docs/RUGNUX.md @@ -761,13 +761,20 @@ The algorithms behind both are in ## Validating against a model (`rugnux --model`) -Given a PDB atomic model of the same structure, `--model model.pdb` scales the model structure +Given an atomic model of the same structure, `--model model.pdb` scales the model structure factors to the merged amplitudes — fitting a flat bulk-solvent contribution and an overall anisotropic *B* — and reports **R-work / R-free** and the mean 2Fo-Fc density at the atom centres. It also writes `_2fofc.ccp4`, `_fofc.ccp4` and `_maps.mtz` next to the merged reflections. Nothing about the model is refined; it is only re-fractionalized into the data cell, so a deposited model with a slightly different cell still lines up. +The model may be **PDB or mmCIF**, gzipped or not, and the format is taken from the file's own +content rather than from its name — a model downloaded as `.cif`, `.pdb`, `.ent` or with no useful +extension at all is read the same way. A model that cannot be read, or that has no atoms, no unit +cell or no usable space group, does not fail the run: it is logged, and the results report carries a +`WARNING: Model validation did not run: …` line, so a run that silently produced no R-free and no +maps cannot be mistaken for one that was never given `--model`. + It is a *data-quality lens*, independent of the internal statistics: R-free measures the merged intensities against external truth, where CC1/2 and Rmeas only measure them against themselves. It also settles the two things merged intensities alone cannot: the enantiomorph (data @@ -990,7 +997,7 @@ Scaling and merging: | `--scaling-iterations ` | Scaling iterations with no reference data (default: 3) | | `-z, --reference-mtz ` | Reference MTZ of the same crystal form: fixes the space group and cell, resolves the [indexing ambiguity](#the-indexing-ambiguity), hands over the R-free set and reports CCref. Not a scale anchor | | `--reference-column