RadCluster
Graph-based cluster dynamics for irradiated materials
Loading...
Searching...
No Matches
he_reduction.py
Go to the documentation of this file.
1"""
2core/reductions/he_reduction.py — Helium-occupancy state-space reductions.
3
4Host-independent declaration of the two helium reductions derived in
5Ghoniem (2026), Sections 5.2-5.3, as systematic limits of the same
6parent master equations. Both collapse the prohibitive two-dimensional
7(m, ell) vacancy-helium grid; they preserve the helium-conservation
8moment exactly.
9
10 CASE1_MEANFIELD (fusion, fast-He equilibration, Section 5.2)
11 Helium migrates far faster than cavities grow, so at each vacancy
12 size m the loading equilibrates to a mean value mu(m, t). The 2-D
13 grid c_{m,ell} collapses to two 1-D arrays (c_m, Q_m) with
14 mu(m) = Q_m / c_m, reducing the vacancy-He block to ~2 N_V ODEs.
15
16 CASE2_DECOUPLED (fission, decoupled inventory, Section 5.3)
17 Helium is a weak perturbation; the per-size loading need not be
18 tracked. A single scalar trapped-He inventory Q_tot is evolved and
19 distributed across cavity sizes algebraically by the capture-rate
20 weight m^{1/3} c_m. The vacancy-He block shrinks to N_V + 1 ODEs.
21
22 DYNAMIC
23 No reduction: free helium c_h is an explicit ODE variable. (A
24 quasi-steady-state variant solves dc_h/dt = 0 algebraically.)
25
26This module only fixes the taxonomy and the block-count contract; the
27size-resolved helium kinetics are supplied by the host material, which
28owns the SOLUTE_TRAPPING edge class.
29"""
30from __future__ import annotations
31
32from enum import Enum
33
34
35class HeReductionMode(Enum):
36 """The helium-occupancy reduction selected for a run."""
37
38 DYNAMIC = "dynamic" # explicit free-He ODE
39 CASE1_MEANFIELD = "case1_meanfield" # fusion: mean loading mu(m) per size
40 CASE2_DECOUPLED = "case2_decoupled" # fission: scalar inventory Q_tot
41
42 @property
43 def is_fusion(self) -> bool:
44 return self is HeReductionMode.CASE1_MEANFIELD
45
46 @property
47 def is_fission(self) -> bool:
48 return self is HeReductionMode.CASE2_DECOUPLED
49
50 def he_block_length(self, n_vac_sizes: int, free_he_tracked: bool) -> int:
51 """ODE count contributed by the helium state for this reduction.
52
53 Parameters
54 ----------
55 n_vac_sizes : int
56 Number of vacancy size classes (or vacancy bins) carrying He.
57 free_he_tracked : bool
58 True if free helium c_h is an explicit ODE (dynamic, non-QSS).
59 """
60 free = 1 if free_he_tracked else 0
61 if self is HeReductionMode.CASE1_MEANFIELD:
62 return n_vac_sizes + free # one Q_m per vacancy class
63 if self is HeReductionMode.CASE2_DECOUPLED:
64 return 1 + free # one scalar Q_tot
65 return free # DYNAMIC: just c_h (if tracked)
66
67 @classmethod
68 def from_cascade(cls, cascade: str) -> "HeReductionMode":
69 """Map a cascade spectrum to its canonical He reduction.
70
71 fission -> Case 2 (decoupled); fusion -> Case 1 (mean-field).
72 """
73 c = str(cascade).lower()
74 if "fus" in c:
75 return cls.CASE1_MEANFIELD
76 if "fis" in c:
77 return cls.CASE2_DECOUPLED
78 raise ValueError(f"unknown cascade spectrum {cascade!r}")
"HeReductionMode" from_cascade(cls, str cascade)
int he_block_length(self, int n_vac_sizes, bool free_he_tracked)