Skip to content

Quasi-stationary: two parallel QS codebases — kill the dead port or finish it #40

Description

@matt-pharr

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

  1. Adopt the pure port (`quasistationary.py`) and delete `qs_bridge` + the `magnetics-code/` dependency, or
  2. 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?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions