Files
beta_shape_pnpi/beta_spectrum/components/screening.py
T
unzhakov 0c5c53688d MVP Correction Implemented
Add implementation for the basic set of spectrum components:

Primary
-------
- Phase Space
- Fermi Function

Corrections
-----------

- Atomic:
  - Screening
  - Atomic exchange
- E/M and finite size:
  - Finite nucleus size and charge distribution
  - Radiative
2026-04-10 15:32:47 +03:00

98 lines
2.5 KiB
Python

import numpy as np
from beta_spectrum.base import SpectrumComponent
from beta_spectrum.utils import momentum
from beta_spectrum.constants import ALPHA
class ScreeningCorrection(SpectrumComponent):
"""
Atomic screning correction S(Z, W).
Implements:
- Ratio method (non-screened to screened F(Z,W)*p*W) using shifted energy W -> W_tilde
- Smooth switching function to regularize low-energy behaviour
S(W) = 1 + f(W) * (S_raw(W) - 1
"""
def __init__(
self,
fermi_function,
V0: float = None,
Ws: float = 1.01,
Delta: float = 0.005,
eps: float = 1e-6,
C=0.015,
):
"""
Parameters
----------
Z : nuclear charge
fermi_function : callable
Instance of FermiFunction class
V0 : screening potential (in m_e units)
If None, uses simple scaling law
Ws : switching midpoint
Delta : switching width
eps : numerical floor for W_tilde
"""
self.fermi = fermi_function
self.Z = fermi_function.Z
self.Ws = Ws
self.Delta = Delta
self.eps = eps
self._C = C
self.V0 = V0 if V0 is not None else self._estimate_V0()
# --------------------
# Core evaluation
# --------------------
def __call__(self, W: np.ndarray) -> np.ndarray:
W = np.asarray(W)
# Energy shift by screening potential V0
W_tilde = self._screened_energy(W)
# Momenta
p = momentum(W)
p_tilde = momentum(W_tilde)
# Fermi functions
F = self.fermi(W)
F_tilde = self.fermi(W_tilde)
# Raw ratio model (for W >> V0)
S_raw = (F_tilde / F) * (p_tilde * W_tilde) / (p * W)
# Smooth switching
f = self._switching_function(W)
return 1.0 + f * (S_raw - 1.0)
# --------------------
# Helpers
# --------------------
def _screened_energy(self, W):
"""
Apply energy shift W -> W_tilde with safe numerical floor
"""
W_tilde = W - self.V0
return np.maximum(W_tilde, 1.0 + self.eps)
def _switching_function(self, W):
"""
Logistic switching function
"""
return 1.0 / (1.0 + np.exp((self.Ws - W) / self.Delta))
def _estimate_V0(self):
"""
Simple scaling estimate for screening potential.
V0 ~ alpha * Z^(4/3) * C
C ~ 0.01-0.02 (tunable constant)
"""
return ALPHA * self.Z ** (4.0 / 3.0) * self._C