From 7624bbe12e2d3d37a271b534b0081ec5ec6a6da7 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Fri, 9 Oct 2026 17:16:37 +0200 Subject: [PATCH] battery: paper_plots.py draws the other figures when no run has REFMAC R-free The REFMAC check is opt-in, so a battery run without --model-check has no R-free pairs, and the axis range min()/max() over them crashed the script before any figure was drawn. The R-free figure is now its own gnuplot block, left out (with a line in summary.txt saying why) when there is nothing to draw; d_min and the time figures are drawn as before. Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01SVmAWnzCmRKAXVUCdc4iNi --- tools/battery/paper_plots.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/tools/battery/paper_plots.py b/tools/battery/paper_plots.py index fbc2a3d6c..5229d5c3e 100644 --- a/tools/battery/paper_plots.py +++ b/tools/battery/paper_plots.py @@ -21,6 +21,7 @@ Left figure: R-free of the deposited model after the battery's REFMAC check on t (x) and on Rugnux's data (y). By default the refined protocol (model_check.py: the same model refined against each data set at its own resolution, R-free over the free reflections both data sets share); --rfree first-cycle draws the first-cycle rigid-body numbers at the common resolution instead. +A run without REFMAC values (the check is opt-in, --model-check) gets no R-free figure; the rest are drawn. Right figure: the deposited high-resolution limit (x) against Rugnux's own cut (y), log axes so the low-resolution entries show. Small molecules (no deposited model) and sets whose verdict is `fail` (a wrong lattice: nothing to compare) are left out. @@ -75,7 +76,10 @@ set style line 2 pt 7 ps 0.35 lc rgb "#0072b2" # counts: names left-aligned, numbers right-aligned in a column beside them set label 11 "Structures\nFacilities\nBeamlines" at graph 0.05, graph 0.93 left front set label 12 "%(n)d\n%(nf)d\n%(nb)d" at graph 0.31, graph 0.93 right front +""" +# Drawn only where the runs carry REFMAC R-free values; the battery's REFMAC check is opt-in. +GNUPLOT_RFREE = r""" # --- R-free set output "%(out)s/rfree.pdf" set xlabel "{/:Italic R}_{free}, depositor data" @@ -86,7 +90,9 @@ set format x "%%.1f"; set format y "%%.1f" set label 2 "Within ±%(band).2f: %(within)d/%(n)d" at graph 0.95, graph 0.07 right front plot x ls 1, "%(out)s/rfree.dat" using 1:2 ls 2 unset label 2 +""" +GNUPLOT_REST = r""" # --- high-resolution limit set output "%(out)s/dmin.pdf" set logscale xy @@ -255,7 +261,8 @@ def main(): else "set key off") params = dict(out=out, tkey=tkey, n=n, nf=nf, nb=nb, dn=dn, dnf=dnf, dnb=dnb, within=within, band=RFREE_BAND, deeper=deeper, shallower=sum(y > x for x, y, _ in dmin), - rlo=0.05 * math.floor((min(values) - 0.01) / 0.05), rhi=0.05 * math.ceil((max(values) + 0.01) / 0.05), + rlo=0.05 * math.floor((min(values, default=0.2) - 0.01) / 0.05), + rhi=0.05 * math.ceil((max(values, default=0.3) + 0.01) / 0.05), dlo=0.5, dhi=8.0, bin=TIME_BIN, thi=TIME_BIN * math.ceil(max(secs) / TIME_BIN), tyhi=10 * math.ceil((tallest + 1) / 10), tmed=tmed, tn=len(times), @@ -263,9 +270,9 @@ def main(): zyhi=5 * math.ceil((max(collections.Counter(math.floor(t / ZOOM_BIN) for t in secs if t < ZOOM_MAX).values()) + 1) / 5)) gp = os.path.join(out, "figures.gp") - open(gp, "w").write(GNUPLOT % params) + open(gp, "w").write((GNUPLOT + (GNUPLOT_RFREE if rfree else "") + GNUPLOT_REST) % params) subprocess.run(["gnuplot", gp], check=True) - for fig in ("rfree", "dmin", "time", "time_zoom"): # the PNG is the PDF rasterised at 600 d.p.i. + for fig in (["rfree"] if rfree else []) + ["dmin", "time", "time_zoom"]: # the PNG is the PDF rasterised at 600 d.p.i. subprocess.run(["pdftoppm", "-r", "600", "-png", "-singlefile", os.path.join(out, fig + ".pdf"), os.path.join(out, fig)], check=True) @@ -276,8 +283,10 @@ def main(): fh.write(f"run {path}\n label {m.get('label')} binary git {b.get('source_head')} " f"dirty {b.get('source_dirty')} sha256 {b.get('sha256')}\n flags {b.get('flags')} " f"runner git {m.get('runner_git')} dirty {m.get('runner_dirty')}\n") - fh.write(f"R-free: {n} structures, {nf} facilities, {nb} beamlines; within +-{RFREE_BAND}: {within}\n" - f"d_min: {dn} structures, {dnf} facilities, {dnb} beamlines; Rugnux reaches further on " + fh.write((f"R-free: {n} structures, {nf} facilities, {nb} beamlines; within +-{RFREE_BAND}: {within}\n" + if rfree else "R-free: no REFMAC values in these runs (run the battery with --model-check); " + "no rfree figure\n") + + f"d_min: {dn} structures, {dnf} facilities, {dnb} beamlines; Rugnux reaches further on " f"{deeper}\n") queue_wait = max(time_rows[s]["elapsed_s"] - t for s, _, t, _, _ in times) fh.write(f"time: {len(times)} sets of arm(s) {', '.join(a.time_arms)}; field rugnux_wall_s "