""" 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")