Differentiable meshing pipeline — design ledger
Trimmed to the final architecture. Full build history (stage-by-stage logs, the adversarial-review fixes, the STEP/OCCT bug hunt) is in git/PR #19.
Started 2026-08-15 on feature/differentiable-meshing-pipeline. The previous spike (archived on feature/adaptive-sdf-meshing) attached a MeshSDF-style implicit gradient post-hoc to vertices coming out of a black-box NumPy extractor. That bridge only recovers normal-direction motion and never differentiates the construction that actually places vertices. This pipeline replaces it: build meshing bottom-up from the inputs in pure JAX, and differentiate each real construction step.
Principles
- Discrete topology, continuous motion. Which grid edges cross the surface, which cells are active, and how cells connect are discrete choices, frozen per extraction. Everything continuous — crossing positions, normals, QEF vertices — carries exact JAX derivatives with respect to design parameters. Optimization loops re-extract between steps when topology may change.
- Implicit differentiation, not unrolling. Iterative solvers run on
stop_gradientvalues; a final differentiable Newton correctiont = t0 - f(x(t0)) / (df/dt)re-attaches the gradient. At a converged root its derivative is exactly the implicit-function-theorem valuedt/dθ = -(∂f/∂θ) / (∂f/∂t), so gradients are exact regardless of how the root was found. - Black-box fields. Stages sample only the field callable and
jax.gradof it, so primitives, CSG, transforms, and user-written fields all take the same path. Structure-aware extras (CSG branch tracking, per-primitive patch fields) are optional layers, never requirements. - min/max is where sharpness lives. Hard CSG enters the field through
jnp.minimum/maximum. Root finding must therefore be kink-robust (bisection brackets by sign and cannot be fooled by piecewise-smooth fields); Hermite normals at seams are one-sided subgradients, which is exactly what dual contouring needs to reconstruct a crease; and the active branch switching on the surface is an exact, threshold-free crease signal.
Final architecture (module → tests)
| Stage | Module | Tests |
|---|---|---|
Hermite edge detection (bisection + secant + IFT Newton polish, frozen start_inside) |
cadjoint/meshing/edge_detection.py |
tests/meshing/test_edge_detection.py |
| Sharp-feature classification (normal-spread SVD + exact min/max seam cells) | cadjoint/meshing/features.py |
tests/meshing/test_features.py |
| Dual contouring (Tikhonov QEF gradient path; rank-revealing sharp forward path; deterministic winding) | cadjoint/meshing/dual_contouring.py |
tests/meshing/test_dual_contouring.py, test_manifold_cells.py |
Octree-pruned detection (bit-identical to dense; lipschitz is the caller’s contract) |
cadjoint/meshing/adaptive.py |
tests/meshing/test_adaptive.py |
| Per-primitive patch fields (exact feature-edge signatures for known trees) | cadjoint/meshing/patch_fields.py |
tests/meshing/test_patch_fields.py |
| Simplification (half-edge collapse under QEF + SDF error bound, features pinned bitwise) | cadjoint/meshing/simplify.py |
tests/meshing/test_simplify.py |
| Export (planar-patch merge, OBJ n-gons, binary STL, STEP AP214 validated against OCCT) | cadjoint/meshing/export.py |
tests/meshing/test_export.py, tests/meshing/test_step_kernel.py |
| CSG stress scenes + viewer edge view | — | tests/meshing/test_scenes.py, tests/viewer/test_edge_artifacts.py |
Known structural limitation (strict xfail in test_scenes.py): when a CSG seam grazes a lattice plane, uniform DC can emit nonmanifold edges — one QEF vertex per cell cannot represent two sheets crossing one cell face; wants manifold DC / cell disambiguation. Multi-size octree leaves (2:1 balancing, transition stitching) also remain open.
Benchmark policy
Every stage tracks four dimensions from day one, in benchmarks/:
- Geometric fidelity — analytic-shape error (roots, corners, Hausdorff distance) with pytest-enforced tolerances.
- Gradient correctness — autodiff against analytic implicit derivatives and central finite differences, including near creases.
- Mesh quality/topology — manifoldness, watertightness, triangle quality.
- Performance — wall-clock and scaling vs resolution as a runnable script; timing lives in benchmarks, not in CI-gating tests.