Magnetostatic Problem on a Topologically Closed Conductor
Summary
Solves for the magnetic field around a topologically closed toroidal conductor carrying a net current, using a magnetic vector potential discretized using conforming Nédélec elements, following the method described in P. Dular, International Compumag Society Newsletter, 7, no. 2 (2000): 4-7. for enforcing global constraints.
Description
This problem solves the magnetostatic problem with strong form:
with the constitutive relations
where is the magnetic flux density, is the magnetic field, is the current density, is the electric field, is the externally applied electric field, is the material permeability, is the material resistivity, and is the material conductivity. To enforce the divergence free condition on , we shall also introduce the magnetic vector potential defined such that .
In addition, we wish to impose a global voltage constraint on a toroidal conductor domain of the form
where is any path traversing around the conductor lying entirely within with winding number equal to one, and is the loop voltage imposed on the conductor.
In a simply connected domain, satisfying can be achieved by introducing a continuous single-valued scalar electric potential such that . However, in order for the electric field to be nonzero circulating the closed conductor, this is no longer sufficient, since . We shall therefore represent the electric field by
With this, we can arrive at the weak form for we intend to solve, of the form
where
Discretizing the External Electric Field
We must now find a suitable choice of basis for the external electric field, such that
for some unique set of degrees of freedom . We shall also wish to restrict the support of to the smallest number of elements possible in to minimise the number of degrees of freedom required to represent .
To do this, we first identify a 'cut' surface of the toroidal conductor that is required to make it simply connected. Next, we define a one element wide 'transition' region on one side of the cut surface, using an MFEMCutTransitionSubMesh
object, comprised of all elements with at least one vertex lying on the cut surface that lie on one side of the cut.
Next, to enforce in this region, we define a scalar field variable defined on a (nodal) conforming finite element space on this submesh such that :
so .
Finally, to impose the global voltage constraint , we identify that
since outside . The loop voltage constraint is thus strongly imposed by Dirichlet conditions on , setting on and on . For lowest order conforming representations of , this fully constrains in the transition region.
This is shown explicitly in the example file:
# Solve for the electric field on a closed conductor subject to
# global loop voltage constraint.
initial_coil_domains = 'TorusCore TorusSheath'
coil_cut_surface = 'Cut'
coil_loop_voltage = -1.0
coil_conductivity = 1.0
[Problem<<<{"href": "../Problem/index.html"}>>>]
type = MFEMProblem
[]
[Mesh<<<{"href": "../Mesh/index.html"}>>>]
type = MFEMMesh
file = ../mesh/embedded_concentric_torus.e
[]
[FunctorMaterials<<<{"href": "../FunctorMaterials/index.html"}>>>]
[Conductor]
type = MFEMGenericFunctorMaterial
prop_names = conductivity
prop_values = ${coil_conductivity}
[]
[]
[ICs<<<{"href": "../ICs/index.html"}>>>]
[coil_external_potential_ic]
type = MFEMScalarBoundaryIC
variable = coil_external_potential
boundary = ${coil_cut_surface}
coefficient = ${coil_loop_voltage}
[]
[]
[SubMeshes]
[cut]
type = MFEMCutTransitionSubMesh
cut_boundary = ${coil_cut_surface}
block = ${initial_coil_domains}
transition_subdomain = transition_dom
transition_subdomain_boundary = transition_bdr
closed_subdomain = coil_dom
[]
[coil]
type = MFEMDomainSubMesh
block = coil_dom
execution_order_group = 2
[]
[]
[FESpaces]
[H1FESpace]
type = MFEMScalarFESpace
fec_type = H1
fec_order = FIRST
[]
[HCurlFESpace]
type = MFEMVectorFESpace
fec_type = ND
fec_order = FIRST
[]
[CoilH1FESpace]
type = MFEMScalarFESpace
fec_type = H1
fec_order = FIRST
submesh = coil
[]
[CoilHCurlFESpace]
type = MFEMVectorFESpace
fec_type = ND
fec_order = FIRST
submesh = coil
[]
[TransitionH1FESpace]
type = MFEMScalarFESpace
fec_type = H1
fec_order = FIRST
submesh = cut
[]
[TransitionHCurlFESpace]
type = MFEMVectorFESpace
fec_type = ND
fec_order = FIRST
submesh = cut
[]
[]
[Variables<<<{"href": "../Variables/index.html"}>>>]
[coil_induced_potential]
type = MFEMVariable
fespace = CoilH1FESpace
[]
[]
[AuxVariables<<<{"href": "../AuxVariables/index.html"}>>>]
[coil_external_potential]
type = MFEMVariable
fespace = CoilH1FESpace
[]
[transition_external_potential]
type = MFEMVariable
fespace = TransitionH1FESpace
[]
[transition_external_e_field]
type = MFEMVariable
fespace = TransitionHCurlFESpace
[]
[induced_potential]
type = MFEMVariable
fespace = H1FESpace
[]
[induced_e_field]
type = MFEMVariable
fespace = HCurlFESpace
[]
[external_e_field]
type = MFEMVariable
fespace = HCurlFESpace
[]
[e_field]
type = MFEMVariable
fespace = HCurlFESpace
[]
[]
[AuxKernels<<<{"href": "../AuxKernels/index.html"}>>>]
[update_induced_e_field]
type = MFEMGradAux
variable = induced_e_field
source = induced_potential
scale_factor = -1.0
execute_on = TIMESTEP_END
[]
[update_external_e_field]
type = MFEMGradAux
variable = transition_external_e_field
source = transition_external_potential
scale_factor = -1.0
execute_on = TIMESTEP_END
[]
[update_total_e_field]
type = MFEMSumAux
variable = e_field
first_source_variable = induced_e_field
second_source_variable = external_e_field
execute_on = TIMESTEP_END
execution_order_group = 3
[]
[]
[Kernels<<<{"href": "../Kernels/index.html"}>>>]
[diff]
type = MFEMDiffusionKernel
variable = coil_induced_potential
coefficient = conductivity
[]
[source]
type = MFEMMixedGradGradKernel
trial_variable = coil_external_potential
variable = coil_induced_potential
coefficient = conductivity
block = 'transition_dom'
[]
[]
[Solver]
type = MFEMSuperLU
[]
[Executioner<<<{"href": "../Executioner/index.html"}>>>]
type = MFEMSteady
[]
[Transfers<<<{"href": "../Transfers/index.html"}>>>]
[submesh_transfer_from_coil]
type = MFEMSubMeshTransfer
from_variable = coil_induced_potential
to_variable = induced_potential
execute_on = TIMESTEP_END
[]
[submesh_transfer_to_transition]
type = MFEMSubMeshTransfer
from_variable = coil_external_potential
to_variable = transition_external_potential
execute_on = TIMESTEP_END
[]
[submesh_transfer_from_transition]
type = MFEMSubMeshTransfer
from_variable = transition_external_e_field
to_variable = external_e_field
execute_on = TIMESTEP_END
execution_order_group = 2
[]
[]
[Outputs<<<{"href": "../Mastodon/Outputs/index.html"}>>>]
[GlobalParaViewDataCollection]
type = MFEMParaViewDataCollection
file_base = OutputData/WholePotentialCoil
vtk_format = ASCII
[]
[TransitionParaViewDataCollection]
type = MFEMParaViewDataCollection
file_base = OutputData/CutPotentialCoil
vtk_format = ASCII
submesh = cut
[]
[CoilParaViewDataCollection]
type = MFEMParaViewDataCollection
file_base = OutputData/Coil
vtk_format = ASCII
submesh = coil
[]
[]
(moose/test/tests/mfem/submeshes/cut_closed_coil.i)Solving for the Total Electric Field
With now constrained, we now must solve for the remaining degrees of freedom in arising due to surface charges in the coil as required for continuity of current in the conductor (), by solving
for . We then can calculate the total electric field from the sum of its induced and external components.
Solving for the Magnetic Flux Density
Finally, with the electric field in the conductor, we can now find the magnetic flux density around the current density flowing in the coil in the magnetostatic limit.
This is typically solved using HypreAMS
as a preconditioner. Note that the above magnetostatic problem is singular in non-conductive regions, and thus either singular = true
should be passed to the preconditioner or a small mass term with should be added for stability.
Example File
The full closed coil magnetostatic example detailed above can be found below:
# Magnetostatic problem solved on a closed conductor subject to
# global loop voltage constraint.
[Mesh<<<{"href": "../Mesh/index.html"}>>>]
type = MFEMMesh
file = ../mesh/embedded_concentric_torus.e
[]
[Problem<<<{"href": "../Problem/index.html"}>>>]
type = MFEMProblem
[]
[FESpaces]
[HCurlFESpace]
type = MFEMVectorFESpace
fec_type = ND
fec_order = FIRST
[]
[HDivFESpace]
type = MFEMVectorFESpace
fec_type = RT
fec_order = CONSTANT
[]
[]
[Variables<<<{"href": "../Variables/index.html"}>>>]
[a_field]
type = MFEMVariable
fespace = HCurlFESpace
[]
[]
[AuxVariables<<<{"href": "../AuxVariables/index.html"}>>>]
[b_field]
type = MFEMVariable
fespace = HDivFESpace
[]
[e_field]
type = MFEMVariable
fespace = HCurlFESpace
[]
[]
[AuxKernels<<<{"href": "../AuxKernels/index.html"}>>>]
[curl]
type = MFEMCurlAux
variable = b_field
source = a_field
scale_factor = 1.0
execute_on = TIMESTEP_END
execution_order_group = 3
[]
[]
[Functions<<<{"href": "../Functions/index.html"}>>>]
[exact_a_field]
type = ParsedVectorFunction<<<{"description": "Returns a vector function based on string descriptions for each component.", "href": "../../source/functions/MooseParsedVectorFunction.html"}>>>
expression_x<<<{"description": "x-component of function."}>>> = '0'
expression_y<<<{"description": "y-component of function."}>>> = '0'
expression_z<<<{"description": "z-component of function."}>>> = '0'
[]
[]
[BCs<<<{"href": "../BCs/index.html"}>>>]
[tangential_a_bdr]
type = MFEMVectorTangentialDirichletBC
variable = a_field
vector_coefficient = exact_a_field
boundary = 'Exterior'
[]
[]
[FunctorMaterials<<<{"href": "../FunctorMaterials/index.html"}>>>]
[Vacuum]
type = MFEMGenericFunctorMaterial
prop_names = reluctivity
prop_values = 1.0
[]
[Conductor]
type = MFEMGenericFunctorMaterial
prop_names = conductivity
prop_values = 1.0
block = 'TorusCore TorusSheath'
[]
[]
[Kernels<<<{"href": "../Kernels/index.html"}>>>]
[mass]
type = MFEMVectorFEMassKernel
variable = a_field
coefficient = 1e-10
[]
[curlcurl]
type = MFEMCurlCurlKernel
variable = a_field
coefficient = reluctivity
[]
[source]
type = MFEMMixedVectorMassKernel
variable = a_field
trial_variable = e_field
coefficient = conductivity
block = 'TorusCore TorusSheath'
[]
[]
[Preconditioner]
[ams]
type = MFEMHypreAMS
fespace = HCurlFESpace
[]
[]
[Solver]
type = MFEMHyprePCG
preconditioner = ams
l_tol = 1e-14
l_max_its = 1000
[]
[Executioner<<<{"href": "../Executioner/index.html"}>>>]
type = MFEMSteady
device = cpu
[]
[MultiApps<<<{"href": "../MultiApps/index.html"}>>>]
[coil]
type = FullSolveMultiApp<<<{"description": "Performs a complete simulation during each execution.", "href": "../../source/multiapps/FullSolveMultiApp.html"}>>>
input_files<<<{"description": "The input file for each App. If this parameter only contains one input file it will be used for all of the Apps. When using 'positions_from_file' it is also admissable to provide one input_file per file."}>>> = cut_closed_coil.i
execute_on<<<{"description": "The list of flag(s) indicating when this object should be executed. For a description of each flag, see https://mooseframework.inl.gov/source/interfaces/SetupInterface.html."}>>> = INITIAL
[]
[]
[Transfers<<<{"href": "../Transfers/index.html"}>>>]
[from_coil]
type = MultiAppMFEMCopyTransfer
source_variable = e_field
variable = e_field
from_multi_app = coil
[]
[]
[Postprocessors<<<{"href": "../Postprocessors/index.html"}>>>]
[CoilPower]
type = MFEMVectorFEInnerProductIntegralPostprocessor
coefficient = conductivity
dual_variable = e_field
primal_variable = e_field
block = 'TorusCore TorusSheath'
[]
[]
[Outputs<<<{"href": "../Mastodon/Outputs/index.html"}>>>]
[ParaViewDataCollection]
type = MFEMParaViewDataCollection
file_base = OutputData/MagnetostaticClosedCoil
vtk_format = ASCII
[]
[ReportedPostprocessors]
type = CSV<<<{"description": "Output for postprocessors, vector postprocessors, and scalar variables using comma seperated values (CSV).", "href": "../../source/outputs/CSV.html"}>>>
file_base<<<{"description": "The desired solution output name without an extension. If not provided, MOOSE sets it with Outputs/file_base when available. Otherwise, MOOSE uses input file name and this object name for a master input or uses master file_base, the subapp name and this object name for a subapp input to set it."}>>> = OutputData/AVMagnetostaticClosedCoilCSV
[]
[]
(moose/test/tests/mfem/submeshes/av_magnetostatic.i)Global Current Constraints
Strongly constraining the total current through the conductor instead of the loop voltage is also possible, by defining a cut plane in the domain outside the conductor region using the H-phi formulation instead of the A-V formulation detailed above; the details are similar, using a magnetic scalar potential instead of an electric scalar potential. The constraint to be enforced is
where is any path encircling the conductor, and I is the total current passing through the path . Outside the conductor, the magnetic field is curl-free, and thus can be expressed by the gradient of a scalar magnetic potential (up to a sign).
An example file for this approach can be found below:
# Solve for the magnetic field around a closed conductor subject to
# global current constraint.
initial_vacuum_domains = 'Exterior'
vacuum_cut_surface = 'Cut'
conductor_current = 1.0
vacuum_permeability = 1.0
[Problem<<<{"href": "../Problem/index.html"}>>>]
type = MFEMProblem
[]
[Mesh<<<{"href": "../Mesh/index.html"}>>>]
type = MFEMMesh
file = ../mesh/split_embedded_concentric_torus.e
[]
[FunctorMaterials<<<{"href": "../FunctorMaterials/index.html"}>>>]
[Conductor]
type = MFEMGenericFunctorMaterial
prop_names = permeability
prop_values = ${vacuum_permeability}
[]
[]
[ICs<<<{"href": "../ICs/index.html"}>>>]
[vacuum_cut_potential_ic]
type = MFEMScalarBoundaryIC
variable = vacuum_cut_potential
boundary = ${vacuum_cut_surface}
coefficient = ${conductor_current}
[]
[]
[SubMeshes]
[cut]
type = MFEMCutTransitionSubMesh
cut_boundary = ${vacuum_cut_surface}
block = ${initial_vacuum_domains}
transition_subdomain = transition_dom
transition_subdomain_boundary = transition_bdr
closed_subdomain = vacuum_dom
[]
[vacuum]
type = MFEMDomainSubMesh
block = vacuum_dom
execution_order_group = 2
[]
[]
[FESpaces]
[VacuumH1FESpace]
type = MFEMScalarFESpace
fec_type = H1
fec_order = FIRST
submesh = vacuum
[]
[VacuumHCurlFESpace]
type = MFEMVectorFESpace
fec_type = ND
fec_order = FIRST
submesh = vacuum
[]
[TransitionH1FESpace]
type = MFEMScalarFESpace
fec_type = H1
fec_order = FIRST
submesh = cut
[]
[TransitionHCurlFESpace]
type = MFEMVectorFESpace
fec_type = ND
fec_order = FIRST
submesh = cut
[]
[HCurlFESpace]
type = MFEMVectorFESpace
fec_type = ND
fec_order = FIRST
[]
[]
[Variables<<<{"href": "../Variables/index.html"}>>>]
[vacuum_magnetic_potential]
type = MFEMVariable
fespace = VacuumH1FESpace
[]
[]
[AuxVariables<<<{"href": "../AuxVariables/index.html"}>>>]
[vacuum_cut_potential]
type = MFEMVariable
fespace = VacuumH1FESpace
[]
[transition_cut_potential]
type = MFEMVariable
fespace = TransitionH1FESpace
[]
[transition_cut_function_field]
type = MFEMVariable
fespace = TransitionHCurlFESpace
[]
[background_h_field]
type = MFEMVariable
fespace = VacuumHCurlFESpace
[]
[cut_function_field]
type = MFEMVariable
fespace = VacuumHCurlFESpace
[]
[vacuum_h_field]
type = MFEMVariable
fespace = VacuumHCurlFESpace
[]
[h_field]
type = MFEMVariable
fespace = HCurlFESpace
[]
[]
[AuxKernels<<<{"href": "../AuxKernels/index.html"}>>>]
[update_background_h_field]
type = MFEMGradAux
variable = background_h_field
source = vacuum_magnetic_potential
scale_factor = -1.0
execute_on = TIMESTEP_END
[]
[update_transition_cut_function_field]
type = MFEMGradAux
variable = transition_cut_function_field
source = transition_cut_potential
scale_factor = -1.0
execute_on = TIMESTEP_END
[]
[update_total_h_field]
type = MFEMSumAux
variable = vacuum_h_field
first_source_variable = background_h_field
second_source_variable = cut_function_field
execute_on = TIMESTEP_END
execution_order_group = 3
[]
[]
[BCs<<<{"href": "../BCs/index.html"}>>>]
# Set zero of magnetic potential on symmetry plane
[Exterior]
type = MFEMScalarDirichletBC
variable = vacuum_magnetic_potential
boundary = 'Cut'
coefficient = 0.0
[]
[]
[Kernels<<<{"href": "../Kernels/index.html"}>>>]
[diff]
type = MFEMDiffusionKernel
variable = vacuum_magnetic_potential
coefficient = permeability
[]
[source]
type = MFEMMixedGradGradKernel
trial_variable = vacuum_cut_potential
variable = vacuum_magnetic_potential
coefficient = permeability
block = 'transition_dom'
[]
[]
[Preconditioner]
[boomeramg]
type = MFEMHypreBoomerAMG
[]
[]
[Solver]
type = MFEMHypreGMRES
preconditioner = boomeramg
l_tol = 1e-8
l_max_its = 100
[]
[Executioner<<<{"href": "../Executioner/index.html"}>>>]
type = MFEMSteady
[]
[Transfers<<<{"href": "../Transfers/index.html"}>>>]
[submesh_transfer_to_transition]
type = MFEMSubMeshTransfer
from_variable = vacuum_cut_potential
to_variable = transition_cut_potential
execute_on = TIMESTEP_END
[]
[submesh_transfer_from_transition]
type = MFEMSubMeshTransfer
from_variable = transition_cut_function_field
to_variable = cut_function_field
execute_on = TIMESTEP_END
execution_order_group = 2
[]
[submesh_transfer_from_vacuum]
type = MFEMSubMeshTransfer
from_variable = vacuum_h_field
to_variable = h_field
execute_on = TIMESTEP_END
execution_order_group = 4
[]
[]
[Postprocessors<<<{"href": "../Postprocessors/index.html"}>>>]
[MagneticEnergy]
type = MFEMVectorFEInnerProductIntegralPostprocessor
coefficient = ${fparse 0.5*vacuum_permeability}
dual_variable = vacuum_h_field
primal_variable = vacuum_h_field
execution_order_group = 4
block = 'Exterior'
[]
[]
[Outputs<<<{"href": "../Mastodon/Outputs/index.html"}>>>]
[ReportedPostprocessors]
type = CSV<<<{"description": "Output for postprocessors, vector postprocessors, and scalar variables using comma seperated values (CSV).", "href": "../../source/outputs/CSV.html"}>>>
file_base<<<{"description": "The desired solution output name without an extension. If not provided, MOOSE sets it with Outputs/file_base when available. Otherwise, MOOSE uses input file name and this object name for a master input or uses master file_base, the subapp name and this object name for a subapp input to set it."}>>> = OutputData/HPhiMagnetostaticClosedCoilCSV
[]
[VacuumParaViewDataCollection]
type = MFEMParaViewDataCollection
file_base = OutputData/HPhiMagnetostaticClosedCoil
vtk_format = ASCII
submesh = vacuum
[]
[]
(moose/test/tests/mfem/submeshes/hphi_magnetostatic.i)