# Physical

The physics domain model: region tags and their materials, boundary and body conditions, and the property functions their values come from.

## femforge.physical

The physics domain model: per-region tags and their materials, the boundary/body conditions, and the property functions those values are written as.

Modules:

- **`conditions`** –

  Conditions attached to a region, each carrying its physics, its body or boundary target and its own Elmer sif emission.
- **`domain`** –

  The simulation domain: the materials and per-region tag overrides shared by the mesh and FEA backends.
- **`expressions`** –

  Typed expression AST over bare SI magnitudes for variable-dependent material properties: evaluates in Python, renders to Elmer MATC or Lua, serializes to JSON.
- **`property_functions`** –

  Material properties as pint-aware callables (Static, Calibration, ClosedForm, Expression) behind the `PropertyFunction` protocol.
- **`units`** –

  The shared pint unit registry, its typed quantity facades and the dimensionality-constrained quantity field types.

Classes:

- **`CoilDrive`** –

  A driven coil under `COIL_MAGNETOSTATICS` (body target): bodies sharing this condition become one massive CoilSolver `Component` normalized to `current`.
- **`CoilTerminal`** –

  One end of an open coil's terminal pair, Elmer's `Coil Start` or `Coil End` marker (`COIL_MAGNETOSTATICS`, boundary target).
- **`Condition`** –

  Base condition: subclasses pin `physics`/`target` defaults and implement `to_elmer`. Never instantiated directly (no `kind` discriminator).
- **`ConditionTarget`** –

  Whether a condition attaches to a 3D body or a 2D boundary.
- **`Convection`** –

  Convective (Newton-cooling) boundary condition (thermal, boundary target); `external_only` — a film BC on an interior interface would bypass the conduction path.
- **`CurrentDensity`** –

  Uniform signed azimuthal current density J = N·I/A over a winding window (axisymmetric magnetostatics, body target), the homogenized stranded-coil drive.
- **`FixedPotential`** –

  Dirichlet electric-potential boundary condition (current conduction, boundary target), one electrode of a phase's terminal pair.
- **`FixedTemperature`** –

  Dirichlet temperature boundary condition (thermal, boundary target).
- **`ForceComponent`** –

  An Elmer `Component` lumping CalcFields' magnetic force and torque over the bodies this condition's tag matches (magnetic physics, body target).
- **`HeatFlux`** –

  Prescribed heat flux boundary condition (thermal, boundary target).
- **`HeatSource`** –

  Volumetric heat source in W/m³ (thermal, body target).
- **`JouleHeat`** –

  Joule heat source body force (coupled current-\>thermal, body target): HeatSolve integrates StatCurrentSolve's loss density as the heat source.
- **`Magnetization`** –

  Permanent-magnet body force (magnetostatics, body target).
- **`DomainConfig`** –

  The materials the mesher matches to STEP parts, plus the per-region `EntityTag` overrides (conditions / mesh refinement).
- **`EntityTag`** –

  A per-region override matched to a mesh entity by its authored tags; carries the region's self-describing `conditions`.
- **`Add`** –

  The sum of two subexpressions.
- **`Const`** –

  A literal SI magnitude.
- **`Div`** –

  The quotient of two subexpressions.
- **`ExprNode`** –

  Base node: shared config + Python operator composition, so laws are authored as plain arithmetic.
- **`Mul`** –

  The product of two subexpressions.
- **`Neg`** –

  The negation of a subexpression.
- **`Param`** –

  A named parameter (e.g. `temperature`), bound at evaluation/render time.
- **`Pow`** –

  One subexpression raised to the power of another.
- **`Sub`** –

  The difference of two subexpressions.
- **`BasePropertyFunction`** –

  Pydantic base implementing parameter checking once; subclasses declare `parameters` / `result_dimensionality` and implement `_evaluate`.
- **`Calibration`** –

  A property defined by sample points and interpolated between them (1-D only for now).
- **`CalibrationPoint`** –

  One measured sample: input quantities by name and the resulting output.
- **`ClosedForm`** –

  A property defined by an explicit Python callable, pint-in / pint-out; the callable is code, not JSON-serializable.
- **`Expression`** –

  A property defined by a serializable typed expression AST (`physical.expressions`) — `ClosedForm` as data instead of code.
- **`PropertyDimensionError`** –

  A supplied parameter had the wrong dimensionality.
- **`PropertyError`** –

  Base class for every property-function error.
- **`PropertyFunction`** –

  A material property as a function of zero or more named pint quantities, returning a pint Quantity.
- **`PropertyFunctionField`** –

  Annotated metadata for a `PropertyFunction` constrained to `dimensionality`.
- **`PropertyParameterError`** –

  A required parameter was not supplied when evaluating a property.
- **`PropertyRangeError`** –

  A parameter fell outside the calibrated range and extrapolation is off.
- **`Static`** –

  A constant property: zero parameters, always returns `value`.
- **`Quantity`** –

  A pint quantity with a float magnitude.
- **`Unit`** –

  A pint unit, typed so that arithmetic with units and numbers keeps its type.
- **`VectorQuantity`** –

  A pint quantity with a `Vec3` magnitude.

Functions:

- **`conditions_for`** –

  The conditions on `tags` that belong to `physics` and attach to `target`.
- **`as_expr`** –

  Wrap a bare number into `Const`; pass nodes through (the operator-composition coercion point).
- **`evaluate`** –

  Module-level convenience mirroring `expr.evaluate`.
- **`render`** –

  Backend source for `expr` with parameter references substituted (e.g. `{"temperature": "tx(0)"}`).
- **`property_function_type`** –

  A `PropertyFunction` constrained to `dimensionality`, usable as a Pydantic field.
- **`quantity`** –

  Statically-typed face of `U.Quantity(...)`: a `float` magnitude yields `Quantity`, a Vec3 yields `VectorQuantity`.

Attributes:

- **`ConditionUnion`** –

  Any concrete condition, discriminated by its `kind`.
- **`Expr`** –

  Any expression node, discriminated by its `op`.
- **`U`** –

  The shared pint unit registry, as in `5 * U.mm` or `U.Quantity(1.2, "T")`.

### ConditionUnion

```python
ConditionUnion = Union[Magnetization, CurrentDensity, FixedTemperature, HeatFlux, Convection, HeatSource, FixedPotential, JouleHeat, CoilDrive, CoilTerminal, ForceComponent]
```

Any concrete condition, discriminated by its `kind`.

### Expr

```python
Expr = Union[Const, Param, Add, Sub, Mul, Div, Pow, Neg]
```

Any expression node, discriminated by its `op`.

### U

```python
U = cast('_TypedRegistry', pint.UnitRegistry(autoconvert_offset_to_baseunit=True))
```

The shared pint unit registry, as in `5 * U.mm` or `U.Quantity(1.2, "T")`.

### CoilDrive

Bases: `Condition`

A driven coil under `COIL_MAGNETOSTATICS` (body target): bodies sharing this condition become one massive CoilSolver `Component` normalized to `current`.

Reverse the drive by swapping the terminal roles, not with a negative current.

Fields:

- `kind` (`Literal['coil_drive']`)
- `physics` (`Physics`)
- `target` (`ConditionTarget`)
- `current` (`Current`)

#### kind

```python
kind: Literal['coil_drive'] = 'coil_drive'
```

Discriminator that names this condition type in a serialized config.

#### physics

```python
physics: Physics = Physics.COIL_MAGNETOSTATICS
```

The physics whose solve this condition feeds.

#### target

```python
target: ConditionTarget = ConditionTarget.BODY
```

Whether the condition attaches to a body or a boundary.

#### current

```python
current: Current
```

`I_coil` `[A]`: The total coil current CoilSolver normalizes this coil's solved distribution to.

#### to\_elmer

```python
to_elmer() -> dict[str, float | str]
```

The `Desired Coil Current` and the massive `Coil Type`.

### CoilTerminal

Bases: `Condition`

One end of an open coil's terminal pair, Elmer's `Coil Start` or `Coil End` marker (`COIL_MAGNETOSTATICS`, boundary target).

The electrode's end face must lie on the domain boundary (`GeometryConfig.terminate_electrodes`); positive coil current flows from start to end.

Fields:

- `kind` (`Literal['coil_terminal']`)
- `physics` (`Physics`)
- `target` (`ConditionTarget`)
- `role` (`Literal['start', 'end']`)

#### kind

```python
kind: Literal['coil_terminal'] = 'coil_terminal'
```

Discriminator that names this condition type in a serialized config.

#### physics

```python
physics: Physics = Physics.COIL_MAGNETOSTATICS
```

The physics whose solve this condition feeds.

#### target

```python
target: ConditionTarget = ConditionTarget.BOUNDARY
```

Whether the condition attaches to a body or a boundary.

#### role

```python
role: Literal['start', 'end']
```

Which end of the coil this electrode is; CoilSolver's normalized current flows start -\> end.

#### to\_elmer

```python
to_elmer() -> dict[str, float | str]
```

The `Coil Start` or `Coil End` flag for this `role`.

### Condition

Bases: `BaseModel`

Base condition: subclasses pin `physics`/`target` defaults and implement `to_elmer`. Never instantiated directly (no `kind` discriminator).

Config:

- `arbitrary_types_allowed`: `True`
- `use_attribute_docstrings`: `True`

Fields:

- `physics` (`Physics`)
- `target` (`ConditionTarget`)

#### external\_only

```python
external_only: bool = False
```

Boundary-target conditions with this set land only on a body's *external* (domain-boundary) surface groups, not its interfaces — e.g. a coil terminal is the electrode's exposed end face, not its interior contacts.

#### physics

```python
physics: Physics
```

The physics whose solve this condition feeds.

#### target

```python
target: ConditionTarget
```

Whether the condition attaches to a body or a boundary.

#### to\_elmer

```python
to_elmer(*args: Any, **kwargs: Any) -> dict[str, float | str]
```

This condition's Elmer sif keyword dict, reflected from each field's `ElmerKeyword` metadata.

#### check\_frame

```python
check_frame(frame: Frame) -> None
```

Raise when this condition cannot drive a `frame` solve.

### ConditionTarget

Bases: `StrEnum`

Whether a condition attaches to a 3D body or a 2D boundary.

Attributes:

- **`BODY`** –

  Attach to a body.
- **`BOUNDARY`** –

  Attach to a boundary surface.

#### BODY

```python
BODY = 'body'
```

Attach to a body.

#### BOUNDARY

```python
BOUNDARY = 'boundary'
```

Attach to a boundary surface.

### Convection

Bases: `Condition`

Convective (Newton-cooling) boundary condition (thermal, boundary target); `external_only` — a film BC on an interior interface would bypass the conduction path.

Fields:

- `kind` (`Literal['convection']`)
- `physics` (`Physics`)
- `target` (`ConditionTarget`)
- `coefficient` (`HeatTransferCoefficient`)
- `ext_temperature` (`Temperature`)

#### kind

```python
kind: Literal['convection'] = 'convection'
```

Discriminator that names this condition type in a serialized config.

#### physics

```python
physics: Physics = Physics.THERMAL
```

The physics whose solve this condition feeds.

#### target

```python
target: ConditionTarget = ConditionTarget.BOUNDARY
```

Whether the condition attaches to a body or a boundary.

#### coefficient

```python
coefficient: HeatTransferCoefficient
```

`h` `[W/(m²·K)]`: Convective heat-transfer coefficient.

#### ext\_temperature

```python
ext_temperature: Temperature
```

`T_amb` `[K]`: External (ambient) temperature the boundary exchanges with.

### CurrentDensity

Bases: `Condition`

Uniform signed azimuthal current density J = N·I/A over a winding window (axisymmetric magnetostatics, body target), the homogenized stranded-coil drive.

Requires `frame=Axisymmetric()`.

Fields:

- `kind` (`Literal['current_density']`)
- `physics` (`Physics`)
- `target` (`ConditionTarget`)
- `value` (`CurrentDensity`)

#### kind

```python
kind: Literal['current_density'] = 'current_density'
```

Discriminator that names this condition type in a serialized config.

#### physics

```python
physics: Physics = Physics.MAGNETOSTATICS_2D
```

The physics whose solve this condition feeds.

#### target

```python
target: ConditionTarget = ConditionTarget.BODY
```

Whether the condition attaches to a body or a boundary.

#### value

```python
value: CurrentDensity
```

`J` `[A/m²]`: Azimuthal current density (signed) imposed uniformly over the body.

#### check\_frame

```python
check_frame(frame: Frame) -> None
```

Raise unless `frame` is axisymmetric.

### FixedPotential

Bases: `Condition`

Dirichlet electric-potential boundary condition (current conduction, boundary target), one electrode of a phase's terminal pair.

Fields:

- `kind` (`Literal['fixed_potential']`)
- `physics` (`Physics`)
- `target` (`ConditionTarget`)
- `value` (`Voltage`)

#### kind

```python
kind: Literal['fixed_potential'] = 'fixed_potential'
```

Discriminator that names this condition type in a serialized config.

#### physics

```python
physics: Physics = Physics.CURRENT_CONDUCTION
```

The physics whose solve this condition feeds.

#### target

```python
target: ConditionTarget = ConditionTarget.BOUNDARY
```

Whether the condition attaches to a body or a boundary.

#### value

```python
value: Voltage
```

`V` `[V]`: Electric potential imposed on the electrode boundary; the keyword is the solver variable's name (Elmer Dirichlet semantics), single-sourced via the enum.

#### to\_elmer

```python
to_elmer() -> dict[str, float | str]
```

The electrode potential plus the `Save Scalars` flag that makes SaveScalars integrate the electrode current.

### FixedTemperature

Bases: `Condition`

Dirichlet temperature boundary condition (thermal, boundary target).

Fields:

- `kind` (`Literal['fixed_temperature']`)
- `physics` (`Physics`)
- `target` (`ConditionTarget`)
- `value` (`Temperature`)

#### kind

```python
kind: Literal['fixed_temperature'] = 'fixed_temperature'
```

Discriminator that names this condition type in a serialized config.

#### physics

```python
physics: Physics = Physics.THERMAL
```

The physics whose solve this condition feeds.

#### target

```python
target: ConditionTarget = ConditionTarget.BOUNDARY
```

Whether the condition attaches to a body or a boundary.

#### value

```python
value: Temperature
```

`T` `[K]`: Fixed temperature imposed on the boundary.

### ForceComponent

Bases: `Condition`

An Elmer `Component` lumping CalcFields' magnetic force and torque over the bodies this condition's tag matches (magnetic physics, body target).

Fields:

- `kind` (`Literal['force_component']`)
- `physics` (`Physics`)
- `target` (`ConditionTarget`)
- `label` (`str | None`)
- `calculate_magnetic_force` (`bool`)
- `calculate_magnetic_torque` (`bool`)
- `torque_origin` (`Vec3Field | None`)
- `torque_axis` (`DirectionField | None`)

#### kind

```python
kind: Literal['force_component'] = 'force_component'
```

Discriminator that names this condition type in a serialized config.

#### physics

```python
physics: Physics = Physics.MAGNETOSTATICS
```

The physics whose solve this condition feeds.

#### target

```python
target: ConditionTarget = ConditionTarget.BODY
```

Whether the condition attaches to a body or a boundary.

#### label

```python
label: str | None = None
```

The Component's `Name`; None uses the authoring tag's name.

#### calculate\_magnetic\_force

```python
calculate_magnetic_force: bool = True
```

Lump the nodal magnetic force over the master bodies.

#### calculate\_magnetic\_torque

```python
calculate_magnetic_torque: bool = False
```

Also lump the magnetic torque (requires `torque_origin`/`torque_axis`).

#### torque\_origin

```python
torque_origin: Vec3Field | None = None
```

`r_0` `[m]`: Torque pivot point.

#### torque\_axis

```python
torque_axis: DirectionField | None = None
```

Torque axis direction.

#### to\_elmer

```python
to_elmer() -> dict[str, float | str]
```

The CalcFields force and torque flags, plus the torque origin and axis when set.

#### check\_frame

```python
check_frame(frame: Frame) -> None
```

Raise when torque is requested under an axisymmetric `frame`.

### HeatFlux

Bases: `Condition`

Prescribed heat flux boundary condition (thermal, boundary target).

Fields:

- `kind` (`Literal['heat_flux']`)
- `physics` (`Physics`)
- `target` (`ConditionTarget`)
- `value` (`HeatFlux`)

#### kind

```python
kind: Literal['heat_flux'] = 'heat_flux'
```

Discriminator that names this condition type in a serialized config.

#### physics

```python
physics: Physics = Physics.THERMAL
```

The physics whose solve this condition feeds.

#### target

```python
target: ConditionTarget = ConditionTarget.BOUNDARY
```

Whether the condition attaches to a body or a boundary.

#### value

```python
value: HeatFlux
```

`q_s` `[W/m²]`: Heat flux through the boundary.

### HeatSource

Bases: `Condition`

Volumetric heat source in W/m³ (thermal, body target).

With `temperature_coefficient` set, the source scales linearly with the local temperature, the σ(T) Joule feedback of a prescribed-current winding.

Fields:

- `kind` (`Literal['heat_source']`)
- `physics` (`Physics`)
- `target` (`ConditionTarget`)
- `power_density` (`PowerDensity`)
- `temperature_coefficient` (`float | None`)
- `reference_temperature` (`Temperature | None`)

#### kind

```python
kind: Literal['heat_source'] = 'heat_source'
```

Discriminator that names this condition type in a serialized config.

#### physics

```python
physics: Physics = Physics.THERMAL
```

The physics whose solve this condition feeds.

#### target

```python
target: ConditionTarget = ConditionTarget.BODY
```

Whether the condition attaches to a body or a boundary.

#### power\_density

```python
power_density: PowerDensity
```

`q` `[W/m³]`: Heat generation density at `reference_temperature` when a coefficient is set, else the constant source.

#### temperature\_coefficient

```python
temperature_coefficient: float | None = None
```

`α` `[1/K]`: Linear coefficient in q(T) = power\_density·(1 + α·(T − reference\_temperature)); None emits the constant.

#### reference\_temperature

```python
reference_temperature: Temperature | None = None
```

`T_ref` `[K]`: The temperature `power_density` holds at; required with `temperature_coefficient`.

#### to\_elmer

```python
to_elmer() -> dict[str, float | str]
```

The `Volumetric Heat Source` keyword, a MATC expression in temperature when `temperature_coefficient` is set.

### JouleHeat

Bases: `Condition`

Joule heat source body force (coupled current-\>thermal, body target): HeatSolve integrates StatCurrentSolve's loss density as the heat source.

Carries no value — the magnitude is the solved current field itself.

Fields:

- `kind` (`Literal['joule_heat']`)
- `physics` (`Physics`)
- `target` (`ConditionTarget`)

#### kind

```python
kind: Literal['joule_heat'] = 'joule_heat'
```

Discriminator that names this condition type in a serialized config.

#### physics

```python
physics: Physics = Physics.JOULE_HEATING
```

The physics whose solve this condition feeds.

#### target

```python
target: ConditionTarget = ConditionTarget.BODY
```

Whether the condition attaches to a body or a boundary.

#### to\_elmer

```python
to_elmer() -> dict[str, float | str]
```

The `Joule Heat` flag.

### Magnetization

Bases: `Condition`

Permanent-magnet body force (magnetostatics, body target).

The direction is per-region and lives here; the magnitude `|M| = Bᵣ/μ₀` is a material property passed into `to_elmer`.

Fields:

- `kind` (`Literal['magnetization']`)
- `physics` (`Physics`)
- `target` (`ConditionTarget`)
- `direction` (`DirectionField | None`)

#### kind

```python
kind: Literal['magnetization'] = 'magnetization'
```

Discriminator that names this condition type in a serialized config.

#### physics

```python
physics: Physics = Physics.MAGNETOSTATICS
```

The physics whose solve this condition feeds.

#### target

```python
target: ConditionTarget = ConditionTarget.BODY
```

Whether the condition attaches to a body or a boundary.

#### direction

```python
direction: DirectionField | None
```

Magnetization direction in the authored model's frame, None for an unmagnetized body; magnitude comes from the material.

#### to\_elmer

```python
to_elmer(magnitude: float, frame: Frame) -> dict[str, float | str]
```

The `Magnetization` components of `magnitude` (A/m) along the direction, in `frame`'s solve coordinates.

#### check\_frame

```python
check_frame(frame: Frame) -> None
```

Raise when an axisymmetric `frame` meets a direction off its symmetry axis.

### DomainConfig

Bases: `ConfigArea`

The materials the mesher matches to STEP parts, plus the per-region `EntityTag` overrides (conditions / mesh refinement).

Fields:

- `materials` (`list[MaterialProperties]`)
- `tags` (`list[EntityTag]`)

#### materials

```python
materials: list[MaterialProperties]
```

The candidate materials; the mesher matches each STEP entity to one by `tag`.

#### tags

```python
tags: list[EntityTag]
```

The per-region overrides, matched to mesh entities by name; each carries its `conditions` and optional `mesh_size`.

#### check\_frame

```python
check_frame(frame: Frame) -> None
```

Raise when a condition here cannot drive a `frame` solve.

### EntityTag

Bases: `ConfigArea`

A per-region override matched to a mesh entity by its authored tags; carries the region's self-describing `conditions`.

Fields:

- `selector` (`TagDict`)
- `conditions` (`list[ConditionUnion]`)
- `mesh_size` (`float | None`)

#### selector

```python
selector: TagDict
```

Compound-key selector: a mesh entity matches when its tag dict contains ALL of these key=value pairs (an empty selector matches every entity).

#### conditions

```python
conditions: list[ConditionUnion]
```

Composable, self-describing conditions (body forces / boundary conditions) this region carries.

#### mesh\_size

```python
mesh_size: float | None = None
```

`h` `[m]`: Target mesh size for this region, such as a finer air gap; None inherits `MeshConfig.global_mesh_size`.

#### name

```python
name: str
```

Stable human-readable stem shared with gmsh/Elmer names: the uppercased part name for a lone `Name` selector, else sorted KeyValue pairs (`CurrentDirEntry_Phase2`).

#### matches

```python
matches(tags: Mapping[str, str]) -> bool
```

Whether an entity's tag dict satisfies every selector pair.

#### print\_tree

```python
print_tree(tree: Tree) -> None
```

Add this tag and its conditions to `tree`.

### Add

Bases: `_Binary`

The sum of two subexpressions.

Fields:

- `left` (`'Expr'`)
- `right` (`'Expr'`)
- `op` (`Literal['add']`)
- `_symbol` (`str`)

#### op

```python
op: Literal['add'] = 'add'
```

Discriminator that names this node type in serialized JSON.

#### evaluate

```python
evaluate(env: Mapping[str, float]) -> float
```

The sum of both operands.

### Const

Bases: `ExprNode`

A literal SI magnitude.

Fields:

- `op` (`Literal['const']`)
- `value` (`float`)

#### op

```python
op: Literal['const'] = 'const'
```

Discriminator that names this node type in serialized JSON.

#### value

```python
value: float
```

`c` `[?]`: The literal magnitude, in SI units.

#### evaluate

```python
evaluate(env: Mapping[str, float]) -> float
```

The literal value.

#### render

```python
render(refs: Mapping[str, str]) -> str
```

The literal at full float precision.

#### parameters

```python
parameters() -> frozenset[str]
```

The empty set: a literal references no parameter.

### Div

Bases: `_Binary`

The quotient of two subexpressions.

Fields:

- `left` (`'Expr'`)
- `right` (`'Expr'`)
- `op` (`Literal['div']`)
- `_symbol` (`str`)

#### op

```python
op: Literal['div'] = 'div'
```

Discriminator that names this node type in serialized JSON.

#### evaluate

```python
evaluate(env: Mapping[str, float]) -> float
```

The left operand divided by the right one.

### ExprNode

Bases: `BaseModel`

Base node: shared config + Python operator composition, so laws are authored as plain arithmetic.

Config:

- `frozen`: `True`
- `use_attribute_docstrings`: `True`

#### evaluate

```python
evaluate(env: Mapping[str, float]) -> float
```

This subtree's value with each parameter bound to a bare SI float.

#### render

```python
render(refs: Mapping[str, str]) -> str
```

This subtree as backend source, with each parameter name replaced by its reference (e.g. `tx(0)`).

#### parameters

```python
parameters() -> frozenset[str]
```

Every parameter name referenced in this subtree.

### Mul

Bases: `_Binary`

The product of two subexpressions.

Fields:

- `left` (`'Expr'`)
- `right` (`'Expr'`)
- `op` (`Literal['mul']`)
- `_symbol` (`str`)

#### op

```python
op: Literal['mul'] = 'mul'
```

Discriminator that names this node type in serialized JSON.

#### evaluate

```python
evaluate(env: Mapping[str, float]) -> float
```

The product of both operands.

### Neg

Bases: `ExprNode`

The negation of a subexpression.

Fields:

- `op` (`Literal['neg']`)
- `operand` (`'Expr'`)

#### op

```python
op: Literal['neg'] = 'neg'
```

Discriminator that names this node type in serialized JSON.

#### operand

```python
operand: 'Expr'
```

The negated subexpression.

#### evaluate

```python
evaluate(env: Mapping[str, float]) -> float
```

The negated operand.

#### render

```python
render(refs: Mapping[str, str]) -> str
```

The negation as `(-operand)`.

#### parameters

```python
parameters() -> frozenset[str]
```

The operand's parameters.

### Param

Bases: `ExprNode`

A named parameter (e.g. `temperature`), bound at evaluation/render time.

Fields:

- `op` (`Literal['param']`)
- `name` (`str`)

#### op

```python
op: Literal['param'] = 'param'
```

Discriminator that names this node type in serialized JSON.

#### name

```python
name: str
```

The parameter name that `env` and `refs` bind.

#### evaluate

```python
evaluate(env: Mapping[str, float]) -> float
```

The value `env` binds to this parameter.

#### render

```python
render(refs: Mapping[str, str]) -> str
```

The backend reference `refs` binds to this parameter.

#### parameters

```python
parameters() -> frozenset[str]
```

This parameter's name.

### Pow

Bases: `ExprNode`

One subexpression raised to the power of another.

Fields:

- `op` (`Literal['pow']`)
- `base` (`'Expr'`)
- `exponent` (`'Expr'`)

#### op

```python
op: Literal['pow'] = 'pow'
```

Discriminator that names this node type in serialized JSON.

#### base

```python
base: 'Expr'
```

The base.

#### exponent

```python
exponent: 'Expr'
```

The exponent.

#### evaluate

```python
evaluate(env: Mapping[str, float]) -> float
```

The base raised to the exponent.

#### render

```python
render(refs: Mapping[str, str]) -> str
```

The power as `(base ^ exponent)`.

#### parameters

```python
parameters() -> frozenset[str]
```

The parameters of the base and the exponent.

### Sub

Bases: `_Binary`

The difference of two subexpressions.

Fields:

- `left` (`'Expr'`)
- `right` (`'Expr'`)
- `op` (`Literal['sub']`)
- `_symbol` (`str`)

#### op

```python
op: Literal['sub'] = 'sub'
```

Discriminator that names this node type in serialized JSON.

#### evaluate

```python
evaluate(env: Mapping[str, float]) -> float
```

The left operand minus the right one.

### BasePropertyFunction

Bases: `BaseModel`

Pydantic base implementing parameter checking once; subclasses declare `parameters` / `result_dimensionality` and implement `_evaluate`.

Extra keyword arguments are ignored, so an operating point may carry more quantities than a property needs.

Config:

- `arbitrary_types_allowed`: `True`
- `use_attribute_docstrings`: `True`

#### parameters

```python
parameters: Mapping[str, str]
```

Required parameter name to expected dimensionality, as a pint string.

#### result\_dimensionality

```python
result_dimensionality: str
```

Dimensionality of the returned quantity.

### Calibration

Bases: `BasePropertyFunction`

A property defined by sample points and interpolated between them (1-D only for now).

Point inputs are validated against `param_dims` at construction; out-of-range raises unless `extrapolate=True`.

Fields:

- `kind` (`Literal['calibration']`)
- `param_dims` (`dict[str, str]`)
- `points` (`list[CalibrationPoint]`)
- `method` (`Literal['linear', 'nearest', 'cubic']`)
- `extrapolate` (`bool`)

Validators:

- `_validate_points`

#### kind

```python
kind: Literal['calibration'] = 'calibration'
```

Discriminator that names this property kind in serialized JSON.

#### param\_dims

```python
param_dims: dict[str, str]
```

The single parameter name and its expected dimensionality, as a pint string.

#### points

```python
points: list[CalibrationPoint]
```

The samples to interpolate between.

#### method

```python
method: Literal['linear', 'nearest', 'cubic'] = 'linear'
```

Interpolation between samples: linear, nearest, or monotone cubic (PCHIP).

#### extrapolate

```python
extrapolate: bool = False
```

Clamp to the end samples outside the calibrated range instead of raising.

#### parameters

```python
parameters: Mapping[str, str]
```

`param_dims` as the call schema.

#### result\_dimensionality

```python
result_dimensionality: str
```

The dimensionality of the sample outputs.

### CalibrationPoint

Bases: `BaseModel`

One measured sample: input quantities by name and the resulting output.

Config:

- `arbitrary_types_allowed`: `True`
- `use_attribute_docstrings`: `True`

Fields:

- `inputs` (`dict[str, Quantity]`)
- `output` (`Quantity`)

Validators:

- `_coerce_inputs` → `inputs`
- `_coerce_output` → `output`

#### inputs

```python
inputs: dict[str, Quantity]
```

`[?]`: The input quantities, keyed by parameter name.

#### output

```python
output: Quantity
```

`[?]`: The property value measured at `inputs`.

### ClosedForm

Bases: `BasePropertyFunction`

A property defined by an explicit Python callable, pint-in / pint-out; the callable is code, not JSON-serializable.

Fields:

- `param_dims` (`dict[str, str]`)
- `result_dim` (`str`)
- `expression` (`Callable[..., Quantity]`)

#### param\_dims

```python
param_dims: dict[str, str]
```

Parameter name to expected dimensionality, as a pint string.

#### result\_dim

```python
result_dim: str
```

The dimensionality the callable must return, as a pint string.

#### expression

```python
expression: Callable[..., Quantity]
```

The callable, given the declared parameters as keyword quantities.

#### parameters

```python
parameters: Mapping[str, str]
```

`param_dims` as the call schema.

#### result\_dimensionality

```python
result_dimensionality: str
```

The declared `result_dim`.

### Expression

Bases: `BasePropertyFunction`

A property defined by a serializable typed expression AST (`physical.expressions`) — `ClosedForm` as data instead of code.

`body` computes the result's SI magnitude in `result_units` from parameters bound as SI-base magnitudes, matching Elmer's `tx`.

Fields:

- `kind` (`Literal['expression']`)
- `param_dims` (`dict[str, str]`)
- `result_units` (`str`)
- `body` (`Expr`)

Validators:

- `_validate_body_parameters`

#### kind

```python
kind: Literal['expression'] = 'expression'
```

Discriminator that names this property kind in serialized JSON.

#### param\_dims

```python
param_dims: dict[str, str]
```

Parameter name to expected dimensionality, as a pint string.

#### result\_units

```python
result_units: str
```

The pint units of the magnitude `body` computes.

#### body

```python
body: Expr
```

The law over parameters bound as SI-base magnitudes.

#### parameters

```python
parameters: Mapping[str, str]
```

`param_dims` as the call schema.

#### result\_dimensionality

```python
result_dimensionality: str
```

The dimensionality of `result_units`.

### PropertyDimensionError

```python
PropertyDimensionError(fn: 'PropertyFunction', name: str, expected: str, got: object)
```

Bases: `PropertyError`

A supplied parameter had the wrong dimensionality.

Parameters:

- **`fn`** (`'PropertyFunction'`) –

  The property that rejected the call.
- **`name`** (`str`) –

  The offending parameter, or `<result>` for a closed form's return value.
- **`expected`** (`str`) –

  The dimensionality the parameter needs.
- **`got`** (`object`) –

  The dimensionality, or the type, that was supplied.

### PropertyError

Bases: `Exception`

Base class for every property-function error.

### PropertyFunction

Bases: `Protocol`

A material property as a function of zero or more named pint quantities, returning a pint Quantity.

Methods:

- **`__call__`** –

  Evaluate. Raises a typed error if a required parameter is missing or has the wrong dimensionality.

Attributes:

- **`parameters`** (`Mapping[str, str]`) –

  Required parameter name -\> expected dimensionality (pint string); this IS the call schema.
- **`result_dimensionality`** (`str`) –

  Dimensionality of the returned quantity, e.g. `'[power]/[length]/[temperature]'`.

#### parameters

```python
parameters: Mapping[str, str]
```

Required parameter name -\> expected dimensionality (pint string); this IS the call schema.

#### result\_dimensionality

```python
result_dimensionality: str
```

Dimensionality of the returned quantity, e.g. `'[power]/[length]/[temperature]'`.

#### \_\_call\_\_

```python
__call__(**kwargs: Quantity) -> Quantity
```

Evaluate. Raises a typed error if a required parameter is missing or has the wrong dimensionality.

### PropertyFunctionField

```python
PropertyFunctionField(dimensionality: str)
```

Annotated metadata for a `PropertyFunction` constrained to `dimensionality`.

Coerces bare quantities/strings into `Static`, validates result dimensionality, and exports quantity\_type's unit-annotated JSON schema.

### PropertyParameterError

```python
PropertyParameterError(fn: 'PropertyFunction', missing: set[str])
```

Bases: `PropertyError`

A required parameter was not supplied when evaluating a property.

### PropertyRangeError

```python
PropertyRangeError(fn: 'PropertyFunction', name: str, value: object, low: object, high: object)
```

Bases: `PropertyError`

A parameter fell outside the calibrated range and extrapolation is off.

Parameters:

- **`fn`** (`'PropertyFunction'`) –

  The calibration that rejected the call.
- **`name`** (`str`) –

  The out-of-range parameter.
- **`value`** (`object`) –

  The supplied value.
- **`low`** (`object`) –

  The lowest calibrated value.
- **`high`** (`object`) –

  The highest calibrated value.

### Static

Bases: `BasePropertyFunction`

A constant property: zero parameters, always returns `value`.

Authored as `Static(value="8.7 W/(m*K)")`; ignores any operating-point arguments.

Fields:

- `value` (`Quantity`)

Validators:

- `_coerce_value` → `value`

#### value

```python
value: Quantity
```

`[?]`: The constant returned at every operating point.

#### parameters

```python
parameters: Mapping[str, str]
```

No parameters: a constant ignores the operating point.

#### result\_dimensionality

```python
result_dimensionality: str
```

The dimensionality of `value`.

### Quantity

Bases: `PlainQuantity[float]`

A pint quantity with a float magnitude.

Methods:

- **`to`** –

  This quantity converted to the units `other` names.

#### to

```python
to(other: object = None, *contexts: object, **ctx_kwargs: object) -> Quantity
```

This quantity converted to the units `other` names.

Parameters:

- **`other`** (`object`, default: `None` ) –

  The target units, as a unit, a quantity or a unit string.
- **`contexts`** (`object`, default: `()` ) –

  The pint contexts, by name or object, that enable the conversion.
- **`ctx_kwargs`** (`object`, default: `{}` ) –

  The parameters those contexts take.

### Unit

Bases: `PlainUnit`

A pint unit, typed so that arithmetic with units and numbers keeps its type.

### VectorQuantity

Bases: `PlainQuantity[Vec3]`

A pint quantity with a `Vec3` magnitude.

Methods:

- **`to`** –

  This vector quantity converted to the units `other` names.

#### to

```python
to(other: object = None, *contexts: object, **ctx_kwargs: object) -> VectorQuantity
```

This vector quantity converted to the units `other` names.

Parameters:

- **`other`** (`object`, default: `None` ) –

  The target units, as a unit, a quantity or a unit string.
- **`contexts`** (`object`, default: `()` ) –

  The pint contexts, by name or object, that enable the conversion.
- **`ctx_kwargs`** (`object`, default: `{}` ) –

  The parameters those contexts take.

### conditions\_for

```python
conditions_for(tags: Iterable[EntityTag], physics: Physics | Iterable[Physics], target: ConditionTarget) -> list[Condition]
```

The conditions on `tags` that belong to `physics` and attach to `target`.

Parameters:

- **`tags`** (`Iterable[EntityTag]`) –

  The region overrides that match the region.
- **`physics`** (`Physics | Iterable[Physics]`) –

  One `Physics`, or several, such as a coupled preset's constituents.
- **`target`** (`ConditionTarget`) –

  Whether to collect body or boundary conditions.

### as\_expr

```python
as_expr(value: 'ExprNode | float') -> 'Expr'
```

Wrap a bare number into `Const`; pass nodes through (the operator-composition coercion point).

### evaluate

```python
evaluate(expr: 'Expr', env: Mapping[str, float]) -> float
```

Module-level convenience mirroring `expr.evaluate`.

### render

```python
render(expr: 'Expr', *, refs: Mapping[str, str]) -> str
```

Backend source for `expr` with parameter references substituted (e.g. `{"temperature": "tx(0)"}`).

### property\_function\_type

```python
property_function_type(dimensionality: str) -> object
```

A `PropertyFunction` constrained to `dimensionality`, usable as a Pydantic field.

### quantity

```python
quantity(value: float, units: Unit | str | None = None) -> Quantity
```

```python
quantity(value: Vec3, units: Unit | str | None = None) -> VectorQuantity
```

```python
quantity(value: float | Vec3, units: Unit | str | None = None) -> Quantity | VectorQuantity
```

Statically-typed face of `U.Quantity(...)`: a `float` magnitude yields `Quantity`, a Vec3 yields `VectorQuantity`.

Prefer a string for composite units (`"newton * meter"`).
