forked from ats-fukuyama/task
-
Notifications
You must be signed in to change notification settings - Fork 1
feat(trlib): plot API + TOML config runner (reference) #83
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
k-yoshimi
wants to merge
15
commits into
develop
Choose a base branch
from
feature/trlib-plot-toml-runner
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
8196b4d
feat(trlib): add plot API + Trlib.plot() / plot_available() methods
k-yoshimi 1154271
feat(trlib): add TOML config loader + python -m trlib runner
k-yoshimi e1e9d36
feat(trlib): add iter01 / tst2 TOML sample configs
k-yoshimi e1f584c
test(trlib): cover plot API, TOML loader, and python -m trlib
k-yoshimi 6ed01c6
docs(trlib): document TOML runner + plot API in README
k-yoshimi 30d287c
fix(trlib-plot): rename plot_sweep arg to sweep_range; keep range alias
k-yoshimi cff02dc
fix(trlib): isolate sweep plots from outer Trlib lifecycle (+ int(n) …
k-yoshimi 60882d4
fix(trlib-plot): sweep re-init per sample + drop dead _PROFILE_XAXIS
k-yoshimi 3eba770
fix(trlib): kind=sweep guard + drop unused tr arg + state is None check
k-yoshimi 55fe509
fix(trlib-plot): scalar xlabel + preserve user alias in legend
k-yoshimi 71b8c65
fix(trlib): default file path uses alias; sweep forwards ntmax/base_p…
k-yoshimi 846788f
fix(trlib-plot): validate output= in plot_sweep too
k-yoshimi 2f97f46
fix(trlib-plot): reject non-scalar y in plot_sweep
k-yoshimi 6a9de89
fix(trlib): drop dead HAS_MATPLOTLIB; classify plot config errors
k-yoshimi d5442fd
fix(trlib): drop unused io / Iterable imports
k-yoshimi File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,170 @@ | ||
| """``python -m trlib <config.toml>`` — TOML-driven runner. | ||
|
|
||
| Pipeline:: | ||
|
|
||
| init → apply_config → run(ntmax) → get_state → run_plots → finalize | ||
|
|
||
| Exit codes: | ||
|
|
||
| * 0 — success | ||
| * 1 — library / calculation error | ||
| * 2 — config error (missing file, malformed TOML, unknown variable) | ||
|
|
||
| Flags: | ||
|
|
||
| * ``--dry-run`` — parse and validate the TOML, print a summary, but | ||
| skip every libtrapi.so call. Useful for CI and quick verification. | ||
| * ``--ntmax N`` — override ``[module].ntmax`` / ``[scalars].NTMAX``. | ||
| * ``--no-plots`` — apply scalars/arrays and run, but skip every plot | ||
| spec. Handy when matplotlib is not installed in the runner env. | ||
| * ``--help`` — argparse-generated usage. | ||
| """ | ||
| from __future__ import annotations | ||
|
|
||
| import argparse | ||
| import sys | ||
| from pathlib import Path | ||
| from typing import List, Optional, Sequence | ||
|
|
||
| from .loader import apply_config, load_config, run_plots, run_sweep_plots | ||
|
|
||
|
|
||
| _EXIT_OK = 0 | ||
| _EXIT_LIB = 1 | ||
| _EXIT_CONFIG = 2 | ||
|
|
||
|
|
||
| def build_parser() -> argparse.ArgumentParser: | ||
| """Return the argparse parser used by :func:`main`.""" | ||
| parser = argparse.ArgumentParser( | ||
| prog="python -m trlib", | ||
| description=( | ||
| "Run a TASK/TR simulation defined by a TOML config file and " | ||
| "optionally render plots. See python/trlib/samples/ for " | ||
| "example configurations." | ||
| ), | ||
| ) | ||
| parser.add_argument( | ||
| "config", type=Path, | ||
| help="Path to a TOML config file.", | ||
| ) | ||
| parser.add_argument( | ||
| "--dry-run", action="store_true", | ||
| help="Parse the config and print a summary; skip every library call.", | ||
| ) | ||
| parser.add_argument( | ||
| "--ntmax", type=int, default=None, | ||
| help="Override the NTMAX scalar from the config.", | ||
| ) | ||
| parser.add_argument( | ||
| "--no-plots", action="store_true", | ||
| help="Skip [plot] / [[plots]] execution even if the config defines them.", | ||
| ) | ||
| return parser | ||
|
|
||
|
|
||
| def _summarise(cfg: dict) -> str: | ||
| """Return a short human-readable summary of a parsed config.""" | ||
| lines = [] | ||
| module = cfg.get("module") or {} | ||
| lines.append(f"module: {module.get('name', '<unnamed>')}") | ||
| ntmax = cfg.get("scalars", {}).get("NTMAX") | ||
| if ntmax is not None: | ||
| lines.append(f"NTMAX: {ntmax}") | ||
| lines.append(f"scalars: {len(cfg.get('scalars', {}))} keys") | ||
| lines.append(f"arrays: {len(cfg.get('arrays', {}))} keys") | ||
| lines.append(f"strings: {len(cfg.get('strings', {}))} keys") | ||
| lines.append(f"plots: {len(cfg.get('plots', []))} specs") | ||
| return "\n".join(lines) | ||
|
|
||
|
|
||
| def main(argv: Optional[Sequence[str]] = None) -> int: | ||
| """Program entry point. Returns a process exit code.""" | ||
| parser = build_parser() | ||
| args = parser.parse_args(argv) | ||
|
|
||
| # --- Config load --------------------------------------------------- | ||
| if not args.config.exists(): | ||
| print(f"[trlib] config not found: {args.config}", file=sys.stderr) | ||
| return _EXIT_CONFIG | ||
| try: | ||
| cfg = load_config(args.config) | ||
| except Exception as exc: | ||
| print(f"[trlib] failed to parse {args.config}: {exc}", file=sys.stderr) | ||
| return _EXIT_CONFIG | ||
|
|
||
| # --- CLI overrides ------------------------------------------------- | ||
| if args.ntmax is not None: | ||
| cfg.setdefault("scalars", {})["NTMAX"] = int(args.ntmax) | ||
| if args.no_plots: | ||
| cfg["plots"] = [] | ||
|
|
||
| # --- Summary + dry run -------------------------------------------- | ||
| print(f"[trlib] loaded {args.config}") | ||
| print(_summarise(cfg)) | ||
| if args.dry_run: | ||
| print("[trlib] --dry-run: skipping library calls") | ||
| return _EXIT_OK | ||
|
|
||
| ntmax = int(cfg.get("scalars", {}).get("NTMAX", 0)) | ||
|
|
||
| # --- Live run ------------------------------------------------------ | ||
| # Lazy import: importing ``Trlib`` triggers _ffi.load_library() which | ||
| # probes libtrapi.so. Doing this only inside the live branch keeps | ||
| # --dry-run functional on systems where the .so is not built. | ||
| try: | ||
| from . import Trlib | ||
| except Exception as exc: # pragma: no cover - extremely unusual | ||
| print(f"[trlib] cannot import Trlib: {exc}", file=sys.stderr) | ||
| return _EXIT_LIB | ||
|
|
||
| try: | ||
| # State-dependent plots run inside the with-block (need live tr). | ||
| with Trlib() as tr: | ||
| apply_config(tr, cfg) | ||
| tr.run(ntmax=ntmax) | ||
| state = tr.get_state() | ||
| print( | ||
| f"[trlib] run complete: NT={state.nt} NRMAX={state.nrmax} " | ||
| f"NSMAX={state.nsmax}" | ||
| ) | ||
| if cfg.get("plots"): | ||
| try: | ||
| results = run_plots(tr, cfg) | ||
| except ImportError as exc: | ||
| print(f"[trlib] plot backend unavailable: {exc}", | ||
| file=sys.stderr) | ||
| return _EXIT_CONFIG | ||
| except (KeyError, ValueError, TypeError) as exc: | ||
| # User-config errors (unknown variable, bad output=, etc.) | ||
| print(f"[trlib] plot config error: {exc}", | ||
| file=sys.stderr) | ||
| return _EXIT_CONFIG | ||
| for name, descriptor in results: | ||
| print(f"[trlib] plot {name} -> {descriptor}") | ||
| # Sweep plots run AFTER the outer Trlib closes — each sweep | ||
| # sample needs its own tr_init/tr_run/tr_finalize cycle and | ||
| # would collide with the still-live outer instance. | ||
| if cfg.get("plots"): | ||
| try: | ||
| sweep_results = run_sweep_plots(cfg) | ||
| except ImportError as exc: | ||
| print(f"[trlib] plot backend unavailable: {exc}", | ||
| file=sys.stderr) | ||
| return _EXIT_CONFIG | ||
| except (KeyError, ValueError, TypeError) as exc: | ||
| # User-config errors in sweep spec (missing range, unknown y, etc.) | ||
| print(f"[trlib] sweep config error: {exc}", | ||
| file=sys.stderr) | ||
| return _EXIT_CONFIG | ||
| for name, descriptor in sweep_results: | ||
| print(f"[trlib] plot {name} -> {descriptor}") | ||
| except Exception as exc: | ||
| print(f"[trlib] library error: {exc}", file=sys.stderr) | ||
| return _EXIT_LIB | ||
|
|
||
| return _EXIT_OK | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| sys.exit(main()) | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.