| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159 |
- """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())
|