# Agent Plan: Physics-AI Vehicle Subsystem Prototype → PhysicsNeMo Port

**Agent role:** Physics-ML prototyping engineer
**Mission:** Reproduce two standalone physics-informed models (TNN for PMSM thermal, PINN4SOH for battery SOH), validate against published baselines, then port their physics residuals into `physicsnemo.sym` and scale with the neural-operator + multi-GPU machinery.
**Mode:** Plan-first, HITL-gated. Stop at every `[GATE]` and present evidence before proceeding.
**Hardware assumptions:** Phase 0–2 run on CPU or a single laptop GPU. Phase 4–5 assume access to a multi-GPU node (adjust `torchrun --nproc_per_node` accordingly; all code must degrade gracefully to 1 GPU).

---

## Operating rules (read first, apply always)

1. Never modify vendored upstream code in `third_party/`. All changes live in `src/` as wrappers, subclasses, or configs.
2. Pin everything. Every phase ends with a frozen `requirements-<phase>.txt` or updated lockfile committed alongside results.
3. Every experiment writes to `runs/<phase>/<exp_id>/` containing: `config.yaml`, `metrics.json`, `git_sha.txt`, plots, and checkpoint. No experiment without a config file.
4. Reproduce before you improve. Do not change architecture, loss weights, or features until the published baseline is matched within tolerance.
5. Separate environments: `venv-standalone` (Phase 1–2) and `venv-nemo` (Phase 3–5). PhysicsNeMo and the legacy repos have conflicting pins; never mix them.
6. Check licenses and citation requirements of each repo before writing any derivative code; record findings in `docs/licenses.md`.
7. All figures use matplotlib defaults suitable for later inclusion in the cream-paper monograph (no seaborn styling, label everything, save PNG + data CSV).
8. When a step fails twice, stop, write `runs/<phase>/BLOCKED.md` with the failure analysis, and surface it. Do not thrash.

---

## Repository layout (create in Phase 0)

```
physics-ai-vehicle/
├── AGENT_PLAN.md                  # this file
├── docs/
│   ├── licenses.md
│   ├── decisions.md               # ADR-style log, one entry per gate
│   └── baseline_targets.md
├── third_party/                   # git submodules or pinned clones, read-only
│   ├── thermal-nn/                # github.com/wkirgsn/thermal-nn
│   ├── PINN4SOH/                  # github.com/wang-fujin/PINN4SOH
│   └── physicsnemo/               # optional source checkout for reference
├── data/
│   ├── pmsm/                      # Paderborn electric motor temperature dataset
│   └── xjtu/                      # XJTU battery dataset (per PINN4SOH README)
├── src/
│   ├── common/                    # metrics, seeding, run-dir utils, config schema
│   ├── tnn/                       # Phase 1 wrappers + Phase 3 residual extraction
│   ├── soh/                       # Phase 2 wrappers + Phase 3 residual extraction
│   └── nemo/                      # Phase 3–5 PhysicsNeMo recipes
├── configs/
├── runs/
├── tests/                         # pytest; physics residual unit tests are mandatory
└── Makefile                       # one target per milestone, e.g. `make m1.2`
```

---

## Phase 0 — Environment and scaffolding (½ day)

**M0.1 Scaffold.** Create the layout above, init git, add `Makefile`, `src/common/` with: `seed_everything()`, `RunDir` context manager, `metrics.py` (MAE, RMSE, MAPE, max-error, R²), config loader (OmegaConf/Hydra-compatible YAML).

**M0.2 Environments.**
- `venv-standalone`: Python 3.10, PyTorch (CPU or CUDA per machine), scikit-learn, pandas, matplotlib. Note: PINN4SOH's README pins ancient versions (torch 1.7); first attempt with modern pins, fall back only if the demo breaks.
- `venv-nemo`: `pip install "nvidia-physicsnemo[sym]"`. Smoke-test: import physicsnemo, run the shortest bundled example (LDC PINN or Darcy FNO) for 50 iterations.

**M0.3 Data acquisition.**
- Paderborn PMSM dataset (Kaggle: `wkirgsn/electric-motor-temperature`). Verify schema: coolant, ambient, u_d/u_q, i_d/i_q, motor_speed, torque, and target temps (pm, stator_yoke, stator_tooth, stator_winding), grouped by `profile_id`.
- XJTU battery dataset per PINN4SOH README. Verify the repo's expected directory structure.
- Write `tests/test_data_integrity.py`: row counts, no-NaN checks, profile/battery counts, checksums.

**[GATE G0]** Present: env freeze files, dataset integrity test output, license summary. Human approves data usage and pins.

---

## Phase 1 — TNN standalone reproduction (1–2 days)

**M1.1 Run upstream as-is.** Execute the thermal-nn demo notebook/script on the Paderborn data inside `venv-standalone`. Capture the published-configuration metrics (MSE / max abs error on the four target temperatures, held-out profiles).

**M1.2 Wrap, don't fork.** In `src/tnn/`, build a thin harness around the upstream TNN cell:
- deterministic profile-based train/val/test split (record profile IDs in config),
- unified metrics + plots: predicted vs. measured temperature per profile, error histograms, and **identified thermal parameters over time** (conductances, capacitances, power losses) — these are the interpretability payload.
- TBPTT training loop config: sequence length, truncation window, LR schedule as per paper.

**M1.3 Baseline record.** Write `docs/baseline_targets.md` §TNN with achieved metrics vs. paper-reported ballpark (paper reports ~1–3 K MSE-scale errors; exact target = whatever upstream demo yields on our split, that becomes the frozen reference).

**Acceptance criteria:**
- Test max abs error and MSE within 10% of the upstream demo run on the same split.
- Thermal-parameter plots produced and physically sane (non-negative conductances/capacitances).
- `make m1.2` reruns end-to-end from raw data with fixed seed and reproduces metrics to 3 decimals.

**[GATE G1]** Present metrics table, 3 representative profile plots, parameter-trajectory plot.

---

## Phase 2 — PINN4SOH standalone reproduction (1–2 days)

**M2.1 Run upstream as-is.** `main_XJTU.py` in `venv-standalone`; then `main_comparison.py` for the CNN/MLP baselines. Capture MAPE/MAE/RMSE per battery and aggregate.

**M2.2 Wrap.** In `src/soh/`:
- config-driven battery-level splits,
- reimplement the evaluation loop with `src/common/metrics.py` so TNN and SOH results are comparable in one reporting format,
- SOH-vs-cycle overlay plots per test battery; physics-loss vs. data-loss curves during training (watch loss balance — this is the classical-PINN fragility point).

**M2.3 Transfer probe (small, honest).** Repeat the paper's small-sample protocol: train on N% of batteries, evaluate degradation of MAPE as N shrinks. This is the property that matters for fleet VHM.

**Acceptance criteria:**
- Aggregate MAPE within 20% relative of the upstream demo result (paper headline across all datasets is 0.87%; XJTU-only demo defines our target).
- PINN beats the CNN and MLP baselines on the same split, as in the paper.
- Loss-balance plot shows physics loss actually contributing (not collapsed to zero weight).

**[GATE G2]** Present comparison table (PINN vs CNN vs MLP), small-sample curve, loss-balance plot. Human decides which model ports first (default: TNN, because its ODE residual is cleanest to express).

---

## Phase 3 — Residual extraction and physicsnemo.sym port (3–5 days)

Goal: express each model's governing physics symbolically and reproduce Phase 1–2 results *inside* PhysicsNeMo. Correctness gate, not performance gate.

**M3.1 Write the physics down first.** In `docs/decisions.md`, derive and record:
- **TNN residual (LPTN ODE system):** for each node i,
  `C_i · dT_i/dt − Σ_j g_ij(ξ)·(T_j − T_i) − P_i(ξ) = 0`
  where ξ is the operating point (speed, currents, voltages, coolant temp). Decide what stays learned (g, C, P as NN outputs) vs. symbolic (the conservation structure).
- **SOH residual (empirical degradation / state-space):** the degradation ODE/state-space relations from the PINN4SOH paper, plus the derivative terms it penalizes (∂SOH/∂cycle, ∂SOH/∂features).

**M3.2 Symbolic implementation.** In `src/nemo/`:
- Define the residuals via the sym module's SymPy PDE interface (custom `PDE` subclasses; the LPTN is an ODE system — treat time as the only coordinate, nodes as separate variables).
- Unit-test the residuals in `tests/test_residuals.py`: feed analytic solutions of a 2-node toy LPTN and a toy exponential-decay SOH curve; residual must vanish to <1e-6. **This test is mandatory before any training.**
- Reference recipes to imitate: the bundled LDC PINN example (workflow), and the inverse heat-sink PINN (inverse-coefficient pattern → maps to identifying thermal parameters and diffusivities).

**M3.3 Parity training.** Train the ported TNN-equivalent and SOH-equivalent in PhysicsNeMo on identical splits to Phase 1/2.

**Acceptance criteria:**
- Residual unit tests pass.
- Parity: metrics within 15% relative of Phase 1/2 standalone results on the same splits.
- One config file per model fully specifies the run (Hydra-style), no hardcoded paths.

**[GATE G3]** Present parity table standalone-vs-nemo, residual test output, and an ADR documenting any modeling compromises made to fit the sym interface.

---

## Phase 4 — Neural-operator upgrade and multi-GPU scaling (3–5 days)

**M4.1 Operator surrogates.**
- **Thermal:** train an FNO (or Transolver, both in the model zoo) mapping operating-point trajectories → temperature trajectories, first purely data-driven (Darcy recipe pattern), then physics-informed via the M3.2 residual (PINO-style fine-tuning). Deliverable: a surrogate that generalizes across drive-cycle profiles unseen in training.
- **Battery:** FNO/DeepONet mapping (feature window, cycle index) → SOH trajectory, physics-fine-tuned with the degradation residual. Compare against the pointwise PINN from Phase 3 on extrapolation: train on cycles 1–60%, predict to end-of-life.

**M4.2 Distributed training.** Enable PhysicsNeMo's `DistributedManager` / torch.distributed path:
- verify single-GPU == multi-GPU convergence (same final loss ±ε at equal effective batch),
- record throughput scaling table (samples/s at 1, 2, 4, 8 GPUs),
- checkpointing + resume tested by killing and restarting a run mid-training.

**M4.3 Inference packaging.** Export best checkpoints; write `src/nemo/infer.py` that loads a checkpoint and serves batch predictions from a CSV of operating points, with latency measurement (target: real-time-plausible per-step inference for the thermal model).

**Acceptance criteria:**
- Operator models match or beat pointwise PINN accuracy on interpolation; report extrapolation honestly either way.
- Physics-informed fine-tuning demonstrably improves extrapolation vs. purely data-driven operator (this is the whole point — if it doesn't, document why).
- Linear-ish scaling to at least 2 GPUs with no accuracy loss.

**[GATE G4]** Present accuracy/extrapolation comparison, scaling table, inference latency.

---

## Phase 5 — VHM evaluation and wrap-up (2–3 days)

**M5.1 Residual-based health signal study.** Using the healthy-physics models: inject synthetic degradation into test data (e.g., scale a thermal conductance by 0.7 to mimic cooling degradation; accelerate SOH fade) and show the model residuals / identified parameters detect it. Quantify detection delay and false-positive rate on healthy data.

**M5.2 Comparative write-up.** `docs/final_report.md`: loss-penalized vs. structural physics — accuracy, extrapolation, interpretability of identified parameters, residual quality for fault detection, training cost, porting effort. Include every table and figure from prior gates.

**M5.3 Handoff artifacts.**
- `make all` reproduces every milestone.
- SKILL.md-style reference doc summarizing the physicsnemo.sym porting pattern (custom ODE residual → sym PDE class → parity test → operator fine-tune) for reuse in future subsystem models (inverter cold plate is the named next candidate, using the heat-sink inverse recipe).

**[GATE G5 — final]** Human review of final report and handoff kit.

---

## Timeline summary

| Phase | Duration | Output |
|---|---|---|
| 0 | 0.5 d | Envs, data, scaffold |
| 1 | 1–2 d | TNN baseline reproduced |
| 2 | 1–2 d | PINN4SOH baseline reproduced |
| 3 | 3–5 d | Residuals in physicsnemo.sym, parity |
| 4 | 3–5 d | FNO/PINO surrogates, multi-GPU |
| 5 | 2–3 d | VHM evaluation, final report, reusable skill |

## Known risks the agent must watch

- **Dependency rot** in PINN4SOH (torch 1.7 pins) — budget time for a modernization patch kept in `src/soh/patches/`, never in `third_party/`.
- **PINN loss balancing** on the SOH port — if physics loss collapses or dominates, apply gradual weighting/curriculum and log the schedule as an ADR.
- **ODE-in-a-PDE-framework friction** — physicsnemo.sym is PDE-oriented; the LPTN is a stiff ODE system. If the sym route is awkward, the fallback is implementing the residual as a plain PyTorch loss inside a PhysicsNeMo training loop (still gets distributed + operator machinery); record this decision at G3.
- **API drift** — PhysicsNeMo examples change rapidly; pin to a tagged release at M0.2 and do not upgrade mid-project.
