fix(output): apply positive-integral export guard to to_one mode

CSVEmitter.export_to_csv raised ValueError only in intensity mode;
degenerate exports with --normalize-to-one silently wrote all-zero
CSV files. The guard now runs before the mode split and no file is
written in either mode.
This commit is contained in:
2026-10-01 23:02:33 +03:00
parent ee7aedc80a
commit 62bf7fdac2
2 changed files with 28 additions and 13 deletions
+11 -11
View File
@@ -19,7 +19,7 @@ Column semantics (v0.4.0 onward):
from __future__ import annotations
from datetime import datetime, timezone
from typing import TYPE_CHECKING, Dict, Optional
from typing import TYPE_CHECKING, Dict
import numpy as np
import pandas as pd
@@ -179,16 +179,17 @@ class CSVEmitter:
"energy_MeV": analyzer.energies_MeV,
}
integral: Optional[float] = None
# Positive-integral guard applies to BOTH normalization modes: a
# degenerate spectrum must never be written (not even as zeros).
total_raw = analyzer.spectrum(analyzer.W)
integral = float(np.trapezoid(total_raw, analyzer.energies_MeV))
if integral <= 0.0:
raise ValueError(
"Total spectrum integral is non-positive: every branch "
"is degenerate (check neutrino_mass vs branch endpoints "
"and intensity_cutoff)"
)
if not to_one:
total_raw = analyzer.spectrum(analyzer.W)
integral = float(np.trapezoid(total_raw, analyzer.energies_MeV))
if integral <= 0.0:
raise ValueError(
"Total spectrum integral is non-positive: every branch "
"is degenerate (check neutrino_mass vs branch endpoints "
"and intensity_cutoff)"
)
data["total_spectrum"] = total_raw / integral
for i in range(n_branches):
@@ -205,7 +206,6 @@ class CSVEmitter:
else:
data[col_name] = np.zeros_like(physical[i])
else:
assert integral is not None
intensity_i = analyzer._unified_branches[i].intensity
data[col_name] = physical[i] * intensity_i / integral