176def build_eurofer_rag(input_data, reaction_rates, *,
177 equations: str =
"discrete",
178 cascade: str =
"fission"):
179 """Build the EUROFER-97 reaction admissibility graph and state layout.
183 input_data : InputData
184 The loaded EUROFER-97 parameter set (sizes ``I``/``V``, mobility
185 cutoffs ``i_mobile``/``v_mobile``, derived physics).
186 reaction_rates : ReactionRates
187 The precomputed rate-constant arrays built from ``input_data``.
188 Its attributes are registered verbatim as the RAG kernel library.
189 equations : {'discrete', 'bin_moment'}
190 Selects the SIA / vacancy state-space representation: one ODE per
191 size (``discrete``) or the logarithmic bin-moment reduction
192 (``bin_moment``, paper Section 5.4).
193 cascade : {'fission', 'fusion'}
194 Selects the cascade production spectrum and, through
195 :meth:`HeReductionMode.from_cascade`, the helium reduction
196 (fission -> Case 2 decoupled; fusion -> Case 1 mean-field).
200 (ReactionAdmissibilityGraph, StateLayout)
201 The host-specific graph G_Eur with all kernels registered, and the
202 contiguous ODE-index layout that packs it.
204 equations = str(equations).lower()
205 if equations
not in (
"discrete",
"bin_moment"):
207 f
"equations must be 'discrete' or 'bin_moment', got {equations!r}")
209 I = int(input_data.I)
210 V = int(input_data.V)
211 i_mobile = int(input_data.i_mobile)
212 v_mobile = int(input_data.v_mobile)
230 n_loop_min = int(getattr(reaction_rates,
"n_loop_min", 4))
231 sia_111 = rag.add_population(
232 Population(
"bulk-111", Polarity.SIA, n_min=1, mobile_max=i_mobile))
233 sia_100 = rag.add_population(
234 Population(
"bulk-100", Polarity.SIA, n_min=n_loop_min, mobile_max=0))
235 vac_bulk = rag.add_population(
236 Population(
"bulk", Polarity.VACANCY, n_min=1, mobile_max=v_mobile))
242 rag.set_monomer_population(sia_111)
243 rag.set_monomer_population(vac_bulk)
254 A_sph = float(input_data.derived[
"A_sph"])
255 A_8pi = rr.A_sph_inv_O23 * (8.0 * np.pi / A_sph)
258 rag.register_kernel(
"K_iv", float(rr.K_iv))
265 rag.register_kernel(
"K_SIA_grow", np.asarray(rr.K_SIA_grow, dtype=float))
266 rag.register_kernel(
"K_SIA_shrink", np.asarray(rr.K_SIA_shrink, dtype=float))
267 rag.register_kernel(
"K_VAC_grow", np.asarray(rr.K_VAC_grow, dtype=float))
268 rag.register_kernel(
"K_VAC_shrink", np.asarray(rr.K_VAC_shrink, dtype=float))
273 rag.register_kernel(
"D_SIA_sink", np.asarray(rr.k2_SIA, dtype=float))
274 rag.register_kernel(
"D_VAC_sink", float(rr.k2_vac_scalar))
279 rag.register_kernel(
"eps_SIA_emit", np.asarray(rr.G_SIA, dtype=float))
280 rag.register_kernel(
"eps_VAC_emit", np.asarray(rr.G_VAC, dtype=float))
296 D_SIA_eff = np.asarray(rr.D_SIA_eff, dtype=float)
297 D_VAC_eff = np.asarray(rr.D_VAC_eff, dtype=float)
300 lambda: (1.0 - np.asarray(rr.phi_junc, dtype=float))
304 lambda: np.asarray(rr.phi_junc, dtype=float)
306 rag.register_kernel(
"K_vv_coal",
311 rag.register_kernel(
"Gamma_uni", np.asarray(rr.Gamma_uni, dtype=float))
329 absorb_boost = float(input_data.reactions.get(
'absorb_boost_100', 1.0)
or 1.0)
339 lambda: (float(rr.conv_psuccess_abs) * absorb_boost
342 rag.register_kernel(
"K_100_grow", np.asarray(rr.K_100_grow, dtype=float))
343 rag.register_kernel(
"K_100_shrink", np.asarray(rr.K_100_shrink, dtype=float))
344 rag.register_kernel(
"eps_100_emit", np.asarray(rr.G_100, dtype=float))
345 rag.register_kernel(
"D_100_sink", np.asarray(rr.k2_100, dtype=float))
347 I_size = int(input_data.I)
360 G = float(input_data.derived[
"G"])
361 G_He_r = float(input_data.derived[
"G_He_r"])
362 Pr_SIA, Pr_VAC, _G_He = production_rates(G, cascade, I, V, G_He_r)
371 T = float(input_data.derived[
"T"])
379 spec = str(input_data.derived.get(
"spectrum", cascade)).lower()
380 b0_key =
"b0_fission" if "fiss" in spec
else "b0_fusion"
381 b0_res = float(input_data.reactions.get(
382 b0_key, 0.01
if "fiss" in spec
else 0.10))
393 EdgeClass.RECOMBINATION,
"P1_recombination", sia_111,
395 meta={
"process":
"P1",
"note":
"V-SIA recombination, paper Eq. 52"}))
401 EdgeClass.GROWTH,
"P2v_cavity_growth", vac_bulk,
403 meta={
"process":
"P2",
"note":
"void + V_1 -> void_{m+1}"}))
405 EdgeClass.SHRINKAGE,
"P2i_cavity_shrink", vac_bulk,
406 kernel=
"K_VAC_shrink",
407 meta={
"process":
"P2/P6",
"note":
"void + I_1 -> void_{m-1}"}))
411 EdgeClass.GROWTH,
"P3_loop_growth", sia_111,
413 meta={
"process":
"P3",
"note":
"loop + I_1 -> loop_{n+1}"}))
415 EdgeClass.SHRINKAGE,
"P3_loop_shrink", sia_111,
416 kernel=
"K_SIA_shrink",
417 meta={
"process":
"P3",
"note":
"loop + V_1 -> loop_{n-1}"}))
422 EdgeClass.SINK,
"P4_SIA_sink", sia_111,
424 meta={
"process":
"P4",
"note":
"SIA fixed-sink loss D_i"}))
426 EdgeClass.SINK,
"P4_VAC_sink", vac_bulk,
428 meta={
"process":
"P4",
"note":
"vacancy fixed-sink loss D_v"}))
433 EdgeClass.DISSOCIATION,
"P5i_SIA_emission", sia_111,
434 kernel=
"eps_SIA_emit",
435 meta={
"process":
"P5",
"note":
"loop_n -> loop_{n-1} + I_1"}))
437 EdgeClass.DISSOCIATION,
"P5v_VAC_emission", vac_bulk,
438 kernel=
"eps_VAC_emit",
439 meta={
"process":
"P5",
"note":
"void_m -> void_{m-1} + V_1"}))
444 EdgeClass.COALESCENCE,
"SIA111_self_coalescence", sia_111,
446 meta={
"note":
"I_n + I_n' -> I_{n+n'} (½<111>), (1-phi) branch, Eq. 79"}))
448 EdgeClass.COALESCENCE,
"VAC_VAC_coalescence", vac_bulk,
450 meta={
"note":
"V_m + V_m' -> V_{m+m'}, paper Eq. 80"}))
457 EdgeClass.COALESCENCE,
"SIA111_junction", sia_111,
458 kernel=
"K_111_junction", product_population=sia_100,
459 meta={
"mechanism":
"Marian junction",
460 "note":
"½<111>_n + ½<111>_n' -> <100>_{n+n'}"}))
464 EdgeClass.INTER_POPULATION,
"loop_111to100_unary", sia_111,
465 kernel=
"Gamma_uni", product_population=sia_100,
466 meta={
"mechanism":
"Dudarev unary transformation",
467 "note":
"½<111>_n -> <100>_n, one-way, gated by ΔF(n,T)>0"}))
472 EdgeClass.ANNIHILATION,
"VI_annihilation", vac_bulk,
473 kernel=
"K_vi_annih", partner_population=sia_111,
474 meta={
"note":
"V_m + I_n -> survivor of size |m-n|, paper Eq. 81"}))
479 EdgeClass.SOURCE,
"cascade_SIA_source", sia_111,
480 kernel=
"G_SIA_cascade",
481 meta={
"process":
"cascade",
"note":
"SIA cascade injection G_n"}))
483 EdgeClass.SOURCE,
"cascade_VAC_source", vac_bulk,
484 kernel=
"G_VAC_cascade",
485 meta={
"process":
"cascade",
"note":
"vacancy cascade injection G_m"}))
493 EdgeClass.COALESCENCE,
"SIA100_absorb", sia_100,
494 kernel=
"K_100_absorb", partner_population=sia_111,
495 meta={
"mechanism":
"Marian absorption growth",
496 "note":
"<100>_m + ½<111>_n -> <100>_{m+n}"}))
499 EdgeClass.GROWTH,
"P3_100_growth", sia_100,
501 meta={
"process":
"P3",
"note":
"<100>_n + I_1 -> <100>_{n+1}"}))
503 EdgeClass.SHRINKAGE,
"P3_100_shrink", sia_100,
504 kernel=
"K_100_shrink",
505 meta={
"process":
"P3",
"note":
"<100>_n + V_1 -> <100>_{n-1}"}))
507 EdgeClass.DISSOCIATION,
"P5_100_emission", sia_100,
508 kernel=
"eps_100_emit",
509 meta={
"process":
"P5",
"note":
"<100>_n -> <100>_{n-1} + I_1"}))
511 EdgeClass.SINK,
"P4_100_sink", sia_100,
513 meta={
"process":
"P4",
"note":
"sessile <100>: D=0 (no fixed-sink loss)"}))
516 EdgeClass.ANNIHILATION,
"VI_annihilation_100", vac_bulk,
517 kernel=
"K_vi_annih_100", partner_population=sia_100,
518 meta={
"note":
"V_m + <100>_n -> survivor of size |m-n|"}))
551 EdgeClass.GROWTH,
"P7_trap_mutation", vac_bulk,
553 meta={
"process":
"P7",
554 "note":
"trap mutation V_m(He) -> V_{m+1} + I_1, paper Eq. 75",
555 "sia_source":
"emits one I_1 monomer per mutation (n=1 SIA "
556 "source); gas-pressure-driven, kernel Gamma_TM",
557 "cpp_status":
"kernel registered; C++ arithmetic not yet "
558 "implemented (Stage-2 review)"}))
571 EdgeClass.SOLUTE_TRAPPING,
"P8_radiation_resolution", vac_bulk,
572 kernel=
"Gamma_res", gas_species=rag.gas_species.index(
"He"),
573 meta={
"process":
"P8",
"direction":
"detrap",
574 "note":
"radiation re-solution He_ell V_m -> He_{ell-1} V_m "
575 "+ He, paper Eq. 75 / Section 5.3",
576 "cpp_status":
"kernel registered; C++ arithmetic not yet "
577 "implemented (Stage-2 review)"}))
582 if equations ==
"discrete":
586 layout.add_discrete(
"SIA", I, population=sia_111)
587 layout.add_discrete(
"SIA100", I, population=sia_100)
588 layout.add_discrete(
"VAC", V, population=vac_bulk)
595 i_discrete = int(input_data.i_discrete)
596 v_discrete = int(input_data.v_discrete)
597 I_bin = int(input_data.I_bin)
598 V_bin = int(input_data.V_bin)
599 shape = str(input_data.shape_function)
601 sia_red = BinMomentReduction(I, i_discrete, I_bin, shape)
602 sia100_red = BinMomentReduction(I, i_discrete, I_bin, shape)
603 vac_red = BinMomentReduction(V, v_discrete, V_bin, shape)
604 layout.add_bin_moment(
605 "SIA", sia_red.n_discrete, sia_red.n_bins,
606 sia_red.moments_per_bin,
607 population=sia_111, reduction=sia_red, n_max=I)
612 layout.add_bin_moment(
613 "SIA100", sia100_red.n_discrete, sia100_red.n_bins,
614 sia100_red.moments_per_bin,
615 population=sia_100, reduction=sia100_red, n_max=I)
616 layout.add_bin_moment(
617 "VAC", vac_red.n_discrete, vac_red.n_bins,
618 vac_red.moments_per_bin,
619 population=vac_bulk, reduction=vac_red, n_max=V)
623 n_vac_classes = vac_red.length
629 he_mode = HeReductionMode.from_cascade(cascade)
630 he_len = he_mode.he_block_length(n_vac_classes, free_he_tracked=
True)
631 layout.add_aux(
"He", he_len,
632 reduction=he_mode.value, free_he_tracked=
True,
633 n_vac_classes=n_vac_classes)
639 layout.add_aux(
"conservation", 5,
640 note=
"cumulative accounting integrals for delta_FP/delta_He")