fix(spectrum): lone branch defines endpoint in single-branch mode
When config.branches carries exactly one branch (e.g. after --intensity-cutoff filtering), the branch endpoint/transition define the spectrum, energy grid, analyzer unified branch view and CSV header. The stale top-level endpoint inherited from the parent decay no longer leaks into physics (proven wrong on Cs137: spectrum extended to 1176 keV while the lone survivor ends at 514 keV).
This commit is contained in:
@@ -12,9 +12,6 @@ from .core import BetaSpectrumAnalyzer, _UnifiedBranch
|
||||
from .csv_export import CSVEmitter
|
||||
from .visualization import Visualizer
|
||||
|
||||
# Re-export the main class for backward compatibility
|
||||
BetaSpectrumAnalyzer = BetaSpectrumAnalyzer
|
||||
|
||||
__all__ = [
|
||||
"BetaSpectrumAnalyzer",
|
||||
"CSVEmitter",
|
||||
|
||||
@@ -55,12 +55,20 @@ class BetaSpectrumAnalyzer:
|
||||
self._is_multi = spectrum._is_multi
|
||||
self._timestamp: Optional[str] = None
|
||||
|
||||
# Unified branch view: single-branch treated as one-branch multi-branch
|
||||
# Unified branch view: single-branch treated as one-branch multi-branch.
|
||||
# When config.branches carries exactly one branch, that branch (not the
|
||||
# top-level decay fields) defines the endpoint and transition type.
|
||||
if not self._is_multi and self.spectrum.branch_spectra == []:
|
||||
endpoint_MeV = config.endpoint_MeV
|
||||
transition_type = config.transition_type
|
||||
if config.branches is not None and len(config.branches) == 1:
|
||||
lone = config.branches[0]
|
||||
endpoint_MeV = float(lone.endpoint_MeV)
|
||||
transition_type = str(lone.transition_type)
|
||||
self._unified_branches: List[_UnifiedBranch] = [
|
||||
_UnifiedBranch(
|
||||
endpoint_MeV=config.endpoint_MeV,
|
||||
transition_type=config.transition_type,
|
||||
endpoint_MeV=endpoint_MeV,
|
||||
transition_type=transition_type,
|
||||
intensity=1.0,
|
||||
)
|
||||
]
|
||||
|
||||
@@ -81,6 +81,18 @@ class CSVEmitter:
|
||||
if config.use_exchange:
|
||||
enabled.append("exchange")
|
||||
|
||||
# The header endpoint must describe the spectrum that is actually
|
||||
# computed. Single mode with exactly one configured branch follows
|
||||
# the branch (the top-level endpoint may be stale from the parent
|
||||
# decay, e.g. after intensity-cutoff filtering).
|
||||
basic_endpoint_MeV = config.endpoint_MeV
|
||||
if (
|
||||
not analyzer._is_multi
|
||||
and config.branches is not None
|
||||
and len(config.branches) == 1
|
||||
):
|
||||
basic_endpoint_MeV = analyzer._unified_branches[0].endpoint_MeV
|
||||
|
||||
parent_symbol = analyzer._element_symbol(config.Z_parent)
|
||||
daughter_symbol = analyzer._element_symbol(config.Z_daughter)
|
||||
|
||||
@@ -99,7 +111,7 @@ class CSVEmitter:
|
||||
f"# nuclide: {parent_symbol}{config.A_number} "
|
||||
f"-> {daughter_symbol}{config.A_number} "
|
||||
f"(Z={config.Z_parent}->{config.Z_daughter})",
|
||||
f"# basic_endpoint: {config.endpoint_MeV * 1000:.1f} keV",
|
||||
f"# basic_endpoint: {basic_endpoint_MeV * 1000:.1f} keV",
|
||||
]
|
||||
|
||||
if config.neutrino_mass_MeV > 0:
|
||||
|
||||
Reference in New Issue
Block a user