Skip to content

pedestal_poloidal_beta and b_field_poloidal_average - #314

Merged
jmcclena merged 3 commits into
masterfrom
eped_nn_ensemble
Oct 2, 2026
Merged

jmcclena merged 3 commits into
masterfrom
eped_nn_ensemble

Conversation

@TimSlendebroek

@TimSlendebroek TimSlendebroek commented Aug 25, 2026 •

Copy link
Copy Markdown
Collaborator

Two small physics functions that the new EPED-NN pedestal model needs, and one de-duplication.

Part of a three-repo change, all branches named eped_nn_ensemble so that CI picks up the matching
branch in each repo. Merge order: EPEDNN first, then this PR, then FUSE.

repo PR what it adds
EPEDNN.jl ProjectTorreyPines/EPEDNN.jl#9 EPED1NNensemble + data/EPED1NNensemble.bson, and a model-agnostic API
IMAS.jl #314 pedestal_poloidal_beta and b_field_poloidal_average
FUSE.jl ProjectTorreyPines/FUSE.jl#1163 act.ActorEPED.nn_model, defaulting to the new model

What this adds

  • b_field_poloidal_average(eqt) = μ₀·Ip/length_pol is the average poloidal field that the flux
    surface code already built inline to normalize beta_pol. It is now a function, used in all three
    places that need it (beta_pol, the new pedestal beta, and FUSE's pedestal_poloidal_βn).
  • pedestal_poloidal_beta(eqt, pped) is that same normalization applied to the pedestal pressure.
    This is the beta that sets the analytic EPED1 pedestal width w_ped = 0.076·√βp,ped, which is how
    the new EPED1NNensemble — a height-only model — gets its width.

Sanity check: fed the volume-averaged pressure, pedestal_poloidal_beta reproduces
eqt.global_quantities.beta_pol to 1e-10, so it is the same normalization, not a parallel
definition.

Version bumped to 7.4.0, which is what the companion FUSE PR requires in its compat.

Full validation write-up for the whole three-repo change: eped/pr_validation/PR_NOTES.md of the
iter_claude repo.

🤖 Generated with Claude Code

`b_field_poloidal_average(eqt)` is the average poloidal field `Bp = μ₀ Ip / length_pol`
that the flux surface calculation already builds to normalize `beta_pol`: it is now a
function, so that everything that needs that same `Bp` uses one definition of it.

`pedestal_poloidal_beta(eqt, pped)` is the poloidal beta of a pedestal pressure against
that field, the same normalization `beta_pol` uses for the volume averaged pressure. It
is what sets the analytic EPED pedestal width `w_ped = 0.076*sqrt(betap_ped)` (used by
the height only EPED-NN models in EPEDNN.jl).
Empty commit, so that the evidence for the eped_nn_ensemble branches of EPEDNN.jl,
IMAS.jl and FUSE.jl sits in the history. The scripts and the figures that produce all
of it live in eped/pr_validation/ of the iter_claude repo (PR_NOTES.md is the same
write-up with the figures inline).

1. Against the EPED physics code, on held-out data
--------------------------------------------------
Held-out 10% of the ensemble training set, 2313 points. The NEW model was fitted to
none of them. The OLD model was trained on the whole multi machine database, so those
rows are training data for it and held-out data for the new one; the ITER scan rows
postdate the old model entirely and are unseen by both.

                        points    old: median err / R2    new: median err / R2
  all                     2313         4.3%   0.973            3.7%   0.982
  multi machine DB        2153         4.1%   0.979            3.7%   0.981
  ITER scans (new data)    160         8.3%   0.750            2.9%   0.958

2. The two inputs that the old model does not have
--------------------------------------------------
Sweeping ne_sep/ne_ped over the range EPED itself covers (0.10 - 0.55) at the ITER
15 MA point moves the predicted pedestal from 68 to 98 kPa. The old network has no
such input, so it is a flat line -- and it crosses the new one at ne_sep/ne_ped =
0.26, which is the single value the original database was generated at. Te_sep does
the same, 75 -> 81 kPa over 50 - 300 eV.

3. Example FUSE runs, old vs new (ActorPedestal, model=:EPED)
-------------------------------------------------------------
  case     R [m]  Ip [MA]   p_ped old   p_ped new       d    sigma  in distribution
  KSTAR     1.78     0.80     7.16 kPa    8.30 kPa  +15.9%    4.7%  yes
  DTT       2.19     5.35    97.09       95.58       -1.6%    4.8%  yes
  SPARC     1.85     8.70   368.14      394.64       +7.2%   60.1%  no (bt out of bounds)
  ITER      6.19    15.00    63.05       66.09       +4.8%    1.2%  yes
  FPP       4.90     7.94    65.17       70.09       +7.5%    5.0%  no (sigma = 5.0%)
  KDEMO     6.83    12.72    86.21       86.55       +0.4%    5.1%  no (a out of bounds)
  NSTX      0.85     0.80     4.17        0.92      -77.9%  134.4%  no (r out of bounds)

FUSE's density profiles all land at ne_sep/ne_ped ~ 0.26, which is exactly where the
old model was trained, so the two agree within a few percent on the mainstream cases
and what is left is the effect of the new ITER scale training data. SPARC (bt = 12.2 T
against a training maximum of 8.0 T) and NSTX (r = 0.85 m against a minimum of 1.5 m)
are outside the training box of BOTH models; the difference is that the new one says
so, with 60% and 134% uncertainty and in_distribution = false.

4. A full ITER workflow (ActorStationaryPlasma)
-----------------------------------------------
  quantity      old        new     delta
  Pfusion     145.2      142.9     -1.6%   [MW]
  Qfusion     1.661      1.635     -1.6%
  Paux_tot     87.4       87.4     +0.0%   [MW]
  Te0         16.04      15.86     -1.1%   [keV]
  Ti0         15.29      15.10     -1.2%   [keV]
  ne0       9.98e19    1.00e20     +0.6%   [m^-3]
  betan       1.135      1.123     -1.0%
  tau_e       2.092      2.086     -0.3%   [s]

Both converge, and the converged profiles sit on top of each other: switching the
default model does not disturb the workflow.

5. Ports and internals
----------------------
- the Julia model reproduces the PyTorch predictions to 1e-14 relative on 500 points
  spanning the training box (with the exact erf GELU, which is what torch.nn.GELU is)
- EPED1NNmodel.bson predictions are bit for bit unchanged by the save/load generalization
- IMAS.pedestal_poloidal_beta, fed the volume averaged pressure, reproduces
  eqt.global_quantities.beta_pol to 1e-10: it is the same normalization, not a second one
- EPEDNN test suite: 76 tests
Comment thread src/physics/equilibrium.jl
@jmcclena
jmcclena merged commit 16d4d16 into master Oct 2, 2026
2 checks passed
@jmcclena
jmcclena deleted the eped_nn_ensemble branch October 2, 2026 21:19
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