Radial grid refinement via stages#

In this notebook we showcase how to perform radial grid refinement in GVEC by utilizing the stages functionality.

stages allows one to chain several GVEC runs together, always restarting from the previous solution. This option is especially useful, when each new restart only changes a few parameters from an original parameter set.

See also

See the stages section in the GVEC user guide(🌐) for more details.

We start again with the necessary imports and set the number of threads to use.

# set the number of OMP threads for gvec (needs to be before import of gvec)
import os

os.environ["OMP_NUM_THREADS"] = "2"
import gvec

Next we simply load the parameters from the .toml file written in the elliptic tokamak tutorial(🌐), and adapt them instead of specifying everything again.

params = gvec.util.read_parameters("elliptok_parameters.toml")

Add stages to parameter dictionary#

Note that:

  • The stages are specified as a list of dictionaries.

  • Each stage restarts from the solution of the previous stage.

  • If a parameter is specified within a stage, it overwrites the parameter from the main dictionary.

  • After the stage is passed, all parameters are reset to ones defined in the main dictionary

params["stages"] = [
    {"sgrid_nElems": 2, "minimize_tol": 5e-7},
    {"sgrid_nElems": 15, "minimize_tol": 2e-7},
    {"sgrid_nElems": 40, "minimize_tol": 1e-7},
]

The three stages defined above will ramp up minimize_tol and also increase the number of radial elements from \(2\) to \(15\) to \(40\). Therefore, each stage tries to find a better converged and more refined equilibrium solution. This ramping can help improve runtime, especially when the initial guess for the equilibrium is poor, e.g. during a cold start.

For potential use later on we can also write params again into a parameter file.

gvec.util.write_parameters(
    params, "radial_refinement_parameters.toml"
)

Lets run GVEC with the new stages! Note the change in the screen output compared to the previous runs.

runpath = "run_radial_refinement"
run = gvec.run(params, runpath=runpath)
GVEC - completed 0/3 stages: |>|.|.|
GVEC - completed 1/3 stages: |=|>|.|
GVEC - completed 2/3 stages: |=|=|>|
GVEC finished after   3.2 seconds  using 6162 iterations (totalIter = 10000)  with |force| = 9.92e-08 (minimize_tol = 1.00e-07)
  • To check everything went as expected we again have a look at the diagnostics.

  • In the visualization, the stages are indicated and the quantities are now plotted over the accumulated GVEC iteration number.

fig = run.plot_diagnostics_minimization()
../../_images/0e898b8b9c720368e6d19d3351c975a0f6b14fa466c215dacaec58a312deba75.png

The spikes in the forces after a restart can be attributed to the interpolation to the refined grid.


Run without stages#

Let us now compare this to a run without refinement stages. For this we just copy params and set the relevant parameters to the ones of the final stage.

params2 = params.copy()
del params2["stages"]
params2["sgrid_nElems"] = 40
params2["minimize_tol"] = 1e-7

runpath = "no_radial_refinement"
run = gvec.run(params2, runpath=runpath)

fig2 = run.plot_diagnostics_minimization()
GVEC - completed 0/2 stages: |>|.|
GVEC - completed 1/2 stages: |=|>|
GVEC finished after  13.4 seconds  using 8925 iterations (totalIter = 10000)  with |force| = 1.00e-07 (minimize_tol = 1.00e-07)
../../_images/a4aec7b26c75e0fba659bd007af3b04c16964130ea889772f061b60e98f4e863.png

As we can see, even for this simple tokamak case we save iterations and runtime using the ramping via stages since the main cost is in the iterations with the highest resolution.

To summarize, the stages functionality allows for running similar GVEC cases in succession and change only some few parameters. This can be used, for example, to perform radial refinement which might improve runtime.