Source code for syssimx.cli

"""Command-line interface for SysSimX.

Provides the ``syssimx`` console script::

    syssimx run system.yaml                    # run with the file's run settings
    syssimx run system.yaml --tf 10 --dt 0.01  # override run settings
    syssimx run system.yaml -o results.csv     # export results (long format)
    syssimx describe system.yaml               # print the structural report
"""

from __future__ import annotations

import argparse
import os
import sys

from .system.loader import ConfigError, build_system, load_config, run_from_config


[docs] def _add_run_overrides(parser: argparse.ArgumentParser) -> None: parser.add_argument("config", help="Path to a YAML/JSON system description") parser.add_argument("--t0", type=float, default=None, help="Override start time [s]") parser.add_argument("--tf", type=float, default=None, help="Override end time [s]") parser.add_argument("--dt", type=float, default=None, help="Override macro step size [s]")
[docs] def main(argv: list[str] | None = None) -> int: """Entry point for the ``syssimx`` console script.""" parser = argparse.ArgumentParser( prog="syssimx", description="Run and inspect SysSimX co-simulation systems from declarative descriptions.", ) subparsers = parser.add_subparsers(dest="command", required=True) run_parser = subparsers.add_parser("run", help="Assemble, initialize, and run a system") _add_run_overrides(run_parser) run_parser.add_argument( "-o", "--output", default=None, help="Write results to this CSV file (tidy long format)", ) run_parser.add_argument( "--quiet", action="store_true", help="Suppress the progress line" ) describe_parser = subparsers.add_parser( "describe", help="Print the structural report of a system description" ) describe_parser.add_argument("config", help="Path to a YAML/JSON system description") describe_parser.add_argument( "--initialize", action="store_true", help="Initialize the system first so the execution order is included", ) args = parser.parse_args(argv) # Make component modules that live relative to the invocation directory # (or next to the description file) importable by their module path. for extra in (os.getcwd(), str(os.path.dirname(os.path.abspath(args.config)))): if extra not in sys.path: sys.path.insert(0, extra) try: if args.command == "run": return _cmd_run(args) if args.command == "describe": return _cmd_describe(args) except ConfigError as exc: print(f"error: {exc}", file=sys.stderr) return 2 return 0
[docs] def _cmd_run(args: argparse.Namespace) -> int: progress = None if not args.quiet: def progress(t: float, tf: float) -> None: print(f"\r t = {t:.6g} / {tf:.6g} s", end="", file=sys.stderr) result = run_from_config( args.config, t0=args.t0, tf=args.tf, dt=args.dt, progress=progress ) if not args.quiet: print(file=sys.stderr) print( f"Completed '{result.system_name}': t in [{result.t0}, {result.tf}] s, " f"dt = {result.dt} s, algorithm = {result.algorithm}, " f"wall time = {result.wall_time:.3f} s" ) if args.output: path = result.to_csv(args.output) print(f"Results written to {path}") return 0
[docs] def _cmd_describe(args: argparse.Namespace) -> int: config = load_config(args.config) system = build_system(config) if args.initialize: run_cfg = config.get("run", {}) or {} system.initialize(t0=float(run_cfg.get("t0", 0.0))) print(system.describe()) return 0
if __name__ == "__main__": raise SystemExit(main())