Rename the project to FieldCraft

Crates fieldcraft-*, binaries fieldcraft and fieldcraft-cli, the .fieldcraft file (format tag
fieldcraft/1, manifest fieldcraft.json), FIELDCRAFT_* environment variables, the MCP server
name, egui widget ids (fc_*), the app icon document FieldCraft.icon and its generated family,
docs and licences. No compatibility shim: no files of the earlier name exist.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm
This commit is contained in:
jyvikoandClaude Opus 5.5 authored and Irakli Kourtis committed 2026-10-13 23:51:40 -04:00
1 parent 9bc4e1b182
commit d5bd74570f
268 files changed
+1666 -1666

No files matched your search

+12 -12
View File
@@ -4,29 +4,29 @@ Status: accepted (2026-10-13)
## Context
ModelCraft is MIT OR Apache-2.0. Everything it links must allow that, and the meshing and solver
FieldCraft is MIT OR Apache-2.0. Everything it links must allow that, and the meshing and solver
algorithms, where the obvious open-source implementations are GPL-family, must come from papers.
## Decision
**Geometry: SolidCraft**, as git dependencies pinned by rev (`solidcraft-kernel`,
`solidcraft-geom`, `solidcraft-doc`, `solidcraft-io`; MIT OR Apache-2.0, built on the Apache-2.0
truck crates). SolidCraft is the primary geometry source: ModelCraft opens SolidCraft designs and
truck crates). SolidCraft is the primary geometry source: FieldCraft opens SolidCraft designs and
meshes from SolidCraft's tessellation, and reads face-tagged meshes SolidCraft exports. Other CAD
exchange files (STEP, which SolidCraft's kernel already reads) can be added as secondary inputs
through the same crate. Only `modelcraft-geometry` may depend on SolidCraft.
through the same crate. Only `fieldcraft-geometry` may depend on SolidCraft.
**Meshing: our own**, implemented from published papers (`docs/meshing/literature.md`).
Robust predicates follow Shewchuk's adaptive-precision arithmetic (the paper; his reference
`predicates.c` is public domain). A permissive crate may be adopted instead after review; record
it here. *Decided 2026-10-13:* our own implementation, `modelcraft_mesh::predicates`, written from
it here. *Decided 2026-10-13:* our own implementation, `fieldcraft_mesh::predicates`, written from
Shewchuk 1997, Devillers–Teillaud 2011 and Attene 2020 (no `unsafe`, deterministic, wasm-safe, a
validated coordinate domain instead of Shewchuk's overflow/underflow caveat, and indirect
predicates that `robust` lacks). `robust` (georust, MIT OR Apache-2.0) and `num-bigint` /
`num-rational` / `num-traits` (MIT OR Apache-2.0) are dev-dependencies only: differential test
oracles, never linked into ModelCraft.
oracles, never linked into FieldCraft.
**Linear algebra: our own.** *Decided 2026-10-13 (implicit solver task):* `modelcraft-solver`
**Linear algebra: our own.** *Decided 2026-10-13 (implicit solver task):* `fieldcraft-solver`
has its own sparse symmetric storage, nested-dissection ordering (George 1973, by coordinate
bisection), up-looking sparse Cholesky (Davis 2006, elimination trees per Liu 1990) and
shift-invert block Lanczos with full reorthogonalization (Ericsson–Ruhe 1980, Grimes–Lewis–Simon
@@ -44,7 +44,7 @@ parallelism task):* the factorization is now our own supernodal left-looking Cho
1994), multithreaded with a fixed operation order (below). Its rounding differs from the old
up-looking factor in the last digits; every oracle fixture stays within its band.
**Threads: rayon** (MIT OR Apache-2.0), in `modelcraft-parallel` only (an L0 crate with no
**Threads: rayon** (MIT OR Apache-2.0), in `fieldcraft-parallel` only (an L0 crate with no
workspace dependencies; *decided 2026-10-13*). The solvers keep the bit-for-bit rule on any
number of threads by construction: work is cut into blocks whose sizes are constants of the
algorithm, never derived from the thread count; each floating-point value is computed by one task
@@ -57,9 +57,9 @@ per time increment (10⁵–10⁷ increments), so a persistent pool is needed, a
re-implement rayon's. rayon was already in the shipped dependency tree (THIRD-PARTY-LICENSES.txt
unchanged). In the browser build (`wasm32`) the crate does not depend on rayon and runs the same
blocks one after another, with the same results. The thread count is a session and `solve.*`
parameter (`threads`, 1–256) whose default is `MODELCRAFT_THREADS` or the available cores. Cost if
parameter (`threads`, 1–256) whose default is `FIELDCRAFT_THREADS` or the available cores. Cost if
this is wrong: rayon's pool is a process-wide resource and nested pools add latency; replacing it
touches only `modelcraft-parallel`.
touches only `fieldcraft-parallel`.
**Allowed:** MIT, BSD-2/3, Apache-2.0, ISC, Zlib, Unicode, MPL-2.0 (as an unmodified dependency),
CC0 and public domain.
@@ -106,8 +106,8 @@ Thingi10K is not used either (owner decision 2026-10-13: authoring tools unrecor
corpus is our own:** parts built with SolidCraft (scripts or designs authored in SolidCraft,
committed as their recipes so the geometry is regenerated, not stored) and analytic shapes.
Recipes are SolidCraft command scripts run through `solidcraft-engine` (same pinned rev), a
dependency of `modelcraft-geometry` only behind its non-default `scripts` feature, which the test
tooling (`modelcraft-testkit`) enables; the shipped library opens designs without it.
dependency of `fieldcraft-geometry` only behind its non-default `scripts` feature, which the test
tooling (`fieldcraft-testkit`) enables; the shipped library opens designs without it.
**Commercial products** (Abaqus, Nastran, LS-DYNA, LS-PrePost, HyperMesh, ANSA, Femap, Patran,
ANSYS) are never run or scripted, and their input files, text and figures are never copied. Deck
@@ -120,5 +120,5 @@ docs/verification.md).
- The tet and hex meshers are significant original work; the literature survey decides the
order and the methods.
- SolidCraft and ModelCraft move together: bumping the pinned rev bumps the repeated
- SolidCraft and FieldCraft move together: bumping the pinned rev bumps the repeated
`[patch.crates-io]` entries in the same commit.
+41 -41
View File
@@ -1,6 +1,6 @@
# Architecture
ModelCraft turns geometry into finite element models, writes them for the solvers engineers
FieldCraft turns geometry into finite element models, writes them for the solvers engineers
already use, and solves linear problems itself.
```
@@ -18,33 +18,33 @@ crates in strictly lower layers.
| Layer | Crate | Role | Status |
|---|---|---|---|
| L0 | `modelcraft-model` | Solver-neutral FE model: nodes and elements by label, their geometry tags, sets, materials, sections, couplings, BCs, loads and steps, the model check and the resolved view the writers read. Knows no file format and no geometry type. | started |
| L0 | `modelcraft-parallel` | Deterministic data parallelism for the solvers: fixed work partitions on a rayon pool, results in block order, the thread-count setting (`MODELCRAFT_THREADS`, `threads`); sequential in the browser. No workspace dependencies. | started |
| L1 | `modelcraft-geometry` | The only door to SolidCraft: opens `.solidcraft` designs (rebuilt from their timeline, bodies with persistent face names), B-rep bodies, measures, tessellation into a face-tagged `SurfaceMesh`; face-tagged 3MF files read into the same type without the kernel (docs/formats/tagged-mesh.md). No SolidCraft type in its API. | started |
| L1 | `modelcraft-mesh` | Surface preparation (weld, watertightness, feature edges), robust predicates, Delaunay tetrahedralization and refinement, Voronoi-based optimization, hex meshing, quality metrics. | started |
| L1 | `modelcraft-fem` | Element kernels shared by every structural solver: the element table (tet4, tet10, wedge6, hex8 full and incompatible modes, hex20 full and reduced), shape functions, quadrature, element stiffness, consistent and lumped mass, body and pressure loads, stresses and their extrapolation, isotropic and orthotropic elasticity, the uniform-strain (one-point) hex8 and tet4 kinematics, hourglass shape vectors and element frequency bounds of the explicit solver, objective stress rates and J2/Johnson–Cook return mapping. Pure functions, no solver loop. | started |
| L1 | `modelcraft-decks` | Abaqus input, Nastran bulk data and LS-DYNA keyword readers and writers, to and from `model`. Text out, no file system; `deck.write` saves it. | started |
| L1 | `modelcraft-render` | Display data without a GPU dependency: the visible faces, element edges and nodes of a model, the orbit camera, a CPU rasterizer for headless snapshots, geometry surfaces with their face boundaries, deformed shapes and banded contour plots of nodal results, picking. | started |
| L2 | `modelcraft-solver` | Implicit solver: assembly from the resolved model, boundary conditions, sparse direct solution, linear static and modal analysis, stresses and reactions. | started |
| L2 | `modelcraft-explicit` | Explicit dynamics: central-difference time integration with lumped mass, one-point hex8 with hourglass control, nodal-pressure tet4, bulk viscosity, rigid walls, large deformation with objective rates, plasticity, damage and erosion, energy account, histories and field frames. | started |
| L2 | `modelcraft-lbm` | Lattice Boltzmann flow solver on the CPU: D3Q19 two-relaxation-time scheme, bounce-back and slip walls, Zou–He inlets and outlets, obstacles voxelised from the face-tagged surface with exact predicates, momentum-exchange forces per face. Uses `mesh` for the predicates and the boundary surface. | started |
| L3 | `modelcraft-fsi` | Fluid–structure coupling between the L2 solvers (later). | planned |
| L4 | `modelcraft-doc` | The document: geometry, mesh, model, results, history. | planned |
| L5 | `modelcraft-io` | `.modelcraft` files (docs/formats/modelcraft.md): text model definition, binary mesh, geometry references with content hashes, the journal; atomic saves; autosave storage for crash recovery; read and write roots that confine an automation client's file access (`roots`). Bytes in, bytes out; the file system only in `fs`, `recovery` and `roots`. Result files later. | started |
| L6 | `modelcraft-engine` | Commands (`CommandSpec`), `Session::execute` with rollback and the panic guard, scripts; every file a command names checked against the session's roots (`Session::file_access`); headless pictures of the session (`view`: model, geometry, deformed shape and contours on the CPU rasterizer). | started |
| L7 | `modelcraft-ui-egui`, `modelcraft-mcp` | Desktop UI in the Craft family's layout (title bar with quick actions, workspace ribbon from the catalogue, browser, viewport with navigation bar and orientation gizmo, context panel, command search and command line, journal timeline; native file pickers as host services, background opening and solving; results display with legend and probe; offscreen capture of the whole window) and control channel requests (docs/control-protocol.md); MCP server over stdio (docs/mcp.md): tools over engine commands, a headless session or the running app through its control channel, read and write roots. | ui, mcp started |
| testkit | `modelcraft-testkit` | Test tooling, a dev-dependency only: the meshing test corpus (`tests/corpus/*/recipe.json`, analytic shapes) and its runner (`cargo xtask corpus`). | started |
| apps | `modelcraft`, `modelcraft-cli`, `modelcraft-web` | Desktop, command line, browser. | desktop, cli started |
| L0 | `fieldcraft-model` | Solver-neutral FE model: nodes and elements by label, their geometry tags, sets, materials, sections, couplings, BCs, loads and steps, the model check and the resolved view the writers read. Knows no file format and no geometry type. | started |
| L0 | `fieldcraft-parallel` | Deterministic data parallelism for the solvers: fixed work partitions on a rayon pool, results in block order, the thread-count setting (`FIELDCRAFT_THREADS`, `threads`); sequential in the browser. No workspace dependencies. | started |
| L1 | `fieldcraft-geometry` | The only door to SolidCraft: opens `.solidcraft` designs (rebuilt from their timeline, bodies with persistent face names), B-rep bodies, measures, tessellation into a face-tagged `SurfaceMesh`; face-tagged 3MF files read into the same type without the kernel (docs/formats/tagged-mesh.md). No SolidCraft type in its API. | started |
| L1 | `fieldcraft-mesh` | Surface preparation (weld, watertightness, feature edges), robust predicates, Delaunay tetrahedralization and refinement, Voronoi-based optimization, hex meshing, quality metrics. | started |
| L1 | `fieldcraft-fem` | Element kernels shared by every structural solver: the element table (tet4, tet10, wedge6, hex8 full and incompatible modes, hex20 full and reduced), shape functions, quadrature, element stiffness, consistent and lumped mass, body and pressure loads, stresses and their extrapolation, isotropic and orthotropic elasticity, the uniform-strain (one-point) hex8 and tet4 kinematics, hourglass shape vectors and element frequency bounds of the explicit solver, objective stress rates and J2/Johnson–Cook return mapping. Pure functions, no solver loop. | started |
| L1 | `fieldcraft-decks` | Abaqus input, Nastran bulk data and LS-DYNA keyword readers and writers, to and from `model`. Text out, no file system; `deck.write` saves it. | started |
| L1 | `fieldcraft-render` | Display data without a GPU dependency: the visible faces, element edges and nodes of a model, the orbit camera, a CPU rasterizer for headless snapshots, geometry surfaces with their face boundaries, deformed shapes and banded contour plots of nodal results, picking. | started |
| L2 | `fieldcraft-solver` | Implicit solver: assembly from the resolved model, boundary conditions, sparse direct solution, linear static and modal analysis, stresses and reactions. | started |
| L2 | `fieldcraft-explicit` | Explicit dynamics: central-difference time integration with lumped mass, one-point hex8 with hourglass control, nodal-pressure tet4, bulk viscosity, rigid walls, large deformation with objective rates, plasticity, damage and erosion, energy account, histories and field frames. | started |
| L2 | `fieldcraft-lbm` | Lattice Boltzmann flow solver on the CPU: D3Q19 two-relaxation-time scheme, bounce-back and slip walls, Zou–He inlets and outlets, obstacles voxelised from the face-tagged surface with exact predicates, momentum-exchange forces per face. Uses `mesh` for the predicates and the boundary surface. | started |
| L3 | `fieldcraft-fsi` | Fluid–structure coupling between the L2 solvers (later). | planned |
| L4 | `fieldcraft-doc` | The document: geometry, mesh, model, results, history. | planned |
| L5 | `fieldcraft-io` | `.fieldcraft` files (docs/formats/fieldcraft.md): text model definition, binary mesh, geometry references with content hashes, the journal; atomic saves; autosave storage for crash recovery; read and write roots that confine an automation client's file access (`roots`). Bytes in, bytes out; the file system only in `fs`, `recovery` and `roots`. Result files later. | started |
| L6 | `fieldcraft-engine` | Commands (`CommandSpec`), `Session::execute` with rollback and the panic guard, scripts; every file a command names checked against the session's roots (`Session::file_access`); headless pictures of the session (`view`: model, geometry, deformed shape and contours on the CPU rasterizer). | started |
| L7 | `fieldcraft-ui-egui`, `fieldcraft-mcp` | Desktop UI in the Craft family's layout (title bar with quick actions, workspace ribbon from the catalogue, browser, viewport with navigation bar and orientation gizmo, context panel, command search and command line, journal timeline; native file pickers as host services, background opening and solving; results display with legend and probe; offscreen capture of the whole window) and control channel requests (docs/control-protocol.md); MCP server over stdio (docs/mcp.md): tools over engine commands, a headless session or the running app through its control channel, read and write roots. | ui, mcp started |
| testkit | `fieldcraft-testkit` | Test tooling, a dev-dependency only: the meshing test corpus (`tests/corpus/*/recipe.json`, analytic shapes) and its runner (`cargo xtask corpus`). | started |
| apps | `fieldcraft`, `fieldcraft-cli`, `fieldcraft-web` | Desktop, command line, browser. | desktop, cli started |
Rules beyond the layer order:
- Nothing below L7 uses egui, eframe, winit, wgpu or rfd.
- Only `modelcraft-geometry` uses `solidcraft-*`, pinned by rev in the workspace `Cargo.toml`.
- Only `fieldcraft-geometry` uses `solidcraft-*`, pinned by rev in the workspace `Cargo.toml`.
SolidCraft's `[patch.crates-io]` (its fixed truck crates) does not reach dependents, so the
workspace repeats it from the same rev; bump both together. The same goes for SolidCraft's
patched `egui-wgpu` (MSAA clamped to what the device supports, 1x on OpenGL adapters, so the
desktop app's 4x never fails pipeline validation at start).
- Everything below the apps builds for `wasm32-unknown-unknown`.
- `modelcraft-geometry`'s non-default `scripts` feature builds designs from SolidCraft command
- `fieldcraft-geometry`'s non-default `scripts` feature builds designs from SolidCraft command
scripts (`script_design`, through `solidcraft-engine`) for the test corpus; the library opens
designs without it.
@@ -56,7 +56,7 @@ Rules beyond the layer order:
them), so a load on a named face follows it when the design is edited and opened again.
Bodies of components are placed in the world through their occurrences (one body per
placement), as SolidCraft displays and exports them.
2. **Surface preparation** (`modelcraft-mesh::surface`, `mesh.surface.check`). Weld the tessellation's per-face
2. **Surface preparation** (`fieldcraft-mesh::surface`, `mesh.surface.check`). Weld the tessellation's per-face
vertex copies (at twice SolidCraft's linear tolerance), check the surface is closed, manifold, consistently and
outwardly oriented (voids inwards) and free of self-intersections (exact triangle–triangle tests), and find
feature edges (face boundaries, sharp dihedral angles). Defects come back located by triangle, vertex and
@@ -64,7 +64,7 @@ Rules beyond the layer order:
3. **Tetrahedral meshing.** Bowyer–Watson Delaunay on Shewchuk's adaptive predicates (symbolic
perturbation for degeneracies), boundary recovery by the robust constrained Delaunay method of
Diazzi et al. 2023 (implicit Steiner points on indirect predicates, gift-wrapping facet
recovery; `modelcraft-mesh::cdt`, command `mesh.tet.generate`), so every boundary triangle and
recovery; `fieldcraft-mesh::cdt`, command `mesh.tet.generate`), so every boundary triangle and
its B-rep face tag survives. Then constrained Delaunay refinement to a
size field, ODT smoothing interleaved as in Tournois et al. 2009, and the Klingner–Shewchuk 2007
improvement schedule against slivers.
@@ -75,12 +75,12 @@ Rules beyond the layer order:
frame-field/integer-grid-map methods stay research. Validity uses a certified trilinear Jacobian
check (Marschner et al. 2020), not corner Jacobians alone.
5. **Structured hex and face meshing.** Faces get all-quad meshes on shared, prescribed edge
nodes (`modelcraft-mesh::quad`): transfinite interpolation for four-sided faces (Gordon and
nodes (`fieldcraft-mesh::quad`): transfinite interpolation for four-sided faces (Gordon and
Hall 1973), and for free faces a half-resolution constrained Delaunay triangulation,
recombination (Lee and Lo 1994) and one uniform split that lands on the boundary nodes, then
smoothing and untangling; every quad is checked with exact predicates. One `SizeField` trait
(`modelcraft-mesh::size`) sets interior sizes and edge divisions, with even counts per loop.
Mapped and swept hex build on these face meshes (`modelcraft-mesh::hex`, `mesh.hex.generate`):
(`fieldcraft-mesh::size`) sets interior sizes and edge divisions, with even counts per loop.
Mapped and swept hex build on these face meshes (`fieldcraft-mesh::hex`, `mesh.hex.generate`):
the B-rep topology is recovered from the face-tagged surface; a body is extruded (straight
multi-level sweep: the levels' outlines imprinted into one cross-section, cut at reflex corners,
regions mapped, O-gridded or free-meshed, then stacked), revolved (the same in a rotating
@@ -91,7 +91,7 @@ Rules beyond the layer order:
result passes the certified validity gate plus tiling and fidelity checks. A body no method
fits gets each method's reason.
Without geometry, `mesh.block`
(`modelcraft-mesh::block`) meshes one six-sided block from its eight corners and optional
(`fieldcraft-mesh::block`) meshes one six-sided block from its eight corners and optional
circular or elliptical edges by the same edge-based transfinite interpolation, as hex8, hex20,
tet4/tet10 (Kuhn's six tetrahedra per cell) or wedge6, with grading; blocks join where their
nodes coincide, face to face (mismatched divisions or kinds are refused), and their named
@@ -102,7 +102,7 @@ Rules beyond the layer order:
## Model definition
`modelcraft-model` holds the analysis model in no solver's vocabulary (the writers map it to
`fieldcraft-model` holds the analysis model in no solver's vocabulary (the writers map it to
element names, cards and keywords):
- **Geometry tags.** Geometry is referred to by name only: a body and, inside it, the persistent
@@ -144,27 +144,27 @@ element names, cards and keywords):
## Implicit solver
`modelcraft-solver` solves a model's linear static and frequency steps (`solve.static`,
`fieldcraft-solver` solves a model's linear static and frequency steps (`solve.static`,
`solve.frequency`; `solve.probe` reads the stored results). Methods and papers are cited in the
module docs; ADR 0001 records why the linear algebra is our own.
1. **System.** `Model::resolve()`; each solid section's elements take their material's
elasticity matrix and the section's formulation (`modelcraft_fem::element::ELEMENT_TYPES`, one
elasticity matrix and the section's formulation (`fieldcraft_fem::element::ELEMENT_TYPES`, one
row per element kind: tet4, tet10, wedge6, hex8, hex20); 2D sections (plane stress, plane
strain, axisymmetric) take the 2D table (`modelcraft_fem::plane::PLANE_TYPES`: tri3, tri6,
strain, axisymmetric) take the 2D table (`fieldcraft_fem::plane::PLANE_TYPES`: tri3, tri6,
quad4, quad8), chosen by the section kind, and the model then has two degrees of freedom per
node: the 2D elements declare `ElementDofs::new(DofSet::PLANE)` (Ux, Uy) to the `DofLayout`. A 2D model
lies in the XY plane (axisymmetric: x the radius, Y the axis; nodes on the axis are held
radially), is loaded on element edges, and cannot mix with solids or couplings yet. Rod
sections' rod2 and rod3 elements are trusses (`modelcraft_fem::truss`). Point masses, rotary
sections' rod2 and rod3 elements are trusses (`fieldcraft_fem::truss`). Point masses, rotary
inertia and springs (`Resolved::masses`, `springs`, expanded per node by the model) assemble on
the unknowns their nodes are given (`discrete::needs`, `discrete::dof_of`); dashpots are
ignored with a warning (no velocities in static and frequency steps). Every reference point a
coupling or a discrete element uses gets six degrees of freedom (translations, rotations) after
the mesh's. Shell sections make quad4 (MITC4) and tri3 (MITC3) flat shells with a drilling
rotation (`modelcraft_fem::shell`; quad8 and tri6 shells are "not supported yet"), beam
rotation (`fieldcraft_fem::shell`; quad8 and tri6 shells are "not supported yet"), beam
sections two-node Timoshenko beams with the profile's section properties and the section's
orientation vector (`modelcraft_fem::beam`); both declare `ElementDofs::new(DofSet::STRUCTURAL)`
orientation vector (`fieldcraft_fem::beam`); both declare `ElementDofs::new(DofSet::STRUCTURAL)`
(`system::Structural`), so their nodes carry translations and rotations and the solids and
trusses sharing those nodes add into the translations. Shells and beams need isotropic
materials until material orientations exist, and are 3D only. The step's boundary conditions
@@ -226,14 +226,14 @@ source, separate from the analytic gate): the Scordelis–Lo roof and the pinche
## Explicit solver
`modelcraft-explicit` integrates a model's `explicit_dynamic` steps in time (`solve.explicit`;
`fieldcraft-explicit` integrates a model's `explicit_dynamic` steps in time (`solve.explicit`;
`solve.history` and `solve.probe` read the stored histories and frames). Methods and papers are
cited in the module docs and in docs/solvers/literature.md (Parts H and J). Both structural solvers
number their degrees of freedom with `modelcraft_fem::DofLayout` (docs/fem.md).
number their degrees of freedom with `fieldcraft_fem::DofLayout` (docs/fem.md).
1. **System.** `Model::resolve()`; hex8 sections with reduced integration become one-point
uniform-strain hexahedra with Flanagan–Belytschko hourglass control, tet4 sections Bonet–Burton
average nodal pressure tetrahedra (`modelcraft_fem::uniform` holds their kinematics), rod2 and
average nodal pressure tetrahedra (`fieldcraft_fem::uniform` holds their kinematics), rod2 and
rod3 trusses (`discrete`). Point masses add to the lumped mass; springs and dashpots (on the
previous half increment's velocity) add internal and viscous forces and their own stable
increment. Other element kinds and formulations, couplings, reference points, rotary inertia,
@@ -277,7 +277,7 @@ cantilever's free-vibration period against `solve.frequency`.
## Lattice Boltzmann solver
`modelcraft-lbm` solves a model's fluid steps (`solve.fluid`; `solve.probe` reads velocity and
`fieldcraft-lbm` solves a model's fluid steps (`solve.fluid`; `solve.probe` reads velocity and
pressure at points and wall force histories). Papers are cited in the module docs and in
`docs/solvers/literature.md` (Part I).
@@ -322,7 +322,7 @@ journal replays as a script. Each journalled command is also an undo step (the s
`edit.redo` puts it back, so the journal always rebuilds the current model. History is bounded by
step count and by an estimate of the memory the kept states hold (oldest steps go first).
Commands of kind `Session` (`file.*`, `edit.*`) are never journalled. `file.save` and `file.open`
write and read `.modelcraft` files; the desktop app autosaves unsaved work for `file.recover`.
write and read `.fieldcraft` files; the desktop app autosaves unsaved work for `file.recover`.
## Test corpus
@@ -330,10 +330,10 @@ Meshers are measured on our own parts (`docs/adr/0001-libraries.md`, test geomet
a SolidCraft command script in `tests/corpus/<name>/recipe.json` (the file `solidcraft-cli run`
takes, plus a `corpus` object with its categories and, when it has one, its closed-form volume)
with a one-line `README.md`; analytic shapes (sphere, torus, cylinder, thick-walled pipe, plate
with a hole) are generated in code. `modelcraft-testkit` runs a recipe in SolidCraft's engine,
with a hole) are generated in code. `fieldcraft-testkit` runs a recipe in SolidCraft's engine,
saves the design and opens it through `open_design`, the path a person's design takes, so no
geometry is stored. `cargo xtask corpus` (a release build of the testkit's `corpus` binary)
builds every part, tessellates it and runs each stage of `modelcraft_testkit::runner`, writing
builds every part, tessellates it and runs each stage of `fieldcraft_testkit::runner`, writing
docs/meshing/corpus.md. A mesher joins by implementing `runner::Stage` (its columns, and a run
over the part's tessellated surfaces) and adding itself to `runner::stages()`.
@@ -343,6 +343,6 @@ over the part's tessellated surfaces) and adding itself to `runner::stages()`.
own model of each problem as a command recipe (`recipe.json`, optionally a SolidCraft
`design.json`), its cited reference values with tolerances and reasons (`expected.json`), and our
frozen results (`fixture.json`). `cargo xtask oracle` runs the testkit's `oracle` binary
(`modelcraft_testkit::oracle`): one `Session` per case, quantities read by JSON pointer from step
(`fieldcraft_testkit::oracle`): one `Session` per case, quantities read by JSON pointer from step
outputs or commands such as `solve.probe {"at": [[x, y, z]]}`, compared with the reference and the
fixture; it writes docs/oracle.md. CI runs it as its own job.
+5 -5
View File
@@ -1,13 +1,13 @@
# Control protocol
`modelcraft --control PORT` (or `MODELCRAFT_CONTROL_PORT=PORT`) listens on `127.0.0.1:PORT` for
`fieldcraft --control PORT` (or `FIELDCRAFT_CONTROL_PORT=PORT`) listens on `127.0.0.1:PORT` for
JSON lines. Each request is one line `{"id": …, "method": "…", "params": {…}}`; each reply is one
line `{"id": …, "ok": true, "result": …}` or `{"id": …, "ok": false, "error": "…"}`. Requests are
handled on the UI thread between frames; pointer and keyboard input is injected as real egui
events, one pointer event per frame. The protocol has the same shape as SolidCraft's.
```text
modelcraft --sample --control 7070 # or --sample cantilever | impact
fieldcraft --sample --control 7070 # or --sample cantilever | impact
{"id":1,"method":"engine.execute","params":{"command":"model.info","params":{}}}
→ {"id":1,"ok":true,"result":{"elements":{"hex8":64,"tet4":162},"nodes":199}}
{"id":2,"method":"ui.render","params":{"path":"/tmp/model.png","width":900,"height":600}}
@@ -28,7 +28,7 @@ checked and clamped (drag steps, wheel lines, window size); `ui.render` refuses
| `engine.script` | `commands`: `[{command, params}, …]` | stops at the first error; `journal`: commands that changed the model so far |
| `engine.commands` | — | every command: `id`, `label`, `params` (the parameter documentation) |
Commands never open forms or file pickers when run this way. `modelcraft-cli commands` prints the
Commands never open forms or file pickers when run this way. `fieldcraft-cli commands` prints the
same registry. `file.sample {name}` opens a sample (`parts`, `cantilever`, `impact`) and
`solve.run {}` solves every step; the Results workspace comes up when a result appears.
@@ -53,8 +53,8 @@ same registry. `file.sample {name}` opens a sample (`parts`, `cantilever`, `impa
| `ui.worldToScreen` | `points`: `[[x, y, z]…]` (at most 1000) | screen points in the viewport drawn last frame (null when not on screen) |
| `ui.resize` | `width`, `height` | window inner size in points |
| `ui.fullscreen` | `on?` (default true) | into or out of full screen; on macOS the title bar's left group moves into the traffic lights' room while there are none |
| `ui.screenshot` | `path?` | PNG of the window, taken a few frames later; waits for a presented frame; when none comes within 8 seconds (a hidden window, a locked screen) it answers with `ui.capture`'s offscreen picture (`"offscreen": true`). Without `path`: `modelcraft-shot.png` in the temporary folder |
| `ui.capture` | `path?`, `width?`, `height?` (points; default the window's), `scale?` (pixels per point, 0.5–4; default the window's) | PNG of the whole window (title bar, ribbon, open menus and search, panels, forms and the viewport) drawn offscreen, without fade-in animations: the UI pass runs in a separate egui context and is rasterised on the CPU, so it works with the window hidden, minimised or the screen locked. At most 8192 pixels a side and 16 megapixels. Without `path`: `modelcraft-shot.png` in the temporary folder |
| `ui.screenshot` | `path?` | PNG of the window, taken a few frames later; waits for a presented frame; when none comes within 8 seconds (a hidden window, a locked screen) it answers with `ui.capture`'s offscreen picture (`"offscreen": true`). Without `path`: `fieldcraft-shot.png` in the temporary folder |
| `ui.capture` | `path?`, `width?`, `height?` (points; default the window's), `scale?` (pixels per point, 0.5–4; default the window's) | PNG of the whole window (title bar, ribbon, open menus and search, panels, forms and the viewport) drawn offscreen, without fade-in animations: the UI pass runs in a separate egui context and is rasterised on the CPU, so it works with the window hidden, minimised or the screen locked. At most 8192 pixels a side and 16 megapixels. Without `path`: `fieldcraft-shot.png` in the temporary folder |
| `ui.render` | `path`, `width?` (default 1280), `height?` (default 800): whole pixels, each 1–8192 and at most 16 megapixels in all | CPU render of the model with the current camera and view settings (no window or GPU needed). A size out of range, or a scene over 20 million primitives, is an error |
| `app.quit` | — | closes the window |
+3 -3
View File
@@ -1,6 +1,6 @@
# Element library
ModelCraft's finite element library (`crates/fem`), family by family, with status. The scope is
FieldCraft's finite element library (`crates/fem`), family by family, with status. The scope is
modelled on what a full CAE code offers (Abaqus's element library is the reference for breadth);
names, formulations and tests are our own, written from the published literature. Deck writers map
each of our elements to each solver's name (see `crates/decks`). Simple elements first: 1D and 2D,
@@ -32,7 +32,7 @@ hex8/20/27 with first and second derivatives).
|---|---|---|
| Truss, 2-node (2D and 3D) | Axial members, cables (compression allowed) | done (rod2: implicit, in plane models with their two unknowns per node; explicit, corotational under nonlinear geometry; Abaqus T3D2 / T2D2, Nastran CROD, LS-DYNA truss beam (3D models)) |
| Truss, 3-node (2D and 3D) | Curved axial members | done (rod3: implicit, plane models too; explicit with small displacements; Abaqus T3D3 / T2D3; no Nastran or LS-DYNA counterpart) |
| Beam, 2-node Timoshenko, 3D | Frames, stiffeners; shear deformable | done (exact interdependent interpolation, profile properties, orientation vector; `modelcraft_fem::beam`) |
| Beam, 2-node Timoshenko, 3D | Frames, stiffeners; shear deformable | done (exact interdependent interpolation, profile properties, orientation vector; `fieldcraft_fem::beam`) |
| Beam, 2-node Euler–Bernoulli (cubic), 2D and 3D | Slender frames; exact for end-loaded prismatic members | planned (1D elements II) |
| Beam, 3-node Timoshenko (quadratic), 2D and 3D | Curved and stocky beams | planned (1D elements II) |
| Beam, 2D (planar frames) | In-plane frames with 3 DOFs per node | planned (1D elements II) |
@@ -57,7 +57,7 @@ hex8/20/27 with first and second derivatives).
| Element | Use | Status |
|---|---|---|
| Shell quad4 (MITC4), triangle (locking-free) | Thin and thick shells | done (flat MITC4 and MITC3 with a Hughes–Brezzi drilling rotation; `modelcraft_fem::shell`) |
| Shell quad4 (MITC4), triangle (locking-free) | Thin and thick shells | done (flat MITC4 and MITC3 with a Hughes–Brezzi drilling rotation; `fieldcraft_fem::shell`) |
| Shell quad8 / tri6 | Curved thick shells | planned |
| Continuum shells (8-node, on swept hex) | Thick-to-thin shells, composites through thickness | planned (M8) |
| Membranes (tri3, quad4, quad8) | Fabrics, inflatables, skins without bending | planned |
+6 -6
View File
@@ -1,7 +1,7 @@
# Features
Generated from the capability catalogue (`crates/engine/src/catalogue.rs`) by
`cargo run -p modelcraft-cli -- features > docs/features.md`; a test fails when it is out of date.
`cargo run -p fieldcraft-cli -- features > docs/features.md`; a test fails when it is out of date.
Every entry is a toolbar button. **Ready** entries run their command; **coming soon** entries are
shown greyed with the roadmap milestone that brings them (ROADMAP.md). Scripts, the command line,
the control channel and AI agents over MCP (docs/mcp.md) run the same commands.
@@ -121,8 +121,8 @@ the control channel and AI agents over MCP (docs/mcp.md) run the same commands.
| Decks | Abaqus Input — Write an Abaqus input file (.inp) | ready | `deck.write {"format":"abaqus"}` |
| Decks | Nastran Deck — Write Nastran bulk data (SOL 101, 103) | ready | `deck.write {"format":"nastran"}` |
| Decks | LS-DYNA Deck — Write an LS-DYNA keyword file | ready | `deck.write {"format":"lsdyna"}` |
| Decks | Read Deck — Read a deck, keeping keywords ModelCraft does not know | coming soon (M9) | |
| Implicit | Static — Linear static (or coupled temperature–displacement) solve of a step with ModelCraft's own solver; heat transfer in the drop-down | ready | `solve.static`, `solve.heat` |
| Decks | Read Deck — Read a deck, keeping keywords FieldCraft does not know | coming soon (M9) | |
| Implicit | Static — Linear static (or coupled temperature–displacement) solve of a step with FieldCraft's own solver; heat transfer in the drop-down | ready | `solve.static`, `solve.heat` |
| Implicit | Frequency — Natural frequencies and mode shapes of a frequency step | ready | `solve.frequency` |
| Explicit | Explicit — Transient dynamics of an explicit step by central differences (contact and erosion coming in M10) | ready | `solve.explicit` |
| Explicit | Blast & Impact — EOS-driven fluids with fluid–structure contact (ALE or SPH) | coming soon (M14) | |
@@ -153,10 +153,10 @@ the control channel and AI agents over MCP (docs/mcp.md) run the same commands.
| Panel | Capability | Status | Command |
|---|---|---|---|
| Model | Model Info — Node and element counts and the model summary | ready | `model.info` |
| File | Open Model — Open a .modelcraft model | ready | `file.open` |
| File | Open Model — Open a .fieldcraft model | ready | `file.open` |
| File | Samples — Open a sample model, ready to solve | ready | `file.sample` |
| File | Save — Save the model to its .modelcraft file | ready | `file.save` |
| File | Save As — Save the model to a new .modelcraft file | ready | `file.save_as` |
| File | Save — Save the model to its .fieldcraft file | ready | `file.save` |
| File | Save As — Save the model to a new .fieldcraft file | ready | `file.save_as` |
| File | Recover — Open a model autosaved by an app that crashed or closed with unsaved changes | ready | `file.recover`, `file.recovery.list`, `file.recovery.discard` |
| History | Undo — Undo the last command that changed the model | ready | `edit.undo` |
| History | Redo — Redo the command undone last | ready | `edit.redo` |
+4 -4
View File
@@ -39,13 +39,13 @@ Lookups: `node(label)` / `slot(label)` (a slot is a position: mesh nodes `0..nod
`point_slot(k)`), `dof(slot, kind)`, `range(slot)`, `kinds(slot)`, `locate(dof) -> (slot,
kind)`, `element_dofs(slots, kinds)`, `describe(dof)`, `stride()` (uniform layouts).
Trusses declare `modelcraft_fem::truss::DOFS` (translations, on `Basis::Line2`/`Line3`).
Trusses declare `fieldcraft_fem::truss::DOFS` (translations, on `Basis::Line2`/`Line3`).
Point masses, springs and dashpots are not mesh elements: the implicit solver asks the layout
for what each needs at its nodes (`modelcraft_solver::discrete::needs`: translations for a mass
for what each needs at its nodes (`fieldcraft_solver::discrete::needs`: translations for a mass
or a translational spring, rotations for an inertia or a torsional spring; a reference point
they use is a point with six) and finds its unknowns with `discrete::dof_of`.
Solvers: `modelcraft_solver::system::Mesh::layout` numbers the implicit system (mesh nodes,
Solvers: `fieldcraft_solver::system::Mesh::layout` numbers the implicit system (mesh nodes,
then six per coupled reference point); assembly (`sparse::add_block(k, layout, slots, kinds,
data)`, `add_scalar`, `add_diagonal`) works for any mix of kinds per node, so a solid sharing
nodes with a shell adds its translation block into the shell nodes' six-unknown blocks.
@@ -108,7 +108,7 @@ A heat conduction element carries one temperature per node (`heat::HEAT_DOFS`, k
`heat::Conduction` gives the conductivity ∫ ∇Nᵀ k ∇N dV (full rule), the capacity ∫ ρc N Nᵀ dV
and a source ∫ N Q dV (mass rule), and the heat flux −k∇T at the integration points;
`heat::face_weights` and `face_film` integrate surface flux and convection on tri3/tri6/quad4/quad8
faces. The solver (`modelcraft_solver::heat`) numbers the temperatures with
faces. The solver (`fieldcraft_solver::heat`) numbers the temperatures with
`DofLayout::uniform(…, DofSet::TEMPERATURE)` and assembles with the same `sparse::add_block`.
Thermal strain ε_th = α (T − T_ref) along the material axes enters a solid as the load
@@ -1,26 +1,26 @@
# The `.modelcraft` file (format `modelcraft/1`)
# The `.fieldcraft` file (format `fieldcraft/1`)
A `.modelcraft` file holds one model: its definition, its mesh, the geometry it is built on and
the commands that built it. It is written and read by `modelcraft-io` (`write`, `read`; bytes in,
A `.fieldcraft` file holds one model: its definition, its mesh, the geometry it is built on and
the commands that built it. It is written and read by `fieldcraft-io` (`write`, `read`; bytes in,
bytes out, so the browser build uses the same code) and by the commands `file.save`,
`file.save_as` and `file.open`.
## Package
The file is a ZIP package with exactly four parts, in this order, all stored uncompressed (so any
unzip tool reads them: `unzip -p bracket.modelcraft model.json`):
unzip tool reads them: `unzip -p bracket.fieldcraft model.json`):
| Part | Content |
|---|---|
| `modelcraft.json` | Manifest: `format` (`"modelcraft/1"`), `generator` (`"ModelCraft 0.1.0"`), `geometry`, and `parts`: the byte size and SHA-256 of each other part. |
| `fieldcraft.json` | Manifest: `format` (`"fieldcraft/1"`), `generator` (`"FieldCraft 0.1.0"`), `geometry`, and `parts`: the byte size and SHA-256 of each other part. |
| `model.json` | The model definition: unit system, sets, materials, sections, reference points, couplings, boundary conditions, loads and steps. Pretty-printed JSON with a fixed key order (maps sorted by name), so a change shows as a line diff. Its form is the model's own JSON form, which commands take as parameters. |
| `mesh.bin` | Nodes, elements and geometry tags, binary (below). |
| `journal.json` | The commands that built the model, `[{"command": id, "params": {...}}, ...]`, one per line. It is a script `modelcraft-cli run` replays. |
| `journal.json` | The commands that built the model, `[{"command": id, "params": {...}}, ...]`, one per line. It is a script `fieldcraft-cli run` replays. |
The same model gives the same bytes on every platform: entry times are fixed (1980-01-01),
permissions are fixed, and every map is written in sorted order. To diff two versions with git,
add `*.modelcraft diff=modelcraft` to `.gitattributes` and
`git config diff.modelcraft.textconv "unzip -p"`; the definition and the journal show line by
add `*.fieldcraft diff=fieldcraft` to `.gitattributes` and
`git config diff.fieldcraft.textconv "unzip -p"`; the definition and the journal show line by
line, the mesh part as binary.
## Geometry
@@ -68,8 +68,8 @@ Every file is treated as hostile:
allocation is larger than the input.
- Only the four parts, each once. The ZIP CRC and the manifest's size and SHA-256 are checked for
every part.
- A `format` other than `modelcraft/1` is refused: a later `modelcraft/N` as a version error, any
other value as not a ModelCraft file. Unknown fields are errors.
- A `format` other than `fieldcraft/1` is refused: a later `fieldcraft/N` as a version error, any
other value as not a FieldCraft file. Unknown fields are errors.
- `mesh.bin`: counts are capped (50 million nodes and elements, one million entities) and checked
against the bytes present before anything is read; labels must ascend; unknown kinds and
trailing bytes are refused.
@@ -87,8 +87,8 @@ refused.
## Autosave and recovery
The desktop app autosaves every 30 seconds while there are unsaved changes, into the recovery
folder (`MODELCRAFT_RECOVERY_DIR`, else `ModelCraft/recovery` in the per-user data folder):
`<id>.modelcraft`, `<id>.json` (the model's own path, time, counts) and `<id>.lock`, held while
folder (`FIELDCRAFT_RECOVERY_DIR`, else `FieldCraft/recovery` in the per-user data folder):
`<id>.fieldcraft`, `<id>.json` (the model's own path, time, counts) and `<id>.lock`, held while
the app runs. Saving (or undoing back to the saved state) drops the autosave. After a crash, the
next launch reports the entries; `file.recovery.list` lists them, `file.recover` opens one as
unsaved work under its original path, and `file.recovery.discard` deletes them.
+5 -5
View File
@@ -1,8 +1,8 @@
# Face-tagged meshes (3MF with B-rep face tags)
Besides opening a `.solidcraft` design, geometry can enter ModelCraft as a triangulated boundary
Besides opening a `.solidcraft` design, geometry can enter FieldCraft as a triangulated boundary
surface written by another program, with each triangle tagged by the B-rep face it lies on.
ModelCraft reads it into a `SurfaceMesh` (`modelcraft_geometry::tagged_mesh`, command
FieldCraft reads it into a `SurfaceMesh` (`fieldcraft_geometry::tagged_mesh`, command
`geometry.import.mesh`) without involving the kernel.
## The format is SolidCraft's
@@ -20,10 +20,10 @@ in the SolidCraft repository. In short:
- Coordinates are written in shortest round-trip `f64` form, so they read back exactly.
- Within an object, either every triangle is tagged or none is.
ModelCraft follows that specification and does not extend it. Because the format is 3MF,
FieldCraft follows that specification and does not extend it. Because the format is 3MF,
untagged 3MF from any other program goes through the same reader, with one face per object.
## What ModelCraft's reader does
## What FieldCraft's reader does
- **Surfaces.** Every build item becomes one `TaggedSurface`: a `SurfaceMesh` with its name and
face count. Lengths are converted to millimetres from `unit`. The surface is named after its
@@ -42,7 +42,7 @@ untagged 3MF from any other program goes through the same reader, with one face
- Each part is at most 1 GB uncompressed, in at most 10 000 zip entries.
- At most 20 million vertices and 20 million triangles, counted over every placement.
- At most 10 000 build items, and XML nesting at most 256 deep.
- Coordinates must be finite and within ±10⁹ mm (`modelcraft_model::MAX_COORD`), both as read
- Coordinates must be finite and within ±10⁹ mm (`fieldcraft_model::MAX_COORD`), both as read
and once placed.
- Every vertex index must exist.
- **Errors.** Any violation is an error that names the problem. Nothing panics.
+17 -17
View File
@@ -1,22 +1,22 @@
# ModelCraft and AI agents (MCP)
# FieldCraft and AI agents (MCP)
ModelCraft speaks the [Model Context Protocol](https://modelcontextprotocol.io) over stdio
FieldCraft speaks the [Model Context Protocol](https://modelcontextprotocol.io) over stdio
(JSON-RPC 2.0, one message per line; protocol revisions 2025-06-18, 2025-03-26 and 2024-11-05).
An agent builds and solves models the way a person does: every tool runs engine commands, the
same ones the UI, scripts, the command line and the control channel run, and never opens a
dialog or a file picker. The server is `crates/mcp` (`modelcraft-mcp`); `modelcraft-cli mcp`
dialog or a file picker. The server is `crates/mcp` (`fieldcraft-mcp`); `fieldcraft-cli mcp`
runs it.
## Start it
```sh
# Headless (the default): an in-process session, no window; screenshots are CPU renders.
modelcraft-cli mcp
modelcraft-cli mcp --headless
fieldcraft-cli mcp
fieldcraft-cli mcp --headless
# Bridged to the running app, so you can watch the agent work:
modelcraft --control 7070 &
modelcraft-cli mcp --connect 127.0.0.1:7070
fieldcraft --control 7070 &
fieldcraft-cli mcp --connect 127.0.0.1:7070
```
With `--connect`, an app that cannot be reached when the server starts gives a headless session
@@ -27,21 +27,21 @@ both must run on the same computer.
### Claude Code
```sh
claude mcp add modelcraft -- /path/to/modelcraft-cli mcp
claude mcp add fieldcraft -- /path/to/fieldcraft-cli mcp
# bridged to a running app:
claude mcp add modelcraft -- /path/to/modelcraft-cli mcp --connect 127.0.0.1:7070
claude mcp add fieldcraft -- /path/to/fieldcraft-cli mcp --connect 127.0.0.1:7070
# kept to one project folder:
claude mcp add modelcraft -- /path/to/modelcraft-cli mcp --automation-read-root /work/bracket --automation-write-root /work/bracket/out
claude mcp add fieldcraft -- /path/to/fieldcraft-cli mcp --automation-read-root /work/bracket --automation-write-root /work/bracket/out
```
Build the binary first (`cargo build --release -p modelcraft-cli`; it is
`target/release/modelcraft-cli`). The same setup as a project `.mcp.json`, or in another client's
Build the binary first (`cargo build --release -p fieldcraft-cli`; it is
`target/release/fieldcraft-cli`). The same setup as a project `.mcp.json`, or in another client's
configuration (Claude Desktop's `claude_desktop_config.json`):
```json
{
"mcpServers": {
"modelcraft": { "command": "/path/to/modelcraft-cli", "args": ["mcp"] }
"fieldcraft": { "command": "/path/to/fieldcraft-cli", "args": ["mcp"] }
}
}
```
@@ -49,13 +49,13 @@ configuration (Claude Desktop's `claude_desktop_config.json`):
## Confining file access
```sh
modelcraft-cli mcp --automation-read-root /work/bracket --automation-write-root /work/bracket/out
fieldcraft-cli mcp --automation-read-root /work/bracket --automation-write-root /work/bracket/out
```
The two flags keep the agent to the folders you give it:
- Every file a command reads must lie inside the **read root**: `open`, `file.open`,
`geometry.open`, `geometry.import.mesh`, the design and meshes a `.modelcraft` file opens
`geometry.open`, `geometry.import.mesh`, the design and meshes a `.fieldcraft` file opens
again, `file.recovery.list` and `file.recover` with a `dir`.
- Every file a command writes must lie inside the **write root**: `save`, `file.save` and
`file.save_as` (also a save to the model's own file), `write_deck` and `deck.write`,
@@ -96,7 +96,7 @@ software on the computer.
| `batch` | `commands: [{command, params}]` | Run steps in order, stop at the first error; the reply has every result and the failing step (`failed.index`, `failed.command`, `failed.error`). Steps before it stay applied (`undo` takes them back). |
| `inspect_model` | — | `model.info` (counts, units, definitions), `model.activity` (the step table) and `geometry.bodies` (bodies with measures and persistent face names, which sets name as `{body, face}`). |
| `check_model` | — | `model.check`: errors and warnings, each naming its item. |
| `open` | `path` | By extension: `.modelcraft` (`file.open`), `.solidcraft` (`geometry.open`), `.3mf` (`geometry.import.mesh`). |
| `open` | `path` | By extension: `.fieldcraft` (`file.open`), `.solidcraft` (`geometry.open`), `.3mf` (`geometry.import.mesh`). |
| `save` | `path?` | `file.save`: to `path` or the model's own file. |
| `write_deck` | `format` (abaqus, nastran, lsdyna), `path`, `steps?` | `deck.write`. |
| `mesh` | `method`, `params?` | Runs the mesher (`tet`: `mesh.tet.generate`; `planar`: `mesh.planar`; the hex and block meshers as they land) and replies with its result, `model.info` and `mesh.quality`. |
@@ -107,7 +107,7 @@ software on the computer.
| `screenshot` | `view?`, `source?` (window, model), `width?`, `height?`, `path?` | A PNG image content block and what it shows. Headless: a CPU render framing the model, the geometry and the results display (deformed shape, contour bands). Bridged: the whole app window drawn offscreen (`ui.capture`, the default) or a model render with the app's camera (`ui.render`); `view` turns the app's camera first. |
| `undo`, `redo` | — | `edit.undo`, `edit.redo`. |
Resources: `modelcraft://model` (`model.info`) and `modelcraft://commands` (the command catalog).
Resources: `fieldcraft://model` (`model.info`) and `fieldcraft://commands` (the command catalog).
Errors: an unknown tool, or arguments that do not match the tool's schema (a missing or unknown
argument, a wrong type, a value outside an enum), are JSON-RPC `-32602` errors; an engine failure
+9 -9
View File
@@ -1,4 +1,4 @@
# Volume meshing literature survey for ModelCraft (tet → hex)
# Volume meshing literature survey for FieldCraft (tet → hex)
Compiled 2026-10-13. Scope: watertight triangulated B-rep tessellation in, then (1) tetrahedral mesh by
Delaunay methods with Voronoi/ODT improvement, then (2) all-hex and hex-dominant meshes.
@@ -110,7 +110,7 @@ Delaunay methods with Voronoi/ODT improvement, then (2) all-hex and hex-dominant
---
**A0.5 Boundary surface preparation (implemented in `modelcraft-mesh::surface`).** **Verdict: BUILD ON.**
**A0.5 Boundary surface preparation (implemented in `fieldcraft-mesh::surface`).** **Verdict: BUILD ON.**
- **Guigue and Devillers 2003.** P. Guigue, O. Devillers. *Fast and Robust Triangle–Triangle Overlap Test Using
Orientation Predicates.* Journal of Graphics Tools 8(1):25–32, 2003. Triangle overlap decided from `orient3d` /
`orient2d` signs alone, so it is exact on the A0.1 predicates. We use the equivalent edge–triangle reduction (two
@@ -151,7 +151,7 @@ Delaunay methods with Voronoi/ODT improvement, then (2) all-hex and hex-dominant
- Hilbert index: J. Skilling, *Programming the Hilbert curve*, AIP Conf. Proc. 707:381–387, 2004, DOI
[10.1063/1.1751381](https://doi.org/10.1063/1.1751381).
- **Code.** For a permissive reference, see geogram `delaunay_3d.cpp` (BSD).
- **Implemented** in `modelcraft-mesh::delaunay` (ghost vertex for the hull, Devillers–Teillaud perturbation for
- **Implemented** in `fieldcraft-mesh::delaunay` (ghost vertex for the hull, Devillers–Teillaud perturbation for
cospherical points, exact verifier).
**A1.2 Marot, Pellerin, Remacle 2019, "One machine, one minute, three billion tetrahedra".** **Verdict: reference (later).**
@@ -238,7 +238,7 @@ Delaunay methods with Voronoi/ODT improvement, then (2) all-hex and hex-dominant
- **Complexity.** High: about 8–12k lines of Rust including the predicate generator. It is the single most valuable
investment in the tet pipeline.
- **Code.** `MarcoAttene/CDT` is **GPL, or LGPL by build option** (README): FORBIDDEN.
- **Implemented** in `modelcraft-mesh::cdt` from the paper only, with these choices:
- **Implemented** in `fieldcraft-mesh::cdt` from the paper only, with these choices:
- Steiner points are LNC points (§4.3) on the original segment, `a + t (b − a)` with `t` a double; the in-sphere test
on them is exact (interval filter, then exact dyadic integers) and perturbed with the same lexicographic lift as
the Delaunay step, so Bowyer–Watson insertion of Steiner points stays consistent with it.
@@ -785,7 +785,7 @@ Delaunay methods with Voronoi/ODT improvement, then (2) all-hex and hex-dominant
- **HexaLab** (MIT, https://github.com/mlivesu/HexaLab, https://www.hexalab.net) is READ OK. It is a hex quality
viewer whose metrics match the literature's.
**B6.6 Element validity and quality metrics (implemented in `modelcraft-mesh::quality`).** **Verdict: BUILD ON.**
**B6.6 Element validity and quality metrics (implemented in `fieldcraft-mesh::quality`).** **Verdict: BUILD ON.**
- **Johnen, Remacle, Geuzaine 2013.** *Geometrical validity of curvilinear finite elements.* J. Comput. Phys.
233:359–372, 2013. The Jacobian
determinant in Bernstein form is bounded by its coefficients, equals them at the vertices and converges under
@@ -803,7 +803,7 @@ Delaunay methods with Voronoi/ODT improvement, then (2) all-hex and hex-dominant
> Shell (curved-face) quad meshing — advancing front in (u,v) with a cross field, recombination and cleanup — is surveyed separately in [shell-quad-literature.md](shell-quad-literature.md).
(implemented in `modelcraft-mesh::quad`)
(implemented in `fieldcraft-mesh::quad`)
The face meshers under mapped and swept hex meshing and shell meshing. All quads on prescribed
boundary nodes, so faces sharing an edge share its nodes. DOIs below were checked through
@@ -878,7 +878,7 @@ input points), Steiner points kept half the local spacing from the boundary.
---
### B8. Mapped and swept hexahedral meshing (implemented in `modelcraft-mesh::hex`)
### B8. Mapped and swept hexahedral meshing (implemented in `fieldcraft-mesh::hex`)
`mesh.hex.generate` (and `mesh.hex.sweep`, `mesh.hex.mapped`). Every method below is implemented from
its paper; no code was read. DOIs marked "checked" were confirmed on 2026-10-13 through a repository
@@ -939,14 +939,14 @@ Collision Detection*, 2005, §5.1.5).
## Part C: Datasets and benchmarks
| Dataset | Content | Licence | Usable for ModelCraft? |
| Dataset | Content | Licence | Usable for FieldCraft? |
|---|---|---|---|
| **Thingi10K**: Zhou & Jacobson 2016, arXiv https://arxiv.org/abs/1605.04797; site https://ten-thousand-models.appspot.com; tooling https://github.com/Thingi10K/Thingi10K | 10,000 STL meshes. 45% self-intersecting, 50% non-solid. The 4,408 "valid" subset is the standard tet-meshing robustness benchmark (fTetWild, Diazzi 2023). | Tooling Apache-2.0. **Each model has its own licence** (10 licences, including CC-BY-NC and GPL). Filter by the `license` field. | **Conditionally.** Use CC-BY / CC0 / public-domain models for robustness testing. **Provenance risk:** Thingiverse records no authoring tool, and many uploads were modelled in commercial CAD. Under the "no test data produced with commercial CAD products" rule this is an **owner decision**. |
| **HexMe**: DOI 10.5281/zenodo.6642020, https://hexme.algohex.eu | 189 tet meshes from 63 CAD models, with feature tags. | Dataset **CC-BY-4.0**. The source models come from the **ABC dataset (Onshape terms), GrabCAD (GrabCAD terms)**, MAMBO (Apache-2.0), and models made with **Gmsh and Siemens NX** (the paper's own statement). | **Only a filtered subset.** The ABC/Onshape, GrabCAD and Siemens NX models are produced with commercial CAD: exclude them. Gmsh-authored ones are acceptable as data. |
| **MAMBO**: https://gitlab.com/franck.ledoux/mambo | STEP models: basic, simple, medium. Designed for hex block-meshing evaluation. | **Apache-2.0** | **Risky.** The STEP headers I sampled say `'Spatial InterOp 3D'` as originating system and authors `'Cubit 15.2'` / `'MGX'`. These are commercial or closed tools. Treat as commercial-CAD-produced unless the owner rules otherwise. |
| **ABC**: Koch et al., CVPR 2019, DOI [10.1109/CVPR.2019.00983](https://doi.org/10.1109/CVPR.2019.00983), arXiv https://arxiv.org/abs/1812.06216, https://deep-geometry.github.io/abc-dataset/ | 1M CAD models (B-rep and meshes). | "Copyright of the CAD models is owned by their creators", under **Onshape Terms of Use**. The models come from Onshape. | **No.** Produced with a commercial CAD product, and the licence is not open. Skip. |
**Recommendation for test data.** Build ModelCraft's own corpus:
**Recommendation for test data.** Build FieldCraft's own corpus:
- **Generated cases.** Parametric primitives plus booleans from our own kernel:
- cubes and cylinders with holes;
- fillets;
+12 -12
View File
@@ -1,11 +1,11 @@
# Shell meshing literature survey for ModelCraft: quad and quad-dominant meshes of curved B-rep faces
# Shell meshing literature survey for FieldCraft: quad and quad-dominant meshes of curved B-rep faces
Compiled 2026-10-13. Scope: all-quad and quad-dominant surface meshes of the curved faces (planes, cylinders,
cones, spheres, tori, NURBS) of SolidCraft parts, meshed in each face's (u,v) parameter space with metric
correction and conforming across shared B-rep edges, for shell analysis (MITC4-class shells now,
continuum shells on swept hexes in M8). This extends `docs/meshing/literature.md` §B7, which compared
paving, Q-Morph and Blossom-Quad for **planar** faces only and chose CDT → greedy recombination →
Catmull–Clark split (`modelcraft-mesh::quad`).
Catmull–Clark split (`fieldcraft-mesh::quad`).
Same format as `docs/meshing/literature.md`: per paper, citation, DOI/URL, method, problem solved,
robustness/limits, complexity, code + licence, verdict. Part P is the opinionated plan.
@@ -126,7 +126,7 @@ robustness/limits, complexity, code + licence, verdict. Part P is the opinionate
**S2.2 Owen and Saigal 2000, Surface mesh sizing control.** **Verdict: build on (size field on faces).**
- **Citation.** IJNME 47(1–3):497–511, 2000. DOI [10.1002/(SICI)1097-0207(20000110/30)47:1/3<497::AID-NME781>3.0.CO;2-H](https://doi.org/10.1002/(SICI)1097-0207(20000110/30)47:1/3%3C497::AID-NME781%3E3.0.CO;2-H). *Read:* metadata.
- **Method.** Automatic sizing on CAD surfaces from curvature and proximity, stored on a background mesh.
- **Use.** The curvature and proximity terms of ModelCraft's surface size field (P3.3).
- **Use.** The curvature and proximity terms of FieldCraft's surface size field (P3.3).
**S2.3 Lo 1989; Lau, Lo, Lee 1997; Lo and Lau 1998: quadrilaterals over curved surfaces.** **Verdict: reference.**
- **Citations.**
@@ -193,7 +193,7 @@ robustness/limits, complexity, code + licence, verdict. Part P is the opinionate
**S3.2 Borouchaki, George, Hecht, Laug, Saltel 1997, Delaunay mesh generation governed by metric specifications.** **Verdict: build on (only if non-conformal parametrizations need an anisotropic Delaunay kernel).**
- **Citation.** Part I: FEAD 25(1–2):61–83, 1997, DOI [10.1016/S0168-874X(96)00057-1](https://doi.org/10.1016/S0168-874X(96)00057-1); Part II: FEAD 25:85–109, DOI [10.1016/S0168-874X(96)00065-0](https://doi.org/10.1016/S0168-874X(96)00065-0). *Read:* metadata.
- **Method.** The Delaunay criterion evaluated in a local metric (anisotropic Bowyer–Watson cavity).
- **Caveat for ModelCraft.** A metric in-circle test is not an exact predicate of the input coordinates; it
- **Caveat for FieldCraft.** A metric in-circle test is not an exact predicate of the input coordinates; it
may only decide *point placement* and *which flip to try*, never validity. Validity stays an exact `orient2d`
sign in (u,v) (see P3.5).
@@ -315,7 +315,7 @@ robustness/limits, complexity, code + licence, verdict. Part P is the opinionate
- **Complexity.** Same as frontal-Delaunay triangulation, O(n log n); "tens of thousands of elements a minute"
(§1) in 2010-era hardware.
- **Why it matters here.** It is a marching front, but one whose collisions cannot fail, and it is a small
change to machinery ModelCraft already has (Bowyer–Watson, constrained recovery, recombination).
change to machinery FieldCraft already has (Bowyer–Watson, constrained recovery, recombination).
**S5.2 Georgiadis, Beaufort, Lambrechts, Remacle 2017, High quality mesh generation using cross and asterisk fields.** **Verdict: reference.**
- **Citation.** arXiv <https://arxiv.org/abs/1706.02236>, 2017. *Read:* abstract.
@@ -346,7 +346,7 @@ robustness/limits, complexity, code + licence, verdict. Part P is the opinionate
slow on faces over 100k vertices; acute corners (< 45°) need artificial singularities; size-map vs
cross-field compatibility "still open".
- **Why it matters here.** Strongest published evidence on CAD B-reps for any automatic all-quad method, and
it uses **the same tri → recombine → split guarantee ModelCraft already ships**, with better point placement
it uses **the same tri → recombine → split guarantee FieldCraft already ships**, with better point placement
in front of it and cleanup behind it. It is the template for P.
- **Data caveat.** Both datasets are excluded for our own tests (see `literature.md` Part C); we cite the numbers only.
@@ -372,7 +372,7 @@ robustness/limits, complexity, code + licence, verdict. Part P is the opinionate
- **Citation.** IJNME 89(9):1102–1119, 2012. DOI [10.1002/nme.3279](https://doi.org/10.1002/nme.3279). *Read:* metadata.
- **Note.** Reberol 2021 replaced Blossom with a greedy, alignment-weighted matching followed by the split, which
removes the "perfect matching may not exist" failure and the cubic-time matching. That supports keeping
ModelCraft's greedy matching.
FieldCraft's greedy matching.
**S6.3 Ramaswami, Ramos, Toussaint 1998, Converting triangulations to quadrangulations.** **Verdict: reference (theory).**
- **Citation.** CGTA 9(4):257–276, 1998. DOI [10.1016/S0925-7721(97)00019-9](https://doi.org/10.1016/S0925-7721(97)00019-9).
@@ -619,14 +619,14 @@ cylinder displacement under the load 1.8248×10⁻⁵ (E = 3×10⁶, P = 1); pin
---
## Part P: Recommended plan for ModelCraft shell meshing (opinionated)
## Part P: Recommended plan for FieldCraft shell meshing (opinionated)
### P1. Position
**I agree with a cross-field-guided advancing front in (u,v) with a metric and topological cleanup, with one
change: the front advances *points over a Delaunay triangulation* (frontal-Delaunay in the cross-field L∞
norm, Remacle 2013), not quads (paving) and not triangle-to-quad transformations (Q-Morph).** All-quad comes
from the recombination + split ModelCraft already ships, and cleanup follows Reberol 2021.
from the recombination + split FieldCraft already ships, and cleanup follows Reberol 2021.
Reasons:
1. **Closure cannot fail.** A frontal-Delaunay front always sits inside a valid constrained triangulation, so
@@ -668,13 +668,13 @@ For each B-rep face set to be shell-meshed (a sheet body, or chosen faces of a s
### P3. Components
**P3.1 Chart abstraction** (`modelcraft-mesh::surface_mesh::chart` or a new `shell` module; trait in `mesh`,
**P3.1 Chart abstraction** (`fieldcraft-mesh::surface_mesh::chart` or a new `shell` module; trait in `mesh`,
implementation in `geometry`, wired in `engine`, so `mesh` does not depend on `geometry`):
`eval(u,v) → [f64;3]`, `derivs(u,v) → (S_u, S_v)` (second derivatives for curvature sizing), `project(p,
hint) → (u,v)`, the face's loops as 3D node chains with their (u,v), periodicity and singular points. Native
charts come from SolidCraft's kernel surfaces (truck's parametric surfaces already have parameter search, used
in 5 SolidCraft kernel files); this needs a new **public** face-surface API in `solidcraft-kernel`, exposed
through `modelcraft-geometry` without leaking SolidCraft types. Handling:
through `fieldcraft-geometry` without leaking SolidCraft types. Handling:
- **Periodic faces** (cylinder, torus, revolved): the seam edge appears twice in the loop; give its nodes
u = 0 on one side and u = period on the other (unwrap by continuity along the loop). The domain becomes simply
connected; seam nodes are the same 3D nodes, so conformity across the seam holds.
@@ -772,7 +772,7 @@ ship.
### P6. Order of work
1. **Chart API** in `solidcraft-kernel` (public face-surface evaluation and parameter search) and
`modelcraft-geometry` (trait implementation, seams, poles). Done when the P5.1 tests pass.
`fieldcraft-geometry` (trait implementation, seams, poles). Done when the P5.1 tests pass.
2. **Port the shipped free mesher to (u,v) + metric**: half-resolution CDT and Ruppert refinement in the
rescaled (u,v) with metric sizing, recombination, split, smoothing with 3D objective. This gives all-quad
conforming meshes on curved faces early, and is the baseline.
+3 -3
View File
@@ -1,12 +1,12 @@
# Verification and validation oracle
Generated by `cargo xtask oracle` from [`tests/oracle/`](../tests/oracle/); the policy is [verification.md](verification.md). Every case is our own model, built with ModelCraft commands from the problem's published description, and compared with the reference value its `expected.json` cites, within the stated tolerance and for the stated reason. Accepted results are frozen in each case's `fixture.json`: a later change that moves one beyond its band (10⁻⁹ of its size) fails CI even while the reference still passes. No reference value was produced with a commercial product.
Generated by `cargo xtask oracle` from [`tests/oracle/`](../tests/oracle/); the policy is [verification.md](verification.md). Every case is our own model, built with FieldCraft commands from the problem's published description, and compared with the reference value its `expected.json` cites, within the stated tolerance and for the stated reason. Accepted results are frozen in each case's `fixture.json`: a later change that moves one beyond its band (10⁻⁹ of its size) fails CI even while the reference still passes. No reference value was produced with a commercial product.
**117 of 123 quantities pass** (6 known failure(s)) in 35 active cases: 26 theory, 9 published benchmark, 0 experiment; 9 pending cases wait for capabilities still being built.
## Theory: closed-form solutions, patch tests and mesh invariants
| Case | Quantity | Reference | ModelCraft | Error | Tolerance | Result | Fixture |
| Case | Quantity | Reference | FieldCraft | Error | Tolerance | Result | Fixture |
|---|---|---|---|---|---|---|---|
| [bar-pressure-wave](../tests/oracle/bar-pressure-wave/) | displacement of the loaded end at t = 0.06 | -6.0000e-4 | -5.9980e-4 | 0.034% | 1% | pass | matches |
| [bar-pressure-wave](../tests/oracle/bar-pressure-wave/) | particle velocity at x = 5, 20 elements behind the front, at t = 0.06 | -0.01 | -0.0098552 | 1.45% | 2% | pass | matches |
@@ -108,7 +108,7 @@ Generated by `cargo xtask oracle` from [`tests/oracle/`](../tests/oracle/); the
## Published benchmarks
| Case | Quantity | Reference | ModelCraft | Error | Tolerance | Result | Fixture |
| Case | Quantity | Reference | FieldCraft | Error | Tolerance | Result | Fixture |
|---|---|---|---|---|---|---|---|
| [mh-curved-cantilever](../tests/oracle/mh-curved-cantilever/) | tip displacement along the in-plane load | 0.08734 | 0.076833 | -12% | 2% | known failure: 0.880 of the theory, grade C: straight-sided hex8 on six elements over 90° (MacNeal–Harder's HEXA(8): 0.880, Table 9 p. 15) | — |
| [mh-curved-cantilever](../tests/oracle/mh-curved-cantilever/) | tip displacement along the out-of-plane load | 0.5022 | 0.40095 | -20.2% | 2% | known failure: 0.798 of the theory, grade D: out-of-plane bending with torsion on one element across (MacNeal–Harder's HEXA(8): 0.849) | — |
+7 -7
View File
@@ -1,6 +1,6 @@
# Capability checklist (reference: Abaqus/CAE)
What an analyst does in a full CAE pre-processor, grouped by milestone, with ModelCraft's status.
What an analyst does in a full CAE pre-processor, grouped by milestone, with FieldCraft's status.
Scope comes from the public documentation of Abaqus/CAE and public analyst discussion,
described in our own words; nothing was taken from the product itself (AGENTS.md: no commercial
products are run, no documentation text is copied). Status: **done**, **started**, **planned**.
@@ -8,7 +8,7 @@ products are run, no documentation text is copied). Status: **done**, **started*
## Where we aim to be better
| # | Opportunity | Why analysts want it | ModelCraft approach |
| # | Opportunity | Why analysts want it | FieldCraft approach |
|---|---|---|---|
| 1 | Hex meshes without manual partitioning | Partitioning a part into sweepable cells by hand is the most cited chore | Sweep and mapped meshing with automatic decomposition that proposes SolidCraft splits (M5); octree all-hex for anything else (M6) |
| 2 | Undo, redo, replay, crash recovery | No general undo; replay files are hard to reuse; corrupted model files | Every action is a journalled command with rollback, undo and redo; autosave with recovery after a crash |
@@ -16,7 +16,7 @@ products are run, no documentation text is copied). Status: **done**, **started*
| 4 | An API that is not a bundled scripting runtime | Version breakage, slow scripts, geometry picked by position | JSON commands over CLI, control channel and MCP |
| 5 | Located diagnostics | Generic error messages | Errors name the element, face or keyword; `mesh.quality` lists failing elements |
| 6 | Lossless deck round trip | Unsupported keywords dropped on import | Deck readers keep unknown keywords and write them back (M9) |
| 7 | Safe, diffable model files | Binary model databases that corrupt or lock to a version | `.modelcraft`: text, line-diffable definition and journal, checksummed binary mesh, versioned format tag, atomic saves with backup, autosave (M3, done) |
| 7 | Safe, diffable model files | Binary model databases that corrupt or lock to a version | `.fieldcraft`: text, line-diffable definition and journal, checksummed binary mesh, versioned format tag, atomic saves with backup, autosave (M3, done) |
| 8 | Geometry checked before meshing | Slivers and tiny faces fail late | Surface preparation reports defects with their location (M1) |
| 9 | No size caps, any solver | Node limits in learning editions; one solver per tool | Free, open source, three deck formats |
| 10 | Clear step history | Loads and BCs propagate between steps implicitly | An explicit step × load/BC table (M3) |
@@ -33,7 +33,7 @@ products are run, no documentation text is copied). Status: **done**, **started*
| Mesh | Size field: global, per face and edge seeds, bias, curvature and proximity refinement | M2 | yes | planned |
| Mesh | Free tet meshing (tet4, tet10 with mid-side nodes on the geometry) | M2 | | started |
| Mesh | Quality metrics, certified validity, verify per set | M1–M2 | yes | done (metrics, gate) |
| Mesh | 2D quad meshing of faces | M5 | yes | started (`modelcraft_mesh::quad`; `mesh.planar`: 2D models of a polygon or a planar face, quad4/quad8/tri3/tri6, edges tagged by their neighbouring face) |
| Mesh | 2D quad meshing of faces | M5 | yes | started (`fieldcraft_mesh::quad`; `mesh.planar`: 2D models of a polygon or a planar face, quad4/quad8/tri3/tri6, edges tagged by their neighbouring face) |
| Mesh | Mapped hex of six-sided regions | M5 | yes | done (`mesh.hex.mapped`) |
| Mesh | Sweep hex (extrusions, revolutions) | M5 | yes | done (`mesh.hex.sweep`: multi-level extrusions, revolutions, one-to-one sweeps) |
| Mesh | Automatic decomposition into sweepable and mappable regions | M5 | yes | planned |
@@ -69,7 +69,7 @@ products are run, no documentation text is copied). Status: **done**, **started*
| Results | Readers for public result formats (Nastran OP2, LS-DYNA d3plot, Abaqus `.fil`) | M9 | | planned |
| Results | Mesh convergence studies | M9 | | planned |
| App | Desktop viewport, model tree, commands, control channel | continuous | | done |
| App | Undo/redo on the command journal, autosave, `.modelcraft` file | M3 | | done |
| App | Undo/redo on the command journal, autosave, `.fieldcraft` file | M3 | | done |
| App | MCP server, browser build | continuous | | planned |
## Deck notes for the writers
@@ -84,14 +84,14 @@ products are run, no documentation text is copied). Status: **done**, **started*
`crates/decks/src/abaqus.rs`). The step table is bridged to Abaqus's propagation: zero-valued
boundary conditions active in every step go to the initial state, and steps restate their
boundary conditions and loads with `OP=NEW` when the active set changes.
- Nastran (`modelcraft_decks::nastran`): entries with a real use large (16-column) fields, the rest
- Nastran (`fieldcraft_decks::nastran`): entries with a real use large (16-column) fields, the rest
small fields; a real is exact when its shortest round-trip form fits 16 columns, else rounded to
at least ten significant digits. Linear solids map full integration to `PSOLID` `TWO`/`THREE` +
`FULL`, hex20 reduced to `TWO` + `FULL`, hex8 incompatible modes to `BUBBLE`; one-point reduced
linear solids, hybrid solids, reduced-integration or one-point shells, body forces, gravity on part
of the model, orthotropic beams and rods, and orthotropic shells off planes of constant Z are
reported as unsupported. Static and frequency steps need separate decks (`deck.write` `steps`).
- LS-DYNA (`modelcraft_decks::lsdyna`, `deck.write {"format": "lsdyna"}`): long format (20-column
- LS-DYNA (`fieldcraft_decks::lsdyna`, `deck.write {"format": "lsdyna"}`): long format (20-column
fields; every value with up to 13 significant digits, and 17-digit values from 0.01 to 1e17, are
written exactly; the rest is rounded to at least 13 digits and counted). The 10-node tetrahedron
follows the manual's figure: mid-side nodes 8, 9, 10 on edges 2-4, 3-4, 1-4 (the model has them
+21 -21
View File
@@ -1,4 +1,4 @@
# Solver literature survey for ModelCraft: explicit dynamics, equations of state, lattice Boltzmann, FSI
# Solver literature survey for FieldCraft: explicit dynamics, equations of state, lattice Boltzmann, FSI
Compiled 2026-10-13. Scope: three new solver families on top of the planned implicit linear solver (M6):
(A) an explicit Lagrangian finite element solver of the LS-DYNA / Abaqus-Explicit class, (B) equations of state for
@@ -560,7 +560,7 @@ JCP 232(1):100–117, 2013, DOI [10.1016/j.jcp.2012.07.023](https://doi.org/10.1
- **Method.** For each wall link, the fraction q ∈ (0, 1] of the link inside the fluid; linear or quadratic
interpolation of the reflected population, second-order for curved walls.
- **Needs from meshing.** q comes from ray–triangle intersection of the lattice link with the face-tagged boundary
surface — robust predicates (modelcraft-mesh) give the inside/outside decision; q itself is a constructed value.
surface — robust predicates (fieldcraft-mesh) give the inside/outside decision; q itself is a constructed value.
- **Limits.** Not mass conservative; small q (< ~0.01) can destabilise: treat as q = 0 or use the Mei variant.
- **Also.** R. Mei, L.-S. Luo, W. Shyy, JCP 155(2):307–330, 1999, DOI [10.1006/jcph.1999.6334](https://doi.org/10.1006/jcph.1999.6334) — the alternative curved-boundary scheme. **Reference.**
@@ -794,7 +794,7 @@ IB is simpler with a deforming FE surface; bounce-back is better for rigid or sl
- S. W. Attaway, M. W. Heinstein, J. W. Swegle. *Coupling of smooth particle hydrodynamics with the finite element method.* Nucl. Eng. Des. 150:199–205, 1994. DOI [10.1016/0029-5493(94)90136-8](https://doi.org/10.1016/0029-5493(94)90136-8).
- C. Antoci, M. Gallati, S. Sibilla. *Numerical simulation of fluid–structure interaction by SPH.* Comput. Struct. 85(11–14):879–890, 2007. DOI [10.1016/j.compstruc.2007.01.002](https://doi.org/10.1016/j.compstruc.2007.01.002).
- **Assessment.** SPH shares the explicit solver's whole stack (time step, EOS, Johnson–Cook, artificial viscosity,
contact via the same penalty), so it slots *into* `modelcraft-explicit` as another discretisation — the natural
contact via the same penalty), so it slots *into* `fieldcraft-explicit` as another discretisation — the natural
home for hypervelocity impact, fragmentation and blast with JWL, which LBM cannot do. As a general fluid solver it is
noisy (pressure), needs many particles for accuracy and has the tensile instability; LBM beats it for viscous
low-Mach flow. Code: SPHinXsys (Apache-2.0), SPlisHSPlasH (MIT), PySPH (BSD-3-style), Cabana (BSD-3): READ OK;
@@ -812,7 +812,7 @@ IB is simpler with a deforming FE surface; bounce-back is better for rigid or sl
codes) but coordinates/displacements over long runs need f64 accumulation; that rules out a naive GPU port.
- **Layering.** `xtask/src/layers.rs` lists `wgpu` in `UI_CRATES`: nothing below L5 may depend on it. A GPU backend
therefore needs either an owner decision to allow `wgpu` in a dedicated compute crate below L5 (headless compute is
not UI), or a `modelcraft-gpu` crate at L5 that implements a backend trait the L1 solver crates define. I recommend
not UI), or a `fieldcraft-gpu` crate at L5 that implements a backend trait the L1 solver crates define. I recommend
the second (no rule change): the solver crate defines a `LatticeBackend` trait and a CPU implementation; the GPU
implementation lives at L5. **Owner decision either way.**
- **Determinism.** The project requires bit-identical output on every platform. GPU f32 results differ from CPU and
@@ -859,25 +859,25 @@ Implicit and explicit share element kinematics (shape functions, quadrature, B-m
| Layer | Crate | Contents |
|---|---|---|
| L0 | `modelcraft-model` | + materials, EOS, sections/formulations, explicit and fluid steps, contact, fluid domains, coupling interfaces (F3) |
| L1 | `modelcraft-fem` (new) | element kernels (shape functions, quadrature, B/B-bar, one-point hex with FB hourglass and Belytschko–Bindeman stabilisation, Bonet–Burton tet, BLT shell), constitutive updates (hypoelastic, objective rates, J2 radial return, Johnson–Cook, damage), EOS evaluation. Pure functions over `model` types; no solver loop. |
| L2 | `modelcraft-lbm` (new) | lattices, collision operators, BCs, voxelisation from the face-tagged surface and the octree from `mesh`\*, stepping on CPU, momentum-exchange forces, IB kernels; a backend trait for GPU |
| L2 | `modelcraft-solver` (moved up from L1) | implicit linear static/modal (M6), later nonlinear implicit; uses `fem` |
| L2 | `modelcraft-explicit` (new) | central-difference driver, time step, mass scaling, q, contact (search + penalty), erosion, energy accounting, output; uses `fem` (and later SPH) |
| L3 | `modelcraft-fsi` (new) | IB coupling, interface mapping, Aitken/IQN-ILS, subcycling, coupled step driver; uses `explicit`, `solver`, `lbm` |
| L0 | `fieldcraft-model` | + materials, EOS, sections/formulations, explicit and fluid steps, contact, fluid domains, coupling interfaces (F3) |
| L1 | `fieldcraft-fem` (new) | element kernels (shape functions, quadrature, B/B-bar, one-point hex with FB hourglass and Belytschko–Bindeman stabilisation, Bonet–Burton tet, BLT shell), constitutive updates (hypoelastic, objective rates, J2 radial return, Johnson–Cook, damage), EOS evaluation. Pure functions over `model` types; no solver loop. |
| L2 | `fieldcraft-lbm` (new) | lattices, collision operators, BCs, voxelisation from the face-tagged surface and the octree from `mesh`\*, stepping on CPU, momentum-exchange forces, IB kernels; a backend trait for GPU |
| L2 | `fieldcraft-solver` (moved up from L1) | implicit linear static/modal (M6), later nonlinear implicit; uses `fem` |
| L2 | `fieldcraft-explicit` (new) | central-difference driver, time step, mass scaling, q, contact (search + penalty), erosion, energy accounting, output; uses `fem` (and later SPH) |
| L3 | `fieldcraft-fsi` (new) | IB coupling, interface mapping, Aitken/IQN-ILS, subcycling, coupled step driver; uses `explicit`, `solver`, `lbm` |
| L4… | `doc`, `io`, `engine`, then L5+ shifts up by two | results (time histories, field frames) in `doc`/`io` |
| L5+ | `modelcraft-gpu` (new, with the UI layer or an owner-approved compute layer) | wgpu implementations of the solver backend traits |
| L5+ | `fieldcraft-gpu` (new, with the UI layer or an owner-approved compute layer) | wgpu implementations of the solver backend traits |
\* `modelcraft-lbm` needs the octree and predicates from `modelcraft-mesh` (L1), so it sits at L2. **`lbm` at L2** next to `solver` and `explicit` (it may then use `mesh`'s octree and
\* `fieldcraft-lbm` needs the octree and predicates from `fieldcraft-mesh` (L1), so it sits at L2. **`lbm` at L2** next to `solver` and `explicit` (it may then use `mesh`'s octree and
predicates), and `fem` at L1. That is one coherent rule: L1 = geometry and math kernels, L2 = solvers, L3 = coupling.
Cost of this being wrong: renumbering the layer table is a mechanical edit to `xtask/src/layers.rs` and
`docs/architecture.md`; the risk is churn, not breakage. The alternative (one `modelcraft-solver` crate with
`docs/architecture.md`; the risk is churn, not breakage. The alternative (one `fieldcraft-solver` crate with
`implicit`/`explicit`/`lbm`/`fsi` modules) needs no layer change, but a 50k-line crate compiles slowly and lets the
LBM depend on FE internals by accident. If the owner prefers no renumbering, take the single-crate option and enforce
module boundaries with `pub(crate)` discipline. This layout change is an owner decision.
### F3. Solver-neutral model extensions in `modelcraft-model`
### F3. Solver-neutral model extensions in `fieldcraft-model`
- **Materials** (named, unit-consistent, no product numbering): density; isotropic elastic; J2 plasticity with
isotropic/kinematic hardening (bilinear, power law, table); Johnson–Cook strength (A, B, n, C, m, ε̇₀, T_room,
@@ -906,7 +906,7 @@ All of these must map to the LS-DYNA keyword and Abaqus input concepts M5 writes
| # | Milestone | Needs from meshing | Verification (analytic first) |
|---|---|---|---|
| X0 | `modelcraft-fem` extraction with M6: hex8/tet4 kinematics, elastic and J2 updates, shared with the implicit solver | M2 tets, generated boxes | patch tests, J2 uniaxial curve, rigid rotation |
| X0 | `fieldcraft-fem` extraction with M6: hex8/tet4 kinematics, elastic and J2 updates, shared with the implicit solver | M2 tets, generated boxes | patch tests, J2 uniaxial curve, rigid rotation |
| X1 | Explicit core: central difference, lumped mass, element Δt (FB 1984), one-point hex8 + FB hourglass, Bonet–Burton tet4, artificial viscosity, energy accounting, prescribed BCs, initial velocity, history output | structured hex8 boxes generated in code (no M3 needed), M2 tets | bar wave (front position and amplitude), bar–rigid wall contact time 2L/c, energy balance, cantilever period vs M6 modal |
| X2 | Large deformation materials: Hughes–Winget Jaumann, Flanagan–Taylor Green–Naghdi, J2 radial return, Johnson–Cook strength + damage, erosion | same | Dienes simple shear (both rates, closed form), Taylor bar (Taylor 1948 analytic estimate; experimental comparison only if the owner allows) |
| X3 | Contact: BVH global search, node-to-segment penalty two-pass + friction, pinball for eroding surfaces, rigid walls | surface extraction of volume meshes (have it) | two bars colliding (momentum exchange, analytic), block sliding with friction on a slope (analytic), Hertz sphere-on-plane at low speed (analytic contact time and force) |
@@ -956,7 +956,7 @@ the better pairing — this is why FSI should support both structure solvers.
## Part G: Implicit solver (M4), as implemented
The papers and books `modelcraft-fem` and `modelcraft-solver` are written from (cited again in
The papers and books `fieldcraft-fem` and `fieldcraft-solver` are written from (cited again in
the module docs):
- Elements: O. C. Zienkiewicz, R. L. Taylor, J. Z. Zhu, *The Finite Element Method: Its Basis
@@ -1031,7 +1031,7 @@ the module docs):
## Part H: Explicit solver core (X1), as implemented
The papers and books `modelcraft-explicit` and `modelcraft_fem::uniform` are written from (cited
The papers and books `fieldcraft-explicit` and `fieldcraft_fem::uniform` are written from (cited
again in the module docs):
- Time integration, energy balance, element eigenvalue inequality: T. Belytschko, W. K. Liu,
@@ -1065,7 +1065,7 @@ again in the module docs):
## Part I: Lattice Boltzmann core (M12, plan L1), as implemented
`modelcraft-lbm` is written from these papers and the book (cited again in its module docs). No
`fieldcraft-lbm` is written from these papers and the book (cited again in its module docs). No
lattice Boltzmann package's code was opened.
- Lattice, equilibrium, units, stream–collide, bounce-back, forcing and boundary conditions:
@@ -1082,7 +1082,7 @@ lattice Boltzmann package's code was opened.
lattice Boltzmann simulations*, J. Stat. Mech. 2010, P01018 (DOI not checked).
- Stability limits (Mach ≤ 0.3, τ⁺ ≥ 0.505, runtime speed ≤ 0.5): Sterling & Chen 1996 and
Lallemand & Luo 2000 (C1.5) for the shrinking stable region as τ → ½.
- Voxelisation: Shewchuk's exact `orient2d`/`orient3d` (`modelcraft_mesh::predicates`) with a
- Voxelisation: Shewchuk's exact `orient2d`/`orient3d` (`fieldcraft_mesh::predicates`) with a
symbolic perturbation after H. Edelsbrunner, E. P. Mücke, *Simulation of Simplicity*, ACM TOG
9(1):66–104, 1990; link faces by nearest triangle, C. Ericson, *Real-Time Collision Detection*,
Morgan Kaufmann 2005, §5.1.5.
@@ -1095,7 +1095,7 @@ lattice Boltzmann package's code was opened.
## Part J: Large deformation and inelastic materials (X2), as implemented
The papers and books `modelcraft_fem::{rotation, plasticity}` and `modelcraft-explicit`'s X2
The papers and books `fieldcraft_fem::{rotation, plasticity}` and `fieldcraft-explicit`'s X2
update are written from (cited again in the module docs):
- Updated Lagrangian one-point elements, strain increments on the midpoint configuration:
@@ -1128,7 +1128,7 @@ update are written from (cited again in the module docs):
- **Conduction.** Galerkin form of ρc Ṫ = ∇·(k∇T) + Q with surface flux and convection:
O. C. Zienkiewicz, R. L. Taylor, J. Z. Zhu, *The Finite Element Method: Its Basis and
Fundamentals*, 7th ed., Butterworth-Heinemann 2013, §3.2; T. J. R. Hughes, *The Finite Element
Method*, Dover 2000, ch. 1. Kernels in `modelcraft_fem::heat`, solver in `modelcraft_solver::heat`.
Method*, Dover 2000, ch. 1. Kernels in `fieldcraft_fem::heat`, solver in `fieldcraft_solver::heat`.
- **Time integration.** The generalized trapezoidal (θ) family, unconditionally stable for
θ ≥ ½ (Hughes 2000, §8.2): backward Euler (θ = 1, the default) and Crank–Nicolson (θ = ½).
- **Thermal strain.** Initial-strain load ∫ Bᵀ D ε_th dV and stress D(ε − ε_th)
+5 -5
View File
@@ -14,11 +14,11 @@ Rules:
material, loads, boundary conditions). We never run a commercial product and never copy its
input files, manual text or figures; only the published numbers are used, with a citation.
- Each case lives in `tests/oracle/<case>/`:
- `recipe.json` — the model as ModelCraft commands (or a SolidCraft recipe for geometry);
- `recipe.json` — the model as FieldCraft commands (or a SolidCraft recipe for geometry);
- `expected.json` — the reference values with `kind` (theory | experiment | benchmark),
`source` (citation: document, table or figure, page), `quantity`, `value`, `tolerance` and
the reason for that tolerance (mesh, measurement scatter, model differences);
- `fixture.json` — ModelCraft's accepted result, written by `cargo xtask oracle --bless <case>`
- `fixture.json` — FieldCraft's accepted result, written by `cargo xtask oracle --bless <case>`
only after the case passes against `expected.json`.
- `cargo xtask oracle` runs every case, compares with `expected.json` (pass/fail with error) and
with `fixture.json` (any change beyond the fixture tolerance fails CI, even if the reference
@@ -30,7 +30,7 @@ Rules:
## The case format
`cargo xtask oracle` builds `modelcraft-testkit`'s `oracle` binary (release) once and runs every
`cargo xtask oracle` builds `fieldcraft-testkit`'s `oracle` binary (release) once and runs every
case through the command engine; the results are in [oracle.md](oracle.md).
```
@@ -40,7 +40,7 @@ cargo xtask oracle --bless nafems-le1 # freeze a passing case's results (or --
cargo xtask oracle --quick # skip cases marked "slow"
```
- `recipe.json` is a script `modelcraft-cli run` also accepts: a JSON array of
- `recipe.json` is a script `fieldcraft-cli run` also accepts: a JSON array of
`{"command", "params"}`; a step may carry an `"id"` so a quantity can read its output. Meshes
come from `mesh.block` (mapped hex, tet or wedge blocks with arcs and elliptical edges, named
faces, edges and vertices that sets select), `mesh.tet.generate`, or nodes and elements written
@@ -56,7 +56,7 @@ cargo xtask oracle --quick # skip cases marked "slow"
"quantities": [{"id": "syy_D", "quantity": "σ_yy at D (2, 0)",
"measure": {"command": "solve.probe", "params": {"step": "Load", "at": [[2, 0, 0]]}, "pointer": "/nodes/0/stress/1"},
"value": 92.7, "tolerance": {"relative": 0.01}, "reason": "why this tolerance",
"known_failure": "optional: why ModelCraft misses the reference today"}]}
"known_failure": "optional: why FieldCraft misses the reference today"}]}
```
A measure reads a JSON pointer either from a recipe step's output (`"from": "<id>"`) or from a
command run after the recipe (`"command"`, `"params"`); an optional `"scale"` multiplies it.