Skip to content

Add gyaradax plugin - #2189

Draft
gerkone wants to merge 9 commits into
google-deepmind:mainfrom
gerkone:qlgyx
Draft

gerkone wants to merge 9 commits into
google-deepmind:mainfrom
gerkone:qlgyx

Conversation

@gerkone

@gerkone gerkone commented Jun 3, 2026 •

Copy link
Copy Markdown

hey Torax team
this PR adds the gyaradax-ql plugin (quasilinear model based on the gyaradax local gyrokinetics code) as an optional transport model. this is still WIP and more results to follow, mostly here to get feedback.

  • gyaradax-ql model: per-radius linear solve => QL saturation => flux, over a few equidistant rho_match then interpolated.
  • basic calibration of gyaradax-ql on ~1000 runs (rlt, rln, q, shat scanned, eps scan left out!, beta=0)
  • early results on ITER hybrid (simplified iterhybrid_predictor_corrector case, ES adiabatic), below.
  • proper validation on the ITER case. requires: broader NL saturation scan for calibration (specifically: eps scan, beta scan).
  • (optional) nonlinear transport variant (using full NL gyaradax).
  • (gyaradax side) validate electromagnetic Bpar and Apar + Bpar.
  • (gyaradax side) investigate high beta instabilities (Apar + Bpar).

Open questions

  • TORAX normalization: TORAX flux minor-radius, gyaradax major-radius + differences in the velocity normalization (should be taken care of).
  • radii: QLKNN runs a batch, gyaradax-QL currently evals a rho_match subset and interpolates.
  • what can we do with AD? advantages in transport modeling?
  • tips on how to calibrate the QL model. would the QLKNN dataset be helpful?
  • what is expected in validation?
  • is the NL model relevant or interesting? QL is already ~100x slower to QLKNN

Early results (iterhybrid_predictor_corrector)

  • calibration set is adiabatic-ES, no eps scan. does this explain the discrepancies?
  • gyaradax-QL evaluated at 8 rho_match radii, interpolated to the face grid.
  • t_final 1s (was 5s).
  • ideas on the diffusivity spike at ~0.25?
image

@google-cla

google-cla Bot commented Jun 3, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@jcitrin

jcitrin commented Jul 14, 2026

Copy link
Copy Markdown
Collaborator

TORAX normalization: TORAX flux minor-radius, gyaradax major-radius + differences in the velocity normalization (should be taken care of).

You mean this normalization here?

You can choose the reference lengths for chiGB and the heat flux in these methods, so TORAX flux is not fixed to be normalized to minor radius (unless I misunderstood something).

radii: QLKNN runs a batch, gyaradax-QL currently evals a rho_match subset and interpolates.

That sounds fine.

what can we do with AD? advantages in transport modeling?

e.g. flux matching with nonlinear solvers will be faster (once we have a stationary state flux matching solver in TORAX). And for time-dependent can use Newton in the inner loop. And of course can build optimization wrappers around all these for various constrained optimization applications (e.g. scenario optimization).

tips on how to calibrate the QL model. would the QLKNN dataset be helpful?
what is expected in validation?

Not sure how relevant the QLKNN dataset is. Fundamentally you need 3 ingredients:
i) A fast linear model for growth rates, QL weights, mode structures
ii) Analytical priors for the saturation rule
iii) A database of NL simulations to tune the saturation rule against.

There is a lot of literature. See e.g. https://iopscience.iop.org/article/10.1088/1741-4326/ad6ba5/meta . fcasson knows a lot about this.

is the NL model relevant or interesting? QL is already ~100x slower to QLKNN

Yes it's interesting, e.g. for ultimate ground-truth validation or for training set generation for surrogates or QL saturation rules.

Two transport models backed by gyaradax, a pure-JAX reimplementation of the
GKW gyrokinetic solver, plus the shared GKW<->TORAX normalization and an
optional host-side diagnostics sink.

gyaradax-QL runs a linear gyrokinetic eigenmode solve at each rho_match
radius, applies a quasilinear saturation rule and interpolates the resulting
fluxes onto the face grid. gyaradax-NL reuses the same profile mapping and
unit conversion but integrates the full nonlinear turbulence to saturation at
each radius; it is for offline ground-truth generation, not transport loops.

Both register themselves through register_transport_model, so no upstream
file is modified: the only edits outside the new files are the two docs
sections describing how to install gyaradax and what the models do.

gyaradax is an optional dependency. Without it the modules are not imported
and TORAX is unaffected.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
gerkone and others added 8 commits October 2, 2026 10:00
Every gyaradax transport model subclassed GyaradaxQLTransportModel, so each
one inherited the quasilinear machinery whether or not it used it. The NL
model's own docstring said as much -- "the head itself is unused here", "the
linear early-stop diagnostics don't apply" -- while still carrying `rule`,
`cn_override`, `cn_scalar` and six `early_stop_*` fields. The gyroflow model
in neugk-jax inherited the same set, plus `n_steps_linear`.

None of that was quasilinear in the first place. `call_implementation` --
build the quasilinear inputs, map rho_match onto face indices, vmap over
radii, convert GKW gyroBohm fluxes to TORAX units -- contains no QL physics,
and neither do the grid fields, the per-radius GKParams/geometry
construction, `topology` or `sink`. They now live on
BaseGKWGyaradaxPlugin, and QL, NL and gyroflow are siblings that supply only
a flux model, by overriding `_per_radius` or `_per_radius_from_profiles`.

Grid resolution no longer reads the Cn calibration head. `_resolve_grid`
takes a fallback grid and each subclass provides one through
`_grid_fallback`, so the base does not depend on QL calibration. NL keeps
its head-derived grid defaults, now declared for what they are -- grid
metadata only, no Cn is applied in a nonlinear run -- so NL configs that
leave grid fields unset behave as before.

The config needed two tiers rather than one. BaseGKWGyaradaxConfig carries
what all three share (rho_match, DV_effective, An_min, diagnostics_path);
SolverGKWGyaradaxConfig adds the grid, backend, mixed_precision and em for
the models that actually run the solver. Collapsing them into one would have
handed gyroflow seven fields it ignores, since its grid is fixed by the
GyroSwin training data -- the same problem in a new place.

Incidentally fixes a leak the old layout hid: the QL model's `sink` reached
for gyroflow's `latent_dump_*` through getattr, so the QL base was already
quietly gyroflow-aware. That hook is now on the shared base, where it is
honest.

QL goes from 512 to 175 lines; the base is 424. Two tests referenced
`face_indices_for_radii` and `gkparams_for_radius` on the QL module and now
use the base. gyaradax_transport_model_test: 14 passed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Merging 41 commits of upstream into qlgyx applies cleanly as text but breaks
the gyaradax plugins at runtime, in two places.

The neoclassical model was renamed from plural to singular upstream:
`neoclassical.build_models()` is now `build_model()`, `initial_core_profiles`
takes `neoclassical_model=`, and `build_source_profiles` no longer takes a
neoclassical argument at all (it takes optional conductivity and
bootstrap_current instead). Only the test helper touched any of this; no
plugin references neoclassical.

`quasilinear_transport_model.RuntimeParams` gained a required
`DV_effective_smooth_width`, which blends the effective D/V split for small
down-gradient flux. BaseGKWGyaradaxConfig now declares it with the same
default upstream uses for its own quasilinear configs (0.01) and passes it
through build_runtime_params.

gyaradax_transport_model_test: 14 passed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
gkparams_for_radius grows a kinetic branch: rlt = [lti, lte], one rln = lne
shared by both species (the data are pure D and 2-species gyaradax needs
gradient quasineutrality, so n_e rather than n_i0), tmp = [1, Te/Ti] against
the GKW ion reference, mas = [1, 2.72e-4], signz = [1, -1], and vthrat =
sqrt(tmp/mas), which the species precompute needs per species rather than as
the scalar default.

The branch is off by default and refuses to build without an explicit
cn_override: no Cn head fitted on kinetic data exists yet, and silently
reusing the adiabatic one would be wrong rather than merely uncalibrated.

The QL rule docstring named six rules that no longer exist; the set is now
canonical / sat0 / sat2, with sat2 reproducing GACODE TGLF SAT2's intensity
spectrum on the full linear eigenmode.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Upstream removed the shared quasilinear base: quasilinear_transport_model is
now quasilinear_utils and keeps only the helpers, while QuasilinearInputs,
QuasilinearTransportModel and the shared RuntimeParams are gone, each model
carrying its own (see TGLFInputs). The gyaradax plugins follow suit.

QuasilinearInputs moves into gyaradax_normalization, which is the lower-level
of the two modules and already builds it. The base class derives from
component.ComponentTransportModel directly, RuntimeParams declares
DV_effective / An_min / DV_effective_smooth_width itself, and
_make_core_transport is vendored unchanged onto the base.

PedestalTransitionState.empty_L_mode is now empty(), defaulting to L mode.

Verified on the merge: gyaradax 16, transport_model 28, pydantic_model 39,
quasilinear_utils 17, all passing. Needs jax >= 0.11.1, as upstream does.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…tion

Nothing about the linear solve should need a source edit to change. The
settings that were module constants are now config fields defaulting to the
values the calibration scans used: vpar_max, nperiod, geom_type,
gkparams_dt, rref, electron_mass_ratio, and the clip box.

Grids come from a named preset -- adiabatic 85x32x16, kinetic 192x32x18 --
rather than from whatever metadata a Cn head carries. The bundled head still
advertises 43x16, which is under the resolution floor, so inheriting from it
was never a safe default. Explicit config fields still win over a preset.

rule_options forwards arbitrary keywords to the selected rule, so sat2's
flux_exponent and kx_width_model, and anything a future rule adds, are
reachable from a TORAX config without touching the plugin.

ikxspace can vary per rho_match radius. It sizes the mode connectivity and
so has to be static, while shat is traced and evolves, so the values are
fixed at build time from a reference profile rather than tracking the live
shear -- ikxspace_for_shat implements floor(6.53*|shat|), the rule the
stored runs follow. Radii then need one topology and one compilation each,
so that path unrolls instead of sharing a vmap.

Five tests cover the new surface, including that every name in
rule_options is a real parameter of the selected rule, and that every rule
registered in gyaradax is selectable. 21 pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
gyaradax builds its kx grid symmetric about kx = 0, so an even nkx
mismatches the field it allocates. The kinetic preset said 192 while every
stored kinetic run is 191, and the mismatch surfaced only at the first
transport call as a bare shape error inside the solver. The preset is now
191 and _resolve_grid rejects any even nkx with a message naming the fix,
so a bad grid fails at config time.

Tests cover both, plus a vmap regression for dlnpdr: it is evaluated per
radius inside the vmap and had been using Python min/max on tracers.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@tamaranorman

Copy link
Copy Markdown
Member

Is this something that you re still working on? If so what about doing something like https://github.com/aaronkho/epednn_mit/tree/main/src/epednn_mit and using the registry while you experiment etc. Then it can live in your own repo but people can still install etc as needed?

If you do let us know as we are planning a docs page of all the registered models that are open-source and we can link to this here. Feel free to still use this for discussion etc in the meantime

@gerkone

gerkone commented Oct 20, 2026

Copy link
Copy Markdown
Author

@tamaranorman thanks, good to know.
I am still working on this albeit slower that I hoped. I was planning to wrap up the QL-gyx model early october but sat rule fitting has been more tricky than anticipated.
If I understand correctly, what you are suggesting is simply moving plugin / interface to https://github.com/gerkone/gyaradax, list torax as an extra dependency and delete my torax fork, or is there more? I can do this this week, and if the partially finished QL model is not a problem I would also appreciate gyaradax being included in the docs. Let me know how I can assist

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.

3 participants