Measure the discretization by the method of manufactured solutions - #784
Open
CharlesCNorton wants to merge 7 commits into
Open
Measure the discretization by the method of manufactured solutions#784CharlesCNorton wants to merge 7 commits into
CharlesCNorton wants to merge 7 commits into
Conversation
Contributor
Author
|
fixing ci and other things |
…force-source installer const
…t-in and restart-safe
… and warm the vacuum before the free-boundary solve
…rton/vmecpp into manufactured-solution
# Conflicts: # src/vmecpp/cpp/vmecpp/vmec/pybind11/pybind_vmec.cc
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.
Reference tests compare against Fortran VMEC, which cannot say whether either code converges to the continuum problem. This measures it: an analytic mapping is made the exact solution of a modified problem by installing the negative of its continuum ideal-MHD force as a source, so the distance from the solver to the mapping is discretization error.
Change
IdealMhdModel::SetForceSourceadds a fixed spectral force to the decomposed force, before the m = 1 gauge rotation. It is refused unless the input sets the newenable_force_source, and it is reinstalled after everyInitializeRadial, which an axis reguess and each multi-grid step trigger.VmecModel.set_state_from_fouriergoes throughFourierGeometry::InitFromState, the routine a hot restart already uses, so the basis conventions keep one implementation.Measured
examples/manufactured_solution.py: helical axis, rotating ellipse, non-trivial lambda;nfp = 3, aspect ratio 18,beta(0) = 2per cent,mpol = 5,ntor = 3, 24 x 24. Errors are relative L2 overs >= 0.1.Angular error falls by 9.4 for every two grid points, from 3.2e-06 at 16 x 16 to 4.2e-11 at 26 x 26. The source drops the force at the mapping by 5.4e+04 at
ns = 25and 7.9e+06 atns = 201, and the solve reachesfsq = 1.5e-16at every resolution.The m = 0 lambda is the exception. Its force is second order, 8.5e-09 at
ns = 201, while its state error sits at 1e-02 and does not fall, so this is conditioning rather than consistency.FourierGeometry::extrapolateTowardsAxiscopies that component from the first interior surface onto the axis, and the force transform does not transpose the copy.Asymmetric and constrained current
The mapping gains a sine series in R and a cosine series in Z and lambda at m <= 1, obeying
RSC_{1n} = ZCC_{1n}: 2.01 for the R, Z force and 2.04 for lambda, with the source cancelling by 4.8e+07 atns = 201. The symmetric mapping run through the asymmetric path reproduces the symmetric energy error exactly at every resolution.With
ncurr = 1the solver solveschi'fromcurrH(s) = <B_u>(s)instead of reading an iota profile. Prescribing the mapping's own<B_u>as acubic_spline_iprofile returns its iota and leaves the order unchanged at 2.01.Free boundary
only_coilstakes the vacuum field from the mgrid with no Laplace solve, and a field bilinear in (R, Z) is interpolated exactly, so the vacuum pressure is analytic. At the last radial node only the half-grid cell inside the boundary exists, so the force there is(1/ds) dw/dx_s + (1/2) EL(w) + edge, whose first and third terms are the pressure jump(1/ds) R (p_total - p_vac) (z_u, -r_u).The edge condition is second order, like the volume. There is no free-boundary counterpart to the solved-state column above: the free-boundary descent limit-cycles around
fsq = 1e-09for 40000 iterations, where the fixed-boundary one reaches 1.5e-16, so the state it stops at is not a solution of the modified problem.Tests
Thirteen Python tests in 8 seconds pin the orders, the rejections and the free-boundary edge;
//vmecpp/vmec/vmec:force_source_testholds the source's effect on the assembled force to within 1e-12 of the source itself across 1, 2, 4 and 8 radial threads, which a source landing on the wrong surfaces would miss by its own size.sympyis a test extra and the module skips without it;scipyis needed only by--study fit.