Skip to content

Add magdrift_passing so one run reproduces MARS-K's orbit-class drift scope - #94

Closed
krystophny wants to merge 38 commits into
mainfrom
agent/mimic-magdrift-orbit-class
Closed

Add magdrift_passing so one run reproduces MARS-K's orbit-class drift scope#94
krystophny wants to merge 38 commits into
mainfrom
agent/mimic-magdrift-orbit-class

Conversation

@krystophny

Copy link
Copy Markdown
Member

MARS-K has no passing magnetic-drift code path. Matching that scope needed two NEO-RT runs whose per-class columns were summed by hand; this does it in one.

magdrift_passing gates the passing branch of Om_tB (now exactly zero) and init_canon_freq_passing_spline. The namelist control is an integer with a negative follow magdrift default, so every existing deck stays bit-identical and no deck must name the new key.

Draft: validation pending, do not merge yet. The oracle is the two-run equivalence — trapped-with-drift plus passing-without, summed from the separate Tco/Tctr/Tt columns, must reproduce a single run with magdrift=.true. and magdrift_passing=0. That compares against an existing independent code path rather than restating the patch. A bespoke unit test was attempted and dropped: driving Om_tB directly needs more orbit-machinery setup than the check is worth, and the two-run comparison is the stronger oracle.

Full suite passes (14/14) with the default, as expected since the default changes nothing.

First of a planned set of code-mimicry flags (collisionality including passing, which #78 currently leaves at R=1, smoothing, spline variants), whose purpose is to let NEO-RT run as MARS-K on the MARS field and as PENTRC on the GPEC field, so residual differences are physics rather than configuration. Context: ITER TC24 NTV benchmark.

The direct GEQDSK path formed the canonical toroidal precession as
drift_phi - q*drift_theta with the *global* safety factor. In geoflux
coordinates theta is the geometric poloidal angle, so alpha = phi - q*theta is
not constant along a field line and the precession derived from it is wrong.
This is the mechanism behind NEO-RT #85, where the direct and straight-field
backends disagree on Omega_d by 53%, 64% and 88% NRMS at rho_tor = 0.2, 0.6
and 0.8, with the correlation degrading to -0.87 at the outer surface.

Along a field line dphi/dtheta = B^phi/B^theta, so the label gradient carries
the local pitch, which reduces to q only when theta is already a
straight-field-line angle. Use hctrvr(2)/hctrvr(3).

Not yet validated against the straight-field backend: the direct path cannot
currently be exercised on the TC24 equilibrium because of a second GEQDSK
reader defect, so this is committed on a branch as a diagnosis with its fix,
not as a closed issue.
…d line

PR #91 substitutes the local pitch hctrvr(2)/hctrvr(3) for the global q in the
field-line label, but nothing tested that the substituted quantity is the pitch.

The oracle is deliberately not the tabulated q: it is a field line integrated in
cylindrical coordinates from field_eq alone,

    dR/dphi = R B_R/B_phi ,   dZ/dphi = R B_Z/B_phi ,

advanced until the geometric angle about the magnetic axis completes one
circuit, giving the rotational transform as Delta_phi/(2 pi). That shares no
code with do_magfie_eqdsk's coordinate transformation, so it is an independent
behavioral oracle rather than a restatement of the patch. The two agree to
7e-4 at s = 0.15, 0.35, 0.60.

The test also asserts the local pitch genuinely varies with theta. Without that
an implementation returning the global q would satisfy the averaged comparison,
and the test would not discriminate the change it exists to protect.

Scope: this validates the substituted quantity, not the full canonical
precession. The straight-field-line angle map also depends on s, so its gradient
carries a radial term that the inp_swi=11 branch still omits; see #85.

Writing this test surfaced a separate defect, now fixed in libneo: geoflux built
both q and the s label from the GEQDSK's stored qpsi record, which on circ.eqdsk
disagrees with the rotational transform of the fixture's own field by a factor
of about 1.55. That is why test_eqdsk_axis could only afford a factor-of-two
bound on the same comparison. This test needs the libneo fix to pass.
…ift scope

MARS-K has no passing magnetic-drift code path at all. Matching that scope in
NEO-RT previously required two runs -- trapped with magdrift, passing without --
whose per-class outputs were added by hand. That works because NEO-RT serializes
Tco, Tctr and Tt separately and the class contributions are additive, but it
doubles the runs and puts the composition in the analysis layer where it is easy
to get wrong.

`magdrift_passing` switches the magnetic drift off for passing orbits only. It
gates two places: the passing branch of Om_tB, which now returns exactly zero
rather than an interpolated value, and init_canon_freq_passing_spline, which no
longer builds a drift spline it will not use.

The namelist control is an integer with a negative "follow magdrift" default, so
every existing deck keeps its behaviour bit-identically and no deck has to name
the new key. Only an explicit 0 or 1 overrides.

VALIDATION IS PENDING and this should not merge without it. The oracle is the
two-run equivalence above: trapped-with-drift plus passing-without, summed from
the separate class columns, must reproduce a single run with magdrift=.true. and
magdrift_passing=0. That compares against an existing, independent code path
rather than restating the patch. A bespoke unit test was attempted and dropped:
driving Om_tB directly needs more orbit-machinery setup than the check is worth,
and the two-run comparison is the stronger oracle anyway.

First of a planned set of code-mimicry flags, whose purpose is to let NEO-RT be
run *as* MARS-K on the MARS field and *as* PENTRC on the GPEC field, so that
residual differences are physics rather than configuration.
@krystophny

Copy link
Copy Markdown
Member Author

Superseded by the clean, independently behavior-tested #97. The original branch accidentally included the #80/#90/#91 stack, so I am closing this oversized version rather than asking reviewers to disentangle 54 unrelated files.

@krystophny krystophny closed this Jul 26, 2026
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.

1 participant