Draw the vacuum field a start-up is read from: one cached evaluation, four quantities, a time slider - #690
Open
HongSik-Yun-Fusion wants to merge 5 commits into
Open
Draw the vacuum field a start-up is read from: one cached evaluation, four quantities, a time slider#690HongSik-Yun-Fusion wants to merge 5 commits into
HongSik-Yun-Fusion wants to merge 5 commits into
Conversation
The startup maps -- flux, poloidal field strength, decay index, the breakdown figure of merit -- are four readings of one field, so they are now four readings of one evaluation. Splitting them across separate computations is how they drift apart. The grid's response to each coil and vessel loop depends on geometry and not on time, so it is built once and cached; a different time then costs a contraction with that instant's currents. On the packaged shot that is 0.67 s once against 44 ms a frame, which is the difference between a time slider and a progress bar. Two details the cache had to get right. Its key comes from the same source extraction the matrices are built from, now factored out of compute_point_response_matrices_ods, so a cached matrix cannot outlive a geometry change it failed to notice. And each waveform is read once per frame rather than once per sample -- the smaller sibling of the defect fixed in #645. dpsi/dt is this map's own flux differenced against its neighbouring samples, so the induced electric field belongs to the same field as everything else instead of being spliced in from a measured loop voltage. The flux agrees with compute_null_ods to 0.0001% at the 95th percentile, which is what makes re-pointing the existing psi map safe. It disagrees only where a grid point lands on a source filament and both answers are meaningless, so the test bounds a percentile rather than a maximum. Note that compute_null_ods lays its grid out (Z, R) and this evaluator lays it out (R, Z). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Four quantities on one plot -- the flux, |B_p| in gauss, the field decay index, and the breakdown figure E_t B_t / B_p -- chosen with field=, and stepped along the PF time base with time_index=. They come from one cached evaluation, so the panels of a start-up figure cannot end up describing four slightly different instants. The map is confined to the limiter outline, and that is the load-bearing choice. VEST's limiter bounding box contains 330 of the machine's 1480 current filaments, so a map over the box is dominated by conductors: at the breakdown instant the whole vessel fell in the bottom contour bin while a handful of coil points took the entire colour range. Not one filament lies inside the limiter outline itself, so masking to it leaves exactly the field a discharge would see -- and the levels then describe that field. Levels come from a percentile of what is left, and Field2D gained an extend policy so the excluded points saturate at the end colours instead of coming out as holes indistinguishable from no data. A dense time base is a slider, not a list. This is the first plot to emit a range control, declared through a times block that names the option it drives, so a stored equilibrium's handful of slices keeps its radio buttons. Discovery resolves the default instant the way the builder does -- from the magnetics, before the private copy that drops them -- so opening the controls does not move the figure. Units are three vocabularies here, not one: gauss for the field, V/m for the breakdown figure, nothing at all for the decay index. The existing applies_to gate handles it, offering the flux units only while the flux is drawn. The vessel currents are cached alongside the response matrices. A recipe hands the evaluator a private copy each frame, which would otherwise repeat the same two-second eddy solve every time; a frame now costs 0.22 s from a caller's untouched ODS. The plan also had equilibrium_field_psi_vacuum move onto this evaluator. Measurement says no: on the 129x129 equilibrium grid that plot draws, the exact elliptic kernels cost 18 s against the polynomial path's 5.8 s and their cached matrices would be 591 MB. That trade buys a slider, not a single figure. It stays where it is, and the evaluator now refuses a grid whose response would not fit its budget rather than quietly allocating half a gigabyte and keeping it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The level percentile's justification had the ratio backwards: away from a null the map's maximum sits about 30% above its 99th percentile, not within a third of it. Also note that only Matplotlib needs telling about the extend policy -- Plotly clamps to its level range already, so the two backends agree on these maps either way. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
With no time= the map is drawn at the breakdown onset, and that timing reads H-alpha from spectrometer_uv alongside the plasma current. I left it out of the plot's ids, so an adapter that loads only the declared IDSs resolved a different onset than one handed the whole entry -- one PF sample apart, which during the ramp is a 1.3% difference in the drawn flux, not just a different number in the title. Only the IMAS side showed it, because the OMAS adapter passes the whole ODS regardless. equilibrium_field_psi_vacuum has declared both all along, for this exact reason. Found by test_imas_omas_plot_equivalence, and now pinned directly so it cannot come back quietly. The flux equivalence test also has to respect the response budget added after it was written: it now compares against every third point of compute_null_ods's own grid, and bounds a percentile plus the fraction of points that disagree at all rather than a 99th percentile that was really measuring the subsampling. Measured: median 3e-8, 95th percentile 7e-7, 1.4% of points past 1e-3, all of them beside a source filament. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
poloidal_field_magnitude, decay_index_from_bz and toroidal_electric_field take the equilibrium category from 107 to 110. Checked against develop's own surface rather than inferred from the failure: exactly those three are new, and nothing develop added was dropped in the rebase. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
An interactive vacuum-field map
vacuum_fielddraws the field the coils and the vessel make with no plasma init: the flux,
|B_p|in gauss, the field decay index, and the breakdown figureof merit
E_t B_t / B_p.field=chooses among them,time_index=steps alongthe PF time base, and
interactive=Truegives both as widgets.All four come from one evaluation,
compute_vacuum_field_map, so the panelsof a start-up figure cannot end up describing four slightly different instants.
Why it is fast enough to slide
A grid's response to each coil and vessel loop is a pure function of geometry,
so it is built once and cached; a different time then costs a contraction with
that instant's currents. The vessel eddy solve is cached the same way, because
a recipe hands the evaluator a private copy of the ODS on every frame and would
otherwise repeat the same two-second solve each time.
The map is confined to the limiter, and that is the load-bearing choice
VEST's limiter bounding box contains 330 of the machine's 1480 current
filaments, so a map over the box is dominated by conductors — at the breakdown
instant the entire vessel fell in the bottom contour bin while a handful of coil
points took the whole colour range. Not one filament lies inside the limiter
outline, so masking to it leaves exactly the field a discharge would see, and
the levels then describe that field.
Levels come from a percentile of what is left, and
Field2Dgained anextendpolicy so the points the percentile excludes saturate at the end colours rather
than appearing as holes indistinguishable from missing data.
A dense time base is a slider, not a list
This is the first plot to emit a
rangecontrol. The kind was declared and unittested but never instantiated, so the widget path was unexercised; it works in
both the Matplotlib and ipywidgets backends. A
timesblock names the option itdrives, so a stored equilibrium's handful of slices keeps its radio buttons.
Discovery resolves the default instant the way the builder does — from the
magnetics, before the private copy that drops them — so opening the controls
does not move the figure.
What the plan asked for and measurement refused
The plan had
equilibrium_field_psi_vacuummove onto the same evaluator. Itshould not: on the 129×129 equilibrium grid that plot draws, the exact elliptic
kernels cost 18 s against the polynomial path's 5.8 s, and their cached matrices
would be 591 MB. That trade buys a slider, not a single figure. It stays where
it is, and the evaluator now refuses a grid whose response would not fit its
budget instead of quietly allocating half a gigabyte and keeping it.
Also here
vaft.formula.equilibrium:poloidal_field_magnitude,decay_index_from_bz(nanwhereB_Zvanishes,not a spike),
toroidal_electric_field(full weber in, per Formula psi helpers assume Wb/rad silently while the Green's functions return full Wb #354).magnetic_field, a newelectric_fieldquantity,and the decay index as dimensionless. Units are three vocabularies here, so
the existing
applies_togate offers the flux units only while flux is drawn._vacuum_sourcesfactored out ofcompute_point_response_matrices_ods, sothe cache key is derived from the same extraction the matrices are built from
rather than restated beside it.
The
idsdeclaration is load-bearingWith no
time=, the map is drawn at the breakdown onset, and that timing readsH-alpha from
spectrometer_uvalongside the plasma current. My first versionleft it out of the plot's
ids. The OMAS adapter hands over the whole ODS, soit never noticed; the IMAS adapter loads only declared IDSs, got no spectrometer
channels, and resolved an onset one PF sample earlier — during the ramp a 1.3%
difference in the drawn flux, not just the title.
test_imas_omas_plot_equivalencecaught it;
equilibrium_field_psi_vacuumhas declared both all along for thisreason, and a direct test now pins it.
30 new tests across
test_vacuum_field_map.pyandtest_vacuum_field_plot.py;the formula catalog count moves 107 → 110 for the three new kernels.
Test run
Full suite on this branch, rebased onto
399f4e13: 9855 passed, 1 failed. Theone failure is
test_flux_loop_voltage.py::test_legacy_flux_is_the_documented_voltage_composition,which fails identically on a clean checkout of
developand is the singlefailure in
develop's own Package CI at the same commit: #679 made a degeneratebaseline window raise, and that test still feeds a 2000-sample signal with the
default windows at samples 3499:5000 and 11999:15000. Not touched here; it needs
its own fix.
Part of #487.
🤖 Generated with Claude Code