Source code for simulator.app

from __future__ import annotations
from pathlib import Path
from . import apis

try:
    from pyfiglet import Figlet
except Exception:  # pragma: no cover
    Figlet = None  # type: ignore[assignment]


[docs] class ICESimulatorApp: """Simple text-based front-end for the ICE simulator. This is deliberately console-first so it's easy to wrap with richer UIs later (PySide6, Tk, web, etc.). """ def __init__(self, root: Path | None = None) -> None: self.root = root or Path(__file__).resolve().parent self.in_dir = self.root / "in" self.out_dir = self.root / "out" # ------------------------------------------------------------------ # UI helpers # ------------------------------------------------------------------ def _print_banner(self) -> None: title = "vICE" if Figlet is not None: fig = Figlet(font="slant") print(fig.renderText(title)) else: print(title) print("-" * len(title)) def _print_menu(self) -> None: print("=" * 70) print("[MAIN MENU] Select an action:") print(" 1) List example input cases") print(" 2) Run simulation from JSON input") print(" 3) Plot indicator diagram (P-V) from result") print(" 4) Quit") print("=" * 70) # ------------------------------------------------------------------ # Main loop # ------------------------------------------------------------------
[docs] def run_main_menu(self) -> None: self._print_banner() while True: self._print_menu() choice = input("Enter option [1-4]: ").strip() if choice == "1": self._menu_list_inputs() elif choice == "2": self._menu_run_simulation() elif choice == "3": self._menu_plot_indicator() elif choice == "4": print("[OK] Exiting vICE. Bye.") return else: print("[WARN] Invalid choice, please select 1-4.")
# ------------------------------------------------------------------ # Menu actions # ------------------------------------------------------------------ def _menu_list_inputs(self) -> None: res = apis.run(apis.RunRequest(verb="list-inputs")) if not res.ok: print(f"[ERROR] Could not list inputs: {res.reason}") return inputs = res.data.get("inputs", []) if not inputs: print(f"[INFO] No JSON input files found in '{self.in_dir}'.") return print("\n[INFO] Available input cases:") for i, path in enumerate(inputs, start=1): print(f" {i:2d}) {path}") print(f"[OK] Listed {len(inputs)} case(s).") def _menu_run_simulation(self) -> None: default_in = self.in_dir / "sample_si_engine.json" path = input(f"Path to JSON input file [default: {default_in}]: ").strip() if not path: path = str(default_in) default_out = self.out_dir / f"{Path(path).stem}_out.json" outfile = input(f"Path to output JSON [default: {default_out}]: ").strip() if not outfile: outfile = str(default_out) req = apis.RunRequest(verb="run-sim", infile=path, outfile=outfile) res = apis.run(req) if not res.ok: print(f"[ERROR] Simulation failed: {res.reason}") return print("[OK] Simulation complete.") print(f" Input : {path}") print(f" Output: {outfile}") summary = res.data.get("summary", {}) if summary: print(" Summary:") for k, v in summary.items(): print(f" - {k}: {v}") def _menu_plot_indicator(self) -> None: result_path = input("Path to result JSON: ").strip() if not result_path: print("[WARN] Result JSON path is required.") return out_html = input("Path to HTML plot [default: next to JSON]: ").strip() params = {"result_path": result_path} if out_html: params["out_html"] = out_html res = apis.run(apis.RunRequest(verb="plot-indicator", params=params)) if not res.ok: print(f"[ERROR] Plotting failed: {res.reason}") return print(f"[OK] Indicator diagram written to: {res.data.get('html')}")
[docs] def run() -> None: ICESimulatorApp().run_main_menu()