RadCluster
Graph-based cluster dynamics for irradiated materials
Loading...
Searching...
No Matches
Classes | Functions | Variables
py_utils.bin_moment_rates Namespace Reference

Classes

class  BinMomentRateEquations
 

Functions

 n_moments_for_shape (shape_function)
 
 build_bins (N_max, n1=1, r=2.0)
 
 moments_from_distribution (c_n, bins, n_mom=2)
 
 distribution_from_moments_pc (mu0, mu1, bins, N_max)
 
 midpoint_distribution_from_moments (mu0, mu1, bins, mu2=None, shape_function='linear')
 
 distribution_from_moments_hat (mu0, mu1, bins, N_max)
 
 distribution_from_moments_lognormal (mu0, mu1, mu2, bins, N_max)
 
 reconstruct_distribution (shape_function, mu0, mu1, mu2, bins, N_max, *smooth_edges=False)
 
 _smooth_bin_edges_inplace (c_n, bins)
 
 distribution_from_moments_continuous (mu0, mu1, bins, N_max)
 

Variables

float _kB = 8.617333262e-5
 
dict _SHAPE_FUNCTIONS = {'constant': 1, 'linear': 2, 'lognormal': 3}
 
dict _SHAPE_FUNCTION_INT = {'constant': 0, 'linear': 1, 'lognormal': 2}
 

Detailed Description

bin_moment_rates.py — Size-bin moment reduction for RadCluster_2_1.

REFERENCE ONLY (ODE RHS) — the `ode_system` method of
BinMomentRateEquations is not used by the solver; the production RHS is the
C++ implementation.  May be stale.  Scheduled for replacement by the
Stage-3 graph-walker.  simulation.py integrates exclusively via the C++
solver and never calls the Python `ode_system`.  Note that the
reconstruction/projection helpers and bin-construction code in this module
ARE used (e.g. by simulation.py's adaptive domain expansion); only the
`ode_system` RHS is dead code.

Implements the Chapter 9 state-space reduction for the SIA and vacancy
cluster populations via logarithmic size bins.  Three intra-bin shape
functions (closures) are supported:

  shape_function = "constant"   — piecewise-constant (1 moment/bin: μ₀)
  shape_function = "linear"     — hat-function / dual-basis (2 moments/bin: μ₀, μ₁)
  shape_function = "lognormal"  — log-normal (3 moments/bin: μ₀, μ₁, μ₂)

Physics reference
-----------------
Ghoniem, N.M. (2026), Chapter 9 (Rate_Equations.pdf):
  Eqs. 188-211.

Bin partition (Eq. 188)
-----------------------
Logarithmic bin edges:
  n_k = floor(n_1 · r^k),  k = 0, 1, ..., K_bins
  r > 1  (typically r = 2)

Bin B_k = {n : n_k ≤ n < n_{k+1}}  (Eq. 189)
Bin width |B_k| = n_{k+1} − n_k    (Eq. 190)

Bin moments (Eq. 192)
---------------------
  μ_k^(0) = Σ_{n ∈ B_k} c_n        (zeroth — bin density)
  μ_k^(1) = Σ_{n ∈ B_k} n · c_n    (first  — bin content)
  μ_k^(2) = Σ_{n ∈ B_k} n² · c_n   (second — used only by lognormal)

Closures
--------
Piecewise-constant (Eq. 198-200):
  c_n ≈ μ_k^(0) / |B_k|   for all n ∈ B_k

Hat-function / linear (Galerkin) (Eq. 201-206):
  c_n = φ_{k,0}(n) · μ_k^(0) + φ_{k,1}(n) · μ_k^(1)

Log-normal (Eq. 213-216):
  c_n ∝ (1/n) exp[−(ln n − m_k)² / (2σ_k²)]
  with m_k, σ_k determined from μ₀, μ₁, μ₂; normalized to preserve μ₀.

Function Documentation

◆ _smooth_bin_edges_inplace()

py_utils.bin_moment_rates._smooth_bin_edges_inplace (   c_n,
  bins 
)
protected
Visualization post-process: kill the staircase jumps at internal bin
boundaries while preserving each bin's μ_k^(0) exactly.

Algorithm:
  1. Record each bin's pre-smoothing sum (= μ_k^(0) of the closure).
  2. At each internal boundary, replace both straddling values
     (last size of bin k, first size of bin k+1) with their
     geometric mean (or arithmetic mean if either is non-positive).
  3. Multiplicatively rescale each bin's interior so the sum is
     restored to step 1.

Width-1 bins are effectively unchanged (the rescale undoes the mean).
First/last bins keep their outer edge untouched.

Definition at line 431 of file bin_moment_rates.py.

◆ build_bins()

py_utils.bin_moment_rates.build_bins (   N_max,
  n1 = 1,
  r = 2.0 
)
Build logarithmic bin partition.

Parameters
----------
N_max : int  — maximum SIA cluster size tracked
n1    : int  — minimum cluster size (first bin starts here)
r     : float — bin ratio n_{k+1}/n_k > 1

Returns
-------
bins : list of (n_lo, n_hi) tuples
    Each tuple gives the inclusive lower and exclusive upper bounds of bin k.
    bins[k] = (n_k, n_{k+1})
edges : ndarray of int bin edges

Definition at line 76 of file bin_moment_rates.py.

◆ distribution_from_moments_continuous()

py_utils.bin_moment_rates.distribution_from_moments_continuous (   mu0,
  mu1,
  bins,
  N_max 
)
Reconstruct per-size concentrations with C⁰ continuity across bin edges.

At each internal bin boundary, the left and right hat-function values
are averaged.  Within each bin, linear interpolation between the
(averaged) edge values replaces the raw hat function.  This removes
the staircase discontinuities visible in the standard reconstruction
while preserving the bin moments to first order.

Parameters
----------
mu0, mu1 : ndarray [K_bins]
bins     : list of (n_lo, n_hi)
N_max    : int

Returns
-------
c_n : ndarray [N_max]

Definition at line 483 of file bin_moment_rates.py.

◆ distribution_from_moments_hat()

py_utils.bin_moment_rates.distribution_from_moments_hat (   mu0,
  mu1,
  bins,
  N_max 
)
Reconstruct per-size concentrations from moments using a linear
dual-basis that exactly preserves both μ₀ and μ₁.

Shape functions (linear dual basis):
    φ₀(n) = (S₂ − S₁·n) / Δ
    φ₁(n) = (bw·n − S₁) / Δ
where
    S₁ = Σ n,  S₂ = Σ n²,  Δ = bw·S₂ − S₁²

This guarantees:
    Σ φ₀ = 1,  Σ φ₁ = 0   →  Σ cₙ = μ₀
    Σ n·φ₀ = 0, Σ n·φ₁ = 1 →  Σ n·cₙ = μ₁

Negative values are clamped to 0 (breaks exact preservation for
strongly skewed bins, but keeps concentrations physical).

Parameters
----------
mu0, mu1 : ndarray [K_bins]
bins     : list of (n_lo, n_hi)
N_max    : int

Returns
-------
c_n : ndarray [N_max]

Definition at line 240 of file bin_moment_rates.py.

◆ distribution_from_moments_lognormal()

py_utils.bin_moment_rates.distribution_from_moments_lognormal (   mu0,
  mu1,
  mu2,
  bins,
  N_max 
)
Reconstruct per-size concentrations from moments using a log-normal
intra-bin shape function (Eq. 213-216).

Within each bin B_k, the distribution is assumed to follow:
    c_n ∝ (1/n) exp[−(ln n − m_k)² / (2σ_k²)]

The two log-normal parameters are determined from the moments:
    n_bar   = μ₁/μ₀
    n2_bar  = μ₂/μ₀
    σ_k²    = ln(n2_bar / n_bar²) = ln(μ₂·μ₀ / μ₁²)
    m_k     = ln(n_bar) − σ_k²/2

The amplitude is set so that Σ_{n∈B_k} c_n = μ₀ exactly.

Falls back to linear (hat-function) closure when σ_k² ≤ 0
(monodisperse limit), and to piecewise-constant when the bin
has only one size.

Parameters
----------
mu0, mu1, mu2 : ndarray [K_bins]
bins          : list of (n_lo, n_hi)
N_max         : int

Returns
-------
c_n : ndarray [N_max]

Definition at line 299 of file bin_moment_rates.py.

◆ distribution_from_moments_pc()

py_utils.bin_moment_rates.distribution_from_moments_pc (   mu0,
  mu1,
  bins,
  N_max 
)
Reconstruct piecewise-constant per-size concentrations from moments.

c_n = μ_k^(0) / |B_k|   for n ∈ B_k   (Eq. 198-200)

Parameters
----------
mu0  : ndarray [K_bins]
mu1  : ndarray [K_bins]  (unused in piecewise-constant)
bins : list of (n_lo, n_hi)
N_max: int

Returns
-------
c_n : ndarray [N_max]

Definition at line 136 of file bin_moment_rates.py.

◆ midpoint_distribution_from_moments()

py_utils.bin_moment_rates.midpoint_distribution_from_moments (   mu0,
  mu1,
  bins,
  mu2 = None,
  shape_function = 'linear' 
)
Evaluate concentration at bin geometric midpoints using the chosen closure.

Parameters
----------
mu0  : ndarray [K]
mu1  : ndarray [K] or None
bins : list of (n_lo, n_hi)
mu2  : ndarray [K] or None  — second moments (used only by lognormal)
shape_function : str — "constant", "linear", or "lognormal"

Returns
-------
midpoints : ndarray [K]  — geometric midpoint of each bin
conc      : ndarray [K]  — concentration at that midpoint

Definition at line 163 of file bin_moment_rates.py.

◆ moments_from_distribution()

py_utils.bin_moment_rates.moments_from_distribution (   c_n,
  bins,
  n_mom = 2 
)
Compute bin moments from per-size concentrations.

Parameters
----------
c_n   : ndarray [N_max]  — concentrations, c_n[n-1] = c_n
bins  : list of (n_lo, n_hi)
n_mom : int — number of moments to compute (1, 2, or 3)

Returns
-------
mu0 : ndarray [K_bins]  — zeroth moments
mu1 : ndarray [K_bins] or None  — first moments (if n_mom >= 2)
mu2 : ndarray [K_bins] or None  — second moments (if n_mom >= 3)

Definition at line 102 of file bin_moment_rates.py.

◆ n_moments_for_shape()

py_utils.bin_moment_rates.n_moments_for_shape (   shape_function)
Return the number of tracked moments per bin (1, 2, or 3).

Definition at line 67 of file bin_moment_rates.py.

◆ reconstruct_distribution()

py_utils.bin_moment_rates.reconstruct_distribution (   shape_function,
  mu0,
  mu1,
  mu2,
  bins,
  N_max,
*  smooth_edges = False 
)
Dispatch to the appropriate reconstruction function.

Parameters
----------
shape_function : str — "constant", "linear", or "lognormal"
mu0 : ndarray [K]
mu1 : ndarray [K] or None
mu2 : ndarray [K] or None
bins : list of (n_lo, n_hi)
N_max : int
smooth_edges : bool, default False
    If True, post-process the reconstructed distribution by averaging
    the two values straddling each internal bin boundary (geometric
    mean in log-space) and rescaling each bin so that
    Σ_{n ∈ B_k} c_n equals its pre-smoothing sum, preserving μ_k^(0)
    exactly. Use for visualization only — ODE right-hand sides and
    conservation diagnostics must pass False.

Returns
-------
c_n : ndarray [N_max]

Definition at line 392 of file bin_moment_rates.py.

Variable Documentation

◆ _kB

float py_utils.bin_moment_rates._kB = 8.617333262e-5
protected

Definition at line 58 of file bin_moment_rates.py.

◆ _SHAPE_FUNCTION_INT

dict py_utils.bin_moment_rates._SHAPE_FUNCTION_INT = {'constant': 0, 'linear': 1, 'lognormal': 2}
protected

Definition at line 64 of file bin_moment_rates.py.

◆ _SHAPE_FUNCTIONS

dict py_utils.bin_moment_rates._SHAPE_FUNCTIONS = {'constant': 1, 'linear': 2, 'lognormal': 3}
protected

Definition at line 61 of file bin_moment_rates.py.