Conditions and physics¶
A Physics member picks what the solver backend, Elmer today, solves, and conditions supply the sources and constraints of that solve. Each condition knows its physics and whether it attaches to a body or a boundary, and it rides on an EntityTag that selects bodies by their tags. One domain can carry conditions for several physics: a solve reads the conditions of its own physics and leaves the rest inert.
Drive a magnet and measure its force¶
import femforge as ff
magnet = ff.EntityTag(
selector={ff.TagKey.NAME: "Magnet"},
conditions=[
ff.Magnetization(direction=ff.Direction(0, 0, 1)),
ff.ForceComponent(
label="MagnetForce",
calculate_magnetic_torque=True,
torque_origin=ff.Vec3(0, 0, 0),
torque_axis=ff.Direction(0, 0, 1),
),
],
)
config = ff.SimulationConfig(
mesh=ff.MeshConfig(step="magnet_in_air.step"),
domain=ff.DomainConfig(materials=[ff.materials.Air(), ff.materials.N52()], tags=[magnet]),
physics=ff.PhysicsSelection(selected=ff.Physics.MAGNETOSTATICS),
)
The STEP holds an air box and a body named Magnet tagged Material=N52. The Magnetization sets the magnet's direction, and the N52 remanence sets its strength. The ForceComponent lumps the magnetic force and torque on the magnet into one Elmer Component named MagnetForce. The result reads them back as result.component_forces["MagnetForce"] and result.component_torques["MagnetForce"]. See Results.
Physics¶
| Member | Solves | Preset solver stack | Frames |
|---|---|---|---|
MAGNETOSTATICS |
The static magnetic field of magnets and steel. | MagnetoDynamicsSolver, MagnetoDynamicsCalcFieldsSolver, SaveScalarsSolver, ResultOutputSolver |
Solid; Axisymmetric as MAGNETOSTATICS_2D |
MAGNETOSTATICS_2D |
Axisymmetric magnetostatics on the r-z half-plane, with CurrentDensity coil drives. |
MagnetoDynamics2DSolver, MagnetoDynamicsCalcFieldsSolver, SaveScalarsSolver, ResultOutputSolver |
Axisymmetric only |
THERMAL |
Steady-state heat conduction. | HeatSolver, SaveScalarsSolver (peak temperature), ResultOutputSolver |
Solid, Axisymmetric |
ELECTROSTATICS |
The electrostatic potential and field. | ElectrostaticsSolver, ResultOutputSolver |
Solid |
CURRENT_CONDUCTION |
The static current density driven by electrode potentials. | StatCurrentSolver, SaveScalarsSolver, ResultOutputSolver |
Solid |
JOULE_HEATING |
Current conduction coupled to heat conduction: the temperature its Joule losses produce. | StatCurrentSolver, HeatSolver, SaveScalarsSolver, ResultOutputSolver |
Solid |
COIL_MAGNETOSTATICS |
Current conduction chained into magnetostatics: the field of a coil's solved current distribution. | CoilCurrentSolver, MagnetoDynamicsSolver, MagnetoDynamicsCalcFieldsSolver, SaveScalarsSolver, ResultOutputSolver |
Solid |
LINEAR_ELASTICITY |
Linear elastic stress and strain. | StressSolver, ResultOutputSolver |
Solid |
LINEAR_ELASTICITY is a scaffold: no condition targets it yet, and the material model has no Poisson ratio.
Select a physics with PhysicsSelection. You never select MAGNETOSTATICS_2D yourself: select MAGNETOSTATICS with frame=ff.Axisymmetric() and the config solves it as MAGNETOSTATICS_2D. A physics with no form in the frame raises when you build the config. See Frames.
Conditions¶
| Class | Physics | Target | What it sets |
|---|---|---|---|
| Magnetization | MAGNETOSTATICS |
body | The magnetization direction. The magnitude B_r/μ₀ comes from the material. |
| CurrentDensity | MAGNETOSTATICS_2D |
body | value [A/m²]: a uniform signed azimuthal current density, the homogenized drive of a stranded coil. |
| FixedTemperature | THERMAL |
boundary | value [K]: a fixed temperature. |
| HeatFlux | THERMAL |
boundary | value [W/m²]: a heat flux through the surface. |
| Convection | THERMAL |
outer shell | coefficient [W/(m²·K)] and ext_temperature [K]: Newton cooling to an ambient. |
| HeatSource | THERMAL |
body | power_density [W/m³]. With temperature_coefficient and reference_temperature, the source scales linearly with the local temperature. |
| FixedPotential | CURRENT_CONDUCTION |
boundary | value [V]: an electrode potential. The run also integrates the electrode current. |
| JouleHeat | JOULE_HEATING |
body | Heats the body with its solved Joule losses. It takes no value. |
| CoilDrive | COIL_MAGNETOSTATICS |
body | current [A]: the total current of a massive coil. Bodies that share one CoilDrive instance form one coil. |
| CoilTerminal | COIL_MAGNETOSTATICS |
outer shell | role: the coil's start or end electrode. Positive current flows from start to end. |
| ForceComponent | MAGNETOSTATICS |
body | Lumps the magnetic force, and optionally the torque about torque_origin and torque_axis, over the matched bodies. |
Every value is a pint quantity of the dimensionality in brackets. Build it with ff.quantity(300, "kelvin") or 300 * ff.U.K. See Materials.
Reverse a coil by swapping its terminal roles, and keep current positive.
Where conditions land¶
A body condition applies to every body its tag matches:
Magnetizationgoes into the magnet's own Material block, where the magnetic solver reads it.CoilDriveandForceComponentbecome Elmer Components. One condition instance gathers every body it matches into one Component.- The rest become one Body Force block per body.
You never tag a surface. A boundary condition on a body's tag lands on every boundary group that body borders, both its interfaces with other bodies and its outer shell. Convection and CoilTerminal land on the outer shell only (<BODY>__EXT): a film coefficient on an interior interface would bypass the conduction path, and a coil terminal is the electrode's exposed end face. When several conditions reach one surface, they merge into one boundary block.
For example, with a copper body named Trace on an FR4 body named Board:
The Board tag carries |
Lands on BOARD__TRACE |
Lands on BOARD__EXT |
|---|---|---|
FixedTemperature |
yes | yes |
Convection |
no | yes |
Some conditions need no authoring:
- The magnetic physics pin the potential to zero on every outer shell, a far-field condition.
- An axisymmetric solve pins the potential to zero on the symmetry axis (
<BODY>__AXIS), which is exact there. - Every magnet body gets its own force Component, named after its body group. An authored
ForceComponentthat matches the magnet replaces it.
Which conditions a physics reads¶
A coupled physics also reads the conditions of the physics it couples, so the same tags drive the standalone and the coupled solves.
| Solved physics | Reads the conditions of |
|---|---|
JOULE_HEATING |
JOULE_HEATING, CURRENT_CONDUCTION, THERMAL |
COIL_MAGNETOSTATICS |
COIL_MAGNETOSTATICS, MAGNETOSTATICS |
MAGNETOSTATICS_2D |
MAGNETOSTATICS_2D, MAGNETOSTATICS |
| Any other | Its own |
COIL_MAGNETOSTATICS leaves FixedPotential inert: it sources the coil from CoilDrive and CoilTerminal.
Checks before the solve¶
The config rejects a condition its frame cannot solve as soon as you build or assign it:
CurrentDensityneedsframe=ff.Axisymmetric().- An axisymmetric
Magnetizationmust point along the symmetry axis. - An axisymmetric
ForceComponentcannot ask for torque.
The sif writer checks the rest before it writes:
| Problem | Result |
|---|---|
| A material lacks a keyword its solvers need | Error |
A magnet has no Magnetization with a direction |
Error |
THERMAL, ELECTROSTATICS, CURRENT_CONDUCTION or JOULE_HEATING resolves no boundary condition |
Warning: the solve is likely ill-posed |
COIL_MAGNETOSTATICS finds no CoilDrive |
Warning: the coil has no source |
| A force Component exists but the stack cannot compute or export it | Warning |
Customize the solver stack¶
Each physics has a preset: a typed PhysicsConfig that holds the ordered solvers, the Simulation settings, the constants and the operating point. config.resolved_stack() returns the stack the run solves. To change it, call customize_physics:
import femforge as ff
config = ff.SimulationConfig(
mesh=ff.MeshConfig(step="magnet_in_air.step"),
physics=ff.PhysicsSelection(selected=ff.Physics.MAGNETOSTATICS),
)
stack = config.customize_physics()
solver = stack.solver(ff.elmer.MagnetoDynamicsSolver)
solver.linear_system_max_iterations = 1000
stack.simulation.max_output_level = 3
customize_physics() copies the preset into config.physics.overrides once and returns it, so later calls edit the same stack. Every field is a typed sif keyword, validated when you assign it.
- The overrides are part of the config, so they enter the run identity and the manifest. Overrides equal to the preset leave the identity unchanged.
- Set the frame before you customize. A stack customized for one frame raises under the other, since the coordinate system differs.
- Every solver and the Simulation settings take
extra_keywordsfor a sif keyword femforge has no field for. GenericSolver adds a whole solver block femforge has no model for.
The solver models and their keyword tables live in the Elmer solvers API.
Reference¶
- Physical API: the conditions,
EntityTagandDomainConfig. - Elmer API:
Physicsand the backends. - Elmer solvers API:
PhysicsSelection,PhysicsConfig, the presets and every solver.