40LABEL_PT, TICK_PT, LEGEND_PT = 22, 20, 15
163 """Add d_100_nm / d_cavity_nm as TIME SERIES.
165 They are not in `results`: post_process stores mean_n_100 and mean_n_v, and
166 the diameters are formed only inside the at_dose ladder. Plotting the raw
167 key therefore silently produced panels with the experimental band and no
168 model curves at all -- caught by looking at the figure, not by the run
169 succeeding. Same expressions the ladder uses, so figure and table agree.
172 idata = d[
"input_data"]
173 Om = float(r.get(
"Omega", idata.derived[
"Omega"]))
174 b111 = float(r.get(
"b_111", idata.derived[
"b_111"]))
175 b100 = float(r.get(
"b_100", idata.energetics.get(
"b_100", 0.2867) * 1e-9))
177 n100 = np.maximum(np.asarray(r.get(
"mean_n_100", []), float), 0.0)
178 nv = np.maximum(np.asarray(r.get(
"mean_n_v", []), float), 0.0)
179 n111 = np.maximum(np.asarray(r.get(
"mean_n_111", []), float), 0.0)
180 out[
"d_100_nm"] = 2 * np.sqrt(n100 * Om / (np.pi * b100)) * 1e9
181 out[
"d_111_nm"] = 2 * np.sqrt(n111 * Om / (np.pi * b111)) * 1e9
182 out[
"d_cavity_nm"] = 2 * (3 * nv * Om / (4 * np.pi)) ** (1.0 / 3.0) * 1e9
202 """Range of the model curves and measurements *inside the plotted window*.
204 Restricted to the panel's own x-limits: the transient below the left edge
205 carries diameters well above anything on screen, and including it set the
206 ordinate from data the reader never sees.
208 lo_x, hi_x = XLIM_OVERRIDE.get(key, XLIM)
210 for _, _, _, dose, r
in traj:
211 y = np.asarray(r.get(key, []), float)
212 if y.size == dose.size:
213 y = y[(dose >= lo_x) & (dose <= hi_x) & np.isfinite(y)]
215 vals.append((y.min(), y.max()))
217 vals.append((float(df[expcol].min()), float(df[expcol].max())))
220 return min(v[0]
for v
in vals), max(v[1]
for v
in vals)
224 fig, ax = plt.subplots(figsize=(11, 7.5))
225 for label, colour, ls, dose, r
in traj:
226 y = np.asarray(r.get(key, []), float)
227 if y.size != dose.size:
230 lw = 3.4
if label.startswith(
"D ")
else 2.4
231 z = 5
if label.startswith(
"D ")
else 3
232 ax.plot(dose[m], y[m], ls, color=colour, lw=lw, label=label, zorder=z)
234 df = EXP[expkey].dropna(subset=[
"Dose [dpa]", expcol])
235 keep = EXP_EXCLUDE.get(key)
236 if keep
is not None and len(df):
239 c = EXP_COLOR[expkey]
240 x0, x1 = df[
"Dose [dpa]"].min(), df[
"Dose [dpa]"].max()
241 y0, y1 = df[expcol].min(), df[expcol].max()
242 if x1 > x0
and y1 > y0:
243 ax.add_patch(Rectangle((x0, y0), x1 - x0, y1 - y0,
244 facecolor=to_rgba(c, 0.12),
245 edgecolor=to_rgba(c, 0.85), lw=2.0,
246 ls=(0, (6, 4)), zorder=1,
247 label=
"EUROFER97 measured range"))
248 ax.scatter(df[
"Dose [dpa]"], df[expcol], s=150, marker=EXP_MARK[expkey],
249 facecolors=c, edgecolors=
"white", linewidths=1.6, zorder=6,
250 label=
"EUROFER97 neutron, 300-350 $^\\circ$C")
253 ax.set_xlim(*XLIM_OVERRIDE.get(key, XLIM))
257 ax.set_ylim(bottom=YMIN[key])
264 pad = 0.05 * (hi - lo)
if hi > lo
else 0.05 * max(hi, 1.0)
265 ax.set_ylim(max(0.0, lo - pad), hi + pad)
266 ax.set_xlabel(
"Dose (dpa)")
267 ax.set_ylabel(ylabel)
268 ax.grid(
True, which=
"both", alpha=0.25)
269 ax.legend(loc=
"best", frameon=
True, framealpha=0.92)
271 OUT.mkdir(parents=
True, exist_ok=
True)
272 p = OUT / f
"size_effect_{key}.pdf"
273 fig.savefig(p, bbox_inches=
"tight")
323 print(f
"{len(traj)} trajectories loaded")
324 for label, _, _, dose, _
in traj:
325 print(f
" {label:26s} {len(dose):3d} points, to {dose.max():.3g} dpa")
327 for key, ylabel, logy, ek, ec,
in [(o[0], o[1], o[2], o[3], o[4])
for o
in OBSERVABLES]:
328 p =
one_figure(key, ylabel, logy, ek, ec, traj, EXP)
329 df = EXP[ek].dropna(subset=[
"Dose [dpa]", ec])
330 keep = EXP_EXCLUDE.get(key)
331 if keep
is not None and len(df):
333 panel_keys[key] =
_keys(df)
334 print(f
" wrote {p.relative_to(REPO)} sources: {', '.join(panel_keys[key])}")
336 print(f
" wrote {sp.relative_to(REPO)}")