# Meshing

The meshing stage: typed gmsh settings, the mesh backends, element sizing, and the body and boundary groups a STEP is meshed into.

## femforge.meshing

The meshing stage: typed gmsh settings, the mesh backends, element sizing, and the body and boundary groups a STEP is meshed into.

Modules:

- **`backend`** –

  The mesh seam: what a meshing job carries and reports, and the backends that mesh it in this process or in a worker.
- **`boundary`** –

  Boundary physical groups derived from body adjacency: the mesh surfaces (3D) or curves (2D) boundary conditions attach to without hand-labelling.
- **`config`** –

  The gmsh mesh settings and the config surface the mesher reads.
- **`firewall`** –

  Keeping gmsh out of a process: an import hook for an entry point that must never load it.
- **`geometry_utils`** –

  Per-entity geometry read from gmsh: bounding box, center of mass and volume.
- **`gmsh_backend`** –

  The in-process gmsh meshing behind `GmshMesher` and the mesh worker.
- **`gmsh_options`** –

  Typed gmsh options, each field carrying its gmsh option name as `Map(...)` metadata.
- **`groups`** –

  The gmsh-free mesh group records: the body groups a mesher builds, their log summaries, and the `groups.json` a cached mesh carries.
- **`mesh_entity`** –

  Resolves the gmsh entities of an imported STEP against the domain's materials and region tags.
- **`mesh_sizing`** –

  Mesh element sizing: the domain-wide size plus per-region overrides, decided without gmsh and applied through injectable setters.
- **`mesher`** –

  The gmsh mesher: a STEP's bodies matched to materials and tags, grouped into physical groups, sized, and meshed into a `.msh`.
- **`naming`** –

  The physical-group name grammar: the normalization and composition rules shared by the mesher (emit) and the bundle readers (require).
- **`spec`** –

  The mesh artifact's spec: the plain data that decides the Elmer mesh files and their group names.
- **`worker`** –

  The mesh worker: `python -m femforge.meshing.worker JOB OUTCOME` meshes one job with gmsh and writes how it ended.

Classes:

- **`MeshConfig`** –

  How the geometry is discretized for the gmsh backend: the STEP source, domain-wide element size, and typed gmsh knobs.
- **`SupportsMeshing`** –

  The config surface the gmsh `Mesher` requires, which `SimulationConfig` satisfies structurally.
- **`GmshOptions`** –

  Typed gmsh meshing options; a knob left at None keeps gmsh's own default.
- **`MeshAlgorithm2D`** –

  A gmsh 2D meshing algorithm, valued as the integer `Mesh.Algorithm` takes.
- **`MeshAlgorithm3D`** –

  A gmsh 3D meshing algorithm, valued as the integer `Mesh.Algorithm3D` takes.
- **`MeshBackend`** –

  Meshes a job into a gmsh `.msh` plus its group records; each backend decides where gmsh runs.
- **`MeshJob`** –

  One meshing request as plain data: the mesh spec, the STEP to read, and the `.msh` to write.
- **`MeshReport`** –

  What one meshing job left: the `.msh`, its group records, and the gmsh release that wrote it.
- **`MeshError`** –

  Meshing failed: the STEP's bodies could not be grouped or meshed, or the mesh worker crashed or ran out of time.
- **`MeshInputs`** –

  The config surface a mesher reads, rebuilt from a `MeshJob` alone.
- **`GmshMesher`** –

  Meshes in this process with gmsh, which loads on the first job and is finalized after every one.
- **`WorkerMesher`** –

  Meshes in a child Python process, so gmsh, its license and its crashes stay out of this one.
- **`MeshSpec`** –

  Everything that decides the Elmer mesh files and their group names, and nothing that only decides the solve.
- **`TagSelectorSpec`** –

  The grouping-relevant half of an `EntityTag`: its selector and per-region size, never its conditions.
- **`PhysicalGroup`** –

  A single gmsh physical group plus the metadata to reconstruct the matching Elmer body; both sides share the same `name` and integer `id`.
- **`MeshGroupsFile`** –

  `groups.json`: the group records and element count a mesh artifact carries beside ElmerGrid's files.
- **`BodyGroupRecord`** –

  One body group of a cached mesh: what it takes to rebuild its `PhysicalGroup` against a config.
- **`BoundaryGroupRecord`** –

  One boundary group of a cached mesh.
- **`BoundaryGroup`** –

  A single gmsh boundary physical group derived from body adjacency — the one-dimension-down sibling of `PhysicalGroup`, targeted by Elmer as `Target Boundaries`.
- **`BoundaryPartition`** –

  One planned boundary group: the output of the pure adjacency partition, before gmsh assigns it a physical-group id.
- **`ResolvedRegionMeshSize`** –

  A resolved per-region target element size and the volume tags it applies to.
- **`EntityGeometry`** –

  Axis-aligned bounding box, center of mass and volume of one gmsh entity.

Functions:

- **`mesh_inputs`** –

  The mesher's inputs for `job`: the frame of its dimension, its mesh settings, and a domain of bare materials and tag selectors.
- **`block_gmsh`** –

  Make every later `import gmsh` in this process raise ImportError, so an entry point can prove it never loads gmsh.
- **`raise_on_duplicate_names`** –

  Raise when two body groups share a name, e.g. one `Name` authored on parts of two materials.
- **`format_physical_groups`** –

  Multi-line material → tag-group → physical-group summary for one log record (embeds newlines).
- **`format_boundary_groups`** –

  Multi-line boundary-group summary for one log record (embeds newlines).
- **`partition_boundary_faces`** –

  Group every boundary face by the bodies it borders into sorted interface (`A__B`), external (`A__EXT`) and symmetry-axis (`A__AXIS`) partitions.
- **`read_face_adjacency`** –

  Map each boundary entity of the `body_dim` body groups to the names of the bodies it bounds, read from a synchronized gmsh model.
- **`axis_entity_tags`** –

  The `tags` whose bounding box lies on the x=0 symmetry axis, read from a live gmsh model.
- **`resolve_region_sizes`** –

  The per-region size overrides to apply: each group's finest requested `mesh_size`, leaving out groups that request none.
- **`apply_mesh_sizing`** –

  Apply the global element size to the whole domain, then each region override on top of it.
- **`gmsh_set_global_size`** –

  Set the characteristic length at every geometry point -- the domain-wide target element size.
- **`gmsh_set_region_size`** –

  Set the characteristic length on the points of the given bodies, overriding the global size there.
- **`extract_entity_geometry`** –

  Read an entity's bounding box, center of mass and volume from a synchronized gmsh model.

Attributes:

- **`BOUNDARY_SEP`** –

  The separator between the body names in a boundary group's name, as in `AIR__N52_MAG_N` or `AIR__EXT`.
- **`EXTERNAL_SUFFIX`** –

  The name suffix of a body's external shell group: the faces it shares with no other body.
- **`AXIS_SUFFIX`** –

  The name suffix of a body's boundary group on the x=0 symmetry axis of a 2D axisymmetric model.
- **`AXIS_TOLERANCE_M`** –

  `[m]`: The largest distance from the symmetry axis at which an entity's bounding box still counts as on it.

### BOUNDARY\_SEP

```python
BOUNDARY_SEP = '__'
```

The separator between the body names in a boundary group's name, as in `AIR__N52_MAG_N` or `AIR__EXT`.

### EXTERNAL\_SUFFIX

```python
EXTERNAL_SUFFIX = 'EXT'
```

The name suffix of a body's external shell group: the faces it shares with no other body.

### AXIS\_SUFFIX

```python
AXIS_SUFFIX = 'AXIS'
```

The name suffix of a body's boundary group on the x=0 symmetry axis of a 2D axisymmetric model.

### AXIS\_TOLERANCE\_M

```python
AXIS_TOLERANCE_M = 1e-06
```

`[m]`: The largest distance from the symmetry axis at which an entity's bounding box still counts as on it.

### MeshConfig

Bases: `ConfigArea`

How the geometry is discretized for the gmsh backend: the STEP source, domain-wide element size, and typed gmsh knobs.

Config:

- `extra`: `forbid`

Fields:

- `step` (`str`)
- `global_mesh_size` (`float`)
- `gmsh_options` (`GmshOptions`)
- `deterministic` (`bool`)

#### step

```python
step: str = 'data/geometry.step'
```

Path to the STEP file the mesher imports; its build123d part names are parsed into materials and region tags (`MeshEntity`).

#### global\_mesh\_size

```python
global_mesh_size: float = 0.001
```

`h` `[m]`: Domain-wide target element size, which a region's `EntityTag.mesh_size` overrides.

#### gmsh\_options

```python
gmsh_options: GmshOptions
```

Typed gmsh options applied before meshing.

#### deterministic

```python
deterministic: bool = False
```

Pin meshing to one thread, so HXT's multithreading cannot vary the result and the same STEP and sizes always yield the identical mesh; slower, and part of the run identity.

#### resolved\_gmsh\_options

```python
resolved_gmsh_options() -> GmshOptions
```

The options the mesher applies: `gmsh_options`, thread-pinned to 1 when `deterministic`.

### SupportsMeshing

Bases: `Protocol`

The config surface the gmsh `Mesher` requires, which `SimulationConfig` satisfies structurally.

Attributes:

- **`frame`** (`Frame`) –

  The solve frame, whose `model_dim` is the body dimension of the STEP.
- **`mesh`** (`MeshConfig`) –

  The gmsh mesh settings (STEP source, element size, gmsh options).
- **`domain`** (`DomainConfig`) –

  The materials + per-region tags the mesher matches STEP entities against.

#### frame

```python
frame: Frame
```

The solve frame, whose `model_dim` is the body dimension of the STEP.

#### mesh

```python
mesh: MeshConfig
```

The gmsh mesh settings (STEP source, element size, gmsh options).

#### domain

```python
domain: DomainConfig
```

The materials + per-region tags the mesher matches STEP entities against.

### GmshOptions

Bases: `BaseModel`

Typed gmsh meshing options; a knob left at None keeps gmsh's own default.

Config:

- `validate_assignment`: `True`
- `use_attribute_docstrings`: `True`

Fields:

- `import_labels` (`bool`)
- `terminal_output` (`bool`)
- `algorithm_2d` (`MeshAlgorithm2D`)
- `algorithm_3d` (`MeshAlgorithm3D`)
- `recombine_all` (`bool`)
- `mesh_size_min` (`float | None`)
- `mesh_size_max` (`float | None`)
- `optimize` (`bool`)
- `smoothing` (`int | None`)
- `num_threads` (`int | None`)
- `target_units` (`str | None`)

#### import\_labels

```python
import_labels: bool = True
```

Import STEP/OpenCASCADE entity labels (Geometry.OCCImportLabels); the mesher needs these to match parts to materials.

#### terminal\_output

```python
terminal_output: bool = False
```

Print gmsh's progress to the terminal (General.Terminal); never changes the mesh, so it stays out of every identity.

#### algorithm\_2d

```python
algorithm_2d: MeshAlgorithm2D = MeshAlgorithm2D.FRONTAL_DELAUNAY
```

2D meshing algorithm (Mesh.Algorithm); the default Frontal-Delaunay gives the all-triangle surface mesh HXT needs and meshes the bodies of a 2D model.

#### algorithm\_3d

```python
algorithm_3d: MeshAlgorithm3D = MeshAlgorithm3D.HXT
```

3D meshing algorithm (Mesh.Algorithm3D); the default HXT runs on `num_threads` and needs the all-triangle surface mesh `recombine_all=False` keeps.

#### recombine\_all

```python
recombine_all: bool = False
```

Recombine the simplex mesh into quads and hexes (Mesh.RecombineAll); keep it False, since WhitneyAVSolver needs tetrahedra and recombining makes 3D meshing fail.

#### mesh\_size\_min

```python
mesh_size_min: float | None = None
```

`h_min` `[m]`: Lower clamp on element size (Mesh.MeshSizeMin); None inherits gmsh's default.

#### mesh\_size\_max

```python
mesh_size_max: float | None = None
```

`h_max` `[m]`: Upper clamp on element size (Mesh.MeshSizeMax); None inherits gmsh's default.

#### optimize

```python
optimize: bool = True
```

Run mesh optimization after generation (Mesh.Optimize).

#### smoothing

```python
smoothing: int | None = None
```

Number of mesh smoothing steps (Mesh.Smoothing); None inherits gmsh's default.

#### num\_threads

```python
num_threads: int | None
```

Meshing threads (General.NumThreads): every physical core by default, None for gmsh's own default of one, and never part of an identity.

#### target\_units

```python
target_units: str | None = 'M'
```

Length unit OpenCASCADE converts the imported STEP to (Geometry.OCCTargetUnit): `"M"` keeps the pipeline in metres, None keeps the STEP's own unit.

#### apply

```python
apply(set_number: Callable[[str, float], None] | None = None, set_string: Callable[[str, str], None] | None = None) -> None
```

Set each option that is not None under its `Map(...)` name, through `set_number` and `set_string` when given, else on the live gmsh option store.

### MeshAlgorithm2D

Bases: `IntEnum`

A gmsh 2D meshing algorithm, valued as the integer `Mesh.Algorithm` takes.

Attributes:

- **`MESH_ADAPT`** –

  MeshAdapt, the most robust on complex curved surfaces.
- **`AUTOMATIC`** –

  Delaunay on plane surfaces and MeshAdapt on the rest.
- **`DELAUNAY`** –

  Delaunay, the fastest on large plane surfaces.
- **`FRONTAL_DELAUNAY`** –

  Frontal-Delaunay, gmsh's own default and the choice for high element quality.

#### MESH\_ADAPT

```python
MESH_ADAPT = 1
```

MeshAdapt, the most robust on complex curved surfaces.

#### AUTOMATIC

```python
AUTOMATIC = 2
```

Delaunay on plane surfaces and MeshAdapt on the rest.

#### DELAUNAY

```python
DELAUNAY = 5
```

Delaunay, the fastest on large plane surfaces.

#### FRONTAL\_DELAUNAY

```python
FRONTAL_DELAUNAY = 6
```

Frontal-Delaunay, gmsh's own default and the choice for high element quality.

### MeshAlgorithm3D

Bases: `IntEnum`

A gmsh 3D meshing algorithm, valued as the integer `Mesh.Algorithm3D` takes.

Attributes:

- **`DELAUNAY`** –

  Delaunay, gmsh's own default and its most robust 3D mesher.
- **`FRONTAL`** –

  Frontal, Netgen's advancing-front tetrahedral mesher.
- **`MMG3D`** –

  MMG3D, for anisotropic tetrahedral meshes.
- **`HXT`** –

  HXT, a parallel reimplementation of Delaunay that spreads over the meshing threads.

#### DELAUNAY

```python
DELAUNAY = 1
```

Delaunay, gmsh's own default and its most robust 3D mesher.

#### FRONTAL

```python
FRONTAL = 4
```

Frontal, Netgen's advancing-front tetrahedral mesher.

#### MMG3D

```python
MMG3D = 7
```

MMG3D, for anisotropic tetrahedral meshes.

#### HXT

```python
HXT = 10
```

HXT, a parallel reimplementation of Delaunay that spreads over the meshing threads.

### MeshBackend

Bases: `Protocol`

Meshes a job into a gmsh `.msh` plus its group records; each backend decides where gmsh runs.

Methods:

- **`mesh`** –

  Mesh `job` into `out_dir`, raising `MeshError` when meshing fails.

#### mesh

```python
mesh(job: MeshJob, out_dir: Path) -> MeshReport
```

Mesh `job` into `out_dir`, raising `MeshError` when meshing fails.

### MeshJob

Bases: `BaseModel`

One meshing request as plain data: the mesh spec, the STEP to read, and the `.msh` to write.

Config:

- `use_attribute_docstrings`: `True`

Fields:

- `spec` (`MeshSpec`)
- `step` (`str`)
- `msh` (`str`)

#### spec

```python
spec: MeshSpec
```

The mesh artifact's spec, which decides the mesh.

#### step

```python
step: str
```

The solve-frame STEP to mesh.

#### msh

```python
msh: str = BundleFile.GEOMETRY_MSH
```

The `.msh` file name to write in the output directory.

### MeshReport

Bases: `BaseModel`

What one meshing job left: the `.msh`, its group records, and the gmsh release that wrote it.

Config:

- `use_attribute_docstrings`: `True`

Fields:

- `msh` (`str`)
- `groups` (`MeshGroupsFile`)
- `gmsh_version` (`str`)
- `duration_s` (`float`)

#### msh

```python
msh: str
```

The `.msh` file name in the output directory.

#### groups

```python
groups: MeshGroupsFile
```

The body and boundary group records and the element count.

#### gmsh\_version

```python
gmsh_version: str
```

The gmsh release that meshed the job.

#### duration\_s

```python
duration_s: float
```

`t` `[s]`: Wall time the meshing took.

### MeshError

Bases: `RuntimeError`

Meshing failed: the STEP's bodies could not be grouped or meshed, or the mesh worker crashed or ran out of time.

### MeshInputs

```python
MeshInputs(frame: Frame, mesh: MeshConfig, domain: DomainConfig)
```

The config surface a mesher reads, rebuilt from a `MeshJob` alone.

Attributes:

- **`frame`** (`Frame`) –

  A frame of the job's body dimension.
- **`mesh`** (`MeshConfig`) –

  The job's STEP and mesh settings.
- **`domain`** (`DomainConfig`) –

  Bare materials named by their tags, and the tag selectors with their element sizes.

#### frame

```python
frame: Frame
```

A frame of the job's body dimension.

#### mesh

```python
mesh: MeshConfig
```

The job's STEP and mesh settings.

#### domain

```python
domain: DomainConfig
```

Bare materials named by their tags, and the tag selectors with their element sizes.

### GmshMesher

Bases: `MeshBackend`

Meshes in this process with gmsh, which loads on the first job and is finalized after every one.

Methods:

- **`mesh`** –

  Mesh `job` into `out_dir` with gmsh in this process.

#### mesh

```python
mesh(job: MeshJob, out_dir: Path) -> MeshReport
```

Mesh `job` into `out_dir` with gmsh in this process.

### WorkerMesher

```python
WorkerMesher(*, python: str = executable, module: str = WORKER_MODULE, timeout_s: float | None = None)
```

Bases: `MeshBackend`

Meshes in a child Python process, so gmsh, its license and its crashes stay out of this one.

Parameters:

- **`python`** (`str`, default: `executable` ) –

  The interpreter that runs the worker.
- **`module`** (`str`, default: `WORKER_MODULE` ) –

  The worker module.
- **`timeout_s`** (`float | None`, default: `None` ) –

  Seconds before a job is stopped; None waits for it.

Methods:

- **`mesh`** –

  Mesh `job` into `out_dir` in a worker process, raising `MeshError` when the worker fails or leaves no outcome.

#### mesh

```python
mesh(job: MeshJob, out_dir: Path) -> MeshReport
```

Mesh `job` into `out_dir` in a worker process, raising `MeshError` when the worker fails or leaves no outcome.

### MeshSpec

Bases: `BaseModel`

Everything that decides the Elmer mesh files and their group names, and nothing that only decides the solve.

Config:

- `use_attribute_docstrings`: `True`

Fields:

- `step_key` (`str`)
- `model_dim` (`Literal[2, 3]`)
- `global_mesh_size` (`float`)
- `gmsh_options` (`GmshOptions`)
- `deterministic` (`bool`)
- `tags` (`list[TagSelectorSpec]`)
- `materials` (`list[str]`)

#### step\_key

```python
step_key: str
```

The geometry identity (`step_key`).

#### model\_dim

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

Body dimension of the STEP, from the frame: 2D cross-section or 3D solids.

#### global\_mesh\_size

```python
global_mesh_size: float
```

`h` `[m]`: Domain-wide target element size.

#### gmsh\_options

```python
gmsh_options: GmshOptions
```

The gmsh knobs (thread count and terminal output are `HashExclude` and drop out).

#### deterministic

```python
deterministic: bool
```

Whether meshing was pinned to one thread for reproducibility.

#### tags

```python
tags: list[TagSelectorSpec]
```

The domain's tags in domain order (an unnamed body's group name concatenates tag names in that order).

#### materials

```python
materials: list[str]
```

The sorted material tags; an unnamed body's group name starts with its material tag.

### TagSelectorSpec

Bases: `BaseModel`

The grouping-relevant half of an `EntityTag`: its selector and per-region size, never its conditions.

Config:

- `use_attribute_docstrings`: `True`

Fields:

- `selector` (`TagDict`)
- `mesh_size` (`float | None`)

#### selector

```python
selector: TagDict
```

The key=value pairs an entity must carry to join the group.

#### mesh\_size

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

`h` `[m]`: The per-region element size, when set.

### PhysicalGroup

```python
PhysicalGroup(dim: int, gmsh_id: int, name: str, material: MaterialProperties, tags: list[EntityTag], entity_tags: list[int], authored: str | None = None)
```

A single gmsh physical group plus the metadata to reconstruct the matching Elmer body; both sides share the same `name` and integer `id`.

Parameters:

- **`dim`** (`int`) –

  Topological dimension of the group.
- **`gmsh_id`** (`int`) –

  The gmsh physical-group tag.
- **`name`** (`str`) –

  The group name shared verbatim with Elmer.
- **`material`** (`MaterialProperties`) –

  The material of every entity in the group.
- **`tags`** (`list[EntityTag]`) –

  The `EntityTag` objects the group matched.
- **`entity_tags`** (`list[int]`) –

  The gmsh entity tags in the group.
- **`authored`** (`str | None`, default: `None` ) –

  The `Name` tag the entities were authored with, or None when the name is composed.

Methods:

- **`physical_group_name`** –

  The stable name the mesher and the sif writer both reference this region by, as `MeshGroupSource` requires.

Attributes:

- **`dim`** –

  Topological dimension of the group (3 = volume in a 3D model, 2 = surface in a 2D one).
- **`id`** –

  The integer the sif targets this region by: the gmsh tag until `reconcile_ids` sets the id ElmerGrid assigned.
- **`name`** –

  The authored part name, else the compound MATERIAL\_TAG1\_TAG2 name; shared verbatim with Elmer.
- **`authored`** –

  The `Name` tag the group's entities were authored with, or None when the name is composed.
- **`material`** –

  The material of every entity in the group.
- **`tags`** –

  EntityTag objects matched to this group (carry per-region overrides: fixed temperature, heat flux, magnetization direction).
- **`entity_tags`** –

  The gmsh entity tags (volumes in 3D, surfaces in 2D) that make up this group.

#### dim

```python
dim = dim
```

Topological dimension of the group (3 = volume in a 3D model, 2 = surface in a 2D one).

#### id

```python
id = gmsh_id
```

The integer the sif targets this region by: the gmsh tag until `reconcile_ids` sets the id ElmerGrid assigned.

#### name

```python
name = name
```

The authored part name, else the compound MATERIAL\_TAG1\_TAG2 name; shared verbatim with Elmer.

#### authored

```python
authored = authored
```

The `Name` tag the group's entities were authored with, or None when the name is composed.

#### material

```python
material = material
```

The material of every entity in the group.

#### tags

```python
tags = tags
```

EntityTag objects matched to this group (carry per-region overrides: fixed temperature, heat flux, magnetization direction).

#### entity\_tags

```python
entity_tags = entity_tags
```

The gmsh entity tags (volumes in 3D, surfaces in 2D) that make up this group.

#### physical\_group\_name

```python
physical_group_name() -> str
```

The stable name the mesher and the sif writer both reference this region by, as `MeshGroupSource` requires.

### MeshGroupsFile

Bases: `BaseModel`

`groups.json`: the group records and element count a mesh artifact carries beside ElmerGrid's files.

Config:

- `use_attribute_docstrings`: `True`

Fields:

- `bodies` (`list[BodyGroupRecord]`)
- `boundaries` (`list[BoundaryGroupRecord]`)
- `element_count` (`int`)

#### bodies

```python
bodies: list[BodyGroupRecord]
```

The body group records, in mesher order.

#### boundaries

```python
boundaries: list[BoundaryGroupRecord]
```

The boundary group records, in mesher order.

#### element\_count

```python
element_count: int = 0
```

Elements of the body dimension in the mesh.

#### capture

```python
capture(physical_groups: Iterable[_BodySource], boundary_groups: Iterable[_BoundarySource], element_count: int) -> MeshGroupsFile
```

Record the mesher's groups.

Parameters:

- **`physical_groups`** (`Iterable[_BodySource]`) –

  The body groups, in mesher order.
- **`boundary_groups`** (`Iterable[_BoundarySource]`) –

  The boundary groups, in mesher order.
- **`element_count`** (`int`) –

  Elements of the body dimension in the mesh.

#### load

```python
load(sim_dir: str | Path) -> MeshGroupsFile
```

Read `groups.json` from `sim_dir`.

#### write

```python
write(sim_dir: str | Path) -> Path
```

Write `groups.json` into `sim_dir` and return its path.

### BodyGroupRecord

Bases: `BaseModel`

One body group of a cached mesh: what it takes to rebuild its `PhysicalGroup` against a config.

Config:

- `use_attribute_docstrings`: `True`

Fields:

- `dim` (`int`)
- `name` (`str`)
- `material` (`str`)
- `selectors` (`list[TagDict]`)
- `entity_tags` (`list[int]`)
- `authored` (`str | None`)

#### dim

```python
dim: int
```

Topological dimension of the group.

#### name

```python
name: str
```

The group name shared verbatim with Elmer.

#### material

```python
material: str
```

The material tag.

#### selectors

```python
selectors: list[TagDict]
```

The selectors of the tags the group matched, in domain order.

#### entity\_tags

```python
entity_tags: list[int]
```

The gmsh entity tags in the group.

#### authored

```python
authored: str | None = None
```

The `Name` tag the group was named by, or None when its name is composed.

### BoundaryGroupRecord

Bases: `BaseModel`

One boundary group of a cached mesh.

Config:

- `use_attribute_docstrings`: `True`

Fields:

- `dim` (`int`)
- `name` (`str`)
- `bodies` (`tuple[str, ...]`)
- `face_tags` (`list[int]`)
- `on_axis` (`bool`)

#### dim

```python
dim: int
```

Topological dimension of the group.

#### name

```python
name: str
```

The compound boundary name shared verbatim with Elmer.

#### bodies

```python
bodies: tuple[str, ...] = ()
```

The one or two body group names the boundary borders.

#### face\_tags

```python
face_tags: list[int]
```

The gmsh entity tags in the group.

#### on\_axis

```python
on_axis: bool = False
```

Whether the group lies on the symmetry axis of a 2D axisymmetric model.

### BoundaryGroup

```python
BoundaryGroup(gmsh_id: int, name: str, bodies: tuple[str, ...], face_tags: list[int], dim: int = 2, on_axis: bool = False)
```

A single gmsh boundary physical group derived from body adjacency — the one-dimension-down sibling of `PhysicalGroup`, targeted by Elmer as `Target Boundaries`.

Names encode the bordering bodies: `<BODYA>__<BODYB>` (interface), `<BODY>__EXT` (external shell), or `<BODY>__AXIS` (symmetry axis).

Parameters:

- **`gmsh_id`** (`int`) –

  The gmsh physical-group tag.
- **`name`** (`str`) –

  The compound name shared verbatim with Elmer.
- **`bodies`** (`tuple[str, ...]`) –

  The one or two body group names the group borders.
- **`face_tags`** (`list[int]`) –

  The gmsh entity tags in the group.
- **`dim`** (`int`, default: `2` ) –

  Topological dimension of the group.
- **`on_axis`** (`bool`, default: `False` ) –

  Whether every entity lies on the symmetry axis of a 2D axisymmetric model.

Methods:

- **`physical_group_name`** –

  The stable name the mesher and the sif writer both reference this boundary by, as `MeshGroupSource` requires.

Attributes:

- **`dim`** –

  Topological dimension of the group -- one below the bodies it separates (2 = surface in a 3D model, 1 = curve in a 2D one), mirroring `PhysicalGroup.dim`.
- **`id`** –

  The integer the sif targets this boundary by: the gmsh tag until `reconcile_ids` sets the id ElmerGrid assigned.
- **`name`** –

  The compound `BODYA__BODYB`, `BODY__EXT` or `BODY__AXIS` name, shared verbatim with Elmer.
- **`bodies`** –

  The 1 (external or axis) or 2 (interface) body group names this boundary borders.
- **`entity_tags`** –

  The gmsh entity tags (surfaces in 3D, curves in 2D) that make up this group, mirroring `PhysicalGroup.entity_tags`.
- **`on_axis`** –

  True when every entity of this single-body group lies on the x=0 symmetry axis of a 2D axisymmetric model.
- **`is_external`** (`bool`) –

  True when this is a body's true external (far-field) shell: bordered by exactly one body and not on the symmetry axis.
- **`is_axis`** (`bool`) –

  True when this is a body's symmetry-axis boundary (the `<BODY>__AXIS` group of a 2D axisymmetric model).

#### dim

```python
dim = dim
```

Topological dimension of the group -- one below the bodies it separates (2 = surface in a 3D model, 1 = curve in a 2D one), mirroring `PhysicalGroup.dim`.

#### id

```python
id = gmsh_id
```

The integer the sif targets this boundary by: the gmsh tag until `reconcile_ids` sets the id ElmerGrid assigned.

#### name

```python
name = name
```

The compound `BODYA__BODYB`, `BODY__EXT` or `BODY__AXIS` name, shared verbatim with Elmer.

#### bodies

```python
bodies = bodies
```

The 1 (external or axis) or 2 (interface) body group names this boundary borders.

#### entity\_tags

```python
entity_tags = face_tags
```

The gmsh entity tags (surfaces in 3D, curves in 2D) that make up this group, mirroring `PhysicalGroup.entity_tags`.

#### on\_axis

```python
on_axis = on_axis
```

True when every entity of this single-body group lies on the x=0 symmetry axis of a 2D axisymmetric model.

#### is\_external

```python
is_external: bool
```

True when this is a body's true external (far-field) shell: bordered by exactly one body and not on the symmetry axis.

#### is\_axis

```python
is_axis: bool
```

True when this is a body's symmetry-axis boundary (the `<BODY>__AXIS` group of a 2D axisymmetric model).

#### physical\_group\_name

```python
physical_group_name() -> str
```

The stable name the mesher and the sif writer both reference this boundary by, as `MeshGroupSource` requires.

### BoundaryPartition

```python
BoundaryPartition(name: str, bodies: tuple[str, ...], face_tags: tuple[int, ...], on_axis: bool = False)
```

One planned boundary group: the output of the pure adjacency partition, before gmsh assigns it a physical-group id.

Attributes:

- **`name`** (`str`) –

  The group name: `A__B` for an interface, `A__EXT` for an external shell, `A__AXIS` for a symmetry-axis boundary.
- **`bodies`** (`tuple[str, ...]`) –

  The one or two body group names the faces border, sorted.
- **`face_tags`** (`tuple[int, ...]`) –

  The boundary entity tags in the group, sorted.
- **`on_axis`** (`bool`) –

  Whether the group is a single body's boundary on the symmetry axis.

#### name

```python
name: str
```

The group name: `A__B` for an interface, `A__EXT` for an external shell, `A__AXIS` for a symmetry-axis boundary.

#### bodies

```python
bodies: tuple[str, ...]
```

The one or two body group names the faces border, sorted.

#### face\_tags

```python
face_tags: tuple[int, ...]
```

The boundary entity tags in the group, sorted.

#### on\_axis

```python
on_axis: bool = False
```

Whether the group is a single body's boundary on the symmetry axis.

### ResolvedRegionMeshSize

```python
ResolvedRegionMeshSize(volume_tags: tuple[int, ...], size: float)
```

A resolved per-region target element size and the volume tags it applies to.

Attributes:

- **`volume_tags`** (`tuple[int, ...]`) –

  The gmsh tags of the region's bodies (volumes in 3D, surfaces in 2D).
- **`size`** (`float`) –

  `h` `[m]`: Target element size.

#### volume\_tags

```python
volume_tags: tuple[int, ...]
```

The gmsh tags of the region's bodies (volumes in 3D, surfaces in 2D).

#### size

```python
size: float
```

`h` `[m]`: Target element size.

### EntityGeometry

```python
EntityGeometry(dim: int, tag: int, bbox_min: tuple[float, float, float], bbox_max: tuple[float, float, float], center_of_mass: tuple[float, float, float], volume: float)
```

Axis-aligned bounding box, center of mass and volume of one gmsh entity.

Attributes:

- **`dim`** (`int`) –

  Topological dimension of the entity.
- **`tag`** (`int`) –

  The gmsh entity tag.
- **`bbox_min`** (`tuple[float, float, float]`) –

  `[m]`: Lower corner of the axis-aligned bounding box.
- **`bbox_max`** (`tuple[float, float, float]`) –

  `[m]`: Upper corner of the axis-aligned bounding box.
- **`center_of_mass`** (`tuple[float, float, float]`) –

  `[m]`: Center of mass.
- **`volume`** (`float`) –

  `V` `[?]`: Volume, area or length of the entity by `dim`, in m³, m² or m.
- **`extent`** (`tuple[float, float, float]`) –

  `[m]`: Size of the bounding box along each axis.

#### dim

```python
dim: int
```

Topological dimension of the entity.

#### tag

```python
tag: int
```

The gmsh entity tag.

#### bbox\_min

```python
bbox_min: tuple[float, float, float]
```

`[m]`: Lower corner of the axis-aligned bounding box.

#### bbox\_max

```python
bbox_max: tuple[float, float, float]
```

`[m]`: Upper corner of the axis-aligned bounding box.

#### center\_of\_mass

```python
center_of_mass: tuple[float, float, float]
```

`[m]`: Center of mass.

#### volume

```python
volume: float
```

`V` `[?]`: Volume, area or length of the entity by `dim`, in m³, m² or m.

#### extent

```python
extent: tuple[float, float, float]
```

`[m]`: Size of the bounding box along each axis.

### mesh\_inputs

```python
mesh_inputs(job: MeshJob) -> MeshInputs
```

The mesher's inputs for `job`: the frame of its dimension, its mesh settings, and a domain of bare materials and tag selectors.

### block\_gmsh

```python
block_gmsh() -> None
```

Make every later `import gmsh` in this process raise ImportError, so an entry point can prove it never loads gmsh.

### raise\_on\_duplicate\_names

```python
raise_on_duplicate_names(groups: Sequence[PhysicalGroup]) -> None
```

Raise when two body groups share a name, e.g. one `Name` authored on parts of two materials.

### format\_physical\_groups

```python
format_physical_groups(groups: Sequence[PhysicalGroup], *, total_entities: int) -> str
```

Multi-line material → tag-group → physical-group summary for one log record (embeds newlines).

### format\_boundary\_groups

```python
format_boundary_groups(groups: Sequence[BoundaryGroup]) -> str
```

Multi-line boundary-group summary for one log record (embeds newlines).

### partition\_boundary\_faces

```python
partition_boundary_faces(face_to_bodies: Mapping[int, set[str]], *, axis_faces: frozenset[int] = frozenset()) -> list[BoundaryPartition]
```

Group every boundary face by the bodies it borders into sorted interface (`A__B`), external (`A__EXT`) and symmetry-axis (`A__AXIS`) partitions.

A face in `axis_faces` becomes an axis partition only when it borders a single body.

### read\_face\_adjacency

```python
read_face_adjacency(body_groups: Iterable[tuple[str, Iterable[int]]], body_dim: int = 3) -> dict[int, set[str]]
```

Map each boundary entity of the `body_dim` body groups to the names of the bodies it bounds, read from a synchronized gmsh model.

### axis\_entity\_tags

```python
axis_entity_tags(tags: Iterable[int], dim: int, tol: float = AXIS_TOLERANCE_M) -> frozenset[int]
```

The `tags` whose bounding box lies on the x=0 symmetry axis, read from a live gmsh model.

Parameters:

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

  The gmsh entity tags to test.
- **`dim`** (`int`) –

  Topological dimension of the entities.
- **`tol`** (`float`, default: `AXIS_TOLERANCE_M` ) –

  The largest distance from the axis, in metres, that still counts as on it.

### resolve\_region\_sizes

```python
resolve_region_sizes(groups: Iterable[_SizedRegion]) -> list[ResolvedRegionMeshSize]
```

The per-region size overrides to apply: each group's finest requested `mesh_size`, leaving out groups that request none.

### apply\_mesh\_sizing

```python
apply_mesh_sizing(global_size: float, region_sizes: Iterable[ResolvedRegionMeshSize], *, set_global: Callable[[float], None], set_region: Callable[[Sequence[int], float], None]) -> None
```

Apply the global element size to the whole domain, then each region override on top of it.

Parameters:

- **`global_size`** (`float`) –

  Domain-wide target element size in metres.
- **`region_sizes`** (`Iterable[ResolvedRegionMeshSize]`) –

  The per-region overrides, applied in order.
- **`set_global`** (`Callable[[float], None]`) –

  Applies the domain-wide size.
- **`set_region`** (`Callable[[Sequence[int], float], None]`) –

  Applies one size to the given body tags.

### gmsh\_set\_global\_size

```python
gmsh_set_global_size(size: float) -> None
```

Set the characteristic length at every geometry point -- the domain-wide target element size.

### gmsh\_set\_region\_size

```python
gmsh_set_region_size(volume_tags: Sequence[int], size: float, body_dim: int = 3) -> None
```

Set the characteristic length on the points of the given bodies, overriding the global size there.

Parameters:

- **`volume_tags`** (`Sequence[int]`) –

  The gmsh tags of the bodies to size.
- **`size`** (`float`) –

  Target element size in metres.
- **`body_dim`** (`int`, default: `3` ) –

  Topological dimension of the bodies.

### extract\_entity\_geometry

```python
extract_entity_geometry(dim: int, tag: int) -> EntityGeometry
```

Read an entity's bounding box, center of mass and volume from a synchronized gmsh model.
