refactor: refine CLI options and enhance debug logging
- Remove --mode, --transition-type, and --decay-index CLI flags
(parameters now come from ENSDF data or custom JSON input)
- Clarify energy units in all CLI help text (MeV throughout, keV for detector params)
- Enhance logging verbosity:
- -v (INFO): shows source, component initialization, workflow steps
- -vv (DEBUG): shows detailed internals of all spectrum components
(parameters, evaluation counts, input/output ranges)
- Improve CSV headers with element notation (e.g. Tc99 -> Ru99)
- Add CONVENTIONS.md documenting energy unit and logging conventions
- Update TODO.md with completion status
This commit is contained in:
+35
-52
@@ -9,13 +9,13 @@ Usage examples:
|
||||
bs_pnpi --input custom_input.json --output spectrum.csv
|
||||
|
||||
# Full analysis with plotting
|
||||
bs_pnpi --nuclide Co60 --mode BM --plot analysis.png --output spectrum.csv
|
||||
bs_pnpi --nuclide Co60 --plot analysis.png --output spectrum.csv
|
||||
|
||||
# With detector response
|
||||
bs_pnpi --nuclide Tc99 --detector sigma=1.0 --output convolved.csv
|
||||
bs_pnpi --nuclide Tc99 --detector gaussian --output convolved.csv
|
||||
|
||||
# Verbose with log file
|
||||
bs_pnpi --nuclide Tc99 --output spectrum.csv -vv --log-file calc.log
|
||||
bs_pnpi --nuclide Tc99 --output spectrum.csv -vv --log-file /tmp/calc.log
|
||||
|
||||
# Dry run to inspect resolved configuration
|
||||
bs_pnpi --nuclide Tc99 --dry-run
|
||||
@@ -42,8 +42,8 @@ def _build_parser() -> argparse.ArgumentParser:
|
||||
" bs_pnpi --nuclide Tc99 --output spectrum.csv\n"
|
||||
" bs_pnpi --input custom_input.json --output spectrum.csv\n"
|
||||
" bs_pnpi --nuclide Tc99 --plot spectrum.png --output spectrum.csv\n"
|
||||
" bs_pnpi --nuclide Tc99 --detector sigma=1.0 --output convolved.csv\n"
|
||||
" bs_pnpi --nuclide Tc99 --output spectrum.csv -vv --log-file calc.log\n"
|
||||
" bs_pnpi --nuclide Tc99 --detector gaussian --output convolved.csv\n"
|
||||
" bs_pnpi --nuclide Tc99 --output spectrum.csv -vv --log-file /tmp/calc.log\n"
|
||||
" bs_pnpi --nuclide Tc99 --dry-run\n"
|
||||
),
|
||||
)
|
||||
@@ -71,31 +71,11 @@ def _build_parser() -> argparse.ArgumentParser:
|
||||
)
|
||||
|
||||
# Common parameters
|
||||
parser.add_argument(
|
||||
"--mode",
|
||||
type=str,
|
||||
default="beta_minus",
|
||||
choices=["beta_minus", "beta_plus", "ec"],
|
||||
help="Decay mode for paceENSDF source (default: beta_minus).",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--decay-index",
|
||||
type=int,
|
||||
default=None,
|
||||
help="Decay index for paceENSDF (0 = ground state, default: auto-select).",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--transition-type",
|
||||
type=str,
|
||||
default=None,
|
||||
choices=["A", "F1", "F1U", "F2", "F2U", "F3", "F3U", "F4"],
|
||||
help="Override transition type (forbiddenness classification).",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--e-step",
|
||||
type=float,
|
||||
default=0.001,
|
||||
help="Energy step size in MeV (default: 0.001).",
|
||||
help="Energy step size in MeV (default: 0.001). All energies are in MeV throughout the toolkit.",
|
||||
)
|
||||
|
||||
# Output
|
||||
@@ -122,28 +102,29 @@ def _build_parser() -> argparse.ArgumentParser:
|
||||
default=None,
|
||||
metavar="MODEL",
|
||||
help="Enable detector response convolution. "
|
||||
"Specify model: 'gaussian', 'gaussian_tail', 'tikhonov', 'tabulated'.",
|
||||
"Specify model: 'gaussian', 'gaussian_tail', 'tikhonov', 'tabulated'. "
|
||||
"All detector parameters are in keV.",
|
||||
)
|
||||
detector_group.add_argument(
|
||||
"--sigma",
|
||||
type=float,
|
||||
default=1.0,
|
||||
metavar="KEV",
|
||||
help="Resolution parameter sigma in keV (default: 1.0).",
|
||||
help="Resolution parameter sigma in keV (default: 1.0). Energy-dependent part: sigma(E) = sigma_a + sigma_b * sqrt(E).",
|
||||
)
|
||||
detector_group.add_argument(
|
||||
"--tau",
|
||||
type=float,
|
||||
default=5.0,
|
||||
metavar="KEV",
|
||||
help="Tail decay constant tau in keV (default: 5.0).",
|
||||
help="Low-energy tail decay constant tau in keV (default: 5.0). Only used with 'gaussian_tail' model.",
|
||||
)
|
||||
detector_group.add_argument(
|
||||
"--tail-fraction",
|
||||
type=float,
|
||||
default=0.0,
|
||||
metavar="FRAC",
|
||||
help="Low-energy tail fraction (0.0–1.0, default: 0.0).",
|
||||
help="Low-energy tail fraction (0.0–1.0, default: 0.0). Only used with 'gaussian_tail' model.",
|
||||
)
|
||||
|
||||
# Logging and output control
|
||||
@@ -153,7 +134,8 @@ def _build_parser() -> argparse.ArgumentParser:
|
||||
"--verbose",
|
||||
action="count",
|
||||
default=0,
|
||||
help="Increase verbosity: -v=INFO, -vv=DEBUG (repeatable).",
|
||||
help="Increase verbosity: -v=INFO (shows source, components, and workflow), "
|
||||
"-vv=DEBUG (detailed internals of all spectrum components). Repeatable.",
|
||||
)
|
||||
log_group.add_argument(
|
||||
"-q",
|
||||
@@ -164,8 +146,9 @@ def _build_parser() -> argparse.ArgumentParser:
|
||||
log_group.add_argument(
|
||||
"--log-file",
|
||||
type=str,
|
||||
metavar="FILE",
|
||||
help="Append log messages to the specified file.",
|
||||
metavar="PATH",
|
||||
help="Write log messages to the specified file path (absolute or relative). "
|
||||
"Log file is always opened in append mode at DEBUG level.",
|
||||
)
|
||||
log_group.add_argument(
|
||||
"--dry-run",
|
||||
@@ -228,12 +211,10 @@ def _run(args: argparse.Namespace) -> None:
|
||||
|
||||
source_type: str
|
||||
if args.nuclide:
|
||||
logger.info("Source: paceENSDF nuclide=%s mode=%s", args.nuclide, args.mode)
|
||||
logger.info("Source: paceENSDF nuclide=%s", args.nuclide)
|
||||
config = create_config_from_source(
|
||||
"paceENSDF",
|
||||
nuclide=args.nuclide,
|
||||
decay_type=args.mode,
|
||||
decay_index=args.decay_index,
|
||||
e_step_MeV=args.e_step,
|
||||
use_detector_response=detector_kwargs.get("use_detector_response", False),
|
||||
detector_model=detector_kwargs.get("detector_model", "gaussian"),
|
||||
@@ -245,19 +226,12 @@ def _run(args: argparse.Namespace) -> None:
|
||||
elif args.input:
|
||||
logger.info("Source: JSON file=%s", args.input)
|
||||
data = load_json_input(args.input)
|
||||
if args.transition_type:
|
||||
data["transition_type"] = args.transition_type
|
||||
config = json_to_config(data)
|
||||
source_type = "json"
|
||||
else:
|
||||
logger.error("No source specified (use --nuclide or --input)")
|
||||
sys.exit(1)
|
||||
|
||||
# Override transition type if explicitly provided
|
||||
if args.transition_type:
|
||||
config.transition_type = args.transition_type
|
||||
logger.info("Override transition_type=%s", args.transition_type)
|
||||
|
||||
# Dry run: display resolved config and exit
|
||||
if args.dry_run:
|
||||
_print_dry_run_output(config, source_type)
|
||||
@@ -266,15 +240,12 @@ def _run(args: argparse.Namespace) -> None:
|
||||
# Create and calculate spectrum
|
||||
start_time = time.time()
|
||||
logger.info(
|
||||
"Creating BetaSpectrum for %s -> Z=%d,%d, A=%d, endpoint=%.3f MeV",
|
||||
_element_symbol(config.Z_parent),
|
||||
config.Z_parent,
|
||||
config.Z_daughter,
|
||||
config.A_number,
|
||||
"Creating BetaSpectrum for %s, endpoint=%.3f MeV",
|
||||
_decay_notation(config.Z_parent, config.Z_daughter, config.A_number),
|
||||
config.endpoint_MeV,
|
||||
)
|
||||
|
||||
spectrum = BetaSpectrum.from_config(config)
|
||||
spectrum = BetaSpectrum.from_config(config, logger=logger)
|
||||
_W, _kinetic_MeV = spectrum.get_energy_grid(config)
|
||||
_ = spectrum(_W)
|
||||
|
||||
@@ -285,13 +256,13 @@ def _run(args: argparse.Namespace) -> None:
|
||||
|
||||
# Export to CSV
|
||||
if args.output:
|
||||
analyzer = BetaSpectrumAnalyzer(spectrum, config)
|
||||
analyzer = BetaSpectrumAnalyzer(spectrum, config, logger=logger)
|
||||
analyzer.export_to_csv(args.output, source_type=source_type)
|
||||
logger.info("Spectrum exported to %s", args.output)
|
||||
|
||||
# Generate plot
|
||||
if args.plot:
|
||||
analyzer = BetaSpectrumAnalyzer(spectrum, config)
|
||||
analyzer = BetaSpectrumAnalyzer(spectrum, config, logger=logger)
|
||||
analyzer.plot_analysis(save_path=args.plot)
|
||||
logger.info("Analysis plot saved to %s", args.plot)
|
||||
|
||||
@@ -322,7 +293,9 @@ def _print_dry_run_output(config, source_type: str) -> None:
|
||||
print(f"Package: beta-spectrum v{__import__('beta_spectrum').__version__}")
|
||||
print(f"Git commit: {get_git_short_hash()}")
|
||||
print(f"Source: {source_type}")
|
||||
print(f"Nuclide: {config.Z_parent} -> {config.Z_daughter}, A={config.A_number}")
|
||||
print(
|
||||
f"Nuclide: {_decay_notation(config.Z_parent, config.Z_daughter, config.A_number)}"
|
||||
)
|
||||
print(f"Endpoint: {config.endpoint_MeV * 1000:.1f} keV")
|
||||
print(f"Transition: {config.transition_type}")
|
||||
print(f"e_step: {config.e_step_MeV:.4f} MeV")
|
||||
@@ -445,6 +418,16 @@ def _element_symbol(Z: int) -> str:
|
||||
return symbols[Z] if Z < len(symbols) else f"Z{Z}"
|
||||
|
||||
|
||||
def _nuclide_symbol(Z: int, A: int) -> str:
|
||||
"""Get nuclide notation like 'Tc99' from atomic and mass numbers."""
|
||||
return f"{_element_symbol(Z)}{A}"
|
||||
|
||||
|
||||
def _decay_notation(Z_parent: int, Z_daughter: int, A: int) -> str:
|
||||
"""Get decay notation like 'Tc99 -> Ru99' from atomic and mass numbers."""
|
||||
return f"{_nuclide_symbol(Z_parent, A)} -> {_nuclide_symbol(Z_daughter, A)}"
|
||||
|
||||
|
||||
def main() -> None:
|
||||
"""Main entry point for the CLI."""
|
||||
parser = _build_parser()
|
||||
|
||||
Reference in New Issue
Block a user