""" run_track1.py Local Track 1 runner entrypoint for renunney. """ from __future__ import annotations import argparse from pathlib import Path import sys REPO_ROOT = Path(__file__).resolve().parents[1] SRC_DIR = REPO_ROOT / "src" if str(SRC_DIR) not in sys.path: sys.path.insert(0, str(SRC_DIR)) from renunney.track1_api import Track1RunConfig, load_config, run_config, save_payload def build_parser() -> argparse.ArgumentParser: parser = argparse.ArgumentParser(description="Run Track 1 cost-of-substitution experiments.") parser.add_argument("--mode", choices=["simulate", "report", "threshold", "search", "loci_regression", "extinction_dataset", "extinction_fit"], default="simulate") parser.add_argument("--config", type=str, default=None) parser.add_argument("--K", type=int, default=5000) parser.add_argument("--N0", type=int, default=500) parser.add_argument("--n", type=int, default=1) parser.add_argument("--u", type=float, default=5.0e-6) parser.add_argument("--M", type=float, default=None) parser.add_argument("--R", type=float, default=10.0) parser.add_argument("--T", type=int, default=300) parser.add_argument("--epochs", type=int, default=8) parser.add_argument("--p", type=float, default=0.5) parser.add_argument("--a-max", dest="a_max", type=int, default=None) parser.add_argument("--seed", type=int, default=0) parser.add_argument("--runs", type=int, default=20) parser.add_argument("--t-start", type=int, default=50) parser.add_argument("--t-stop", type=int, default=500) parser.add_argument("--t-step", type=int, default=10) parser.add_argument("--t-values", type=str, default=None) parser.add_argument("--loci-values", type=str, default=None) parser.add_argument("--cache-path", type=str, default=None) parser.add_argument("--jobs", type=int, default=1) parser.add_argument("--report-dir", type=str, default=None) parser.add_argument("--dataset-dir", type=str, default=None) parser.add_argument("--run-rows-path", type=str, default=None) parser.add_argument("--output", type=str, default=None) return parser def config_from_args(args: argparse.Namespace) -> Track1RunConfig: loci_values = None if args.loci_values: loci_values = [int(part.strip()) for part in args.loci_values.split(",") if part.strip()] t_values = None if args.t_values: t_values = [float(part.strip()) for part in args.t_values.split(",") if part.strip()] return Track1RunConfig( mode=args.mode, K=args.K, N0=args.N0, n=args.n, u=args.u if args.M is None else None, M=args.M, R=args.R, T=args.T, epochs=args.epochs, p=args.p, a_max=args.a_max, seed=args.seed, runs=args.runs, t_start=args.t_start, t_stop=args.t_stop, t_step=args.t_step, t_values=t_values, loci_values=loci_values, cache_path=args.cache_path, jobs=args.jobs, report_dir=args.report_dir, dataset_dir=args.dataset_dir, run_rows_path=args.run_rows_path, ) def main() -> int: parser = build_parser() args = parser.parse_args() if args.config: config = load_config(args.config) else: config = config_from_args(args) payload = run_config(config) import json rendered = json.dumps(payload, indent=2, sort_keys=True) if args.output: save_payload(payload, Path(args.output)) print(rendered) return 0 if __name__ == "__main__": raise SystemExit(main())