Skip to content

ErrorFields - FEATURE - Add tolerance sampling distributions - #450

Merged
ebursch merged 1 commit into
developfrom
feature/errorfields-sampling
Sep 25, 2026
Merged

ebursch merged 1 commit into
developfrom
feature/errorfields-sampling

Conversation

@logan-nc

@logan-nc logan-nc commented Sep 11, 2026 •

Copy link
Copy Markdown
Collaborator

Fifth PR of the OMFIT → Julia error-field tolerance migration, stacked on #449. It adds the random-draw primitives a tolerance Monte Carlo recombines with the coil sensitivities: the radial sampling shapes, the disk draw, the Gaussian placement uncertainty, and the two tolerance models (additive shift + tilt, and the cylinder axis-line model). No dependency added (Random only); no driver or output change.

What it does (src/ErrorFields/Sampling.jl)

  • RadialDistribution with Flat (p = 1, uniform in radius — OMFIT's flat, kept exactly), UniformArea (p = 1/2, new), Hollow (p = 1/3, OMFIT default), Ring (p = 0), PowerLaw(p); randpow, and radial_distribution(name) for the TOML strings PR4 validates.
  • Scalar, allocation-free kernels on a caller rng and a Float64 exponent so PR6's hot loop resolves dispatch outside the loop: disk_radius, sample_disk (→ Δx + iΔy), sample_uncertainty (OMFIT's signed-normal-times-uniform-phase construction, documented as half-normal rather than Rayleigh).
  • Every sampler takes optional fixed directions (phase, phase_top/phase_bot) so coherent groups sharing a phase_group pass one direction and draw their own radii — the OMFIT phasing_index semantics settled in PR4.
  • sample_additive → independent shift (m) and tilt (deg) draws. sample_cylinder(rng, R, z_top, p) → the axis endpoints drawn in the top and bottom disks, the coil placed at the midplane crossing and tilted by the lean: shift = (p_top + p_bot)/2, α = atan(|p_top − p_bot|, 2 z_top), tilt expressed as the (θx, θy) rotation angles apply_transforms uses so the lean direction and the shift direction are physically correlated.

Verification (test/runtests_sampling.jl, 55 tests)

  • Radial CDFs at three quantiles for Flat, UniformArea, Hollow, PowerLaw(0.25) at N = 2×10⁵; Ring always on the edge; disk points isotropic with ⟨x²⟩ = R²/4 for UniformArea.
  • Uncertainty: E|u|² = σ², E|u| = σ√(2/π).
  • Cylinder: |shift| ≤ R, |tilt| ≤ atan(R/z_top), ⟨|shift|²⟩ = R²/6 for Flat (mean of two draws), tall cylinder → zero tilt, zero radius → zero everything, endpoint swap flips the lean; closed-form check against hand-computed endpoints.
  • Seed reproducibility; injected phase reproduces the default path; shared phase gives equal directions with distinct radii.
  • Sign convention against the geometry: tilting a hoop by the sampler's (θx, θy) for an axis leaning toward +x (and +y) raises the hoop on the −x (−y) side, as it must.

Two OMFIT points, for the record (documented in the sample_cylinder docstring):

  • OMFIT's cylinder branch measures the endpoint separation in units of the tolerance radius against a height in metres and then scales by the tabulated tilt tolerance, so its tilt magnitude is tilt_tol · atan(|d|/R, 2 z_top) rather than the physical atan(|d|, 2 z_top). This sampler works in physical units from (R, z_top) alone; the paper's cylinder rows were run with pre-derived tilt tolerances, so PR6's benchmark against OMFIT is exact for the additive model and in-kind for the cylinder model.
  • OMFIT reuses the top endpoint's direction for the bottom one (phase_unique_bot is computed and never used). Endpoints are independent here; a reproduction toggle is yours to call for.

cc @matt-pharr

Release note

  • Audience: developers
  • Numerical impact: none (harness @ 5b182e9)
  • Migration: none

ErrorFields gains the misalignment samplers a tolerance Monte Carlo needs: the radial sampling shapes (Flat, UniformArea, Hollow, Ring, PowerLaw), disk and uncertainty draws, and the additive and cylinder axis-line tolerance models, all seedable and with injectable shared directions for coherent groups.

Regression report

Regression Report: diiid_n1
==============================================================================================================
Ref 1: develop  @ 9578c9b86 (2026-09-24)
       env: julia 1.11.7, x86_64-linux-gnu, manifest 06e27666 (pinned), 16 threads/16 BLAS
Ref 2: feature/errorfields-sampling  @ 5b182e9a9 (2026-09-24)
       env: julia 1.11.7, x86_64-linux-gnu, manifest 06e27666 (pinned), 16 threads/16 BLAS
--------------------------------------------------------------------------------------------------------------
Quantity                                      develop          feature/errorfields-sampling  Diff       Status
--------------------------------------------------------------------------------------------------------------
total energy Re(et[1])                        8.012318e-01     8.012318e-01                  0.0e+00    OK    
total energy Im(et[1])                        4.142529e-05     4.142529e-05                  0.0e+00    OK    
plasma energy Re(ep[1])                       -1.348486e+00    -1.348486e+00                 0.0e+00    OK    
vacuum energy Re(ev[1])                       2.149718e+00     2.149718e+00                  0.0e+00    OK    
vacuum matrix min eigenvalue                  1.873976e-01     1.873976e-01                  0.0e+00    OK    
plasma energy (all)                           [35 elem]        [35 elem]                     0.0e+00    OK    
vacuum energy (all)                           [35 elem]        [35 elem]                     0.0e+00    OK    
total energy (all)                            [35 elem]        [35 elem]                     0.0e+00    OK    
ODE steps (saved)                             2576             2576                          0.0e+00    OK    
ODE steps (total)                             4572             4572                          0.0e+00    OK    
q0                                            1.204212e+00     1.204212e+00                  0.0e+00    OK    
q95                                           4.781723e+00     4.781723e+00                  0.0e+00    OK    
beta_t                                        1.327024e-02     1.327024e-02                  0.0e+00    OK    
beta_n                                        1.372511e+00     1.372511e+00                  0.0e+00    OK    
internal inductance li1                       8.842392e-01     8.842392e-01                  0.0e+00    OK    
internal inductance li2                       7.080847e-01     7.080847e-01                  0.0e+00    OK    
internal inductance li3                       7.304433e-01     7.304433e-01                  0.0e+00    OK    
poloidal beta betap1                          6.680744e-01     6.680744e-01                  0.0e+00    OK    
poloidal beta betap2                          5.349834e-01     5.349834e-01                  0.0e+00    OK    
poloidal beta betap3                          5.518761e-01     5.518761e-01                  0.0e+00    OK    
# singular surfaces                           5                5                             0.0e+00    OK    
singular psi locations                        [5 elem]         [5 elem]                      0.0e+00    OK    
singular q values                             [5 elem]         [5 elem]                      0.0e+00    OK    
current beta betaj                            4.236478e-01     4.236478e-01                  0.0e+00    OK    
plasma volume                                 1.829472e+01     1.829472e+01                  0.0e+00    OK    
plasma current                                1.152130e+00     1.152130e+00                  0.0e+00    OK    
mpert                                         35               35                            0.0e+00    OK    
npert                                         1                1                             0.0e+00    OK    
toroidal field bt0                            2.006573e+00     2.006573e+00                  0.0e+00    OK    
wall field bwall                              3.880145e-01     3.880145e-01                  0.0e+00    OK    
aspect ratio                                  2.845746e+00     2.845746e+00                  0.0e+00    OK    
elongation kappa                              1.708350e+00     1.708350e+00                  0.0e+00    OK    
q profile (checksum)                          0cd285cea88d...  0cd285cea88d...               identical  OK    
pressure profile (checksum)                   a1c48b266622...  a1c48b266622...               identical  OK    
Mercier D_I profile (checksum)                eeb06744e795...  eeb06744e795...               identical  OK    
resistive interchange D_R profile (checksum)  fa37296851f6...  fa37296851f6...               identical  OK    
ballooning Delta' profile (checksum)          6eb0ea075ccf...  6eb0ea075ccf...               identical  OK    
island half-widths                            [5 elem]         [5 elem]                      0.0e+00    OK    
Chirikov parameter                            [5 elem]         [5 elem]                      0.0e+00    OK    
||resonant area-weighted field||              5.189179e-04     5.189179e-04                  0.0e+00    OK    
dominant-coupling singular values             [3 elem]         [3 elem]                      0.0e+00    OK    
|forcing overlap with dominant mode|          1.415683e-04     1.415683e-04                  0.0e+00    OK    
|delta_nominal| of coil set 1                 7.055228e-05     7.055228e-05                  0.0e+00    OK    
||ddelta/d(shift)|| over coil sets            1.246233e-04     1.246233e-04                  0.0e+00    OK    
||ddelta/d(tilt)|| over coil sets             4.180643e-07     4.180643e-07                  0.0e+00    OK    
PE plasma energy                              3.422677e+00     3.422677e+00                  0.0e+00    OK    
PE vacuum energy                              3.174510e+00     3.174510e+00                  0.0e+00    OK    
PE surface energy                             5.826684e+00     5.826684e+00                  0.0e+00    OK    
PE toroidal torque                            5.087465e-02     5.087465e-02                  0.0e+00    OK    
NTV torque FGAR [N·m]                         5.296762e-01     5.296762e-01                  0.0e+00    OK    
NTV kinetic energy dW FGAR [J]                7.924971e-02     7.924971e-02                  0.0e+00    OK    
Runtime (s)                                   280.2s           285.7s                                   --    
||forcing b~|| (root-area-weighted)           4.683328e-04     4.683328e-04                  0.0e+00    OK    
resonant area-weighted field b^r              [5 elem]         [5 elem]                      0.0e+00    OK    
==============================================================================================================
Summary: 53 unchanged

Harness, re-run at this branch head

5b182e9a9 compared against develop (9578c9b86), case diiid_n1:

Summary: 53 unchanged

Every tracked quantity is bit-identical; only wall-clock Runtime differs, which the
harness does not track. The branch carries a merge of the current develop.

@logan-nc

Copy link
Copy Markdown
Collaborator Author

Stack summary — OMFIT → Julia error-field tolerance migration (updated 2026-09-17)

Nothing in this set merges without a third-party human review, the three small bugfix PRs included.

Full page with the diagram, per-PR table, review order and links to every review package (a private claude.ai artifact until the author shares it; DIII-D-like and synthetic data only): https://claude.ai/code/artifact/408ddd36-e52c-42d8-8f5c-52f680f41da9

Group PRs Base
Bugfixes the stack's numbers depend on — review first #458 root-area weight (careful review: Fourier convention inside one routine), #457 helicity from the current sign, #460 interior-start initialization develop
Prerequisites #446 resonant-coupling SVD API, #447 per-coil-set forcing modes develop
ErrorFields stack, each based on the previous branch #448 sensitivities → #449 tolerance TOML → #450 sampling → #451 Monte Carlo → #452 risk + scan → #453 plots + phasing → #455 NTV limits → #462 NTV torque against rotation #448 on develop (carries merges of #446/#447); rebase the chain after the bugfixes and #446/#447 land

Benchmark, qualitatively. The original OMFIT project's case, rebuilt from that project's own run inputs, is reproduced once #458, #457 and #460 are in: dominant-mode singular values agree to 1e-4, singular-coupling rows match Fortran GPEC at 1.0000 correlation and within 0.5 % in norm, and every coil set's dominant-mode overlap agrees within 1 % once both codes use the same converged toroidal coil grid. The DIII-D-like example agrees with Fortran to 1e-4 throughout. Any comparison shown on these PRs uses the DIII-D-like examples only.

Design issue for what comes after the stack: #461 (momentum-balance module fed by tabulated torque surfaces; stationary solvers only).

@logan-nc
logan-nc marked this pull request as ready for review September 23, 2026 02:24
@ebursch
ebursch added this pull request to stack #466 September 23, 2026 14:43
Base automatically changed from feature/errorfields-tolerance-toml to develop September 25, 2026 11:37
Random draws of coil misalignment within a tolerance, the primitives a tolerance Monte Carlo
recombines with the coil sensitivities: the RadialDistribution shapes (Flat = uniform in
radius, UniformArea, Hollow, Ring, PowerLaw) with radial_distribution for the tolerance-file
names; disk_radius / sample_disk (Δx + iΔy) / sample_uncertainty (signed normal amplitude with
a uniform direction); and the two tolerance models — sample_additive (independent shift and
tilt disks) and sample_cylinder (axis endpoints drawn in the top and bottom disks of a cylinder,
the coil placed at the midplane crossing and tilted by the lean, as the (θx, θy) rotation angles
apply_transforms uses). Every sampler takes the caller's rng, scalar exponents, and optional
fixed directions so coherent groups can share a direction.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzKDmtKYDotJWrcxWf1oJu
@logan-nc
logan-nc force-pushed the feature/errorfields-sampling branch from 5b182e9 to 6e69220 Compare September 25, 2026 11:37

@ebursch ebursch left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved

@ebursch
ebursch merged commit 9ff10c7 into develop Sep 25, 2026
9 checks passed
@ebursch
ebursch deleted the feature/errorfields-sampling branch September 25, 2026 15:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New capability

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants