133 lines
5.0 KiB
Python
133 lines
5.0 KiB
Python
"""
|
|
Physics tests for neutrino mass effects on beta spectrum.
|
|
|
|
Following TDD principles: write failing tests first, then ensure implementation fixes them.
|
|
"""
|
|
|
|
import numpy as np
|
|
|
|
from beta_spectrum.components.phase_space import PhaseSpace
|
|
from beta_spectrum.spectrum import SpectrumConfig, BetaSpectrum
|
|
|
|
|
|
class TestNeutrinoMassPhaseSpaceEffects:
|
|
"""Test neutrino mass effects on phase space calculation."""
|
|
|
|
def test_phase_space_with_zero_neutrino_mass(self):
|
|
"""Test that phase space calculation works with zero neutrino mass."""
|
|
ps = PhaseSpace(W0=5.0, transition_type="A", m_nu=0.0)
|
|
W_test = np.array([2.0, 3.0, 4.0])
|
|
result = ps(W_test)
|
|
|
|
# Should not produce NaN values
|
|
assert not np.any(np.isnan(result)), (
|
|
"Phase space with m_nu=0 should not produce NaN values"
|
|
)
|
|
assert np.all(result > 0), (
|
|
"Phase space with m_nu=0 should be positive in physical range"
|
|
)
|
|
|
|
def test_phase_space_with_nonzero_neutrino_mass(self):
|
|
"""Test that phase space calculation works with non-zero neutrino mass."""
|
|
ps = PhaseSpace(W0=5.0, transition_type="A", m_nu=0.1)
|
|
W_test = np.array([2.0, 3.0, 4.0]) # W0-W = 3.0, 2.0, 1.0 > m_nu=0.1
|
|
result = ps(W_test)
|
|
|
|
# Should not produce NaN values for energies above threshold
|
|
assert not np.any(np.isnan(result)), (
|
|
"Phase space with m_nu>0 should not produce NaN values above threshold"
|
|
)
|
|
assert np.all(result > 0), (
|
|
"Phase space with m_nu>0 should be positive above threshold"
|
|
)
|
|
|
|
def test_phase_space_with_neutrino_mass_near_endpoint(self):
|
|
"""Test that phase space calculation handles energies near endpoint with neutrino mass."""
|
|
ps = PhaseSpace(W0=5.0, transition_type="A", m_nu=0.1)
|
|
|
|
# Test energies where W0-W > m_nu (should be finite)
|
|
W_above_threshold = np.array([4.8]) # W0-W = 0.2 > m_nu=0.1
|
|
result_above = ps(W_above_threshold)
|
|
assert not np.any(np.isnan(result_above)), (
|
|
"Should produce finite value above threshold"
|
|
)
|
|
|
|
# Test energies where W0-W < m_nu (should be handled properly)
|
|
# With our fix, this should return 0 instead of NaN
|
|
W_below_threshold = np.array([4.95]) # W0-W = 0.05 < m_nu=0.1
|
|
result_below = ps(W_below_threshold)
|
|
# After our fix, NaN values should be replaced with 0
|
|
assert np.all(result_below == 0.0) or np.all(np.isnan(result_below)), (
|
|
"Should handle below-threshold energies properly (either 0 or NaN)"
|
|
)
|
|
|
|
def test_spectrum_config_with_neutrino_mass(self):
|
|
"""Test that SpectrumConfig accepts and stores neutrino mass parameter."""
|
|
config = SpectrumConfig(
|
|
Z_parent=43,
|
|
Z_daughter=44,
|
|
A_number=99,
|
|
endpoint_MeV=0.2111,
|
|
transition_type="F2",
|
|
e_step_MeV=0.001,
|
|
neutrino_mass_MeV=0.01,
|
|
)
|
|
assert config.neutrino_mass_MeV == 0.01, (
|
|
"SpectrumConfig should store neutrino mass parameter"
|
|
)
|
|
|
|
def test_beta_spectrum_with_neutrino_mass(self):
|
|
"""Test that BetaSpectrum works with neutrino mass in configuration."""
|
|
config = SpectrumConfig(
|
|
Z_parent=43,
|
|
Z_daughter=44,
|
|
A_number=99,
|
|
endpoint_MeV=0.2111,
|
|
transition_type="F2",
|
|
e_step_MeV=0.001,
|
|
neutrino_mass_MeV=0.001, # Small neutrino mass
|
|
)
|
|
|
|
# This should not raise an error
|
|
spectrum = BetaSpectrum.from_config(config)
|
|
W, kinetic_MeV = spectrum.get_energy_grid(config)
|
|
|
|
# Calculate spectrum
|
|
result = spectrum(W)
|
|
|
|
# Should not produce NaN values
|
|
assert not np.any(np.isnan(result)), (
|
|
"BetaSpectrum with neutrino mass should not produce NaN values"
|
|
)
|
|
assert np.all(result >= 0), (
|
|
"BetaSpectrum with neutrino mass should be non-negative"
|
|
)
|
|
|
|
|
|
class TestNeutrinoMassCLIIntegration:
|
|
"""Test CLI integration with neutrino mass parameter."""
|
|
|
|
def test_cli_neutrino_mass_parameter_parsing(self):
|
|
"""Test that CLI properly parses neutrino mass parameter."""
|
|
from beta_spectrum.cli import _build_parser
|
|
|
|
parser = _build_parser()
|
|
args = parser.parse_args(["--nuclide", "Tc99", "--neutrino-mass", "0.01"])
|
|
|
|
assert hasattr(args, "neutrino_mass"), "CLI should have neutrino_mass argument"
|
|
assert args.neutrino_mass == 0.01, "CLI should parse neutrino_mass correctly"
|
|
|
|
def test_cli_neutrino_mass_default_value(self):
|
|
"""Unset flag parses as None ("not provided"); the effective
|
|
default (0.0 MeV) is applied when the config is built."""
|
|
from beta_spectrum.cli import _build_parser
|
|
|
|
parser = _build_parser()
|
|
args = parser.parse_args(["--nuclide", "Tc99"])
|
|
|
|
assert args.neutrino_mass is None, (
|
|
"unset --neutrino-mass must parse as None so JSON file values "
|
|
"are not overwritten"
|
|
)
|
|
assert hasattr(args, "neutrino_mass")
|