Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
9.9 KiB
name, description
| name | description |
|---|---|
| fieldcraft-meshing | Agentic hex meshing (AHM) in FieldCraft — read the part, plan partitions, and build a structured all-hex (or hex-dominant) mesh an analyst would accept. Use before any mesh.* command on a part that matters, and whenever a mesh comes back with fans, slivers or a low scaled Jacobian. |
Agentic hex meshing (AHM)
You mesh like an experienced analyst: you look first, plan the blocks, and only then call a mesher. A mesh is judged by its worst elements, not its count. A fast mesh with fans, slivers or collapsed corners is a failed mesh, even when every element is "valid".
0. Start from the provenance graph (SolidCraft designs)
A .solidcraft design is rebuilt from its feature timeline, so how every body was made is known,
not guessed. Read it before you plan anything:
geometry.features {"body": "<body>"}: the features that built the body, in order, with their evaluated parameters (sketch profiles with circles and arcs, extrude direction and extent, primitive placement, hole axis and diameter, shell thickness, pattern/mirror transforms, join/cut targets and tools) and the persistent faces and edges each one made.mesh.plan {"body": "<body>"}: the block plan the features give — the sweep direction, a template per feature (sweep,block,butterfly,o_grid,layers,imprint,copy,partition), theringsround circles, the partitioncutsthat frame them, the element size (layers through the thinnest wall) and thecopiesof a pattern or mirror. Read theunmappedlist: fillets, chamfers, revolves, sweeps and lofts have no template yet, and a feature not prismatic along the sweep needs projection blocking (#399).- Edit the plan if a cut or the size is wrong (apply the edited object), then
mesh.plan.apply {"plan": "Plan-<body>"}. Checkall_hex,conforming,min_scaled_jacobianandpending(the rings today's meshers only box with frame cuts). - Then verify as in §4. When the plan does not fit (unmapped primary features, a failed cell), fall back to the manual process below, keeping the plan's cuts that work.
Shapes without a timeline (STEP, 3MF) start at §1.
1. Look before you mesh (always)
Before the first mesh command:
inspect_model/geometry.bodies: bodies, volumes, bounding boxes, faces, holes, fillets.- Take screenshots from the principal views and an iso view. Name, in words, what the part is.
- Symmetry. Test it geometrically (mirror the bounding box and the key faces). If the part (and
the loads you will apply) are symmetric, mesh one half or quarter only and mirror the mesh
(
mesh.mirror). Never mesh a symmetric part whole. - Primary vs secondary features.
- Primary: what carries the physics and sets the topology — the main body, walls, bosses, the load path, thin directions, the direction a section is swept along.
- Secondary: small fillets, chamfers, logos, small holes far from the region of interest. Start the block structure from the primary features. Secondary features are fitted into it (or defeatured), never allowed to drive it.
- Where to split. Before meshing, list the cuts: planes or curved surfaces that turn every region into a six-sided block or a sweepable prism. Say why each cut is there.
2. Plan the blocks (the rules)
- Never make sharp corners. No element angle near 0° or 180°. Where a block would have a corner angle far from 90°, cut differently or add a block (an O-grid) so every corner in the mesh is close to 90°.
- Partitions must never create skewed, tapered or high-aspect-ratio hex. Check every cell you create: if it is a wedge, a sliver or a long thin strip relative to the element size, the cut is wrong. Move or remove it.
- Butterfly (O-grid) around curved parts. Around a hole, a boss, a cylinder or a fillet, cut a square block around it and an O-grid ring between the square and the curve, so element lines run radially and the corners of the square sit at 45° on the curve. Never let a mesh fan into a hole or pinch at a tangency.
- Split and merge to make it square. When a region is far from a square (an L, a long strip with a bump), split it into pieces and merge pieces again so each final cell is closer to a cube. Aim for cells with aspect ratio near 1 at the target size.
- Curved splits are allowed. A cut does not have to be a plane: use a cylindrical or offset surface (a ring around a boss, an offset of a fillet) when a plane would create slivers.
- Never cut along an existing face (a plane coincident with a face within tolerance leaves micrometre slivers, #384) and never through the axis of a small hole (degenerate tessellation at the hole edge). Offset the cut to just outside the feature instead.
- Keep cuts consistent across touching bodies so their meshes can match, or tie them
deliberately (
interaction.tie; linear faces only today).
3. Mesh
- Mesh each cell with the structured method that fits (
mesh.hex.generateextrude/sweep/revolve/ mapped;mesh.cellsfor partitioned parts;mesh.hex.blockswhen every cell is a block). - Use edge seeds (
mesh.seed.edge) so counts match across shared edges and so there are enough elements through thin walls (at least 2–3 through a wall for bending, 1 for pure conduction only). - Tet (
tet10preferred for stress) only for cells that are not worth blocking, and only where they are far from the region of interest. Before falling back to tet on a region that ends on a curved face, try extrude-to-surface (§3b).
3b. Extrude up to a surface — try it before giving up on a region
A region that is one section carried to a curved or tilted end (a boss or rib meeting a curved
wall, an air column under a domed lid, a fillet region capped by a curved face) is not sweepable
between parallel faces, but mesh.hex.extrude meshes it:
source: the section's face. If a neighbour (or the cell below) is already meshed there, its quads are reused and the two meshes share nodes; else a planar face is meshed here atsize. A 2D mesh works too (source_set).to_surface: the end faces;sides: the region's side faces (give them whenever they are not straight along the path, so every layer follows them).directionfor a straight region, elsenormal;layers(orsize) andbias(< 1 grades toward the target, e.g. for a boundary layer under a lid).- Check the reply:
max_target_gap≈ 0,min_scaled_jacobian≥ 0.5,section.shared_nodesequal to the section's nodes when it should conform. An error names the node whose path misses the target or the element that would invert: shorten the region (cut it where the end turns steep) rather than falling back to tets.
3a. Projection blocking
When partitioning the real geometry into sweepable cells is awkward (round parts, branches,
handles, curved caps), lay a block topology over the part and project it (mesh.hex.project):
- Sphere or ball-like region:
"template": "sphere"(inner cube + six blocks). Never a single block on a sphere. - Disc, rod, tube, any round section:
"template": "butterfly"(centre square + four petals) along the axis, withlevelsat every change along it. A plain grid block projected onto a cylinder flattens its corners to 180° — the command refuses it (min_quality). - Holes, bosses, floors of cups: O-grid the block (
{"op": "o_grid", "block", "open", "inset"}); open faces let the inner block reach that face. A cup floor needs its own O-grid inside the wall's butterfly (open: [1, 2]on the centre block), the cavity is thenremoved. - Side branch: O-grid the block under the branch's footprint open toward it and extrude the
open face (
"extrude": {"offset", "layers"}, facesall= round branch). The junction edges go onto the curve where the two surfaces meet automatically. - Square stubs, handles, ribs: O-grid open toward the stub, extrude
inner, chainextrudeops, and close loops withconnect. Inner corners of a stretched topology follow the projection, but keep the initial blocks roughly where the geometry is (offsets measured from the block faces, not from the surface). - Use
"preview": trueto list block indices before meshing; faces can be given as"+x"…"-z". - Targets default to the smooth group of B-rep faces each outer block face faces; set them with
faces: [{block, face, to}]when a block face is near two surfaces. - Read the reply:
initial_min_scaled_jacobian(transfinite grid) vsmin_scaled_jacobian(after elliptic smoothing),max_gap(should be ~0). An error names the worst block and where.
4. Verify (every time, before solving)
mesh.quality: all valid; scaled Jacobian min ≥ 0.3 (≥ 0.5 in the region of interest); edge ratio max ≤ 10; no element below these is acceptable without a stated reason. Isolated spikes (a few bad elements in an otherwise good mesh) are fixed last, withmesh.node.relax {"around_element": <worst>}(orcenter+radius): nodes there relax, surface nodes sliding on their faces, nothing inverting. It is a final touch, never a substitute for a better block plan: many bad elements mean the cuts are wrong (§2). Pass"reapply": true(or runmesh.node.relax.apply {field}) so the relaxation follows a later remesh.- Look at it: screenshots of each body and a section. Fans, pinches, wedges, slivers → back to §2.
- Volume:
mesh.qualityvolume equals the geometry volume (a mismatch means orphan or missing cells, #385). mesh.check.duplicates: no cracks or free edges inside a body.- After solving, refine once and compare the quantity of interest (convergence).
5. Report
State: symmetry used, primary features, every cut and why, method per cell, element counts, quality numbers, and anything you defeatured. If the plan failed, say which rule failed and the next cut you will try — don't silently fall back to a worse mesh.