fem.tetmesh.sdf_to_tet_mesh

fem.tetmesh.sdf_to_tet_mesh(
    sdf,
    grid,
    *,
    sharp=True,
    min_ratio=1.5,
    min_dihedral=10.0,
    max_refinements=2,
)

Extract the DC surface of sdf on grid and tet-mesh its inside.

The DC vertices are Newton-projected onto the zero set before tetrahedralization (QEF vertices sit near but not exactly on the surface), so the meshed boundary is the projected surface and :func:~cadjoint.fem.motion.recompute_tet_points — which runs the identical projection from the frozen raw DC positions — reproduces mesh.points exactly at the nominal design. Without this, re-projection at solve time would move the boundary of an already-meshed volume and collapse sliver tets.

Automatic refinement. Tets need a finer grid than hexes on thin features: the hex mesher only has to decide in/out per cell, while TetGen needs the DC surface to be a valid PLC, and a wall thinner than about two cells makes dual contouring fold that surface over itself. So this function walks a ladder of grids over the same box — the declared resolution, then x1.5 and x2.25 (rounded up per axis, see :data:_REFINEMENT_FACTORS) — and at each rung tries exact sharp-feature placement first and the more robust Tikhonov placement second, exactly as a caller would by hand. Before each TetGen call the projected surface goes through the sampled self-intersection diagnostic, so a rung it catches is recorded as folded, with a count, rather than as an opaque TetGen string (it is a sampled check, and cheap, but it is not a speed-up – see :data:_DIAGNOSTIC_PAIRS_PER_TRIANGLE). The first rung that TetGen accepts wins.

Parameters

Name Type Description Default
sdf Callable[[Any], Any] Signed distance field callable on (..., 3) points. required
grid GridSpec DC sampling lattice (must fully contain the surface); its box is held fixed while the ladder re-dices it. required
sharp bool Try exact sharp-feature vertex placement at each rung (False uses only the Tikhonov QEF placement, which is more robust against self-intersections at coarse grids). True
min_ratio float TetGen radius-edge quality bound. 1.5
min_dihedral float TetGen minimum dihedral angle bound in degrees. 10.0
max_refinements int How many refinement rungs to try after the declared resolution (0 restores the pre-refinement behaviour of failing at the declared grid). 2

Returns

Name Type Description
The TetMesh class:TetMesh; its first num_surface points are the
TetMesh projected DC surface vertices, its base_points hold the raw
TetMesh DC positions the projection restarts from, its grid is the
TetMesh rung that succeeded, and its
TetMesh attr:~TetMesh.refinement records the ladder:: {“declared”: (26, 26, 13), # the resolution asked for “used”: (39, 39, 20), # the resolution that worked “factor”: 1.5, # scale of the winning rung “refined”: True, # used != declared “attempts”: [ # every rung/placement tried {“resolution”: (26, 26, 13), “factor”: 1.0, “sharp”: True, “self_intersections”: 3, “pairs_tested”: 146432, “outcome”: “self-intersecting”}, … {“resolution”: (39, 39, 20), “factor”: 1.5, “sharp”: True, “self_intersections”: 0, “pairs_tested”: 331264, “outcome”: “meshed”}]}
TetMesh outcome is "meshed", "self-intersecting" (the
TetMesh diagnostic fired, TetGen was not run) or "rejected" (TetGen
TetMesh ran and refused; the attempt also carries "error").

Raises

Name Type Description
RuntimeError If no rung of the ladder produces a mesh. The message names the declared and the finest attempted resolution and the thinnest-feature heuristic.