Skip to content

Geometry and tags

A femforge model is a STEP file whose bodies carry tags in their names: key=value pairs separated by commas, such as Material=N52, Name=MAGNET. The mesher reads the tags back from the STEP, and every later stage selects bodies by them. One vocabulary connects the CAD to the materials, conditions and mesh sizes, so you never number a volume or a surface by hand.

The STEP file comes from one of two routes:

  • Any CAD that writes body names into the STEP, such as Fusion 360, SolidWorks or FreeCAD. Name each body with its tags, and make sure the names reach the STEP file.
  • A build123d script that uses the femforge tagged containers: TaggedPart, TaggedCompound and Build123dGeometry. They write the names for you.

The next two sections cover the build123d route. The tag keys, selectors and names apply to both.

Build a tagged model

import build123d as b3d

import femforge as ff


class MagnetInAir(ff.Build123dGeometry):
    """A cube magnet at the centre of an air box."""

    magnet_size: float = 10.0
    """Edge length of the magnet, in millimetres."""

    air_size: float = 40.0
    """Edge length of the air box, in millimetres."""

    def model(self) -> ff.TaggedCompound:
        air = ff.TaggedPart(
            b3d.Box(self.air_size, self.air_size, self.air_size),
            tags={ff.TagKey.MATERIAL: ff.materials.Air().tag},
            name="Air",
        )
        magnet = ff.TaggedPart(
            b3d.Box(self.magnet_size, self.magnet_size, self.magnet_size),
            tags={ff.TagKey.MATERIAL: ff.materials.N52().tag, ff.TagKey.MAGNETIZATION: "N"},
            name="Magnet",
        )

        return ff.TaggedCompound(children=[air, magnet])


config = ff.SimulationConfig(
    geometry=MagnetInAir(magnet_size=8.0),
    mesh=ff.MeshConfig(global_mesh_size=0.004),
    domain=ff.DomainConfig(
        materials=[ff.materials.Air(), ff.materials.N52()],
        tags=[
            ff.EntityTag(
                selector={ff.TagKey.MAGNETIZATION: "N"},
                conditions=[ff.Magnetization(direction=ff.Direction(0, 0, 1))],
            ),
        ],
    ),
)

The two boxes overlap. The mesher splits them into a conformal decomposition, and the overlap goes to the magnet, the smaller body. See Mesh.

From model to STEP

Build123dGeometry is a Pydantic model. Its fields are the geometry parameters, and model() returns the tagged assembly. When SimulationConfig.geometry is set, the driver calls build_step into the run directory before meshing and points mesh.step at the result. The STEP is derived output, and the run identity comes from the parameters, so a new magnet_size gives a new run.

build_step exports model() with every leaf flattened to world placement. A part inherits the tags of the compounds above it, and a deeper tag wins over an ancestor's tag with the same key.

Without geometry, the mesher imports the file at MeshConfig.step. An authored STEP, such as a CAD export, works as long as its solid names carry key=value pairs, and the run identity then follows the file's content digest.

gmsh converts the STEP from its own unit to metres on import (GmshOptions.target_units="M"), and build123d writes millimetres. Author the CAD in millimetres and give every mesh size in metres. The mesher warns when the meshed model spans more than 2 m, which usually means a unit slip.

The model stays in the frame you author it in. SimulationConfig.frame maps it onto the solve, for example to an axisymmetric half-plane. See Frames.

Tagged shapes

Class Wraps Use it for
TaggedPart build123d.Part A body of a 3D model: one material, one region.
TaggedCompound build123d.Compound A group of tagged parts. Its tags pass down to every tagged leaf on export.
TaggedFace build123d.Face A body of a planar 2D model.

Each takes build123d shapes and the keyword tags=: TaggedPart(shapes) the solids it holds, such as [box] or a build123d part, TaggedCompound(children=...) the tagged shapes below it, and TaggedFace(face) one build123d face. TaggedPart and TaggedFace also take name=. The tags set the label, which the STEP file carries as the part name.

Tag keys

A tag key is any name that starts with a letter and continues with letters, digits or underscores. TagKey holds the shared keys:

Member Key Meaning
MATERIAL Material The registry tag of the body's material. Every body needs one.
NAME Name The authored body name. Set it through name=.
MAGNETIZATION Magnetization A magnet's magnetization label, such as N or S.
PHASE Phase The winding phase a conductor belongs to.
CURRENT_DIR CurrentDir Whether an electrode is a current Entry or Exit.
SEGMENT Segment The winding segment a conductor belongs to.
LAYER Layer The layer a conductor lies on, such as a PCB copper layer.
TYPE Type The kind of part, such as Trace or Via.
SLOT Slot The pole or slot position a part occupies.

Tag values cannot contain /, ,, _ or whitespace, because the STEP name carries them as key=value pairs. femforge removes those characters and logs a warning, so name="Left Magnet" becomes LeftMagnet. A value that is empty after cleaning raises.

Select bodies with tags

The mesher gives each body the material whose tag equals its Material value, ignoring case. A body without a Material tag, or with a tag that no material in DomainConfig.materials carries, stops the mesh with an error.

An EntityTag selects bodies by a selector. A body matches when its tags contain every pair of the selector, and an empty selector matches every body. The tag then carries what applies to the matched bodies:

Field What it applies
selector The key=value pairs a body must carry.
conditions Body forces and boundary conditions. See Conditions and physics.
mesh_size A target element size in metres. See Mesh.

A body can match several tags. It collects the conditions of all of them, and the finest mesh_size wins. Select by a shared tag such as Magnetization=N to reach many bodies at once, or by Name to reach one.

You never tag faces. A boundary condition on a body's tag lands on the surfaces that body borders. See Conditions and physics.

Body and boundary names

The mesher writes one physical group per body, and Elmer, entities.json and the viewer all use the same name.

Body Group name Rule
name="Magnet" MAGNET The authored name, uppercased.
No name, Material=N52, matched by Magnetization=N N52_MAGNETIZATIONN The material tag, then each matched tag's name, joined by _.
No name, Material=Air, no matched tags AIR The material tag alone.

A matched tag's name is its sorted pairs written as KeyValue and joined by _, such as CurrentDirEntry_Phase2. A tag whose selector is only Name uses the uppercased name. Bodies that share a material, an authored name and the same matched tags merge into one group.

Boundary groups take the names of the bodies they border:

Boundary Name Example
Interface between two bodies <A>__<B>, sorted AIR__MAGNET
A body's outer shell, shared with no other body <BODY>__EXT AIR__EXT
A body's edge on the symmetry axis of a 2D axisymmetric model <BODY>__AXIS AIR__AXIS

Keep the names unique and short:

  • Two body groups with the same name raise an error, for example one Name on parts of two materials.
  • Elmer reads names into 128-character buffers, and an interface name joins two body names. The mesher warns when a body name passes 60 characters.

If a body arrives at the mesher without a name, give the build123d solid a color. The STEP export can drop the name of an uncoloured solid.

Reference