Hand every force iteration to a callback and watch a solve converge - #839
Open
CharlesCNorton wants to merge 2 commits into
Open
Hand every force iteration to a callback and watch a solve converge#839CharlesCNorton wants to merge 2 commits into
CharlesCNorton wants to merge 2 commits into
Conversation
|
Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits. |
…example without a display
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.
Change -
vmecpp.runtakes aniteration_callback, called once per force iteration from the master thread with anIterationSnapshot: the iteration counter and multigrid stage,ns, the three invariant residuals and the stage'sftol, the time step, the restart reason, the Jacobian-reset count, whether the vacuum pressure is in the force balance, the MHD energy, and the R, Z and lambda coefficients of the state as aGeometry. ReturningFalsestops the run, which returns the state reached withier_flag = 2, VMEC 8.52'smore_iter_flag, added asVmecStatus::MORE_ITERATIONS_NEEDED.vmecpp.watch(input)sits on it: the same solve asrun, drawn while it runs as the flux surfaces at a few toroidal angles above the residual trace, with the multigrid stages and the restarts marked, into a window, a.gifor video file, or both; closing the window stops the solve. On the C++ siderun,Vmec::FromIndataand the constructor take anIterationCallbackbeside the interrupt callback,GatherSpectralStateFromThreadscollects the spectral state and the flux profiles without the real-space fields and shares its per-surface copy with the full gather, andMakeGeometryturns that into the snapshot's geometry.Cause - the loop offered no view of an iteration: the residual history after the fact and the printout every
nstep. The geometry of an iteration was reachable only through the Python-owned single-thread loop, which does not run free-boundary cases.Evidence -
examples/data/solovev.json(every 10th iteration), the free-boundarycth_like_free_bdy(every 4th) andexamples/data/w7x.json(every 20th), recorded withvmecpp.watch:The snapshot is a copy of the spectral state and one Python call, about a millisecond per iteration:
cth_like_fixed_bdytakes 0.57 s without and 0.67 s with a callback that stores every snapshot,cth_like_fixed_bdy_asym1.34 s and 1.39 s. A drawn frame costs 60 ms.Tests -
IterationCallbackSeesEveryIterationAndCanStopinvmec_test: one snapshot per entry of the residual history with bit-identical residuals, one converged snapshot per multigrid stage whose geometry equals the output's, and a stop at iteration 20 that returnsns_array[0]withier_flag2.tests/test_watch.py: the same through Python on solovev and the symmetric and asymmetric cth cases, an exception raised in the callback propagating, the drawn cross-sections againstvmecpp.geometry.evaluateon every surface to 1e-12, the frame count of a recorded animation, the stop when the window closes, and the refusal to run with neither a window nor a file.bazel test --config=opt //vmecpp/...andpytestpass.Scope - without a callback nothing changes: no barrier is added to the loop and the outputs are the ones the existing tests compare.
matplotlibis imported insidewatch, so it stays an optional dependency; the README gains a paragraph andexamples/watch_solve.pyrecords or shows a solve from the command line.