review fixes: two silent wrong outputs, and one rule for a quantity nobody measured
From four whole-branch code reviews of rc166. Reviewing the net diff rather than the commits found what per-commit review structurally cannot: a later commit leaving an earlier one's claim standing, and two cases of a later commit quietly undoing an earlier one. THE FITTED RESOLUTION WAS THE P1 CROSS-CHECK'S. The block that merges in P1 to write <prefix>_P1.mtz saves and restores the error model around itself, because that merge is not the run's answer. A later commit taught the same function to report the CC1/2 resolution fit and did not extend the list, so every de-novo rotation run in a non-P1 group has been quoting FITTED_RESOLUTION - the number the report itself calls the one to quote - from a merge with n_ops times the unique reflections at a fraction of the multiplicity. AND IT ROUND-TRIPPED THE SPACE GROUP THROUGH ITS NUMBER. A number names only the reference setting, which stopped being enough when the search learned to adopt P 1 1 2(1) or I 1 2 1. Everything written after that block - the unmerged MTZ included - therefore carried the reference setting while the merged file carried the adopted one: two files describing one dataset in two different settings. It now carries the group. A PONI CANNOT STATE A MIRRORED OR QUARTER-TURNED DETECTOR, and the fits became orientation-aware on this branch while the writer did not. It wrote five numbers that silently described a different geometry from the one measured; it now refuses, and says the JSON beside it has the full one. A REFUSED FIT'S ERROR BARS COULD BE HANDED BACK AS AN ACCEPTED GEOMETRY'S. RingOptimizer::Run writes its uncertainty only where the solve is usable, and CalibrateFromSpots runs it twice - tilt free, then tilt pinned. A failed second fit kept the first's sigmas, valid flag and all. It is cleared on the way in. ONE RULE FOR NOT MEASURED. The report had four conventions for it and printed the same missing quantity two ways on adjacent lines: SIGANO as the literal "nan" and CC_ANOM by absence, for a Friedel-merged run that split no Bijvoet pair - which is the default. A quantity a run did not measure now writes no key, and the shell table's dash follows the same rule rather than a 0.0% that reads as a measured total failure. ANISOTROPY_D_MIN_BEST also stops printing nan when only its first principal direction is unmeasured. Four claims that a later commit made false are corrected where they stand: the merge header promising an order-independence the balancing rule gave up, the reference page arguing against CCanom 28 minutes before it shipped, the screw threshold whose "three dead reflections clear it" the evidence floor caps at 19.2 nats, and a shell comment calling equal width in 1/d^2 equal volume. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+16
-3
@@ -9,6 +9,7 @@
|
||||
#include <fstream>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <regex>
|
||||
#include <stdexcept>
|
||||
|
||||
@@ -19,11 +20,23 @@ namespace minicbf {
|
||||
namespace {
|
||||
|
||||
// One capture group, first match, or nothing. The headers are a few kB, so a regex per field is
|
||||
// cheap and keeps each rule next to the thing it reads.
|
||||
// cheap and keeps each rule next to the thing it reads - but COMPILING one is not: measured at ~60 us
|
||||
// here, and a header parse runs 26 of them. Parsing happens once per image read across a whole sweep,
|
||||
// so the same two dozen patterns were being recompiled thousands of times. They are compiled once and
|
||||
// kept; std::map never invalidates a reference, so the pointer outlives the lock.
|
||||
std::optional<std::string> Match(const std::string &text, const char *pattern) {
|
||||
static std::mutex cache_mutex;
|
||||
static std::map<std::string, std::regex> cache;
|
||||
const std::regex *re;
|
||||
{
|
||||
const std::lock_guard<std::mutex> lock(cache_mutex);
|
||||
auto it = cache.find(pattern);
|
||||
if (it == cache.end())
|
||||
it = cache.emplace(pattern, std::regex(pattern)).first;
|
||||
re = &it->second;
|
||||
}
|
||||
std::smatch m;
|
||||
const std::regex re(pattern);
|
||||
if (!std::regex_search(text, m, re) || m.size() < 2)
|
||||
if (!std::regex_search(text, m, *re) || m.size() < 2)
|
||||
return {};
|
||||
return m[1].str();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user