Tet-mesh energy, surface encoder and two contact paths for LIDO
This page shows the mechanisms the plan turns on. Teal marks the tet mesh and the new energy. Orange marks contact planes and constraints. Green is the certified anchor state, purple the trial state. Formulas are in LIDO's normalised units: cell size 1, time step 1, the scene's reference shear modulus 1.
1. What changes and what stays
Today the energy is the trilinear hex energy of the voxel body. P01 keeps the cell grid, the corner degrees of freedom, the network and the fusion, and swaps the energy for the energy of a tet mesh whose vertices ride on the corners. The hex energy stays behind a switch.
2. Energy transfer: tets ride on corners
Each tet vertex sits at fixed trilinear coordinates inside one cell. Its position is a convex combination of that cell's eight corners. The tet deformation gradient uses these embedded positions. The gradient goes back to the corners by the same weights.
F_t = Ds_t(x_v) Dm_t^-1, x_v = J x, Dm_t from the rest vertices
E_el = sum_t mu_scale_o V_t psi(F_t; lam_o) psi as physics.stable_neo_hookean, same inversion rule
E_damp = sum_t mu_scale_o V_t 0.5 eta_o |F_t^T F_t - C_prev_t|^2 C_prev_t at step start, [T,3,3]
g_corner = J^T g_vertex mode gradient paths unchanged (step.py:214, fusion.py:672)
m_corner = J^T m_vertex, m_vertex = sum over incident tets of rho V_t / 4 every corner weighted (coverage rule)
floor = volume sum_t V_t h^3, samples = surface vertices
occupancy: the cells that contain a tet vertex; the body is scaled to a drawn cell count
Invariants to test
Zero energy and gradient at rest. Exact equality with the hex energy for any affine deformation of a five-tet lattice body, because the tet volumes of a cell sum to one. Translation invariance. Float64 finite differences. Warp against torch at the existing tolerances. Stress against Newton's formula.
Decision 1, energy transfer: Option A, accepted 2026-10-10
Per-tet F from embedded vertices, the proposal. Option B, the hex F at tet quadrature points, stays the fallback. Verified against the Newton kernels: on lattice tets the forces equal VBD's exactly, damping included, when the inversion stiffening factor is 0 and the masses are tet-lumped. Recorded as ADR 0003.
3. Surface encoder: the rest surface as a per-cell input
Today a cell knows its rest surface through six exposed-face bits. With a tet mesh the surface is a set of triangles that cross the cell. The tokens are built once per mesh. The encoder is small and trained with the network.
Proof-of-concept restriction: cells that join two sheets
4. Contact path A: decoupled DAT planes
Pairs are detected once per step at the step start by Newton's trimesh detector over one model that holds every body's tet surface: vertex-triangle and edge-edge pairs, self-contact on behind a switch, the plane and static quads analytic against surface vertices. The reach is one scalar per step, the radius plus the margin plus twice a budget that exceeds the largest inertial corner displacement. Each pair gets one division plane, placed at a certified, penetration-free anchor. The energy of every vertex is a cubic of its penetration over the plane offset by the radius r, plus gap-rate damping and IPC friction against the plane with the held cubic load, decision F1. The plane is fixed during a query, so the two sides do not exchange momentum within a query. Sliding the plane between truncation rounds is the only exchange.
Truncation on corners, not on vertices
LIDO's degrees of freedom are the corners. The embedding weights are fixed material coordinates, so a vertex path is linear when its eight corners share one factor; with different factors the vertex follows a convex combination and can swerve. The rule agreed on 2026-10-10: truncate at the vertex first, dividing its clearance by the harmful part of its corner motion, then apply that factor to the harmful corners only. It is exact on lattice tets and conservative mid-cell.
for vertex v and plane (p, n): c_v = n . (x_v(anchor) - p) - m >= 0 clearance at the certified anchor
harmful corners k of v: a_k = n . dx_k < 0 sign per side
t_v = min(1, gamma c_v / sum over harmful k of N_k |a_k|) harmful part, not the net n . dx_v
for each harmful k: t_k = min(t_k, t_v) atomic minimum; helpful corners untouched
anchor_k = anchor_k + t_k dx_k, then clamp |anchor_k - x_start_k| <= B displacement clamp per corner
B = 1.25 x largest inertial corner displacement; reach R = r + m + 2 B one scalar per step for the detector
5. Contact path B: coupled smooth-extrema constraint
One constraint per pair couples both sides, so the forces are exactly equal and opposite. Two corrections to the text: the radius enters with a minus sign, and the energy must be unilateral.
C = softmin_b - softmax_a + rC stays non-negative while the sides overlap by up to r.
C = softmin_b - softmax_a - rSeparation by r means C at least zero, as in the ALM contact design note.
E = C^3Negative and unbounded below for C below zero; pulls the sides together for C above zero.
E = ke/(3r) relu(-C)^3Zero when separated, cubic penalty on the overlap, same unit scale as the plane law.
U = (1/beta) log sum_i exp(+beta n . a_i) soft-max of side A
L = -(1/beta) log sum_j exp(-beta n . b_j) soft-min of side B
C = L - U - r, E = ke / (3 r) relu(-C)^3
dC/da_i = -w_i n, dC/db_j = +v_j n (softmax and softmin weights) -> equal and opposite
world edges: two directed cell-graph edges per pair in per-cell slots reserved at the detector's row
capacities, marked valid per step; features: zeros plus a flag for the rest offset, the usual
current geometry, the partner's mass-ratio and kappa channels; edge width 27, zero-column pad
Decision of 2026-10-11: the coupled path builds the same division planes from the same pairs and runs the same final truncation, so the two paths differ only in the energy. The coupled energy without truncation stays as an ablation arm.
No path promises penetration freedom. The DAT certificate needs complete detection within the reach, strict separation at the step start, linear committed motion and convex primitives. With truncation on both paths the committed state is certified on both, under those assumptions only. The plan measures each assumption: coverage flag, plane-crossing share, true surface penetration on the tet surface.
6. Decisions taken in the review session
Recorded in the worktree glossary and ADR 0003 on 2026-10-10 and 2026-10-11.
- Goal. Fidelity on lattice tets against Newton VBD is the first gate; capability on real assets is the second.
- Energy transfer. Option A: one deformation gradient per tet from embedded vertices, gradient to corners through the embedding transpose. Option B is the fallback. ADR 0003.
- Mass. Linear-FEM lumping to the tet vertices, carried to corners by the embedding transpose; the library enforces corner coverage.
- Mesh source. Lattice tets for gates A and B; TetWild assets, QEM-decimated and re-meshed with fTetWild at about one cell edge length, for gates C and D; the fTetWild wrapper is the one new dependency; the library ships as a versioned archive; splits by mesh id.
- Surface encoder. One token per triangle, at most 16 per cell, volume fraction as a channel; encoder on against off is the ablation.
- Loss location. L1: the potential at the trial with the planes as step constants; the anchor is committed; the truncation fraction is logged.
- Tangential forces. F1: gap-rate damping and IPC friction against the plane with the held cubic load; F0 is an ablation.
- Schedule. Planes rebuilt after every query, three final rounds, normals refreshed every round; the margin is a small float32 band and the radius r is the whole cushion.
- Coupled path. Same planes and truncation as the decoupled path; energy only as an ablation.
- World edges. Per-cell slots reserved at the detector's row capacities, marked valid per step; edge width 27 with a zero-column pad.
- Detection. Newton's trimesh detector over one model with every body's tet surface; analytic plane and quads against vertices; one scalar reach per step from the largest inertial displacement; self-contact on behind a switch.
- Body from a mesh. Scaled to a drawn cell count; occupancy is the cells that contain a vertex; filters for components, closed surface, dihedral angle, joined sheets and coverage.
Defects in the proposal text, corrected
- Coupled constraint sign and unilateral cubic energy, section 5.
- "Offline, costs nothing" holds for the tokens; the encoder forward runs on every training update.
- The decoupled path trades the pair reaction for two forces on a fixed plane; no momentum exchange within a query.
- The two signatures of the plane builder differ; the two-argument form, with the trial for the rates, is right everywhere.
- "Newton's second law" reads as the third law.
- Not copied from the reference code: the path-length budget lock-in, the missing friction and damping, and pairs dropped by a full detection buffer, which lose their plane. The coverage flag is the mitigation.
Still open
- Approval of the fTetWild wrapper install at implementation time.
- Whether the contact architecture gets its own ADR 0004.
- Small implementation defaults: the owner cell of an edge-edge pair, the tie rule for a vertex on a cell face, one density per body, fresh training rather than warm starts for tet arms.
7. Phases, each behind a switch with the v8 default
| Phase | Content | Code locations | Tests |
|---|---|---|---|
| P0 | Mesh library and embedding: tets, trilinear weights, vertex-lumped corner masses, occupancy from vertex cells, corner coverage, surface tokens, joined-sheet check. Kinds: five-tet lattice; TetWild assets decimated and re-meshed at about one cell edge length. | new tetmesh.py; BodySpec gains mesh beside shape; realise; five-tet tables in pinning_gallery.py:91 | test_tetmesh.py: weights sum to one, mass totals, sheet check |
| P1 | Tet elastic and damping energy with gradient to corners; floor from tet volume; fused inference launch. | new tet_energy_kernel.py; dispatch at physics.py:122; energy_kernel.py:252 | test_tet_energy.py: affine equality, finite differences, Warp against torch, Newton stress |
| P2 | Surface encoder, tokens in lattice coordinates, zero-init output, concat or add rule. | network.py beside ContactEncoder; adapter at network.py:410 | test_surface_encoder.py: zero-init identity, loading of old checkpoints |
| P3 | Tet-surface detection: Newton's trimesh detector over one model with all bodies' surfaces, vertex-triangle and edge-edge pairs, scalar reach per step, self-contact behind a switch; analytic plane and quads against vertices. | contact.py:162, contact.py:271; Newton TriMeshCollisionDetector | test_tet_collision.py: brute force pairs, capacity layout |
| P4 | Division planes and corner truncation with the harmful-corner rule, ported from the sibling worktree kernels; F1 damping and friction against the plane; schedule N = 1, T = 3, M = 1 in Step; loss at the trial. | new dat_planes.py; step.py:382, step.py:478; source particle_dat_kernels.py of alm-dat-solver | test_dat_planes.py: no committed vertex crosses, resting truncation fraction near zero |
| P5 | Coupled constraint with the corrected sign and unilateral cubic, anchor-picked normals, the same planes and truncation, world edges in per-cell slots at the detector's capacities. | contact.py, features.py, network.py, grid.py | test_coupled_contact.py: third law to 1e-10, conservative bound |
8. Arms, references and gates
| Arm | Energy | Surface encoder | Collision surface | Contact method | World edges |
|---|---|---|---|---|---|
| base | hex | off | voxel | pairs | no |
| T0 | tet, lattice | off | voxel | pairs | no |
| T1 | tet, library | off | voxel | pairs | no |
| T2 | tet, library | on | voxel | pairs | no |
| C1 | tet | best of T1, T2 | tet | pairs | no |
| D1 | tet | same | tet | DAT planes | no |
| K1 | tet | same | tet | coupled | no |
| K2 | tet | same | tet | coupled | yes |
Ablation arms added in the review session, each one switch away from its parent: L3 loss with a trial-to-anchor penalty; F0 normal cubic only; N = K planes rebuilt only after the queries; T in 2 and 4; slide-only final rounds; K-A coupled energy without truncation; world-edge capacities 4 and 8; hand-pooled surface features instead of attention; self-contact off; a resolution split in tets per cell.
- References. Newton SolverVBD on the same tet mesh with true tet degrees of freedom, for beams and drops. On lattice tets the two potentials coincide, so the hex-versus-tet floor of today's beam harness vanishes. The float64 fixed-point reference of the benchmark needs a tet-aware dispatch at
bench/reference.py:310. - Regime. The 24-hour ablation regime: 32k cells, 96 scenes per epoch, 20 epochs, cosine from 1.4e-4 to 1e-6, seed 73, gradient input local, 4 GPUs per arm. Then 60 epochs and two seeds for finalists.
- Splits. Disjoint mesh-library seeds for training, validation and test. Asset shapes and materials widened by a factor of three as out of distribution.
- Metrics. Benchmark position and residual ratios after 8 queries; surface-vertex error against VBD; penetration in units of r; plane-crossing share; truncation fraction; survival; milliseconds per query; memory; in-to-out distribution ratios.
First step. P0 for lattice tets, P1 and its tests, then T0 against base on 4 GPUs each, scored by the beam harness against VBD on the same mesh and by the benchmark with a tet-aware reference. Estimate: one week of implementation, one day of training. Everything stays read-only until you approve and assign a worktree.