Skip to content

Elmer solvers

Typed Elmer configuration: Pydantic models whose fields are their sif keywords, grouped by physics.

femforge.elmer.config

Typed Elmer configuration: Pydantic models whose fields ARE their sif keywords, grouped by physics (common, electromagnetism, thermal, mechanics, output), plus the per-physics presets.

Modules:

  • common –

    What every physics shares: the keyword-model base, the solver hierarchy's base and mixins, the Simulation/Constants blocks, the stack container, presets, and selection.

  • electromagnetism –

    Electromagnetic solvers: magnetostatics (3D and axisymmetric), electrostatics, current conduction, and the coil current source.

  • mechanics –

    Mechanical solvers: linear elasticity.

  • output –

    Output solvers: VTU result files and scalar reductions.

  • thermal –

    Thermal solvers: steady heat conduction.

Classes:

  • PhysicsSelection –

    Which physics the Elmer stage solves; SimulationConfig derives the solved stack from this selection and its frame.

  • PhysicsConfig –

    The fully populated, typed solver stack for one physics: ordered solvers plus simulation settings, activated constants and operating point.

  • OperatingPoint –

    The point at which a material's property functions are evaluated when stripping to Elmer's bare SI floats.

  • SimulationSettings –

    The Elmer Simulation block. Defaults are a 3D Cartesian steady-state run, used for magnetostatics and steady thermal.

  • Constants –

    The Elmer Constants block: each constant is an optional field carrying its sif keyword; a physics sets only the constants it needs, and an unset one is omitted.

  • SifKeywordModel –

    Base for a config model whose fields ARE its sif keywords: each field carries its Elmer keyword as Map(...)

  • SolverBase –

    Base for a typed Elmer solver: its fields are its sif keywords.

  • LinearSystem –

    Mixin: the Linear System * settings for a solver that does a linear solve. Defaults are sensible iterative values; concrete solvers tune the iteration cap and tolerances they need.

  • NonlinearSystem –

    Mixin: the Nonlinear System * (outer-iteration) convergence settings.

  • SteadyState –

    Mixin: the Steady State Convergence Tolerance for a steady-state run.

  • MagnetoDynamicsSolver –

    3D magnetostatics (WhitneyAVSolver), with each magnet's drive entering as Magnetization on its material rather than as a body force.

  • MagnetoDynamics2DSolver –

    Axisymmetric magnetostatics (MagnetoDynamics2D): the scalar azimuthal potential A_phi under Coordinate System = Axi Symmetric.

  • MagnetoDynamicsCalcFieldsSolver –

    Post-processing: recover B, H, fluxes and nodal forces from the computed A. Inherits Linear System * because

  • ResultOutputSolver –

    Write VTU output for ParaView.

  • HeatSolver –

    SCAFFOLD: steady heat conduction. Wire-ready; its boundary conditions land on the adjacency-derived surface groups via the condition-driven boundary loop.

  • StatCurrentSolver –

    Static current conduction (Elmer's StatCurrentSolve): solves Potential from ∇·(σ∇φ) = 0, excited by per-phase

  • CoilCurrentSolver –

    Elmer's CoilSolver: the divergence-conforming coil current distribution, the source stage of the COIL_MAGNETOSTATICS chain.

  • SaveScalarsSolver –

    SaveScalars (SaveData): export scalar reductions to scalars.dat and its .names sidecar.

  • ElectrostaticsSolver –

    SCAFFOLD: electrostatics (StatElecSolver). No nonlinear iteration.

  • StressSolver –

    SCAFFOLD: linear elasticity (Elmer's StressSolve). Consumes Youngs Modulus and Poisson Ratio material

  • GenericSolver –

    Escape hatch: an arbitrary Elmer solver block for anything the typed hierarchy doesn't model yet — set

  • CoordinateSystem –

    Elmer's Coordinate System.

  • SimulationType –

    Elmer's Simulation Type.

  • TimesteppingMethod –

    Elmer's Timestepping Method (paired with BDF Order for BDF).

  • ExecSolver –

    When Elmer executes a solver (the Exec Solver keyword).

  • LinearSolverType –

    The Linear System Solver strategy: an iterative Krylov method or a direct factorization.

  • IterativeMethod –

    The Krylov method for an iterative linear solve (Linear System Iterative Method).

  • Preconditioning –

    The Linear System Preconditioning for an iterative solve.

Functions:

  • physics_config –

    The fully-populated, typed solver stack for physics, keyed by an exhaustive match on the Physics enum (a new physics is a static obligation).

  • solved_stack –

    The preset stack physics solves as under frame; an axisymmetric form runs in the Axi Symmetric coordinate system.

  • prepare_for_mpi –

    Adjust a solver stack for a partitioned (MPI) solve: CoilSolver's serial-only umfpack Direct solve switches to MUMPS, and any other Direct solve raises.

  • needs_halobc –

    Whether partitioning must add halo elements (-halobc): only the coil stack's boundary-terminated electrodes need them, and elsewhere they skew CalcFields' force lumping.

  • convergence_targets –

    The per-(solver, loop) iteration caps and tolerances the stack authors, keyed the way Elmer tags ComputeChange lines.

  • bare_save_scalars –

    A SaveScalars with no configured reductions: exports every registered res: simulation/component scalar (Component force/torque, field energy) to scalars.dat.

Attributes:

  • STEFAN_BOLTZMANN (float) –

    σ_SB [W/(m²·K⁴)]: The Stefan-Boltzmann constant thermal radiation needs.

  • SifValue –

    An Elmer sif keyword value, copied verbatim into the sif.

STEFAN_BOLTZMANN module-attribute

STEFAN_BOLTZMANN: float = 5.6704e-08

σ_SB [W/(m²·K⁴)]: The Stefan-Boltzmann constant thermal radiation needs.

SifValue module-attribute

SifValue = str | int | float | bool

An Elmer sif keyword value, copied verbatim into the sif.

PhysicsSelection pydantic-model

Bases: ConfigArea

Which physics the Elmer stage solves; SimulationConfig derives the solved stack from this selection and its frame.

Fields:

Validators:

selected pydantic-field

The physics as authored (magnetostatics / thermal / ...); the config's frame decides the form it solves as.

overrides pydantic-field

overrides: PhysicsConfig | None = None

The authored solver stack for this run (see SimulationConfig.customize_physics); None solves the preset. Part of the config, so authored settings feed the run identity (cache_key) and the manifest.

selectable pydantic-validator

selectable(selected: Physics) -> Physics

Reject the internal axisymmetric stack.

Source code in src/femforge/elmer/config/common/selection.py
@field_validator("selected")
@classmethod
def selectable(cls, selected: Physics) -> Physics:
    """Reject the internal axisymmetric stack."""
    if selected is Physics.MAGNETOSTATICS_2D:
        raise ValueError(f"Physics '{selected.value}' is not selectable: select '{Physics.MAGNETOSTATICS.value}' with frame=Axisymmetric().")

    return selected

check_frame

check_frame(frame: Frame) -> None

Raise when selected has no form under frame or authored overrides disagree with it.

Source code in src/femforge/elmer/config/common/selection.py
def check_frame(self, frame: Frame) -> None:
    """Raise when ``selected`` has no form under ``frame`` or authored ``overrides`` disagree with it."""
    _ = self.selected.in_frame(frame)

    if self.overrides is not None:
        self.overrides.check_frame(frame)

PhysicsConfig pydantic-model

Bases: BaseModel

The fully populated, typed solver stack for one physics: ordered solvers plus simulation settings, activated constants and operating point.

Config:

  • arbitrary_types_allowed: True
  • validate_assignment: True
  • use_attribute_docstrings: True

Fields:

solvers pydantic-field

solvers: list[SolverUnion]

The ordered concrete solver instances Elmer runs for this physics.

simulation pydantic-field

simulation: SimulationSettings

The Elmer Simulation block (run type, coordinate system, output files).

constants pydantic-field

constants: Constants

The physical constants this physics activates.

operating_point pydantic-field

operating_point: OperatingPoint

Where material property functions are evaluated when stripping to SI.

solver

solver(kind: type[SolverT]) -> SolverT

The live solver instance of type kind in this stack; raises KeyError when it has none.

Source code in src/femforge/elmer/config/common/physics_config.py
def solver(self, kind: type[SolverT]) -> SolverT:
    """The live solver instance of type ``kind`` in this stack; raises ``KeyError`` when it has none."""
    for spec in self.solvers:
        if isinstance(spec, kind):
            return spec
    raise KeyError(f"No {kind.__name__} in this physics' solver stack ({[type(s).__name__ for s in self.solvers]}).")

check_frame

check_frame(frame: Frame) -> None

Raise when this stack's coordinate system disagrees with frame: per-radian exactly when the frame is axisymmetric.

Source code in src/femforge/elmer/config/common/physics_config.py
def check_frame(self, frame: Frame) -> None:
    """Raise when this stack's coordinate system disagrees with ``frame``: per-radian exactly when the frame is axisymmetric."""
    coordinate_system: CoordinateSystem = self.simulation.coordinate_system
    axisymmetric: bool = isinstance(frame, Axisymmetric)

    if coordinate_system.per_radian == axisymmetric:
        return

    raise ValueError(f"The solver stack's Coordinate System '{coordinate_system.value}' cannot solve frame={type(frame).__name__}(); re-customize the physics after setting the frame.")

OperatingPoint pydantic-model

Bases: BaseModel

The point at which a material's property functions are evaluated when stripping to Elmer's bare SI floats. Static properties ignore it; temperature-dependent properties consume it via as_mapping.

Config:

  • arbitrary_types_allowed: True
  • validate_assignment: True
  • use_attribute_docstrings: True

Fields:

temperature pydantic-field

temperature: Temperature

T [K]: Evaluation temperature for material property functions.

as_mapping

as_mapping() -> dict[str, Quantity]

The ephemeral name->quantity mapping the property functions consume (prop(**at)).

Source code in src/femforge/elmer/config/common/operating_point.py
def as_mapping(self) -> dict[str, Quantity]:
    """The ephemeral name->quantity mapping the property functions consume (``prop(**at)``)."""
    return {"temperature": self.temperature}

SimulationSettings pydantic-model

Bases: SifKeywordModel

The Elmer Simulation block. Defaults are a 3D Cartesian steady-state run, used for magnetostatics and steady thermal.

Fields:

max_output_level pydantic-field

max_output_level: int = 5

Verbosity of ElmerSolver's console output (0-quiet … higher-noisier).

coordinate_system pydantic-field

The simulation coordinate system.

coordinate_mapping pydantic-field

coordinate_mapping: str = '1 2 3'

Axis permutation for the coordinate system.

simulation_type pydantic-field

Steady-state, transient, or scanning run.

steady_state_max_iterations pydantic-field

steady_state_max_iterations: int = 1

Max steady-state (coupled-system) iterations.

output_intervals pydantic-field

output_intervals: int = 1

Write results every N steps.

timestepping_method pydantic-field

timestepping_method: TimesteppingMethod = TimesteppingMethod.BDF

Time integration scheme.

bdf_order pydantic-field

bdf_order: int = 1

Order of the BDF timestepping method.

solver_input_file pydantic-field

solver_input_file: str = 'case.sif'

Name of the generated .sif.

post_file pydantic-field

post_file: str | None = None

ParaView/VTU post-processing output file; None (the default) leaves VTU output to the ResultOutputSolver — setting both trips Elmer's AddVtuOutputSolverHack and its log spam.

output_file pydantic-field

output_file: str | None = None

ElmerSolver restart/result file; None (the default) skips it — nothing downstream reads it and it grows to multi-GB on large solves. Set a name only when a restart is wanted.

Constants pydantic-model

Bases: SifKeywordModel

The Elmer Constants block: each constant is an optional field carrying its sif keyword; a physics sets only the constants it needs, and an unset one is omitted.

Fields:

permeability_of_vacuum pydantic-field

permeability_of_vacuum: float | None = None

μ₀ [H/m]: Needed by the magnetostatic solver.

permittivity_of_vacuum pydantic-field

permittivity_of_vacuum: float | None = None

ε₀ [F/m]: Needed by the electrostatic solver.

stefan_boltzmann pydantic-field

stefan_boltzmann: float | None = None

σ_SB [W/(m²·K⁴)]: Needed for thermal radiation.

SifKeywordModel pydantic-model

Bases: BaseModel

Base for a config model whose fields ARE its sif keywords: each field carries its Elmer keyword as Map(...) metadata, and to_elmer reflects the pairs back out via mapped_items (no parallel string-keyed table).

Fields:

extra_keywords pydantic-field

extra_keywords: dict[str, SifValue]

Escape hatch: verbatim sif keyword/value pairs merged (last, so they win) into to_elmer — any Elmer keyword the typed fields don't model yet stays authorable without subclassing.

to_elmer

to_elmer() -> dict[str, SifValue]

The sif keyword/value dict reflected from each field's Map(...) keyword, with extra_keywords merged last.

None fields are left out so Elmer keeps its defaults, and a list expands to a numbered family such as Vector Field 1..n.

Source code in src/femforge/elmer/config/common/keywords.py
def to_elmer(self) -> dict[str, SifValue]:
    """The sif keyword/value dict reflected from each field's ``Map(...)`` keyword, with ``extra_keywords`` merged last.

    None fields are left out so Elmer keeps its defaults, and a list expands to a numbered family such as ``Vector Field 1..n``.
    """
    out: dict[str, SifValue] = {}
    for key, value in mapped_items(self):
        if isinstance(value, list):
            for index, item in enumerate(value, 1):  # pyright: ignore[reportUnknownVariableType, reportUnknownArgumentType]  # mapped_items erases the item type
                if isinstance(item, (str, int, float)):
                    out[f"{key} {index}"] = item
        elif isinstance(value, (str, int, float)):
            out[key] = value
    out.update(self.extra_keywords)
    return out

SolverBase pydantic-model

Bases: SifKeywordModel

Base for a typed Elmer solver: its fields are its sif keywords.

Fields:

  • extra_keywords (dict[str, SifValue])
  • kind (str)
  • equation (EquationField)
  • procedure (ProcedureField)
  • variable (VariableField)
  • variable_dofs (VariableDofsField)
  • exec_solver (ExecSolverField)
  • stabilize (StabilizeField)
  • optimize_bandwidth (OptimizeBandwidthField)

kind pydantic-field

kind: str

Discriminator that names this solver, doubling as its sif Solver label.

required_material_keys class-attribute

required_material_keys: frozenset[ElmerMaterialKeyword] = frozenset()

The material keywords every body this solver acts on must supply, checked by Sim.validate.

conductor_only class-attribute

conductor_only: bool = False

Restrict this solver's equation to conductor bodies: solving a conduction variable over dielectrics too puts ~21 decades of σ contrast into one matrix — singular for a direct factorization, a stall for preconditioned CG.

LinearSystem pydantic-model

Bases: BaseModel

Mixin: the Linear System * settings for a solver that does a linear solve. Defaults are sensible iterative values; concrete solvers tune the iteration cap and tolerances they need.

Config:

  • use_attribute_docstrings: True

Fields:

  • linear_system_solver (LinearSolverTypeField)
  • linear_system_direct_method (LinearDirectMethodField)
  • linear_system_iterative_method (LinearIterativeMethodField)
  • linear_system_max_iterations (LinearMaxIterationsField)
  • linear_system_convergence_tolerance (LinearConvToleranceField)
  • linear_system_preconditioning (LinearPreconditioningField)
  • linear_system_residual_output (LinearResidualOutputField)
  • linear_system_abort_not_converged (LinearAbortNotConvergedField)
  • bicgstabl_polynomial_degree (BiCGStablPolynomialDegreeField)

NonlinearSystem pydantic-model

Bases: BaseModel

Mixin: the Nonlinear System * (outer-iteration) convergence settings.

Fields:

  • nonlinear_system_convergence_tolerance (NonlinearConvToleranceField)
  • nonlinear_system_max_iterations (NonlinearMaxIterationsField)
  • nonlinear_system_newton_after_iterations (NonlinearNewtonAfterIterationsField)
  • nonlinear_system_newton_after_tolerance (NonlinearNewtonAfterToleranceField)
  • nonlinear_system_relaxation_factor (NonlinearRelaxationFactorField)
  • nonlinear_system_convergence_measure (NonlinearConvMeasureField)

SteadyState pydantic-model

Bases: BaseModel

Mixin: the Steady State Convergence Tolerance for a steady-state run.

Fields:

  • steady_state_convergence_tolerance (SteadyStateConvToleranceField)

MagnetoDynamicsSolver pydantic-model

Bases: SolverBase, LinearSystem, NonlinearSystem, SteadyState

3D magnetostatics (WhitneyAVSolver), with each magnet's drive entering as Magnetization on its material rather than as a body force.

Leave variable unset, so the far-field boundary condition can still name AV {e}.

Fields:

  • steady_state_convergence_tolerance (SteadyStateConvToleranceField)
  • nonlinear_system_convergence_measure (NonlinearConvMeasureField)
  • linear_system_solver (LinearSolverTypeField)
  • linear_system_direct_method (LinearDirectMethodField)
  • extra_keywords (dict[str, SifValue])
  • variable (VariableField)
  • variable_dofs (VariableDofsField)
  • exec_solver (ExecSolverField)
  • stabilize (StabilizeField)
  • kind (Literal['MagnetoDynamics'])
  • equation (EquationField)
  • procedure (ProcedureField)
  • optimize_bandwidth (OptimizeBandwidthField)
  • nonlinear_system_convergence_tolerance (NonlinearConvToleranceField)
  • nonlinear_system_max_iterations (NonlinearMaxIterationsField)
  • nonlinear_system_newton_after_iterations (NonlinearNewtonAfterIterationsField)
  • nonlinear_system_newton_after_tolerance (NonlinearNewtonAfterToleranceField)
  • nonlinear_system_relaxation_factor (NonlinearRelaxationFactorField)
  • linear_system_iterative_method (LinearIterativeMethodField)
  • bicgstabl_polynomial_degree (BiCGStablPolynomialDegreeField)
  • linear_system_preconditioning (LinearPreconditioningField)
  • linear_system_max_iterations (LinearMaxIterationsField)
  • linear_system_convergence_tolerance (LinearConvToleranceField)
  • linear_system_abort_not_converged (LinearAbortNotConvergedField)
  • linear_system_residual_output (LinearResidualOutputField)
  • fix_input_current_density (bool | None)
  • use_elemental_coilcurrent (bool | None)

kind pydantic-field

kind: Literal['MagnetoDynamics'] = 'MagnetoDynamics'

Discriminator that names this solver, doubling as its sif Solver label.

fix_input_current_density pydantic-field

fix_input_current_density: bool | None = None

Project the source J onto a divergence-free field before the AV solve: the discrete J is not exactly solenoidal edge-element-wise, and an unfixed source makes the gauge-non-unique system inconsistent. None omits the keyword.

use_elemental_coilcurrent pydantic-field

use_elemental_coilcurrent: bool | None = None

Read the source J from CoilSolver's elemental (DG) field instead of a nodal Body Force: nodal J is Galerkin-averaged across the conductor-air interface and silently dilutes the drive ~2x on thin traces. Requires a CoilSolver in the stack; None omits the keyword.

MagnetoDynamics2DSolver pydantic-model

Bases: SolverBase, LinearSystem, NonlinearSystem, SteadyState

Axisymmetric magnetostatics (MagnetoDynamics2D): the scalar azimuthal potential A_phi under Coordinate System = Axi Symmetric.

The mesh lies flat in the XY plane (Z = 0), with X the radial distance from the symmetry axis (X >= 0) and Y the position along it.

Fields:

  • nonlinear_system_newton_after_iterations (NonlinearNewtonAfterIterationsField)
  • nonlinear_system_newton_after_tolerance (NonlinearNewtonAfterToleranceField)
  • linear_system_iterative_method (LinearIterativeMethodField)
  • linear_system_max_iterations (LinearMaxIterationsField)
  • linear_system_convergence_tolerance (LinearConvToleranceField)
  • linear_system_preconditioning (LinearPreconditioningField)
  • linear_system_residual_output (LinearResidualOutputField)
  • linear_system_abort_not_converged (LinearAbortNotConvergedField)
  • bicgstabl_polynomial_degree (BiCGStablPolynomialDegreeField)
  • extra_keywords (dict[str, SifValue])
  • exec_solver (ExecSolverField)
  • stabilize (StabilizeField)
  • kind (Literal['MagnetoDynamics2D'])
  • equation (EquationField)
  • procedure (ProcedureField)
  • variable (VariableField)
  • variable_dofs (VariableDofsField)
  • optimize_bandwidth (OptimizeBandwidthField)
  • nonlinear_system_max_iterations (NonlinearMaxIterationsField)
  • nonlinear_system_convergence_tolerance (NonlinearConvToleranceField)
  • nonlinear_system_convergence_measure (NonlinearConvMeasureField)
  • nonlinear_system_relaxation_factor (NonlinearRelaxationFactorField)
  • linear_system_solver (LinearSolverTypeField)
  • linear_system_direct_method (LinearDirectMethodField)
  • steady_state_convergence_tolerance (SteadyStateConvToleranceField)

kind pydantic-field

kind: Literal['MagnetoDynamics2D'] = 'MagnetoDynamics2D'

Discriminator that names this solver, doubling as its sif Solver label.

MagnetoDynamicsCalcFieldsSolver pydantic-model

Bases: SolverBase, LinearSystem

Post-processing: recover B, H, fluxes and nodal forces from the computed A. Inherits Linear System * because nodal-field recovery solves an (SPD, hence CG) mass-matrix system — without a linear solver Elmer aborts.

Fields:

kind pydantic-field

kind: Literal['MagnetoDynamicsCalcFields'] = 'MagnetoDynamicsCalcFields'

Discriminator that names this solver, doubling as its sif Solver label.

potential_variable pydantic-field

potential_variable: str | None = None

The vector-potential variable to post-process; None lets the solver pick up the (default-named) MgDyn variable.

average_within_materials pydantic-field

average_within_materials: bool | None = True

Average recovered fields within each material so the B/H jump at a magnet surface is resolved cleanly.

calculate_magnetic_field_strength pydantic-field

calculate_magnetic_field_strength: bool = True

Recover H.

calculate_magnetic_flux_density pydantic-field

calculate_magnetic_flux_density: bool = True

Recover B.

calculate_nodal_forces pydantic-field

calculate_nodal_forces: bool = True

Recover nodal forces (drives the motor-force optimisation).

calculate_nodal_fields pydantic-field

calculate_nodal_fields: bool = False

Recover nodal field values.

calculate_joule_heating pydantic-field

calculate_joule_heating: bool | None = None

Recover the eddy/Joule loss field. Identically zero for a steady real-valued solve — set False there: the zero-RHS projection it triggers when a Current Density body force is present segfaults CalcFields.

calculate_electric_field pydantic-field

calculate_electric_field: bool | None = None

Recover E = -dA/dt - grad V. Identically zero at steady state — set False for the chained coil solve, where its zero-RHS projection is what segfaults CalcFields after the B components.

calculate_magnetic_vector_potential pydantic-field

calculate_magnetic_vector_potential: bool | None = None

Project the edge-element av onto a nodal A field; None keeps the solver default.

separate_magnetic_energy pydantic-field

separate_magnetic_energy: bool | None = None

Export the magnetic field energy as SaveScalars-visible scalars (the ElmerCSC mgdyn_bh recipe) — the energy-method inductance observable: L_eff = 2W/I².

calculate_relative_permeability pydantic-field

calculate_relative_permeability: bool | None = None

Recover the local relative permeability; the mgdyn_bh energy recipe enables it alongside the energy export.

calculate_elemental_fields pydantic-field

calculate_elemental_fields: bool = True

Recover elemental field values.

ResultOutputSolver pydantic-model

Bases: SolverBase

Write VTU output for ParaView.

Fields:

kind pydantic-field

kind: Literal['ResultOutputSolver'] = 'ResultOutputSolver'

Discriminator that names this solver, doubling as its sif Solver label.

vtu_format pydantic-field

vtu_format: bool = True

Write VTU (ParaView) output.

output_file_name pydantic-field

output_file_name: str = 'File "case"'

Stem of the written VTU (Elmer emits e.g. case_t0001.vtu); pinned so the name never depends on Elmer defaults.

save_geometry_ids pydantic-field

save_geometry_ids: bool = True

Tag output cells with their gmsh geometry ids.

saved_scalar_fields pydantic-field

saved_scalar_fields: list[str] | None = None

Scalar fields to save (each a full sif RHS, e.g. 'String "joule heating"'); None saves every active variable.

saved_vector_fields pydantic-field

saved_vector_fields: list[str] | None = None

Vector fields to save; None saves every active variable.

discontinuous_bodies pydantic-field

discontinuous_bodies: bool | None = None

Average elemental fields body-wise onto a minimal discontinuous node set, so the VTU keeps cross-body discontinuities.

HeatSolver pydantic-model

Bases: SolverBase, LinearSystem, NonlinearSystem, SteadyState

SCAFFOLD: steady heat conduction. Wire-ready; its boundary conditions land on the adjacency-derived surface groups via the condition-driven boundary loop.

Fields:

  • nonlinear_system_newton_after_iterations (NonlinearNewtonAfterIterationsField)
  • nonlinear_system_newton_after_tolerance (NonlinearNewtonAfterToleranceField)
  • nonlinear_system_relaxation_factor (NonlinearRelaxationFactorField)
  • nonlinear_system_convergence_measure (NonlinearConvMeasureField)
  • linear_system_iterative_method (LinearIterativeMethodField)
  • linear_system_convergence_tolerance (LinearConvToleranceField)
  • linear_system_residual_output (LinearResidualOutputField)
  • linear_system_abort_not_converged (LinearAbortNotConvergedField)
  • bicgstabl_polynomial_degree (BiCGStablPolynomialDegreeField)
  • extra_keywords (dict[str, SifValue])
  • exec_solver (ExecSolverField)
  • kind (Literal['HeatSolver'])
  • equation (EquationField)
  • procedure (ProcedureField)
  • variable (VariableField)
  • variable_dofs (VariableDofsField)
  • stabilize (StabilizeField)
  • optimize_bandwidth (OptimizeBandwidthField)
  • linear_system_solver (LinearSolverTypeField)
  • linear_system_direct_method (LinearDirectMethodField)
  • steady_state_convergence_tolerance (SteadyStateConvToleranceField)
  • nonlinear_system_convergence_tolerance (NonlinearConvToleranceField)
  • nonlinear_system_max_iterations (NonlinearMaxIterationsField)
  • linear_system_max_iterations (LinearMaxIterationsField)
  • linear_system_preconditioning (LinearPreconditioningField)

kind pydantic-field

kind: Literal['HeatSolver'] = 'HeatSolver'

Discriminator that names this solver, doubling as its sif Solver label.

StatCurrentSolver pydantic-model

Bases: SolverBase, LinearSystem, NonlinearSystem, SteadyState

Static current conduction (Elmer's StatCurrentSolve): solves Potential from ∇·(σ∇φ) = 0, excited by per-phase FixedPotential terminal pairs. The nonlinear block is inert while σ is Static.

Fields:

  • nonlinear_system_newton_after_iterations (NonlinearNewtonAfterIterationsField)
  • nonlinear_system_newton_after_tolerance (NonlinearNewtonAfterToleranceField)
  • nonlinear_system_relaxation_factor (NonlinearRelaxationFactorField)
  • nonlinear_system_convergence_measure (NonlinearConvMeasureField)
  • linear_system_preconditioning (LinearPreconditioningField)
  • linear_system_residual_output (LinearResidualOutputField)
  • linear_system_abort_not_converged (LinearAbortNotConvergedField)
  • bicgstabl_polynomial_degree (BiCGStablPolynomialDegreeField)
  • extra_keywords (dict[str, SifValue])
  • exec_solver (ExecSolverField)
  • kind (Literal['StatCurrent'])
  • equation (EquationField)
  • procedure (ProcedureField)
  • variable (VariableField)
  • variable_dofs (VariableDofsField)
  • stabilize (StabilizeField)
  • optimize_bandwidth (OptimizeBandwidthField)
  • steady_state_convergence_tolerance (SteadyStateConvToleranceField)
  • nonlinear_system_convergence_tolerance (NonlinearConvToleranceField)
  • nonlinear_system_max_iterations (NonlinearMaxIterationsField)
  • linear_system_solver (LinearSolverTypeField)
  • linear_system_direct_method (LinearDirectMethodField)
  • linear_system_iterative_method (LinearIterativeMethodField)
  • linear_system_max_iterations (LinearMaxIterationsField)
  • linear_system_convergence_tolerance (LinearConvToleranceField)
  • calculate_volume_current (bool)
  • calculate_joule_heating (bool)

kind pydantic-field

kind: Literal['StatCurrent'] = 'StatCurrent'

Discriminator that names this solver, doubling as its sif Solver label.

calculate_volume_current pydantic-field

calculate_volume_current: bool = True

Recover the volume current density J = -σ∇φ.

calculate_joule_heating pydantic-field

calculate_joule_heating: bool = True

Recover the Joule loss density σ|∇φ|² (the heat-solve coupling source).

CoilCurrentSolver pydantic-model

Bases: SolverBase, LinearSystem, NonlinearSystem, SteadyState

Elmer's CoilSolver: the divergence-conforming coil current distribution, the source stage of the COIL_MAGNETOSTATICS chain.

It acts only on CoilDrive bodies, because Elmer requires every body it covers to belong to a Component.

Config:

  • validate_assignment: True
  • use_attribute_docstrings: True

Fields:

  • steady_state_convergence_tolerance (SteadyStateConvToleranceField)
  • nonlinear_system_convergence_tolerance (NonlinearConvToleranceField)
  • nonlinear_system_max_iterations (NonlinearMaxIterationsField)
  • nonlinear_system_newton_after_iterations (NonlinearNewtonAfterIterationsField)
  • nonlinear_system_newton_after_tolerance (NonlinearNewtonAfterToleranceField)
  • nonlinear_system_relaxation_factor (NonlinearRelaxationFactorField)
  • nonlinear_system_convergence_measure (NonlinearConvMeasureField)
  • linear_system_convergence_tolerance (LinearConvToleranceField)
  • linear_system_preconditioning (LinearPreconditioningField)
  • linear_system_residual_output (LinearResidualOutputField)
  • linear_system_abort_not_converged (LinearAbortNotConvergedField)
  • bicgstabl_polynomial_degree (BiCGStablPolynomialDegreeField)
  • extra_keywords (dict[str, SifValue])
  • variable (VariableField)
  • variable_dofs (VariableDofsField)
  • stabilize (StabilizeField)
  • kind (Literal['CoilCurrent'])
  • equation (EquationField)
  • procedure (ProcedureField)
  • exec_solver (ExecSolverField)
  • optimize_bandwidth (OptimizeBandwidthField)
  • linear_system_solver (LinearSolverTypeField)
  • linear_system_direct_method (LinearDirectMethodField)
  • linear_system_iterative_method (LinearIterativeMethodField)
  • linear_system_max_iterations (LinearMaxIterationsField)
  • coil_closed (bool)
  • normalize_coil_current (bool)
  • calculate_elemental_fields (bool)

kind pydantic-field

kind: Literal['CoilCurrent'] = 'CoilCurrent'

Discriminator that names this solver, doubling as its sif Solver label.

coil_closed pydantic-field

coil_closed: bool = False

False: an open coil whose ends are the Coil Start / Coil End electrode boundaries.

normalize_coil_current pydantic-field

normalize_coil_current: bool = False

Must stay OFF for a massive coil: it rescales |J| to a UNIFORM magnitude, which on a varying cross-section authors a non-conservative source that Jfix redistributes (silently reduced drive current in the winding). Desired Coil Current scaling happens regardless, so the total current is still exact with this off.

calculate_elemental_fields pydantic-field

calculate_elemental_fields: bool = True

Export the DG CoilCurrent e field (what Use Elemental CoilCurrent reads); the nodal field stays too.

SaveScalarsSolver pydantic-model

Bases: SolverBase

SaveScalars (SaveData): export scalar reductions to scalars.dat and its .names sidecar.

Its diffusive flux operator integrates each Save Scalars = True electrode's terminal current, the I in R = ΔV / I.

Fields:

kind pydantic-field

kind: Literal['SaveScalars'] = 'SaveScalars'

Discriminator that names this solver, doubling as its sif Solver label.

save_component_results pydantic-field

save_component_results: bool | None = None

Also export the scalars arising from Component sections.

parallel_reduce pydantic-field

parallel_reduce: bool | None = None

Reduce a partitioned run's output to one scalars.dat instead of per-rank .dat.<rank> files.

filename pydantic-field

filename: str = '"scalars.dat"'

The .dat the scalars land in (the run parser reads it, or its per-rank .dat.<rank> siblings, via the .names sidecar).

variable_1 pydantic-field

variable_1: str | None = ElmerVariable.POTENTIAL

The variable the operator reduces.

operator_1 pydantic-field

operator_1: str | None = 'diffusive flux'

The reduction: boundary integral of the conjugate flux of variable_1.

coefficient_1 pydantic-field

coefficient_1: str | None = 'Electric Conductivity'

The material coefficient weighting the flux (σ ∂φ/∂n integrates to a current).

variable_2 pydantic-field

variable_2: str | None = ElmerVariable.JOULE_HEATING

Second reduction: the Joule loss field (requires Calculate Joule Heating).

operator_2 pydantic-field

operator_2: str | None = 'int'

Volume integral: total dissipated power P (W), the flux-independent cross-check R = ΔV²/P.

variable_3 pydantic-field

variable_3: str | None = None

Third reduction; the coupled joule-heating stack sets Temperature here.

operator_3 pydantic-field

operator_3: str | None = None

Reduction for variable_3; the coupled stack uses max (peak temperature).

ElectrostaticsSolver pydantic-model

Bases: SolverBase, LinearSystem, SteadyState

SCAFFOLD: electrostatics (StatElecSolver). No nonlinear iteration.

Fields:

  • linear_system_solver (LinearSolverTypeField)
  • linear_system_direct_method (LinearDirectMethodField)
  • linear_system_iterative_method (LinearIterativeMethodField)
  • linear_system_preconditioning (LinearPreconditioningField)
  • linear_system_residual_output (LinearResidualOutputField)
  • linear_system_abort_not_converged (LinearAbortNotConvergedField)
  • bicgstabl_polynomial_degree (BiCGStablPolynomialDegreeField)
  • extra_keywords (dict[str, SifValue])
  • variable_dofs (VariableDofsField)
  • exec_solver (ExecSolverField)
  • optimize_bandwidth (OptimizeBandwidthField)
  • kind (Literal['Electrostatics'])
  • equation (EquationField)
  • procedure (ProcedureField)
  • variable (VariableField)
  • stabilize (StabilizeField)
  • steady_state_convergence_tolerance (SteadyStateConvToleranceField)
  • linear_system_max_iterations (LinearMaxIterationsField)
  • linear_system_convergence_tolerance (LinearConvToleranceField)
  • calculate_electric_field (bool)

kind pydantic-field

kind: Literal['Electrostatics'] = 'Electrostatics'

Discriminator that names this solver, doubling as its sif Solver label.

calculate_electric_field pydantic-field

calculate_electric_field: bool = True

Recover E from the potential.

StressSolver pydantic-model

Bases: SolverBase, LinearSystem, NonlinearSystem, SteadyState

SCAFFOLD: linear elasticity (Elmer's StressSolve). Consumes Youngs Modulus and Poisson Ratio material keywords; the latter is not yet stored on MechanicalProperties.

Fields:

  • nonlinear_system_newton_after_iterations (NonlinearNewtonAfterIterationsField)
  • nonlinear_system_newton_after_tolerance (NonlinearNewtonAfterToleranceField)
  • nonlinear_system_relaxation_factor (NonlinearRelaxationFactorField)
  • nonlinear_system_convergence_measure (NonlinearConvMeasureField)
  • linear_system_solver (LinearSolverTypeField)
  • linear_system_direct_method (LinearDirectMethodField)
  • linear_system_iterative_method (LinearIterativeMethodField)
  • linear_system_convergence_tolerance (LinearConvToleranceField)
  • linear_system_preconditioning (LinearPreconditioningField)
  • linear_system_residual_output (LinearResidualOutputField)
  • linear_system_abort_not_converged (LinearAbortNotConvergedField)
  • bicgstabl_polynomial_degree (BiCGStablPolynomialDegreeField)
  • extra_keywords (dict[str, SifValue])
  • exec_solver (ExecSolverField)
  • stabilize (StabilizeField)
  • kind (Literal['StressSolver'])
  • equation (EquationField)
  • procedure (ProcedureField)
  • variable (VariableField)
  • variable_dofs (VariableDofsField)
  • optimize_bandwidth (OptimizeBandwidthField)
  • steady_state_convergence_tolerance (SteadyStateConvToleranceField)
  • nonlinear_system_convergence_tolerance (NonlinearConvToleranceField)
  • nonlinear_system_max_iterations (NonlinearMaxIterationsField)
  • linear_system_max_iterations (LinearMaxIterationsField)
  • calculate_stresses (bool)

kind pydantic-field

kind: Literal['StressSolver'] = 'StressSolver'

Discriminator that names this solver, doubling as its sif Solver label.

calculate_stresses pydantic-field

calculate_stresses: bool = True

Recover the stress tensor from the displacement.

GenericSolver pydantic-model

Bases: SolverBase, LinearSystem, NonlinearSystem, SteadyState

Escape hatch: an arbitrary Elmer solver block for anything the typed hierarchy doesn't model yet — set equation/procedure and author the rest through extra_keywords (plus the shared typed knobs).

Fields:

  • steady_state_convergence_tolerance (SteadyStateConvToleranceField)
  • nonlinear_system_convergence_tolerance (NonlinearConvToleranceField)
  • nonlinear_system_max_iterations (NonlinearMaxIterationsField)
  • nonlinear_system_newton_after_iterations (NonlinearNewtonAfterIterationsField)
  • nonlinear_system_newton_after_tolerance (NonlinearNewtonAfterToleranceField)
  • nonlinear_system_relaxation_factor (NonlinearRelaxationFactorField)
  • nonlinear_system_convergence_measure (NonlinearConvMeasureField)
  • linear_system_solver (LinearSolverTypeField)
  • linear_system_direct_method (LinearDirectMethodField)
  • linear_system_iterative_method (LinearIterativeMethodField)
  • linear_system_max_iterations (LinearMaxIterationsField)
  • linear_system_convergence_tolerance (LinearConvToleranceField)
  • linear_system_preconditioning (LinearPreconditioningField)
  • linear_system_residual_output (LinearResidualOutputField)
  • linear_system_abort_not_converged (LinearAbortNotConvergedField)
  • bicgstabl_polynomial_degree (BiCGStablPolynomialDegreeField)
  • extra_keywords (dict[str, SifValue])
  • equation (EquationField)
  • procedure (ProcedureField)
  • variable (VariableField)
  • variable_dofs (VariableDofsField)
  • exec_solver (ExecSolverField)
  • stabilize (StabilizeField)
  • optimize_bandwidth (OptimizeBandwidthField)
  • kind (Literal['Generic'])

kind pydantic-field

kind: Literal['Generic'] = 'Generic'

Discriminator that names this solver, doubling as its sif Solver label.

CoordinateSystem

Bases: StrEnum

Elmer's Coordinate System.

Attributes:

  • CARTESIAN –

    Cartesian coordinates.

  • CYLINDRIC –

    Full cylindrical coordinates.

  • CYLINDRIC_SYMMETRIC –

    2D cylindrically symmetric (r, z) coordinates, integrated per radian.

  • AXI_SYMMETRIC –

    2D axisymmetric (r, z) coordinates, integrated per radian.

  • POLAR –

    Polar coordinates.

  • per_radian (bool) –

    Whether Elmer integrates domain integrals per radian here (the 2D symmetric systems), so lumped outputs need a 2π revolution factor.

CARTESIAN class-attribute instance-attribute

CARTESIAN = 'Cartesian'

Cartesian coordinates.

CYLINDRIC class-attribute instance-attribute

CYLINDRIC = 'Cylindric'

Full cylindrical coordinates.

CYLINDRIC_SYMMETRIC class-attribute instance-attribute

CYLINDRIC_SYMMETRIC = 'Cylindric Symmetric'

2D cylindrically symmetric (r, z) coordinates, integrated per radian.

AXI_SYMMETRIC class-attribute instance-attribute

AXI_SYMMETRIC = 'Axi Symmetric'

2D axisymmetric (r, z) coordinates, integrated per radian.

POLAR class-attribute instance-attribute

POLAR = 'Polar'

Polar coordinates.

per_radian property

per_radian: bool

Whether Elmer integrates domain integrals per radian here (the 2D symmetric systems), so lumped outputs need a 2π revolution factor.

SimulationType

Bases: StrEnum

Elmer's Simulation Type.

Attributes:

  • STEADY_STATE –

    A steady-state solve.

  • TRANSIENT –

    A time-dependent solve.

  • SCANNING –

    A sweep of steady-state solves over a scanned parameter.

STEADY_STATE class-attribute instance-attribute

STEADY_STATE = 'Steady state'

A steady-state solve.

TRANSIENT class-attribute instance-attribute

TRANSIENT = 'Transient'

A time-dependent solve.

SCANNING class-attribute instance-attribute

SCANNING = 'Scanning'

A sweep of steady-state solves over a scanned parameter.

TimesteppingMethod

Bases: StrEnum

Elmer's Timestepping Method (paired with BDF Order for BDF).

Attributes:

  • BDF –

    Backward differentiation formula, of order bdf_order.

  • NEWMARK –

    The Newmark-beta method.

  • RUNGE_KUTTA –

    A Runge-Kutta method.

BDF class-attribute instance-attribute

BDF = 'BDF'

Backward differentiation formula, of order bdf_order.

NEWMARK class-attribute instance-attribute

NEWMARK = 'Newmark'

The Newmark-beta method.

RUNGE_KUTTA class-attribute instance-attribute

RUNGE_KUTTA = 'Runge-Kutta'

A Runge-Kutta method.

ExecSolver

Bases: StrEnum

When Elmer executes a solver (the Exec Solver keyword).

Attributes:

ALWAYS class-attribute instance-attribute

ALWAYS = 'Always'

Run in the normal solve sequence.

BEFORE_SIMULATION class-attribute instance-attribute

BEFORE_SIMULATION = 'Before simulation'

Run once before the simulation.

AFTER_SIMULATION class-attribute instance-attribute

AFTER_SIMULATION = 'After simulation'

Run once after the simulation.

BEFORE_TIMESTEP class-attribute instance-attribute

BEFORE_TIMESTEP = 'Before timestep'

Run at the start of each timestep.

AFTER_TIMESTEP class-attribute instance-attribute

AFTER_TIMESTEP = 'After timestep'

Run at the end of each timestep.

NEVER class-attribute instance-attribute

NEVER = 'Never'

Never run.

LinearSolverType

Bases: StrEnum

The Linear System Solver strategy: an iterative Krylov method or a direct factorization.

Attributes:

  • ITERATIVE –

    A Krylov iteration, chosen by linear_system_iterative_method.

  • DIRECT –

    A direct factorization, chosen by linear_system_direct_method.

ITERATIVE class-attribute instance-attribute

ITERATIVE = 'Iterative'

A Krylov iteration, chosen by linear_system_iterative_method.

DIRECT class-attribute instance-attribute

DIRECT = 'Direct'

A direct factorization, chosen by linear_system_direct_method.

IterativeMethod

Bases: StrEnum

The Krylov method for an iterative linear solve (Linear System Iterative Method).

Attributes:

  • BICGSTAB –

    Biconjugate gradient stabilized.

  • BICGSTABL –

    BiCGStab(l), of degree bicgstabl_polynomial_degree.

  • CG –

    Conjugate gradient, for symmetric positive-definite systems.

  • CGS –

    Conjugate gradient squared.

  • GMRES –

    Generalized minimal residual.

  • GCR –

    Generalized conjugate residual.

  • TFQMR –

    Transpose-free quasi-minimal residual.

BICGSTAB class-attribute instance-attribute

BICGSTAB = 'BiCGStab'

Biconjugate gradient stabilized.

BICGSTABL class-attribute instance-attribute

BICGSTABL = 'BiCGStabl'

BiCGStab(l), of degree bicgstabl_polynomial_degree.

CG class-attribute instance-attribute

CG = 'CG'

Conjugate gradient, for symmetric positive-definite systems.

CGS class-attribute instance-attribute

CGS = 'CGS'

Conjugate gradient squared.

GMRES class-attribute instance-attribute

GMRES = 'GMRES'

Generalized minimal residual.

GCR class-attribute instance-attribute

GCR = 'GCR'

Generalized conjugate residual.

TFQMR class-attribute instance-attribute

TFQMR = 'TFQMR'

Transpose-free quasi-minimal residual.

Preconditioning

Bases: StrEnum

The Linear System Preconditioning for an iterative solve.

Attributes:

  • NONE –

    No preconditioning.

  • DIAGONAL –

    Diagonal (Jacobi) scaling.

  • ILU0 –

    Incomplete LU without fill-in.

  • ILU1 –

    Incomplete LU with fill level 1.

  • ILU2 –

    Incomplete LU with fill level 2.

  • ILU –

    Incomplete LU without an explicit fill level.

  • ILUT –

    Incomplete LU with threshold dropping.

NONE class-attribute instance-attribute

NONE = 'None'

No preconditioning.

DIAGONAL class-attribute instance-attribute

DIAGONAL = 'Diagonal'

Diagonal (Jacobi) scaling.

ILU0 class-attribute instance-attribute

ILU0 = 'ILU0'

Incomplete LU without fill-in.

ILU1 class-attribute instance-attribute

ILU1 = 'ILU1'

Incomplete LU with fill level 1.

ILU2 class-attribute instance-attribute

ILU2 = 'ILU2'

Incomplete LU with fill level 2.

ILU class-attribute instance-attribute

ILU = 'ILU'

Incomplete LU without an explicit fill level.

ILUT class-attribute instance-attribute

ILUT = 'ILUT'

Incomplete LU with threshold dropping.

physics_config

physics_config(physics: Physics) -> PhysicsConfig

The fully-populated, typed solver stack for physics, keyed by an exhaustive match on the Physics enum (a new physics is a static obligation).

Source code in src/femforge/elmer/config/common/presets.py
def physics_config(physics: Physics) -> PhysicsConfig:
    """The fully-populated, typed solver stack for ``physics``, keyed by an exhaustive ``match`` on the [`Physics`][femforge.elmer.physics.Physics] enum (a new physics is a static obligation)."""
    match physics:
        case Physics.MAGNETOSTATICS:
            return PhysicsConfig(
                solvers=[MagnetoDynamicsSolver(), MagnetoDynamicsCalcFieldsSolver(), bare_save_scalars(), ResultOutputSolver()],
                simulation=SimulationSettings(),
                constants=Constants(permeability_of_vacuum=PERMEABILITY_OF_VACUUM),
                operating_point=OperatingPoint(),
            )
        case Physics.MAGNETOSTATICS_2D:
            # What MAGNETOSTATICS solves as under frame=Axisymmetric(), on the 2D cross-section the frame maps the model
            # onto (X = radial >= 0, Y = along the axis). CalcFields pairs with the 2D solver (Potential Variable pins
            # the scalar A_phi); nodal fields stay ON — turning them off also suppresses the nodal force variable the
            # force reduction reads.
            return PhysicsConfig(
                solvers=[
                    MagnetoDynamics2DSolver(),
                    MagnetoDynamicsCalcFieldsSolver(
                        potential_variable=f'String "{ElmerVariable.POTENTIAL}"',
                        calculate_nodal_fields=True,
                    ),
                    bare_save_scalars(),
                    ResultOutputSolver(),
                ],
                simulation=SimulationSettings(coordinate_system=CoordinateSystem.AXI_SYMMETRIC),
                constants=Constants(permeability_of_vacuum=PERMEABILITY_OF_VACUUM),
                operating_point=OperatingPoint(),
            )
        case Physics.THERMAL:
            # The one SaveScalars reduction is the peak temperature — Result.temperature_max, the thermal-rating observable.
            return PhysicsConfig(
                solvers=[
                    HeatSolver(),
                    SaveScalarsSolver(variable_1=ElmerVariable.TEMPERATURE, operator_1="max", coefficient_1=None, variable_2=None, operator_2=None),
                    ResultOutputSolver(),
                ],
                simulation=SimulationSettings(),
                constants=Constants(stefan_boltzmann=STEFAN_BOLTZMANN),
                operating_point=OperatingPoint(),
            )
        case Physics.CURRENT_CONDUCTION:
            return PhysicsConfig(
                solvers=[StatCurrentSolver(), SaveScalarsSolver(), ResultOutputSolver()],
                simulation=SimulationSettings(),
                constants=Constants(),
                operating_point=OperatingPoint(),
            )
        case Physics.JOULE_HEATING:
            # Coupled StatCurrentSolve -> HeatSolve; one-way while sigma is Static, the iteration head-room is for a future two-way sigma(T).
            return PhysicsConfig(
                solvers=[
                    StatCurrentSolver(),
                    HeatSolver(),
                    SaveScalarsSolver(variable_3=ElmerVariable.TEMPERATURE, operator_3="max"),
                    ResultOutputSolver(),
                ],
                simulation=SimulationSettings(steady_state_max_iterations=10),
                constants=Constants(stefan_boltzmann=STEFAN_BOLTZMANN),
                operating_point=OperatingPoint(),
            )
        case Physics.COIL_MAGNETOSTATICS:
            # Chained CoilSolver -> WhitneyAV (one-way: J is independent of A). The AV source is CoilSolver's ELEMENTAL
            # coil current — a nodal Volume Current bridge silently dilutes the drive ~2x on thin conductors.
            return PhysicsConfig(
                solvers=[
                    # Before Simulation: the source must exist before the AV assembly reads it.
                    CoilCurrentSolver(),
                    # Jfix stays ON even with the elemental source: the DG coil current is not exactly solenoidal
                    # edge-element-wise, and without the projection the singular curl-curl solve diverges.
                    MagnetoDynamicsSolver(fix_input_current_density=True, use_elemental_coilcurrent=True),
                    # Potential Variable is pinned (typed String) so CalcFields latches onto the edge-element av; nodal forces
                    # off (meaningless without magnets); Separate Magnetic Energy prints "Magnetic Field Energy" to the log.
                    # H recovery off: μr ≡ 1 in these solves (H = B/μ0), and skipping it drops a 3-component CG
                    # recovery plus a quarter of the VTU on the big L meshes.
                    MagnetoDynamicsCalcFieldsSolver(
                        potential_variable='String "av"',
                        calculate_magnetic_field_strength=False,
                        calculate_magnetic_vector_potential=False,
                        calculate_relative_permeability=True,
                        calculate_nodal_forces=False,
                        separate_magnetic_energy=True,
                    ),
                    bare_save_scalars(),
                    # The pipeline reads only B back (energy cross-check, field sampling), so the VTU saves just that.
                    ResultOutputSolver(saved_vector_fields=[f'String "{elemental(ElmerVariable.MAGNETIC_FLUX_DENSITY)}"']),
                ],
                simulation=SimulationSettings(),
                constants=Constants(permeability_of_vacuum=PERMEABILITY_OF_VACUUM),
                operating_point=OperatingPoint(),
            )
        case Physics.ELECTROSTATICS:
            return PhysicsConfig(
                solvers=[ElectrostaticsSolver(), ResultOutputSolver()],
                simulation=SimulationSettings(),
                constants=Constants(permittivity_of_vacuum=PERMITTIVITY_OF_VACUUM),
                operating_point=OperatingPoint(),
            )
        # SCAFFOLD physics: the solver stack is complete, but the per-body wiring in Sim is a marked stub.
        case Physics.LINEAR_ELASTICITY:
            return PhysicsConfig(
                solvers=[StressSolver(), ResultOutputSolver()],
                simulation=SimulationSettings(),
                constants=Constants(),
                operating_point=OperatingPoint(),
            )

solved_stack

solved_stack(physics: Physics, frame: Frame) -> PhysicsConfig

The preset stack physics solves as under frame; an axisymmetric form runs in the Axi Symmetric coordinate system.

Source code in src/femforge/elmer/config/common/presets.py
def solved_stack(physics: Physics, frame: Frame) -> PhysicsConfig:
    """The preset stack ``physics`` solves as under ``frame``; an axisymmetric form runs in the Axi Symmetric coordinate system."""
    config: PhysicsConfig = physics_config(physics.in_frame(frame))

    if isinstance(frame, Axisymmetric):
        config.simulation.coordinate_system = CoordinateSystem.AXI_SYMMETRIC

    return config

prepare_for_mpi

prepare_for_mpi(config: PhysicsConfig) -> None

Adjust a solver stack for a partitioned (MPI) solve: CoilSolver's serial-only umfpack Direct solve switches to MUMPS, and any other Direct solve raises.

Source code in src/femforge/elmer/config/common/physics_config.py
def prepare_for_mpi(config: PhysicsConfig) -> None:
    """Adjust a solver stack for a partitioned (MPI) solve: CoilSolver's serial-only umfpack Direct solve switches to MUMPS, and any other Direct solve raises."""
    for solver in config.solvers:
        if isinstance(solver, CoilCurrentSolver):
            solver.linear_system_direct_method = "MUMPS"
        elif isinstance(solver, LinearSystem) and solver.linear_system_solver is LinearSolverType.DIRECT:
            raise ValueError(f"{type(solver).__name__} uses a Direct linear solve, which is unvalidated under partitioning — run it serially (mpi_processes=1).")

needs_halobc

needs_halobc(config: PhysicsConfig) -> bool

Whether partitioning must add halo elements (-halobc): only the coil stack's boundary-terminated electrodes need them, and elsewhere they skew CalcFields' force lumping.

Source code in src/femforge/elmer/config/common/physics_config.py
def needs_halobc(config: PhysicsConfig) -> bool:
    """Whether partitioning must add halo elements (``-halobc``): only the coil stack's boundary-terminated electrodes need them, and elsewhere they skew CalcFields' force lumping."""
    return any(isinstance(solver, CoilCurrentSolver) for solver in config.solvers)

convergence_targets

convergence_targets(config: PhysicsConfig) -> dict[tuple[str, Literal['NS', 'SS']], LoopTargets]

The per-(solver, loop) iteration caps and tolerances the stack authors, keyed the way Elmer tags ComputeChange lines.

Source code in src/femforge/elmer/config/common/physics_config.py
def convergence_targets(config: PhysicsConfig) -> dict[tuple[str, Literal["NS", "SS"]], LoopTargets]:
    """The per-(solver, loop) iteration caps and tolerances the stack authors, keyed the way Elmer tags ComputeChange lines."""
    targets: dict[tuple[str, Literal["NS", "SS"]], LoopTargets] = {}

    for solver in config.solvers:
        key: str = normalize_solver_key(solver.equation)

        if isinstance(solver, NonlinearSystem):
            targets[(key, "NS")] = LoopTargets(
                max_iterations=solver.nonlinear_system_max_iterations,
                tolerance=solver.nonlinear_system_convergence_tolerance,
            )

        if isinstance(solver, SteadyState):
            targets[(key, "SS")] = LoopTargets(
                max_iterations=config.simulation.steady_state_max_iterations,
                tolerance=solver.steady_state_convergence_tolerance,
            )

    return targets

bare_save_scalars

bare_save_scalars() -> SaveScalarsSolver

A SaveScalars with no configured reductions: exports every registered res: simulation/component scalar (Component force/torque, field energy) to scalars.dat.

Source code in src/femforge/elmer/config/output/save_scalars.py
def bare_save_scalars() -> SaveScalarsSolver:
    """A SaveScalars with no configured reductions: exports every registered ``res:`` simulation/component scalar (Component force/torque, field energy) to ``scalars.dat``."""
    return SaveScalarsSolver(variable_1=None, operator_1=None, coefficient_1=None, variable_2=None, operator_2=None)