# Config

The composed simulation config that ties the mesh, the domain and the Elmer physics together, and the solve frame it maps the authored model into.

## femforge.config

The composed simulation config: the composition root that ties the gmsh mesh, the domain and the Elmer physics areas together.

Classes:

- **`RunMeta`** –

  Searchable run metadata: a description and free key=value tags, recorded verbatim in the bundle manifest and
- **`SimulationConfig`** –

  The single config spanning the whole pipeline, one area model per concern; `solved_physics` / `resolved_stack` give what the run solves under `frame`.

### RunMeta

Bases: `ConfigArea`

Searchable run metadata: a description and free key=value tags, recorded verbatim in the bundle manifest and NEVER part of the run identity — editing them re-labels a run without re-solving it.

Config:

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

Fields:

- `description` (`str | None`)
- `tags` (`TagDict`)

#### description

```python
description: str | None = None
```

One line on what this run is for (shown in the driver log, searchable via `run.find_runs`).

#### tags

```python
tags: TagDict
```

Free key=value labels (the same tag-dict shape the geometry uses); `find_runs` matches by subset.

#### matches

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

Whether these tags satisfy every selector pair (the same containment rule as `EntityTag.matches`).

### SimulationConfig

Bases: `ConfigArea`

The single config spanning the whole pipeline, one area model per concern; `solved_physics` / `resolved_stack` give what the run solves under `frame`.

Config:

- `validate_assignment`: `True`

Fields:

- `geometry` (`SerializeAsAny[GeometryArea] | None`)
- `frame` (`Frame`)
- `mesh` (`MeshConfig`)
- `domain` (`DomainConfig`)
- `physics` (`PhysicsSelection`)
- `meta` (`RunMeta`)

Validators:

- `frame_fits_inputs` → `frame`
- `domain_fits_frame` → `domain`
- `physics_fits_frame` → `physics`

#### geometry

```python
geometry: SerializeAsAny[GeometryArea] | None = None
```

Optional parametric geometry: when set, the driver calls its `build_step` into the run directory before meshing and repoints `mesh.step` at it — the STEP is derived output, and the run identity comes from these parameters rather than an authored file.

#### frame

```python
frame: Frame
```

How the authored model maps onto the solve: as-is in 3D, or its axisymmetric r–z half-plane.

#### mesh

```python
mesh: MeshConfig
```

The gmsh mesh settings: STEP source, global element size, gmsh options.

#### domain

```python
domain: DomainConfig
```

Materials + per-region tags.

#### physics

```python
physics: PhysicsSelection
```

Which physics the Elmer stage solves.

#### meta

```python
meta: RunMeta
```

Searchable description + tags; excluded from `cache_key`, so labeling never re-identifies a run.

#### frame\_fits\_inputs

```python
frame_fits_inputs(frame: Frame, info: ValidationInfo) -> Frame
```

On reassignment, reject a `frame` the domain or the physics selection cannot solve.

#### domain\_fits\_frame

```python
domain_fits_frame(domain: DomainConfig, info: ValidationInfo) -> DomainConfig
```

Reject conditions the frame cannot solve.

#### physics\_fits\_frame

```python
physics_fits_frame(physics: PhysicsSelection, info: ValidationInfo) -> PhysicsSelection
```

Reject a selection the frame cannot solve.

#### solved\_physics

```python
solved_physics() -> Physics
```

The physics the selection solves as under `frame` (`MAGNETOSTATICS` becomes `MAGNETOSTATICS_2D` when axisymmetric).

#### resolved\_stack

```python
resolved_stack() -> PhysicsConfig
```

The solver stack the run solves: the authored `physics.overrides`, else the solved physics' preset in `frame`.

#### customize\_physics

```python
customize_physics() -> PhysicsConfig
```

Materialize the resolved stack into `physics.overrides` (idempotent) and return it for typed editing.

## femforge.common.frame

The solve frame: how an authored model maps onto the frame Elmer solves in.

Classes:

- **`Axis`** –

  A line through `origin` along `direction`, in the authored model's frame.
- **`Solid`** –

  Solve the authored 3D model as-is.
- **`Axisymmetric`** –

  Solve the r–z half-plane of a model symmetric about `axis`: X = radial, Y = along the axis, Z = 0.

Attributes:

- **`ALIGNMENT_TOLERANCE`** –

  `[-]`: The largest transverse share of a unit direction still counted as parallel to an axis.

### ALIGNMENT\_TOLERANCE

```python
ALIGNMENT_TOLERANCE = 1e-06
```

`[-]`: The largest transverse share of a unit direction still counted as parallel to an axis.

### Axis

Bases: `ConfigArea`

A line through `origin` along `direction`, in the authored model's frame.

Config:

- `frozen`: `True`

Fields:

- `origin` (`Vec3Field`)
- `direction` (`DirectionField`)

#### origin

```python
origin: Vec3Field
```

`[mm]`: A point on the axis.

#### direction

```python
direction: DirectionField
```

`[-]`: The axis direction; a scaled direction is the same axis.

#### label

```python
label: str
```

`Z` or `-X` for a coordinate axis through the origin, else its direction and origin.

#### along

```python
along(direction: Vec3) -> float | None
```

The cosine between `direction` and this axis (±1), or None when they are not parallel within `ALIGNMENT_TOLERANCE`.

### Solid

Bases: `ConfigArea`

Solve the authored 3D model as-is.

Config:

- `frozen`: `True`

Fields:

- `kind` (`Literal['solid']`)

#### kind

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

Discriminator that names this frame in a serialized config.

#### label

```python
label: str
```

A short human-readable name.

#### model\_dim

```python
model_dim: Literal[2, 3]
```

The mesh dimension this frame solves on.

### Axisymmetric

Bases: `ConfigArea`

Solve the r–z half-plane of a model symmetric about `axis`: X = radial, Y = along the axis, Z = 0.

Config:

- `frozen`: `True`

Fields:

- `kind` (`Literal['axisymmetric']`)
- `axis` (`Axis`)
- `radial` (`DirectionField | None`)

Validators:

- `perpendicular` → `radial`

#### kind

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

Discriminator that names this frame in a serialized config.

#### axis

```python
axis: Axis = Axis.Z
```

The authored model's axis of symmetry.

#### radial

```python
radial: DirectionField | None = None
```

`[-]`: The direction from the axis toward the sectioned half-plane, stored as its unit part perpendicular to the axis; None picks the world axis least aligned with the symmetry axis.

#### label

```python
label: str
```

A short human-readable name.

#### model\_dim

```python
model_dim: Literal[2, 3]
```

The mesh dimension this frame solves on.

#### perpendicular

```python
perpendicular(radial: Direction | None, info: ValidationInfo) -> Direction | None
```

Reject an axis-parallel radial and store its unit component perpendicular to the axis.
