|
| | __init__ (self, I=None, V=None, solver_mode=None, physics_option=None, equations=None, cascade=None, excel_file=None, C_floor=None, he_kinetics=None, i_mobile=None, v_mobile=None, **legacy_kw) |
| |
| | rebuild_rates (self) |
| |
| | run_adaptive (self, solver_config=None, save_output=True, progress_callback=None, timeout_s=None, boundary_threshold=0.01, max_doublings=6, points_per_segment=10) |
| |
| | run (self, solver_config=None, save_output=True, progress_callback=None, timeout_s=None, y0_override=None) |
| |
|
| | _reconstruct_sia_per_size (self, sia_block) |
| |
| | _loop_network_update (self, results, dt) |
| |
| | _resize_domain (self, I_new, V_new) |
| |
| | _boundary_fraction_at (self, results, idx) |
| |
| | _boundary_fraction (self, results) |
| |
| | _find_first_exceedance (self, results, threshold) |
| |
| | _resume_state (self, results, idx=-1) |
| |
| | _expand_state (self, y_old, I_new, V_new, y100_old=None) |
| |
| | _slice_results (self, results, start, end) |
| |
| | _merge_results (self, accumulated, new_segment) |
| |
| | _run_cpp (self, solver_config, progress_callback=None, timeout_s=None, y0_override=None) |
| |
| | _default_solver_config (self) |
| |
| | _write_dict_block (cls, f, title, d) |
| |
| | _machine_info (self) |
| |
| | _save_output (self, results, solver_config) |
| |
| | _save_output_impl (self, results, solver_config) |
| |
Orchestrates the RadCluster_2_1 simulation workflow.
Parameters
----------
I : int, optional — override max SIA cluster size
V : int, optional — override max vacancy cluster size
solver_mode : str, optional — 'full_system' | 'active_window'
physics_option : str, optional — 'full_CD_fission' | 'full_CD_fusion' |
'bin_moment_CD_fission' | 'bin_moment_CD_fusion'.
Mutually exclusive with the new (equations,
cascade) pair below.
equations : str, optional — 'discrete' | 'bin_moment'. Use together with
`cascade` instead of `physics_option`.
Legacy 'full_CD' is silently aliased to
'discrete'.
cascade : str, optional — 'fission' | 'fusion'. Use together with
`equations`.
excel_file : path-like, optional
C_floor : float, optional — concentration floor (default 1e-15).
Any state variable below this is clamped
before evaluating rate terms.
he_kinetics : str, optional — 'dynamic' (default) integrates free He as a
full ODE (Eq. 157); 'quasi_steady_state'
eliminates it via dc_h/dt = 0 (valid because
E_m_h = 0.06 eV gives rapid equilibration).
i_mobile : int, optional — max mobile SIA cluster size (default 1).
1 = mono-defect form; set > 1 to enable 1D
glide and SIA–SIA coalescence.
v_mobile : int, optional — max mobile vacancy cluster size (default 1).
1 = mono-defect form; set > 1 to enable
vacancy–vacancy coalescence.
Notes
-----
Two-layer RAG description. Alongside the legacy RateEquations /
BinMomentRateEquations objects that drive the C++ solver, every
RadClusterSimulation also carries the abstract-core + EUROFER-97
instantiation as ``self.material_rag`` (the reaction admissibility
graph G_Eur, paper Section 4) and ``self.state_layout`` (its
contiguous ODE-index map). This makes the graph-based formulation
the live structural description of every run. The RAG build is
advisory: it is wrapped in try/except so a RAG-build issue can never
break a run, and the C++ drive path is byte-identical with or
without it. ``material_rag`` / ``state_layout`` are ``None`` if the
build failed.
Definition at line 187 of file simulation.py.
| py_utils.simulation.RadClusterSimulation._expand_state |
( |
|
self, |
|
|
|
y_old, |
|
|
|
I_new, |
|
|
|
V_new, |
|
|
|
y100_old = None |
|
) |
| |
|
protected |
Map ODE state from the current domain to a larger (I_new, V_new) domain.
1. Reconstruct per-size distributions from old state.
2. Pad with C_floor for new sizes beyond old I, V.
3. Resize domain (rebuilds bins and rate equations).
4. Project padded distributions onto new bins.
Returns y0_new for the enlarged domain.
Parameters
----------
y100_old : ndarray or None
The appended ⟨100⟩ block AS SOLVED (``results['y_sia100_raw']``),
i.e. per-size in discrete modes and discrete-prefix + bin moments in
bin-moment modes. When given it is remapped by the SAME
reconstruct → pad → project path as the ½⟨111⟩ block (the two share
a layout) and appended to the returned state, so the C++ receives a
y0 of the full width. Omitting it returns the ⟨100⟩-free state,
which the solver zero-fills to 1e-100 — that erases the population
at the doubling, so pass it whenever loop conversion is on.
Definition at line 616 of file simulation.py.
| py_utils.simulation.RadClusterSimulation._loop_network_update |
( |
|
self, |
|
|
|
results, |
|
|
|
dt |
|
) |
| |
|
protected |
Operator-split advance of the dynamic network density ρ_net between
integration segments (loop_network_loss.tex §Implementation).
ρ_net is held piecewise-constant *within* a segment (so the Jacobian /
Woodbury structure is untouched) and advanced *between* segments by an
explicit Euler step of Eq. (rho_net_balance):
ρ_net ← ρ_net + dt · [ (π/Ω) Σ d_n Λ_n c_n − K_rec ρ_net^{3/2} ]
The segment-end SIA/vacancy monomers are frozen into ``ci1_seg`` /
``cv1_seg`` (they set the network climb velocity v_net for the next
segment), and ``rebuild_rates`` refreshes ReactionRates so the P4 sink
and Λ_n^net pick up the new ρ_net. No-op unless the channel is on.
The per-size loop distributions that drive the growth term come from the
post-processed segment and so work in BOTH discrete and bin-moment modes:
* ½⟨111⟩ — the SIA block of ``results['y']`` (per-size in discrete
mode; reconstructed from the SIA bin moments via the active shape
function in bin-moment mode);
* ⟨100⟩ — ``results['y_sia100']``, which cpp_bridge has already
reconstructed to per-size [I, n_t] in both modes. (Note ``results['y']``
no longer carries the appended ⟨100⟩ block — cpp_bridge splits it
off — so it must be read from this dedicated key, not the y tail.)
Definition at line 414 of file simulation.py.
| py_utils.simulation.RadClusterSimulation._resume_state |
( |
|
self, |
|
|
|
results, |
|
|
|
idx = -1 |
|
) |
| |
|
protected |
Full C++ state vector at time index *idx*, ready to resume from.
``results['y']`` has the appended ⟨100⟩ block split off by cpp_bridge,
so resuming from it alone hands the solver a SHORT y0. The C++ reads
missing ``y0_k`` keys as 1e-100 (parameters.h), so this did not fail —
it silently erased the entire ⟨100⟩ population at every segment
boundary, which the population then had to regrow from nothing. That
produced the once-per-segment sawtooth in the ⟨100⟩ number density and
a violent restart transient for CVODE. Re-attach the block here.
Definition at line 601 of file simulation.py.
| py_utils.simulation.RadClusterSimulation._save_output |
( |
|
self, |
|
|
|
results, |
|
|
|
solver_config |
|
) |
| |
|
protected |
Write timestamped output directory.
Resilient to partial/interrupted runs: each artifact (provenance,
summary, diagnostics, .npy, plots) is written under its own try/except
so a failure in one does not abort the others.
The whole body runs under an `_InterruptDeferred` shield so that a
Ctrl+C arriving mid-save does not abandon partially-written files —
the current write completes, the rest of the artifacts are flushed,
then the interrupt is re-raised for the caller. A second Ctrl+C in
the same block restores the default handler so the user can still
force-abort if a save step hangs.
Definition at line 1506 of file simulation.py.
| py_utils.simulation.RadClusterSimulation.run |
( |
|
self, |
|
|
|
solver_config = None, |
|
|
|
save_output = True, |
|
|
|
progress_callback = None, |
|
|
|
timeout_s = None, |
|
|
|
y0_override = None |
|
) |
| |
Run the simulation using the configured solver mode and physics option.
Parameters
----------
solver_config : dict, optional
Keys: t_span, n_points, rtol, atol, log_time,
solver_method (dict with linsol, window_*, etc.)
save_output : bool
Write timestamped output/ directory.
progress_callback : callable or None
Called once per output time step during the C++ solver run with a
dict of concentrations and rate-breakdown values (atom fraction).
Enables verbose mode in the C++ solver automatically.
timeout_s : float or None
Maximum wall-clock seconds for the C++ solver.
y0_override : ndarray or None
Custom initial conditions (adaptive continuation).
Returns
-------
results : dict (see post_process.calculate_derived_quantities)
Definition at line 1294 of file simulation.py.