Source code for specsrbench.cli

"""``specsrbench`` -- one entry point for every product in this repository.

    specsrbench figures all              # the six paper figures, from the cache
    specsrbench figures 4                # just one
    specsrbench build all                # the cache, from JADES DR4 + the Hub
    specsrbench paths                    # where everything is being looked for

The figure commands need only the committed cache; the build commands need the
raw JADES tree and, for the ML arm, the checkpoints on the Hugging Face Hub.
``specsrbench build`` prints what it is missing rather than guessing.
"""
from __future__ import annotations

import argparse
import sys
from pathlib import Path

from . import __version__, paths


def _add_figures(sub):
    p = sub.add_parser("figures", help="Build paper figures from the cache.")
    p.add_argument("which", nargs="+",
                   help="'all', a figure number (1-6), or a name "
                        "(toy, qualitative, residuals, mae, per-line-snr, redshift)")
    p.add_argument("--outdir", type=Path, default=None,
                   help="where to write the PDFs (default: figures/)")
    p.add_argument("--cache", type=Path, default=None,
                   help="cache directory to read (default: cache_logR_tuned/)")


def _add_build(sub):
    p = sub.add_parser("build", help="Rebuild the cache the figures read.")
    p.add_argument("stage", nargs="+", help="'all' or one of: "
                   + ", ".join(BUILD_STAGES))
    p.add_argument("--jades-root", type=Path, default=None,
                   help="raw JADES DR4 tree, needed by the 'lsf' stage")
    p.add_argument("--dataset", type=Path, default=None,
                   help="paired dataset built by `specsr build` (predictions stage)")
    p.add_argument("--nproc", type=int, default=None,
                   help="worker processes; this box is shared, so leave headroom")
    p.add_argument("--dry-run", action="store_true",
                   help="print the stages and their inputs, run nothing")


#: Ordered.  Each stage consumes what the one before it wrote.
BUILD_STAGES = ("predictions", "sets", "lsf", "tune", "classical", "lines")


[docs] def main(argv: list[str] | None = None) -> int: ap = argparse.ArgumentParser( prog="specsrbench", description="Benchmarking deep learning against classical deconvolution " "for galaxy spectral super-resolution.") ap.add_argument("--version", action="version", version=f"specsrbench {__version__}") sub = ap.add_subparsers(dest="command", metavar="<command>") _add_figures(sub) _add_build(sub) sub.add_parser("paths", help="Print the directories that will be used.") args = ap.parse_args(argv) if args.command is None: ap.print_help() return 2 if args.command == "paths": print(paths.describe()) return 0 if args.command == "figures": from . import figures names = list(figures.REGISTRY) if "all" in args.which else args.which cache = None if args.cache is not None: from .data import load_cache cache = load_cache(args.cache) written = [] for name in names: written.append(figures.build(name, cache=cache, outdir=args.outdir)) print(f"\n{len(written)} figure(s) written:") for w in written: print(f" {w}") return 0 if args.command == "build": from .build import run_stage stages = list(BUILD_STAGES) if "all" in args.stage else args.stage unknown = [s for s in stages if s not in BUILD_STAGES] if unknown: print(f"unknown stage(s): {', '.join(unknown)}\n" f"choose from: {', '.join(BUILD_STAGES)}", file=sys.stderr) return 2 for stage in stages: run_stage(stage, args) return 0 ap.print_help() return 2
if __name__ == "__main__": # pragma: no cover raise SystemExit(main())