Summary
There are two coexisting quasi-stationary (SLCONTOUR) implementations, born in the same WIP commit (`b68647f`, 2026-06-30). One is wired and running; the other has never been called. We need to pick one and delete the duplication before it causes a correctness bug.
The two codebases
| File |
Status |
Notes |
| `src/magnetics/core/qs_bridge.py` |
LIVE — the service path |
Adapts the `magnetics-code/` OMFIT/xarray pipeline (`run_steps`, `omfit_compat.load_wall`) into GUI `kind`-nodes. ~70 lines of `xr.Dataset` (`.values`/`.attrs`/`.sizes`) coupling. Impure — violates the "core is pure numpy/scipy" contract. |
| `src/magnetics/core/quasistationary.py` |
DEAD — zero importers |
The intended pure-numpy port (`FitResult`, `form_basis_function`). Confirmed nothing imports it; it has never produced a fit; no tests. |
Why this matters (not just cleanup)
The two share duplicated logic that has already diverged:
- Opposite sign conventions in the mode reconstruction: bridge uses `exp(-i(nφ+mθ))`, port uses `exp(+i…)`. Fit with one + render with the other → field flips.
- Two different K→quality mappings: `qs_bridge._quality_status` returns `error/warn/ok`; `core/contracts.quality_for_k` returns `bad/warn/good`. The GUI seam has two disagreeing quality vocabularies.
- Verbatim-duplicated amp/phase helpers (`_amp_phase` ≈ `amp_phase_with_errors`).
Decision needed
- Adopt the pure port (`quasistationary.py`) and delete `qs_bridge` + the `magnetics-code/` dependency, or
- Keep the bridge and delete the unused port.
Recommendation: adopt the port (it's the "core stays pure" target), but note it's untested and unvalidated — this is greenfield adoption, not a revert.
Port work (if we go with option 1) — this is real, not mechanical
- Sever OMFIT: the shim threads `OMFITexception`, `printw/printv/printe`, `delta_degrees`, `is_device`, `list_sensor_subsets`, `resolve_channel_filter`, `sensor_geometry` through `fit.py`/`io_data.py`.
- Convert the data model: `xr.Dataset` in/out → plain numpy + `FitResult`; rewrite `qs_bridge`'s ~70 Dataset touchpoints to consume the new dataclass.
- Replace `load_wall`/`sensor_geometry` with the real data layer (sensor φ/θ extents, wall, helicity) — gated on the h5source geometry work.
- Reconcile the sign convention + quality mapping, delete the duplicated helpers.
- Validate numerically against the OMFIT/SLCONTOUR reference (K, χ², mode amplitudes) — the port has never been run.
Tracking as a follow-up push (Phase 4 of the overnight cleanup); tonight's reorg only relocates `magnetics-code/` into the package, it does not port.
cc @mfairborn23 @priyanshlunia — you two own the SLCONTOUR/QS side; which option do you want, and is the port something you want to drive?
Summary
There are two coexisting quasi-stationary (SLCONTOUR) implementations, born in the same WIP commit (`b68647f`, 2026-06-30). One is wired and running; the other has never been called. We need to pick one and delete the duplication before it causes a correctness bug.
The two codebases
Why this matters (not just cleanup)
The two share duplicated logic that has already diverged:
Decision needed
Recommendation: adopt the port (it's the "core stays pure" target), but note it's untested and unvalidated — this is greenfield adoption, not a revert.
Port work (if we go with option 1) — this is real, not mechanical
Tracking as a follow-up push (Phase 4 of the overnight cleanup); tonight's reorg only relocates `magnetics-code/` into the package, it does not port.
cc @mfairborn23 @priyanshlunia — you two own the SLCONTOUR/QS side; which option do you want, and is the port something you want to drive?