Skip to content

How it works

This page is for the curious user who wants to understand the machinery before relying on it. The authoritative, read-only design docs live in the internal dev/design_docs/ tree of the private development repository; this is a guided tour.

The six layers

Each layer owns one subpackage under packages/mechdsl-core/src/mechdsl/ and one representation. Information only ever flows downward, through the IRs.

Layer Package Responsibility
1 · Frontend mechdsl.frontend Parse LaTeX + % mechanics directives; resolve two-point tensor indices
2 · Symbolic mechdsl.symbolic Kinematics (F→C→E→J), constitutive evaluation, Voigt contraction
3 · Mechanics IR mechdsl.ir ProblemIR — the semantic centre (formulation, frame, stress measure)
4 · Lowering mechdsl.lowering Localise ProblemIR → Element IR; extract einsum strings
4b · Einsum optimiser mechdsl.codegen.einsum_optimizer opt_einsum contraction paths + JIT-budget counter
5 · Codegen mechdsl.codegen.taichi_printer Taichi source emission (sole MVP backend)
6 · Verify mechdsl.verify Reference comparison, AD oracle, patch tests

Supporting packages: mechdsl.solver (Newton driver + imported linear solver adapter) and mechdsl.lib (the Tier-1 @ti.func library and plasticity orchestration).

Beneath all of that sits ti-runtime, the neutral Taichi runtime that generated code lands on — vector primitives, Tier-1 @ti.func tensor helpers, Hex8 shape gradients, and the injection seams. The direction matters: emitted artifacts import ti_runtime, never mechdsl, so a generated kernel outlives the compiler run that produced it.

LaTeX ──▶ SymPy tensors ──▶ ProblemIR ──▶ ElementIR ──▶ EinsumIR ──▶ Taichi
        frontend        symbolic       lowering      optimiser     codegen

IR discipline

Three rules keep the pipeline correct and testable:

  1. All information flows through the three IRs — Mechanics IR → Element IR → Einsum IR. Symbolic expressions never emit backend code directly.
  2. IRs are immutable dataclasses, validated at construction. A malformed problem fails fast at the IR boundary, not deep in codegen.
  3. Unsupported constructs raise explicitly — with the specific plan phase that will add support — instead of silently emitting wrong code.

Determinism & golden files

compile_latex returns a bundle with a content_hash(). Identical inputs always produce an identical hash and identical emitted source. That determinism is what makes the compiler testable: serialized output bundles are stored as golden files under packages/mechdsl-core/tests/golden/, and any change to generated code shows up as a visible diff. Golden updates require explicit intent — they are never auto-applied.

Verification

Correctness is anchored to hand-written reference kernels in packages/mechdsl-core/tests/ref/ (e.g. ref_hex8_elastic.py, ref_hex8_plastic.py), which are the ground truth. Generated code must match them within the tolerances fixed in dev/design_docs/07-CONVENTIONS.md §6:

  • generated vs. reference displacement: max diff < 1e-10
  • patch test (constant strain): exact reproduction
  • Cook's membrane: within 2% of literature
  • necking bar: load–displacement within 2% of Simo & Hughes (1998)

An automatic-differentiation oracle (mechdsl.verify.ad_oracle) independently checks that derived stresses/tangents match a numerical derivative of the energy — catching a mis-derivation that a single load case might hide.

mechdsl-corealgo2code

The two packages have a strict consumer/producer relationship: mechdsl-core consumes algo2code-generated artifacts; algo2code is runtime-free and never imports mechdsl. The seam is the LinearSolverInterface protocol in mechdsl.solver.import_adapter, which the Newton driver calls through. See the algo2code page for the full story, and dev/design_docs/11-ALGO2CODE.md for the authoritative reference.

mechdsl.integration — the public façade

Everything above describes the machinery. Tools that consume MechDSL — the browser workbench, downstream adapters, anything embedding the compiler — should not reach into it. They call mechdsl.integration, the stable, machine-readable Tier-1 surface, which is exactly five entry points:

Function Returns Needs Taichi?
capabilities() A manifest: version, profiles, backends, actions, models No
model_catalog() Every constitutive model with tier, dissipative flag, params, state variables No
compile_from_sources(...) {element_ir_summary, emitted_source, content_hash, derived_energy_present} No
transpile_algorithm(algpseudocode, backend) {code, entry_point, line_count, valid_python} No
verify(kind, params) {kind, passed, details} Yes
from mechdsl.integration import capabilities, compile_from_sources

caps = capabilities()
print(caps["taichi_required_for"])   # -> ["verify"]

result = compile_from_sources(problem_source="% mechanics dim 3\n...")
print(result["content_hash"])        # 64-char sha-256 hex digest

The Taichi-required-for contract: capabilities() declares taichi_required_for: ["verify"]. The other four entry points are guaranteed never to trigger ti.init, so importing mechdsl.integration and calling them is safe in a Taichi-free environment — which is why the base pip install mechdsl-core can leave Taichi out entirely (see Installation). Only verify() pays the Taichi cost, and it imports lazily at call time.

This is a machine API contract, not a convenience library; entry points are not added to it without a deliberate design decision.

Where to read more

Topic Design doc
Document map 00-OVERVIEW.md
Pipeline structure 01-ARCHITECTURE.md
LaTeX DSL grammar 02-LATEX-DSL.md
Symbolic engine 03-SYMBOLIC-ENGINE.md
Mechanics / Element IR 04-MECHANICS-IR.md, 05-ELEMENT-IR.md
Codegen 06-CODEGEN.md
Conventions (authoritative) 07-CONVENTIONS.md
Verification matrix 08-VERIFICATION.md
Einsum optimiser 09-EINSUM-OPTIMISER.md
Boundaries 10-BOUNDARIES.md
algo2code 11-ALGO2CODE.md