"""Single-point electromagnetic simulation verification script. Loads the MARS SSSR baseline model, runs one magnetic calculation with the model's default operating point, and extracts Phase 1 core metrics: average torque, torque ripple (%), system efficiency, total losses. Usage: python scripts/run_single.py python scripts/run_single.py --model models/MARS-12S10P_SSSR_D76-C150_V5.0-0819.mot python scripts/run_single.py --quit (close Motor-CAD after run) All source is ASCII. """ from __future__ import annotations import argparse import json import os import sys import time from datetime import datetime from pathlib import Path # Add project root to sys.path so we can import src.solver_core. PROJECT_ROOT = Path(__file__).resolve().parent.parent sys.path.insert(0, str(PROJECT_ROOT)) from src.solver_core import ( # noqa: E402 MotorCADSolver, METRIC_LABELS, REQUIRED_METRICS, ) DEFAULT_MODEL = PROJECT_ROOT / "models" / "MARS-12S10P_SSSR_D76-C150_V5.0-0819.mot" DEFAULT_OUTPUT = PROJECT_ROOT / "output" def _log(text: str) -> None: stamp = datetime.now().strftime("%H:%M:%S") print(f"[{stamp}] {text}", flush=True) def main() -> int: parser = argparse.ArgumentParser(description="Single-point Motor-CAD simulation") parser.add_argument("--model", type=str, default=str(DEFAULT_MODEL), help="Path to .mot model file") parser.add_argument("--output-dir", type=str, default=str(DEFAULT_OUTPUT), help="Directory for raw export and result JSON") parser.add_argument("--quit", action="store_true", help="Close Motor-CAD after simulation (default: keep open)") args = parser.parse_args() model_path = Path(args.model) if not model_path.exists(): print(f"ERROR: Model file not found: {model_path}") return 1 output_dir = Path(args.output_dir) output_dir.mkdir(parents=True, exist_ok=True) _log("=" * 60) _log("PCB Axial Flux Motor - Single Point Simulation") _log("=" * 60) _log(f"Model: {model_path.name}") _log(f"Output: {output_dir}") _log("") solver = MotorCADSolver(log_cb=_log) result = {} try: solver.connect() _log("") _log("Running single-point simulation (model default operating point)...") _log("") result = solver.run_single( model_path=model_path, params=None, # use model default operating point output_dir=output_dir, tag="single", ) _log("") _log("=" * 60) _log("RESULTS") _log("=" * 60) _log(f"Status: {result['status']}") _log(f"Solve time: {result['solve_time_s']}s") if result.get("error"): _log(f"Error: {result['error']}") _log("") metrics = result.get("metrics", {}) # Print Phase 1 required metrics first. _log("--- Phase 1 Core Metrics ---") for key in REQUIRED_METRICS: label = METRIC_LABELS.get(key, key) value = metrics.get(key, "N/A") if isinstance(value, float): _log(f" {label}: {value:.4f}") else: _log(f" {label}: {value}") _log("") # Print all other extracted metrics. other = {k: v for k, v in metrics.items() if k not in REQUIRED_METRICS} if other: _log("--- Additional Metrics ---") for key, value in other.items(): label = METRIC_LABELS.get(key, key) if isinstance(value, float): _log(f" {label}: {value:.4f}") else: _log(f" {label}: {value}") _log("") # Save result JSON. ts = datetime.now().strftime("%Y%m%d_%H%M%S") result_path = output_dir / f"single_result_{ts}.json" with open(result_path, "w", encoding="utf-8") as f: json.dump(result, f, indent=2, ensure_ascii=False) _log(f"Result saved: {result_path}") if result["status"] == "OK": _log("") _log("SUCCESS: All Phase 1 required metrics extracted.") elif result["status"] == "UNCERTAIN": _log("") _log("WARNING: Some required metrics missing - check raw export.") else: _log("") _log("FAILED: Simulation or extraction failed.") except KeyboardInterrupt: _log("Interrupted by user.") except Exception as exc: _log(f"FATAL: {type(exc).__name__}: {exc}") import traceback _log(traceback.format_exc()) return 1 finally: if args.quit: solver.disconnect() else: _log("") _log("Motor-CAD kept open for manual inspection.") _log("Use --quit flag to auto-close.") _log("") _log("Done.") return 0 if result.get("status") in ("OK", "UNCERTAIN") else 1 if __name__ == "__main__": sys.exit(main())