The Open FUSION Toolkit 1.0.0-8905cc5
Modeling tools for plasma and fusion research and engineering
Loading...
Searching...
No Matches
MUG Example: Spheromak Heating

This example demonstrates the use of MUG to model self-heating of a spheromak in a unit cylinder. This process provides a simple example case illustrating the basic aspects of an MHD simulation, including: 1) Temperature dependent resistivity, 2) Anisotropic thermal conduction and 3) Ohmic and Viscous heating.

The dynamics in this example will be predominetly limited to heating. However, if the simulation is run long enough evolution of the equilibrium profile will be observed and eventual instability due to current peaking will occur.

Code Walk Through

The code consists of three basic sections, required imports and variable definitions, finite element setup, and system creation and solution.

Module Includes

The first thing that we must do is include the OFT modules which contain the required functions and variables. It is good practice to restrict the included elements to only those needed. This is done using the ONLY: clause to specifically include only certain definitions. The exceptions to this practice are the oft_local and oft_base modules, which contain a controlled set of commonly used elements that can be safely imported as a whole.

PROGRAM mug_sph_heat
!---Runtime
!---Grid
!---Linear algebra
!---Lagrange FE space
!---H1 FE space (Grad(H^1) subspace)
!---Full H(Curl) FE space
!---Physics
IMPLICIT NONE
Multigrid initialization using nested meshes.
Definition multigrid_build.F90:14
subroutine multigrid_add_quad(mg_mesh)
Add node points for quadratic elements.
Definition multigrid_build.F90:164
subroutine multigrid_construct(mg_mesh, grnd_pt)
Construct multi-level mesh.
Definition multigrid_build.F90:440
Multi-Level grid implementation using nested meshes.
Definition multigrid.F90:14
Base environment functions and aliases for Open FUSION Toolkit.
Definition oft_base.F90:23
Base scalar H^1 FE class and basis evaluation.
Definition h1_basis.F90:22
subroutine oft_h1_setup(mg_mesh, order, ml_h1_obj, ml_bh1_obj, minlev)
Construct H^1 scalar FE on each mesh level.
Definition h1_basis.F90:99
H^1 FE operator definitions.
Definition h1_operators.F90:22
subroutine oft_h1_getlop(fe_rep, mat, bc)
Construct laplacian matrix for H^1 scalar representation.
Definition h1_operators.F90:389
Base H(Curl) FE class and basis evaluation.
Definition hcurl_basis.F90:22
subroutine oft_hcurl_grad_setup(ml_hcurl_obj, ml_h1_obj, ml_hcurl_grad_obj, ml_h1grad_obj, minlev)
Construct a vector FE space for H(Curl) and it's compliment ( )
Definition hcurl_basis.F90:176
subroutine oft_hcurl_setup(mg_mesh, order, ml_hcurl_obj, ml_bhcurl_obj, minlev)
Construct H(Curl) FE basis on each mesh level.
Definition hcurl_basis.F90:104
FE operators for full H(Curl) + Grad(H^1) space.
Definition hcurl_grad_operators.F90:27
subroutine hcurl_grad_mc(mesh, a, hcpc, hcpv, new_tol)
Compute the 0-th order gradient due to a jump plane.
Definition hcurl_grad_operators.F90:600
Abstract vector and matrix interfaces.
Definition lin_alg_base.F90:20
Base Lagrange FE class and basis evaluation.
Definition lagrange_basis.F90:22
subroutine oft_lag_setup(mg_mesh, order, ml_lag_obj, ml_blag_obj, ml_vlag_obj, minlev)
Construct lagrange scalar FE on each mesh level.
Definition lagrange_basis.F90:317
Abstract solver interfaces and select native implementations.
Definition solver_base.F90:32
Matrix and vector management routines.
Definition solver_utils.F90:14
subroutine create_ilu_pre(pre)
Create ILU(0) preconditioner (native or MKL)
Definition solver_utils.F90:633
subroutine create_diag_pre(pre)
Needs docs.
Definition solver_utils.F90:619
subroutine create_bjacobi_pre(pre, nlocal)
Needs docs.
Definition solver_utils.F90:647
subroutine create_cg_solver(solver, force_native)
Needs docs.
Definition solver_utils.F90:437
Subroutines and fields for Taylor state calculations using mimetic operators.
Definition taylor.F90:21
subroutine taylor_hmodes(self, nm, rst_filename)
Compute 'taylor_nm' Force-Free eignemodes.
Definition taylor.F90:295
Module for modeling extended MHD with a mixed conforming/lagrange basis set.
Definition xmhd.F90:73
real(r8), public vel_scale
Velocity scale factor.
Definition xmhd.F90:346
type(oft_ml_fem_comp_type), pointer, public xmhd_ml_hcurl_grad
Definition xmhd.F90:395
real(r8), public temp_floor
Temperature floor.
Definition xmhd.F90:351
real(r8), public den_floor
Density floor.
Definition xmhd.F90:350
real(r8), public den_scale
Density scale factor.
Definition xmhd.F90:347
subroutine, public xmhd_run(initial_fields, driver, probes, profile_only)
Main driver subroutine for extended MHD time advance.
Definition xmhd.F90:554
type(oft_ml_fem_type), pointer, public xmhd_ml_lagrange
Definition xmhd.F90:391
type(oft_ml_fem_comp_type), pointer, public xmhd_ml_vlagrange
Definition xmhd.F90:396
type(oft_ml_fem_type), pointer, public xmhd_ml_h1
Definition xmhd.F90:392
integer(i4), public xmhd_taxis
Axis for toroidal flux and current.
Definition xmhd.F90:354
subroutine, public xmhd_plot(probes)
Plotting subroutine for xMHD post-processing.
Definition xmhd.F90:4562
type(oft_ml_fem_type), pointer, public xmhd_ml_hcurl
Definition xmhd.F90:394
type(oft_ml_fem_type), pointer, public xmhd_ml_h1grad
Definition xmhd.F90:393
Multigrid meshes and ML context structure.
Definition multigrid.F90:44
Needs docs.
Definition h1_operators.F90:76
Clean the divergence from a H(Curl) + Grad(H^1) vector field.
Definition hcurl_grad_operators.F90:103
Abstract matrix class.
Definition lin_alg_base.F90:566
Abstract vector class.
Definition lin_alg_base.F90:69
Base class for OFT solvers.
Definition solver_base.F90:99
Force-free, uniform eigenmode object.
Definition taylor.F90:75
Object for sub-fields used by oft_xmhd_push and oft_xmhd_pop.
Definition xmhd.F90:245

Local Variables

Next we define the local variables needed to initialize our case and run the time-dependent solve and post-processing.

!---H(Curl) divergence cleaner
CLASS(oft_solver), POINTER :: linv => null()
TYPE(oft_hcurl_grad_divout) :: divout
CLASS(oft_matrix), POINTER :: lop => null()
!---Local variables
INTEGER(i4) :: ierr,io_unit
REAL(r8), POINTER, DIMENSION(:) :: tmp => null()
TYPE(xmhd_sub_fields) :: ic_fields
TYPE(multigrid_mesh) :: mg_mesh
TYPE(oft_taylor_hmodes) :: taylor_states
TYPE(oft_h1_zerogrnd), TARGET :: h1_zerogrnd
!---Runtime options
INTEGER(i4) :: order = 2
REAL(r8) :: b0_scale = 1.e-1_r8
REAL(r8) :: n0 = 1.d19
REAL(r8) :: t0 = 6.d0
LOGICAL :: plot_run=.false.
LOGICAL :: pm=.false.
NAMELIST/sph_heat_options/order,b0_scale,n0,t0,plot_run,pm

OFT Initialization

See API Example 1: Helmholtz solve for a detailed description of calls in this section.

!---Read in options
OPEN(newunit=io_unit,file=oft_env%ifile)
READ(io_unit,sph_heat_options,iostat=ierr)
CLOSE(io_unit)
!------------------------------------------------------------------------------
! Setup grid
!------------------------------------------------------------------------------
CALL multigrid_construct(mg_mesh,[2.d0,0.d0,0.d0])
!------------------------------------------------------------------------------
! Build FE structures
!------------------------------------------------------------------------------
!--- Lagrange
CALL oft_lag_setup(mg_mesh,order,xmhd_ml_lagrange,ml_vlag_obj=xmhd_ml_vlagrange,minlev=-1)
!--- Grad(H^1) subspace
CALL oft_h1_setup(mg_mesh,order+1,xmhd_ml_h1,minlev=-1)
!--- H(Curl) subspace
CALL oft_hcurl_setup(mg_mesh,order,xmhd_ml_hcurl,minlev=-1)
!--- Full H(Curl) space
h1_zerogrnd%ML_H1_rep=>xmhd_ml_h1grad
type(oft_env_type) oft_env
Global container for environment information.
Definition oft_base.F90:145
subroutine oft_init(nthreads)
Initializes Open FUSION Toolkit run environment.
Definition oft_base.F90:193

Perform post-processing

To visualize the solution fields once a simulation has completed the xmhd_plot subroutine is used. This subroutine steps through the restart files produced by xmhd_run and generates plot files, and optionally probe signals at evenly spaced points in time as specified in the input file, see xmhd_plot and Post-Processing options.

IF(plot_run)THEN
!---Run post-processing routine
CALL xmhd_plot
!---Finalize enviroment and exit
CALL oft_finalize()
END IF
subroutine oft_finalize()
Finalize Open FUSION Toolkit environment.
Definition oft_base.F90:356

Computing Initial Conditions

For this simulation we only need the spheromak mode, which is the lowest force-free eignstate in this geometry. As a result the initial condition is stable to all types of mode activity.

CALL taylor_states%setup(xmhd_ml_hcurl,xmhd_ml_lagrange)
CALL taylor_hmodes(taylor_states,1)
CALL xmhd_ml_lagrange%set_level(xmhd_ml_lagrange%nlevels)

As in MUG Example: Spheromak Tilt we must transform the gauge of the Taylor state solution to the appropriate magnetic field BCs. For more information on this see the description in Computing Initial Conditions of that example.

!------------------------------------------------------------------------------
! Create divergence cleaner
!------------------------------------------------------------------------------
NULLIFY(lop)
CALL oft_h1_getlop(xmhd_ml_h1%current_level,lop,"grnd")
CALL create_cg_solver(linv)
linv%A=>lop
linv%its=-2
!---Setup Preconditioner
CALL create_bjacobi_pre(linv%pre,-1)
DEALLOCATE(linv%pre%pre)
CALL create_ilu_pre(linv%pre%pre)
divout%solver=>linv
divout%bc=>h1_zerogrnd
divout%keep_boundary=.true.
!------------------------------------------------------------------------------
! Setup initial conditions
!------------------------------------------------------------------------------
CALL xmhd_ml_hcurl_grad%vec_create(ic_fields%B)
CALL taylor_states%hffa(1,xmhd_ml_hcurl%level)%f%get_local(tmp)
CALL ic_fields%B%restore_local(tmp,1)
CALL divout%apply(ic_fields%B)
NULLIFY(divout%solver)
CALL divout%delete()
CALL linv%pre%pre%delete()
DEALLOCATE(linv%pre%pre)
CALL linv%pre%delete()
DEALLOCATE(linv%pre)
CALL linv%delete()
DEALLOCATE(linv)

Now we set initial conditions for the simulation using the computed taylor state, flat temperature and density profiles and zero initial velocity. The lower bound for density (den_floor) and temperature (temp_floor) in the simulation are also set. These variables act to prevent very low density and negative temperature regions in the simulation. The scale factors for the velocity (vel_scale) and density (den_scale) evolution equations are also set. These variables are used to scale the corresponding rows in the non-linear and linear operators to provide even weighting in the residual calculations. In general these scale factors should be set to the order of magnitude expected for the corresponding variables, \( km/s \) and \( 10^{19} m^{-3} \) in this simulation.

CALL ic_fields%B%scale(b0_scale*taylor_states%hlam(1,xmhd_ml_hcurl%level))
!---Clean up temporary matrices and fields
CALL lop%delete
DEALLOCATE(tmp,lop)
!---Create velocity field
CALL xmhd_ml_vlagrange%vec_create(ic_fields%V)
vel_scale = 1.d3
!---Create density field
CALL xmhd_ml_lagrange%vec_create(ic_fields%Ne)
CALL ic_fields%Ne%set(n0)
den_scale = n0
den_floor = n0*1.d-2
!---Create temperature field
CALL xmhd_ml_lagrange%vec_create(ic_fields%Ti)
CALL ic_fields%Ti%set(t0)
temp_floor = t0*1.d-2

Run Simulation

Finally, the simulation can be run using the driver routine for non-linear extended MHD (xmhd_run). This routine advances the solution in time with the physics specified in the input file, see the documentation for xmhd_run, and produces restart files that contain the solution at different times.

Several quantities are also recorded to a history file xmhd.hist during the simulation, including the toroidal current (where the symmetry axis is specified by xmhd_taxis). The data in the history file may be plotted using the script plot_mug_hist.py, which is located in src/utilities/scripts or python directories for the repository and an installation respectively.

Note
OFT plotting scripts require the python packages numpy and matplotlib as well as path access to the python modules provided in python for installations or src/utilities in the repo.

To visualize the solution fields once a simulation has completed the xmhd_plot subroutine is used. This subroutine steps through the restart files produced by xmhd_run and generates plot files, and optionally probe signals at evenly spaced points in time as specified in the input file, see xmhd_plot.

xmhd_taxis=3
oft_env%pm=pm
!---Run simulation
CALL xmhd_run(ic_fields)
!---Finalize enviroment
END PROGRAM MUG_sph_heat
void oft_finalize()

Input file

Below is an input file which can be used with this example in a parallel environment. As with Example 5 this example should only be run with multiple processes. Some annotation of the options is provided inline below, for more information on the available options in the xmhd_options group see xmhd_plot.

&runtime_options
 ppn=1
 debug=0
/

&mesh_options
 meshname='test'
 cad_type=0
 nlevels=2
 nbase=1
 grid_order=2
 fix_boundary=T
/

&native_mesh_options
 filename='cyl_heat.h5'
/

&sph_heat_options
 order=3
 b0_scale=1.e-1
 n0=1.e19
 t0=6.
 plot_run=F
/

&xmhd_options
 xmhd_ohmic=T      ! Include Ohmic heating
 xmhd_visc_heat=T  ! Include viscous heating
 bbc='bc'          ! Perfectly-conducting BC for B-field
 vbc='all'         ! Zero-flow BC for velocity
 nbc='d'           ! Dirichlet BC for density
 tbc='d'           ! Dirichlet BC for temperature
 dt=2.e-7          ! Maximum time step
 eta=25.           ! Resistivity at reference temperature (Spitzer-like)
 eta_temp=6.       ! Reference temperature for resistivity
 nu_par=400.       ! Fluid viscosity
 d_dens=10.        ! Density diffusion
 kappa_par=1.E4    ! Parallel thermal conduction (fixed)
 kappa_perp=1.E2   ! Perpendicular thermal conduction (fixed)
 nsteps=2000       ! Number of time steps to take
 rst_freq=10       ! Restart file frequency
 lin_tol=1.E-9     ! Linear solver tolerance
 nl_tol=1.E-5      ! Non-linear solver tolerance
 xmhd_mfnk=T       ! Use matrix-free Jacobian operator
 rst_ind=0         ! Index of file to restart from (0 -> use subroutine arguments)
 ittarget=40       ! Target for # of linear iterations per time step
 mu_ion=2.         ! Ion mass (atomic units)
 xmhd_prefreq=20   ! Preconditioner update frequency
/

Solver specification

Time dependent MHD solvers are accelerated significantly by the use of a more sophisticated preconditioner than the default method. Below is an example oft_in.xml file that constructs an appropriate ILU(0) preconditioner. Currently, this preconditioner method is the suggested starting preconditioner for all time-dependent MHD solves.

<oft>
<xmhd>
<pre type="gmres">
<its>8</its>
<nrits>8</nrits>
<pre type="block_jacobi">
<nlocal>-1</nlocal>
<solver type="ilu"></solver>
</pre>
</pre>
</xmhd>
</oft>

This solver can be used by specifying both the FORTRAN input and XML input files to the executable as below.

~$ ./MUG_sph_heat oft.in oft_in.xml

Post-Processing options

During the simulation the evolution of some global quantities is written to the history file xmhd.hist. A utility script (plot_mug_hist.py located in bin after installation) is included as part of OFT for plotting the signals in this file. This is useful for monitoring general progress of the simulation as well as numerical parameters like the iteration count and solver time. Using this script we can see the increase in the average temperature in time and a brief velocity transient early in time as equilibrium adjusts slightly to be consistent with the magnetic BCs used in the simulation.

~$ python plot_mug_hist.py xmhd.hist
Time evolution of volume averaged temperature, showing heating due to Ohmic dissipation of current.
Time evolution of kinetic energy throughout simulation, showing an initial transient that damps away.

Creating plot files

To generate 3D plots, and perform additional diagnostic sampling (see oft_xmhd_probe), a plot run can be performed by setting plot_run=T in the sph_tilt_options input group, which calls xmhd_plot. With this option additional run time options are available in the xmhd_plot_options group that control how restart files are sampled for plotting.

&xmhd_plot_options
 t0=1.E-8
 dt=1.E-5
 rst_start=0
 rst_end=2000
/

Once the post-processing run is complete bin/build_xdmf.py can be used to generate *.xmf files that can be loaded by VisIt, ParaView, or other visualization programs.

Resulting temperature distribution (shading) and magnetic field (vectors) at the end of the simulation, showing thermal confinement in the core of the torus.

Mesh Creation

A mesh file cyl_heat.h5 is provided with this example. Instructions to generate your own mesh for the geometry using CUBIT and GMSH.

Meshing with CUBIT

A suitable mesh for this example, with radius of 1m and height of 1m, can be created using the CUBIT script below.

reset

create Cylinder height 1 radius 1

volume 1 scheme Tetmesh
set tetmesher interior points on
set tetmesher optimize level 3 optimize overconstrained  off sliver  off
set tetmesher boundary recovery  off
volume 1 size .2
mesh volume 1

set duplicate block elements off
block 1 add volume 1 
block 1 element type tetra10

set large exodus file on
export Genesis  "cyl_heat.g" overwrite block 1

Once complete the mesh should be converted into the native mesh format using the convert_cubit.py script as below. The script is located in bin following installation or src/utilities in the base repo.

~$ python convert_cubit.py --in_file=cyl_heat.g

Meshing with Gmsh

If the CUBIT mesh generation codes is not avilable the mesh can be created using the Gmsh code and the geometry script below.

Coherence;
Point(1) = {0, 0, 0, 1.0};
Point(2) = {1, 0, 0, 1.0};
Point(3) = {0, 1, 0, 1.0};
Point(4) = {-1, 0, 0, 1.0};
Point(5) = {0, -1, 0, 1.0};
Circle(1) = {2, 1, 3};
Circle(2) = {3, 1, 4};
Circle(3) = {4, 1, 5};
Circle(4) = {5, 1, 2};
Line Loop(5) = {2, 3, 4, 1};
Plane Surface(6) = {5};
Extrude {0, 0, 1} {
  Surface{6};
}

To generate a mesh, with resolution matching the Cubit example above, place the script contents in a file called cyl_heat.geo and run the following command.

~$ gmsh -3 -format mesh -optimize -clscale .2 -order 2 -o cyl_heat.mesh cyl_heat.geo

Once complete the mesh should be converted into the native mesh format using the convert_gmsh.py script as below. The script is located in bin following installation or src/utilities in the base repo.

~$ python convert_gmsh.py --in_file=cyl_heat.mesh

Complete Source

PROGRAM mug_sph_heat
!---Runtime
!---Grid
!---Linear algebra
!---Lagrange FE space
!---H1 FE space (Grad(H^1) subspace)
!---Full H(Curl) FE space
!---Physics
IMPLICIT NONE
!------------------------------------------------------------------------------
! Local Variables
!------------------------------------------------------------------------------
!---H(Curl) divergence cleaner
CLASS(oft_solver), POINTER :: linv => null()
TYPE(oft_hcurl_grad_divout) :: divout
CLASS(oft_matrix), POINTER :: lop => null()
!---Local variables
INTEGER(i4) :: ierr,io_unit
REAL(r8), POINTER, DIMENSION(:) :: tmp => null()
TYPE(xmhd_sub_fields) :: ic_fields
TYPE(multigrid_mesh) :: mg_mesh
TYPE(oft_taylor_hmodes) :: taylor_states
TYPE(oft_h1_zerogrnd), TARGET :: h1_zerogrnd
!---Runtime options
INTEGER(i4) :: order = 2
REAL(r8) :: b0_scale = 1.e-1_r8
REAL(r8) :: n0 = 1.d19
REAL(r8) :: t0 = 6.d0
LOGICAL :: plot_run=.false.
LOGICAL :: pm=.false.
NAMELIST/sph_heat_options/order,b0_scale,n0,t0,plot_run,pm
!------------------------------------------------------------------------------
! OFT Initialization
!------------------------------------------------------------------------------
!---Read in options
OPEN(newunit=io_unit,file=oft_env%ifile)
READ(io_unit,sph_heat_options,iostat=ierr)
CLOSE(io_unit)
!------------------------------------------------------------------------------
! Setup grid
!------------------------------------------------------------------------------
CALL multigrid_construct(mg_mesh,[2.d0,0.d0,0.d0])
!------------------------------------------------------------------------------
! Build FE structures
!------------------------------------------------------------------------------
!--- Lagrange
CALL oft_lag_setup(mg_mesh,order,xmhd_ml_lagrange,ml_vlag_obj=xmhd_ml_vlagrange,minlev=-1)
!--- Grad(H^1) subspace
CALL oft_h1_setup(mg_mesh,order+1,xmhd_ml_h1,minlev=-1)
!--- H(Curl) subspace
CALL oft_hcurl_setup(mg_mesh,order,xmhd_ml_hcurl,minlev=-1)
!--- Full H(Curl) space
h1_zerogrnd%ML_H1_rep=>xmhd_ml_h1grad
!------------------------------------------------------------------------------
! Perform post-processing
!------------------------------------------------------------------------------
IF(plot_run)THEN
!---Run post-processing routine
CALL xmhd_plot
!---Finalize enviroment and exit
CALL oft_finalize()
END IF
!------------------------------------------------------------------------------
! Computing Initial Conditions
!------------------------------------------------------------------------------
CALL taylor_states%setup(xmhd_ml_hcurl,xmhd_ml_lagrange)
CALL taylor_hmodes(taylor_states,1)
CALL xmhd_ml_lagrange%set_level(xmhd_ml_lagrange%nlevels)
!------------------------------------------------------------------------------
! Create divergence cleaner
!------------------------------------------------------------------------------
NULLIFY(lop)
CALL oft_h1_getlop(xmhd_ml_h1%current_level,lop,"grnd")
CALL create_cg_solver(linv)
linv%A=>lop
linv%its=-2
!---Setup Preconditioner
CALL create_bjacobi_pre(linv%pre,-1)
DEALLOCATE(linv%pre%pre)
CALL create_ilu_pre(linv%pre%pre)
divout%solver=>linv
divout%bc=>h1_zerogrnd
divout%keep_boundary=.true.
!------------------------------------------------------------------------------
! Setup initial conditions
!------------------------------------------------------------------------------
CALL xmhd_ml_hcurl_grad%vec_create(ic_fields%B)
CALL taylor_states%hffa(1,xmhd_ml_hcurl%level)%f%get_local(tmp)
CALL ic_fields%B%restore_local(tmp,1)
CALL divout%apply(ic_fields%B)
NULLIFY(divout%solver)
CALL divout%delete()
CALL linv%pre%pre%delete()
DEALLOCATE(linv%pre%pre)
CALL linv%pre%delete()
DEALLOCATE(linv%pre)
CALL linv%delete()
DEALLOCATE(linv)
CALL ic_fields%B%scale(b0_scale*taylor_states%hlam(1,xmhd_ml_hcurl%level))
!---Clean up temporary matrices and fields
CALL lop%delete
DEALLOCATE(tmp,lop)
!---Create velocity field
CALL xmhd_ml_vlagrange%vec_create(ic_fields%V)
vel_scale = 1.d3
!---Create density field
CALL xmhd_ml_lagrange%vec_create(ic_fields%Ne)
CALL ic_fields%Ne%set(n0)
den_floor = n0*1.d-2
!---Create temperature field
CALL xmhd_ml_lagrange%vec_create(ic_fields%Ti)
CALL ic_fields%Ti%set(t0)
temp_floor = t0*1.d-2
!------------------------------------------------------------------------------
! Run Simulation
!------------------------------------------------------------------------------
oft_env%pm=pm
!---Run simulation
CALL xmhd_run(ic_fields)
!---Finalize enviroment
END PROGRAM MUG_sph_heat