Skip to content

feat(kstar): live KSTAR rotating-mode analysis end-to-end#55

Merged
matt-pharr merged 9 commits into
developfrom
kstar_int
Jul 1, 2026
Merged

feat(kstar): live KSTAR rotating-mode analysis end-to-end#55
matt-pharr merged 9 commits into
developfrom
kstar_int

Conversation

@ebursch

@ebursch ebursch commented Jul 1, 2026

Copy link
Copy Markdown
Collaborator

Summary

Integrates KSTAR into the fetch → process → service → GUI path. Rotating-mode
(MODESPEC) analysis now works end-to-end against live KSTAR shots (e.g. 42477):
mode_number / spectrogram / coherence / phase_fit all serve real data.

Rebased onto latest develop (merges cleanly with the network.py fetch refactor and
QS-correctness tests) and squashed into 5 logical commits.

What's included

  • Transport + fetchkstar_transport (KFE VPN + nkstar SSH tunnel); fetch_shot
    routes an access="mdsplus_tree" device through its own transport (never the omega
    cluster), defaults a tree device with no sensor set to its declared arrays
    (toroidal + poloidal), converts the ms window to seconds for the resample, and fails
    loudly on a zero-channel pull.
  • Device configdata/device/kstar.json (segmented since_shot model matching
    diiid.json) + kstar_mirnov_config.json (per-year archive angles/polarity) +
    scripts/kstar/build_kstar_device.py generator.
  • Service nodes — device-driven toroidal/poloidal arrays so KSTAR renders in the
    rotating views.
  • GUI — device-reactive pull (sensor sets + VPN 2FA vs DIII-D key/Duo credential
    hints), KSTAR in the rotating views.
  • Tests — transport-routing + KSTAR node tests; synthetic-shot/conftest updates.

Known follow-up (not a regression)

QS / poloidal nodes still return 422 for KSTAR — the poloidal Mirnov θ geometry isn't
populated yet. Rotating analysis is unaffected.

Verification

  • uv run pytest237 passed, 2 skipped
  • uv run ruff format --check . → clean; uv run ruff check . → clean
  • npm --prefix gui/web test24 passed
  • Manual: live VPN pull of KSTAR 42477 (narrow window) → rotating nodes 200

🤖 Generated with Claude Code

ebursch and others added 5 commits July 1, 2026 13:48
Add magnetics.data.fetch.kstar_transport (KFE VPN + nkstar SSH tunnel) and wire
fetch_shot to reach an access="mdsplus_tree" device through its own transport
instead of the DIII-D omega cluster / mdsthin gateway. A tree device with no
explicit sensor set defaults to its declared `arrays` (toroidal + poloidal), and
its ms window is converted to seconds for the resample (KSTAR MDS time is in
seconds). Fail loudly on a pull that resolves zero usable channels.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Add data/device/kstar.json (segmented since_shot model, matching diiid.json) with
the MC Mirnov toroidal/poloidal arrays, saddle/flux loops, and plasma pointnames,
plus kstar_mirnov_config.json (per-campaign-year angles/polarity from the /PRISM
archive) and scripts/kstar/build_kstar_device.py that regenerates the device file.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
…ometry)

Serve the rotating-mode nodes from a device's declared toroidal/poloidal arrays
so KSTAR shots render end-to-end; add the poloidal-geometry plumbing (QS/poloidal
nodes still 422 until poloidal theta lands — follow-up).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Make the device dropdown drive sensor sets and credential hints (KFE VPN 2FA vs
DIII-D key/Duo), and render KSTAR in the rotating views.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
matt-pharr and others added 4 commits July 1, 2026 15:24
Integrate develop's NSTX/NSTX-U fetch + node genericization with the KSTAR
rotating-mode work. Both branches added an MDSplus-tree device and genericized
the same fetch/node paths; conflicts resolved to keep each device on its tested
path:

- toksearch.py: split the tree dispatch into `if _tree_transport:` (KSTAR: KFE
  VPN + nkstar tunnel) / `elif tree_access:` (NSTX: mdsthin-over-flux). Unified
  the sensor_set guard (require a set only for tree devices with no `arrays`
  block — NSTX; KSTAR defaults to its declared toroidal+poloidal arrays). Kept
  develop's device_id + per-channel channel_geometry write path.
- nodes.py: hybrid channel selection — KSTAR keeps its precise
  `_arrays`/`_set_channels` path; NSTX + DIII-D flow through develop's
  `_dev_geom`/`_pick_pair_prefs`/`_array_channels` membership machinery.
- app.py / api.ts: unioned the device-info fields (access, remote_capable,
  needs_ssh_creds, connect_note, default_shot).
- PullControl.tsx: kept KSTAR's store-owned device + VPN cred UI; folded in
  NSTX's snapDeviceDefaults, tree-aware window/backend gating, generic copy.
- conftest.py: kept both kstar_shot and nstx_shot synthetic fixtures.

QS realignment: develop's early "QS is DIII-D-only" 422 guard in _prep_qs_ds
supersedes KSTAR's device-specific QS channel_filter (which PR #55 already
documents as a 422 follow-up). Kept the guard; renamed the KSTAR test to
test_qs_is_diiid_only asserting KSTAR QS → 422.

Verified: ruff/ty/pytest (254 passed, 5 skipped)/eslint/tsc/vitest/vite build
all green; Playwright drove the NSTX-U render path end-to-end (Sensors geometry
+ Rotating modes) against a synthetic shot with zero API/console errors.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
The develop→kstar_int merge kept KSTAR's passcode-only 2FA UI, which dropped
develop's Duo push/passcode dropdown for the flux gateway (DIII-D / NSTX-U).
Flux Duo supports push, so restore the dropdown for non-KSTAR devices: Push
(sends "1") or a typed passcode, with the passcode field shown only when
"Enter passcode…" is selected. KSTAR/KFE VPN keeps passcode-only (no push).

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
…ch fix)

Second develop→kstar_int sync. develop advanced with PR #53 (per-node plot
image + HDF5 data export) and PR #54 (fetch EFIT tree signals via mdsip on the
toksearch backend, + tree-fetch wrapper tests). Only one conflict, in
toksearch.py: develop added a `server=None` param to `_fetch_toksearch` (routing
EFIT tree signals over a direct mdsip connection via `_toksearch_tree_channels`)
right where KSTAR's `_node_tree_map`/`_fetch_mds_tree` functions were inserted.
Kept both — the KSTAR mds-tree functions and develop's new `_fetch_toksearch`
signature/body — and restored the toksearch section header above it.

api.ts (nodeDownloadUrl) and app.py (/download endpoint + export module) merged
cleanly, carrying both sides' additions.

Verified: ruff/ty/pytest (301 passed, 5 skipped)/eslint/tsc/vitest (27)/vite
build all green.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
…relock)

Third develop→kstar_int sync. develop advanced with PR #65 (rotating-live
wiring: 2-D Gaussian pre-smoothing, download-500 hardening, heatmap null-cell
handling) and PR #46 (gui-sensors: device-agnostic coil overlay, saddle-loop
tilt). Only one conflict — uv.lock — since pyproject.toml is identical on both
sides; resolved by taking develop's lockfile and regenerating with `uv lock`
(135 packages, `uv lock --check` clean). app.py, nodes.py, and test_nodes.py
auto-merged.

Verified: ruff/ty/pytest (312 passed, 5 skipped)/eslint/tsc/vitest (29)/vite
build all green.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@matt-pharr matt-pharr merged commit 8abf073 into develop Jul 1, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants