1"""Score a results .jsonl against the six-observable target set.
3Usage: python score_six_targets.py results/S8_15dpa.jsonl [design/S8_labels.json]
5The six are N_100, d_100, N_111, d_111, N_voids, d_cavity at EUROFER97
6330 C / 15 dpa (targets_330C_15dpa.json). f_100 is NOT scored as an
7independent observable -- it is N_100/(N_100+N_111), so it is reported as a
10A row "passes" an observable when the model value lies inside [lo, hi]. The
11headline number is how many of the six are in range; ratio-to-target is shown
12so a near-miss is distinguishable from a three-order-of-magnitude miss.
14Rows that did not reach the target dose, or that piled at the grid ceiling,
15are marked -- their size readouts are not measurements and must not be scored
19from pathlib
import Path
20sys.stdout.reconfigure(encoding=
'utf-8', errors=
'replace')
22HERE = Path(__file__).resolve().parent
23TGT = json.load(open(HERE /
'targets_330C_15dpa.json'))
24OBS = TGT[
'observables']
25ORDER = [
'N_loops_100',
'd_100_nm',
'N_loops_111',
'd_111_nm',
'N_voids',
'd_cavity_nm']
26SHORT = {
'N_loops_100':
'N_100',
'd_100_nm':
'd_100',
'N_loops_111':
'N_111',
27 'd_111_nm':
'd_111',
'N_voids':
'N_void',
'd_cavity_nm':
'd_void'}
29res = Path(sys.argv[1])
if len(sys.argv) > 1
else HERE /
'results/S8_15dpa.jsonl'
30labf = Path(sys.argv[2])
if len(sys.argv) > 2
else res.parent.parent /
'design/S8_labels.json'
31labels = json.load(open(labf))
if labf.exists()
else {}
32rows = sorted((json.loads(l)
for l
in open(res)), key=
lambda r: r[
'row_id'])
34print(
'target set: %s %s C / %s dpa (%s)' % (
35 TGT[
'condition'][
'material'], TGT[
'condition'][
'T_C'],
36 TGT[
'condition'][
'dose_dpa'], TGT[
'condition'][
'irradiation']))
38hdr =
'%-20s %6s' % (
'row',
'dose') +
''.join(
'%12s' % SHORT[k]
for k
in ORDER) +
'%7s %8s %6s' % (
'in-rng',
'f_100',
'flags')
39print(hdr); print(
'-' * len(hdr))
42 lab = labels.get(str(r[
'row_id']), str(r[
'row_id']))
48 cells.append(
'%12s' %
'-');
continue
49 ok = o[
'lo'] <= v <= o[
'hi']
51 rat = v / o[
'target']
if o[
'target']
else float(
'nan')
52 s = (
'%.2e' % v)
if v >= 1e4
else (
'%.2f' % v)
53 cells.append(
'%12s' % (s + (
'*' if ok
else '')))
54 N1, N0 = r.get(
'N_loops_111'), r.get(
'N_loops_100')
55 f100 = N0 / (N0 + N1)
if (N0
and N1)
else float(
'nan')
57 if r.get(
'grid_limited'):
59 if abs(r.get(
'dose_reached', 0) - TGT[
'condition'][
'dose_dpa']) > 0.02 * TGT[
'condition'][
'dose_dpa']:
63 print(
'%-20s %6.3g' % (lab, r.get(
'dose_reached', 0)) +
''.join(cells)
64 +
'%7s %8.3f %6s' % (
'%d/6' % n_ok, f100,
','.join(flags)
or '-'))
67print(
' * = inside the experimental range. GRID = piled at the grid ceiling')
68print(
' (size readout invalid). DOSE = did not reach 15 dpa (nothing is')
69print(
' comparable). Ratios to target:')
71print(
'%-20s' %
'row' +
''.join(
'%12s' % SHORT[k]
for k
in ORDER))
73 lab = labels.get(str(r[
'row_id']), str(r[
'row_id']))
76 v, t = r.get(k), OBS[k][
'target']
77 out.append(
'%12s' % (
'-' if v
is None else '%.3gx' % (v / t)))
78 print(
'%-20s' % lab +
''.join(out))