feat(cli): separate-branches rename, short aliases, clean dry-run

- --normalize-to-one renamed to --separate-branches (no alias; the
  name now describes the output choice: total spectrum with
  intensity-normalized branches vs separate branches, each
  normalized to unit area with intensities left to the data user).
  SpectrumConfig.normalize_to_one -> separate_branches, CSV header
  word to_one -> separate.
- every long option gains a single-letter alias: -N -i -s -m -o -p
  -L -d -c -V -S -b (only -v/-q existed before)
- dry-run drops the top-level Transition: line — the per-branch
  list below already reports each branch's transition type
- version bumped to 0.4.1 (pyproject, __version__, CSV semantics
  docstring, TODO roadmap entry)
This commit is contained in:
2026-10-03 01:08:51 +03:00
parent 7f47a876ae
commit 2788ea0683
12 changed files with 210 additions and 53 deletions
+7 -7
View File
@@ -1,7 +1,7 @@
"""
CSV export module — CSV export functionality for BetaSpectrumAnalyzer.
Column semantics (v0.4.0 onward):
Column semantics (v0.4.1 onward):
- The basic spectrum is ALWAYS core = phase_space x fermi; the Fermi function
is a core spectrum component, never an optional correction. Higher-order
corrections (finite size, charge distribution, screening, exchange,
@@ -12,7 +12,7 @@ Column semantics (v0.4.0 onward):
(the total column itself is normalized to integrate to 1). In the legacy
export branch columns contained only the per-branch phase-space x
radiative product WITHOUT the Fermi function — physically wrong.
- ``normalize_to_one`` mode: each branch column is normalized to
- ``separate_branches`` mode: each branch column is normalized to
integrate to 1 individually, intensity is ignored, no total column.
"""
@@ -62,7 +62,7 @@ class CSVEmitter:
"""
components = analyzer.components
config = analyzer.config
to_one = config.normalize_to_one
separate = config.separate_branches
n_branches = analyzer._n_branches
# Physical branch spectra: core(phase_space x fermi) x corrections.
@@ -127,9 +127,9 @@ class CSVEmitter:
header_lines.append(f"# e_step: {config.e_step_MeV:.4f} MeV")
header_lines.append(f"# n_points: {len(analyzer.energies_MeV)}")
if to_one:
if separate:
header_lines.append(
"# branch normalization: to_one "
"# branch normalization: separate "
"(each branch integrates to 1, intensity ignored)"
)
else:
@@ -189,7 +189,7 @@ class CSVEmitter:
"is degenerate (check neutrino_mass vs branch endpoints "
"and intensity_cutoff)"
)
if not to_one:
if not separate:
data["total_spectrum"] = total_raw / integral
for i in range(n_branches):
@@ -199,7 +199,7 @@ class CSVEmitter:
else:
col_name = f"branch_{key_i}_spectrum"
if to_one:
if separate:
area = float(np.trapezoid(physical[i], analyzer.energies_MeV))
if area > 0.0:
data[col_name] = physical[i] / area