Source code for att.cli.main

"""ATT command-line interface."""

import argparse
import sys


[docs] def main(): """Entry point for the `att` CLI.""" parser = argparse.ArgumentParser( prog="att", description="Attractor Topology Toolkit — topological analysis of dynamical attractors", ) subparsers = parser.add_subparsers(dest="command") # att benchmark run bench_parser = subparsers.add_parser("benchmark", help="Benchmark coupling methods") bench_sub = bench_parser.add_subparsers(dest="bench_command") run_parser = bench_sub.add_parser("run", help="Run a coupling benchmark sweep") run_parser.add_argument("--config", required=True, help="YAML config file") run_parser.add_argument("--output", required=True, help="Output CSV file") run_parser.add_argument("--plot", default=None, help="Output plot PNG file") args = parser.parse_args() if args.command == "benchmark" and getattr(args, "bench_command", None) == "run": return _benchmark_run(args) parser.print_help() return 0
def _benchmark_run(args): """Execute a benchmark sweep from YAML config.""" from pathlib import Path import numpy as np from att.config import load_config, set_seed from att.benchmarks import CouplingBenchmark from att.synthetic import generators config = load_config(args.config) seed = config.get("seed", 42) set_seed(seed) # Resolve system generator system_name = config.get("system", "coupled_lorenz") system_fn = getattr(generators, system_name, None) if system_fn is None: print(f"Error: unknown system '{system_name}'", file=sys.stderr) return 1 n_steps = config.get("n_steps", 10000) dt = config.get("dt", 0.01) def generator_fn(coupling, seed): return system_fn(n_steps=n_steps, dt=dt, coupling=coupling, seed=seed) coupling_values = config.get("coupling_values", list(np.linspace(0, 1, 11))) methods = config.get("methods", None) normalization = config.get("normalization", "rank") transient_discard = config.get("transient_discard", 1000) bench = CouplingBenchmark(methods=methods, normalization=normalization) df = bench.sweep( generator_fn=generator_fn, coupling_values=coupling_values, seed=seed, transient_discard=transient_discard, ) # Save CSV Path(args.output).parent.mkdir(parents=True, exist_ok=True) df.to_csv(args.output, index=False) print(f"Results saved to {args.output}") # Optional plot if args.plot: import matplotlib matplotlib.use("Agg") from att.viz import plot_benchmark_sweep fig = plot_benchmark_sweep(df) Path(args.plot).parent.mkdir(parents=True, exist_ok=True) fig.savefig(args.plot, dpi=150, bbox_inches="tight") print(f"Plot saved to {args.plot}") return 0 if __name__ == "__main__": sys.exit(main())