tools/battery: the comparable R leads the report

R_model with one free scale per resolution shell is the number that can be
read between two runs; the placement R beside it cannot, because the fixed
model is scaled by k and an anisotropic B only and a change in the
amplitudes' radial profile has nowhere to go but the residual. Both are
still printed, with the radial misfit next to them, so a reader can see
when the placement R stopped meaning anything.

Nothing is scored on any of them.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013nW6FNRP1bBJJ8pfHiByAT
This commit is contained in:
2026-09-21 14:13:31 +02:00
co-authored by Claude Opus 5
parent 1ddd409fd5
commit fdcbb0d700
+8 -7
View File
@@ -187,12 +187,12 @@ def changes(ra, rb):
if ra.get("volume_ratio") and rb.get("volume_ratio") and \
abs(ra["volume_ratio"] - rb["volume_ratio"]) > 0.05:
out.append("lattice")
for name in ("d_min", "isa", "r_meas", "cc_half", "completeness", "cell_dev_pct", "rfree"):
for name in ("d_min", "isa", "r_meas", "cc_half", "completeness", "cell_dev_pct"):
if beyond_noise(name, ra.get(name), rb.get(name)):
out.append(name)
# The R that is comparable between runs, and the radial profile that decides whether `rfree`
# beside it can be read at all (both only where both runs carry them).
for name in ("rmodel_shell_scaled", "radial_misfit"):
for name in ("rmodel_shell_scaled", "radial_misfit", "rfree"):
if ra.get(name) is not None and rb.get(name) is not None and beyond_noise(name, ra[name], rb[name]):
out.append(name)
# the like-for-like table only where both runs have one (a pre-schema-3 run has none)
@@ -222,7 +222,7 @@ def arrow(x, y, fmt=lambda v: str(v)):
def compare_table(doc, rows, only_changed=True):
head = ["set", "arm", "verdict", "space group", "d_min", "ISa", "R_meas", "CC1/2",
"cell dev %", "R_free", "R_model (shell-scaled)", "radial misfit",
"cell dev %", "R_model (shell-scaled)", "R_free", "radial misfit",
"ref-range R_meas", "ref-range low-res R_meas", "time s", "beyond noise"]
out = []
for (arm, s), ra, rb, ch in rows:
@@ -236,8 +236,8 @@ def compare_table(doc, rows, only_changed=True):
arrow(ra.get("r_meas"), rb.get("r_meas"), lambda v: f"{100 * v:.1f}%"),
arrow(ra.get("cc_half"), rb.get("cc_half"), lambda v: f"{v:.3f}"),
arrow(ra.get("cell_dev_pct"), rb.get("cell_dev_pct"), lambda v: f"{v:.2f}"),
arrow(ra.get("rfree"), rb.get("rfree"), lambda v: f"{v:.3f}"),
arrow(ra.get("rmodel_shell_scaled"), rb.get("rmodel_shell_scaled"), lambda v: f"{v:.3f}"),
arrow(ra.get("rfree"), rb.get("rfree"), lambda v: f"{v:.3f}"),
arrow(ra.get("radial_misfit"), rb.get("radial_misfit"), lambda v: f"{v:.2f}"),
arrow(ra.get("refres_r_meas"), rb.get("refres_r_meas"), lambda v: f"{100 * v:.1f}%"),
arrow(ra.get("refres_lowres_r_meas"), rb.get("refres_lowres_r_meas"),
@@ -351,8 +351,8 @@ def build(run_dir, baseline=None, allow_incomplete=False):
("lowres_r_meas", "low-res shell R_meas", None),
("lowres_r_meas_ratio", "ref-range low-res R_meas / XDS", "{:.3f}"),
("cc_half_noise_ratio", "ref-range CC1/2 noise / XDS", "{:.2f}"),
("rfree", "R_free (placement)", "{:.3f}"),
("rmodel_shell_scaled", "R_model, shell-scaled", "{:.3f}"),
("rfree", "R_free (placement, within-run only)", "{:.3f}"),
("radial_misfit", "radial misfit", "{:.2f}"),
("rfree_ratio", "R_free ratio", "{:.3f}"), ("wall_s", "time s", "{:.0f}")):
q = quartiles(r.get(name) for r in rs)
@@ -478,8 +478,9 @@ def build(run_dir, baseline=None, allow_incomplete=False):
"read in a delta table. Radial misfit is how big that per-shell rescale had to be (the "
"RMS of its logarithm): when it moves between two runs, R_free between them means "
"little. Both are reported for a human to judge; nothing is scored on them.")
model = [("R_free", "rfree"), ("R_work", "rwork"), ("R_model (shell-scaled)", "rmodel_shell_scaled"),
("radial misfit", "radial_misfit"), ("CC model", "cc_model"), ("dep R_free", "rfree_deposited"),
model = [("R_model (shell-scaled)", "rmodel_shell_scaled"), ("radial misfit", "radial_misfit"),
("CC model", "cc_model"), ("R_free (within-run)", "rfree"), ("R_work", "rwork"),
("dep R_free", "rfree_deposited"),
("R_free ratio", "rfree_ratio")] if any(r.get("rfree") for r in res) else []
model += [("REFMAC R_free", "refmac_rfree_depflags"), ("REFMAC dep data", "refmac_rfree_depdata"),
("REFMAC ratio", "refmac_rfree_ratio")] if any(r.get("refmac_status") for r in res) else []