explicit: deformable contact and friction, verified by bars, sliding blocks, the patch test and Hertz

Segment-to-segment penalty contact between element faces: each secondary
face and each main face facing it are projected onto the secondary face's
plane, split into triangles, clipped (Sutherland–Hodgman) and integrated
with a three-point rule per sub-triangle (Puso–Laursen segmentation, the
penalty at the integration points as Fischer–Wriggers), so a uniform
pressure gives the consistent nodal forces on both meshes and the contact
patch test passes on non-matching meshes. Every contact runs both ways at
half the penalty: pairs with each surface as the secondary, general and
self contact face against face. A bucket grid of face boxes every
increment, faces integrated in parallel and their forces added in face
order: the same numbers on any thread count.

The penalty per area ε = s γ min(m/A)/Δt² comes from the lumped masses,
each node's directional area and the stable increment, bounded by
Gershgorin's row sums so contact never shortens the increment. Coulomb
friction with exponential decay by a regularised return map at the
secondary nodes; rigid walls take Coulomb impulses. Contact work and
friction dissipation join the energy balance; each contact reports its
peak force, first and last contact, deepest penetration, friction and the
nodes adjusted at the start (initial penetrations adjusted strain-free or
refused with the node, face and depth); a cap on contact faces.

Verified (crates/explicit/tests/contact.rs, tests/oracle/explicit-*):
colliding bars (2L/c +1.2%, ρcAv₀/2, KE kept to 0.005%, contact energy
back to 8e-5 of it), blocks sliding to a stop on a rigid wall and on a
plate under constant and decaying friction (0.005–0.2%), the patch test
(σ_zz uniform to 0.06%), two spheres colliding against Hertz (peak +2.3%,
duration −0.4%; the oracle case waits for a graded sphere mesher), a free
body untouched by general contact, determinism across threads. Oracle
measures gain `over` (ratios). Existing fixtures do not move.

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-14 12:49:45 -04:00
1 parent ecf947c090
commit a30d0b5c5b
37 files changed
+2459 -55

No files matched your search

+23 -1
View File
@@ -2,7 +2,7 @@
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.
**176 of 182 quantities pass** (6 known failure(s)) in 53 active cases: 44 theory, 9 published benchmark, 0 experiment; 9 pending cases wait for capabilities still being built.
**193 of 199 quantities pass** (6 known failure(s)) in 57 active cases: 48 theory, 9 published benchmark, 0 experiment; 10 pending cases wait for capabilities still being built.
## Theory: closed-form solutions, patch tests and mesh invariants
@@ -28,6 +28,23 @@ Generated by `cargo xtask oracle` from [`tests/oracle/`](../tests/oracle/); the
| [cdt-stepped-block](../tests/oracle/cdt-stepped-block/) | volume of the tetrahedra | 47000 | 47000 | < 1e-7% | 1e-12 rel. | pass | matches |
| [cdt-stepped-block](../tests/oracle/cdt-stepped-block/) | elements that fail the certified Jacobian check | 0 | 0 | ≈ 0 | exact | pass | matches |
| [cdt-stepped-block](../tests/oracle/cdt-stepped-block/) | elements the Jacobian check could not decide | 0 | 0 | ≈ 0 | exact | pass | matches |
| [explicit-bars-collision](../tests/oracle/explicit-bars-collision/) | time of the last contact (the bars touch from t = 0) against 2L/c = 0.2 | 0.2 | 0.20242 | 1.21% | 2% | pass | matches |
| [explicit-bars-collision](../tests/oracle/explicit-bars-collision/) | the largest force across the interface against ρcAv₀/2 = 0.05 | 0.05 | 0.05147 | 2.94% | 4% | pass | matches |
| [explicit-bars-collision](../tests/oracle/explicit-bars-collision/) | velocity of the struck bar's far end after the impact (0: the striker stops) | 0 | -0.0033987 | -3.4e-3 | ± 0.005 | pass | matches |
| [explicit-bars-collision](../tests/oracle/explicit-bars-collision/) | velocity of the struck bar's far end after the impact (v₀ = 0.1) | 0.1 | 0.1034 | 3.4% | 5% | pass | matches |
| [explicit-bars-collision](../tests/oracle/explicit-bars-collision/) | kinetic energy after the impact over ½mv₀² (frictionless elastic impact) | 1 | 0.99995 | -0.00468% | 1% | pass | matches |
| [explicit-bars-collision](../tests/oracle/explicit-bars-collision/) | energy left in the contact after the separation, over ½mv₀² (its drift) | 0 | -7.7435e-5 | -7.7e-5 | ± 0.001 | pass | matches |
| [explicit-contact-patch](../tests/oracle/explicit-contact-patch/) | σ_zz of the lower block's corner element under the interface (element 10) over that of the upper block's corner element over it (element 19) | 1 | 1.0001 | 0.0118% | 0.5% | pass | matches |
| [explicit-contact-patch](../tests/oracle/explicit-contact-patch/) | σ_zz of the lower block's centre element under the interface (element 14) over that of element 19 | 1 | 1.0003 | 0.0287% | 0.5% | pass | matches |
| [explicit-contact-patch](../tests/oracle/explicit-contact-patch/) | σ_zz of the lower block's bottom corner element (element 1) over that of element 19 | 1 | 1.0001 | 0.0134% | 0.5% | pass | matches |
| [explicit-contact-patch](../tests/oracle/explicit-contact-patch/) | σ_zz of the upper block's top far corner element (element 26) over that of element 19 | 1 | 0.99944 | -0.0564% | 0.5% | pass | matches |
| [explicit-contact-patch](../tests/oracle/explicit-contact-patch/) | the force across the interface over −σ_zz A (A = 1) | 1 | 1.0026 | 0.259% | 1% | pass | matches |
| [explicit-contact-patch](../tests/oracle/explicit-contact-patch/) | σ_xx of element 14 over its σ_zz (uniaxial stress: 0) | 0 | -3.6052e-4 | -3.6e-4 | ± 0.005 | pass | matches |
| [explicit-sliding-block-contact](../tests/oracle/explicit-sliding-block-contact/) | distance travelled (top centre node) against ∫ v dv / (g μ(v)) = 2.01524 | 2.0152 | 2.0118 | -0.172% | 1% | pass | matches |
| [explicit-sliding-block-contact](../tests/oracle/explicit-sliding-block-contact/) | velocity of the top centre node after the stop | 0 | ≈ 0 | ≈ 0 | ± 0.03 | pass | matches |
| [explicit-sliding-block-wall](../tests/oracle/explicit-sliding-block-wall/) | distance travelled (top centre node) against v₀²/(2μg) = 1.5 | 1.5 | 1.4999 | -0.0053% | 1% | pass | matches |
| [explicit-sliding-block-wall](../tests/oracle/explicit-sliding-block-wall/) | velocity of the top centre node after the stop | 0 | ≈ 0 | ≈ 0 | ± 0.03 | pass | matches |
| [explicit-sliding-block-wall](../tests/oracle/explicit-sliding-block-wall/) | friction dissipation over ½mv₀² = 2.25 | 1 | 1.0012 | 0.121% | 1% | pass | matches |
| [filleted-bracket-fillet-stress](../tests/oracle/filleted-bracket-fillet-stress/) | largest nodal von Mises stress on the fillet face (MPa) | 213 | mesh-dependent | within 3% | 3% | pass | — |
| [filleted-bracket-fillet-stress](../tests/oracle/filleted-bracket-fillet-stress/) | total reaction x (N) | -2000 | -2000 | < 1e-7% | 1e-9 rel. | pass | matches |
| [filleted-bracket-fillet-stress-coarse](../tests/oracle/filleted-bracket-fillet-stress-coarse/) | largest nodal von Mises stress on the fillet face (MPa) | 213 | mesh-dependent | within 3% | 3% | pass | — |
@@ -206,6 +223,10 @@ Generated by `cargo xtask oracle` from [`tests/oracle/`](../tests/oracle/); the
- **[cantilever-tet10](../tests/oracle/cantilever-tet10/)** (theory): Cantilever under a tip load, Timoshenko deflection (tet10). Source: Timoshenko and Gere, Mechanics of Materials (beam with shear deformation: δ = PL³/3EI + PL/κGA, κ = 5/6 for a rectangle); Cowper, J. Appl. Mech. 33 (1966) 335–340 for the shear coefficient. Tolerances — tip_uz: beam theory vs 3D elasticity (a few tenths of a percent at L/h = 10); quadratic tetrahedra are converged on this mesh; reaction: equilibrium holds to rounding
- **[cdt-cylinder](../tests/oracle/cdt-cylinder/)** (theory): Constrained Delaunay mesh of a cylinder: volume within the chordal bound, valid elements. Source: mesh invariants: an inscribed polygon of sagitta s loses at most 2s/R of a circle's area (elementary geometry); constrained Delaunay tetrahedralization after Diazzi et al., ACM TOG 42(6) 2023. Tolerances — volume: the tessellation inscribes the cylinder within the chordal tolerance s = 0.05: the polygon section loses between 0 and 2s/R = 0.5% of the area; the reference is the middle of that band; invalid: every element of a valid mesh has positive volume
- **[cdt-stepped-block](../tests/oracle/cdt-stepped-block/)** (theory): Constrained Delaunay mesh of a stepped block: exact volume, valid elements. Source: mesh invariants: a tetrahedralization of a polyhedron fills its volume exactly (Si, TetGen paper ACM TOMS 41(2) 2015 for the definition of a CDT; Diazzi et al., ACM TOG 42(6) 2023); the volume is 60·40·10 + 40·40·10 + 20·40·10 − 10·10·10. Tolerances — volume: a planar boundary is tessellated exactly and the constrained Delaunay mesh fills it exactly: only rounding; invalid: every element of a valid mesh has positive volume; undetermined: a linear tetrahedron's sign is exact
- **[explicit-bars-collision](../tests/oracle/explicit-bars-collision/)** (theory): Two identical elastic bars colliding (explicit contact). Source: One-dimensional elastic impact of equal bars: contact for 2L/c, interface force ρcAv₀/2, exchange of velocities, no loss of energy; Graff, Wave Motion in Elastic Solids, Dover 1991, §2.1–2.3; Johnson, Impact Strength of Materials, Arnold 1972, §1.6. Tolerances — duration: the penalty springs at the interface delay the release by a few element transit times (about 1% of 2L/c with 200 elements per bar); force: the plateau is ρcAv₀/2 to 0.01%; the peak is the plateau plus the ringing behind the discrete wave front, a few percent; v_a: the striker stops on average (its kinetic energy is under 0.01% of the start's, see ke); its far end node keeps the ringing of the discrete release front, a few percent of v₀; v_b: the struck bar leaves at v₀ on average; its far end node keeps the ringing of the discrete wave fronts, a few percent; ke: an elastic impact keeps the kinetic energy; the quadratic bulk viscosity at the compression fronts and the vibration left in the bars take a fraction of a percent; contact_energy: the penalty springs give back what they took; the trapezoidal work of a spring that engages between increments drifts by far less than 0.1%
- **[explicit-contact-patch](../tests/oracle/explicit-contact-patch/)** (theory): Contact patch test: two blocks with non-matching meshes in uniaxial compression (explicit contact). Source: The contact patch test: a contact discretisation must transmit a uniform pressure across a non-matching interface exactly; Taylor & Papadopoulos, On a patch test for contact problems in two dimensions, Nonlinear Computational Mechanics, Springer 1991, 690–702; Crisfield, Re-visiting the contact patch test, IJNME 48:435–449, 2000. Uniaxial stress between frictionless symmetry planes is uniform in both blocks. Tolerances — lower_corner: a uniform stress is an equilibrium of the discrete system (the integrated contact forces are the consistent nodal forces of a uniform pressure on both meshes); what is left is the ringing of the loading, a hundred wave transits slow; lower_centre: as for the corner element; lower_base: as for the corner element; upper_top: as for the corner element; force: the integrated contact pressure carries the whole load; the largest force of the run is the final one in a slow squeeze, up to the ringing; lateral: frictionless symmetry planes and a frictionless interface leave the blocks free to expand sideways; the non-matching interface must not hold them
- **[explicit-sliding-block-contact](../tests/oracle/explicit-sliding-block-contact/)** (theory): Block sliding to a stop on a deformable plate, friction decaying with the slip rate (explicit contact). Source: A rigid block launched at v₀ with friction μ(v) = μk + (μs − μk) e^(−d v) decelerates at g μ(v); it travels ∫₀^v₀ v dv / (g μ(v)) (Simpson's rule, 200 000 intervals) and stops after [v₀ + ln((μk + (μs − μk) e^(−d v₀))/μs)/d]/(g μk) = 1.2001; Meriam & Kraige, Engineering Mechanics: Dynamics, §3/5; the exponential decay law as in Oden & Martins, CMAME 52:527–634, 1985. Tolerances — distance: the block bounces on the penalty springs and the plate under it shears elastically, so the normal force and the slip rate it feels vary by a little around their rigid-body values; velocity: the block sticks; what is left is its elastic vibration, under 1% of v₀
- **[explicit-sliding-block-wall](../tests/oracle/explicit-sliding-block-wall/)** (theory): Block sliding to a stop on a rigid wall with Coulomb friction (explicit). Source: A rigid block launched at v₀ on a horizontal plane with Coulomb friction μ decelerates at μg and stops after v₀/(μg) at v₀²/(2μg), its kinetic energy all dissipated by friction; Meriam & Kraige, Engineering Mechanics: Dynamics, §3/5 (work and energy). Tolerances — distance: the wall's friction impulses are exact Coulomb impulses; the block's elastic vibration from the sudden gravity and the friction moment move the node by a fraction of a percent; velocity: the block sticks; what is left is its elastic vibration, under 1% of v₀; dissipated: the kinetic energy goes into friction; the vibration and the work of gravity as the block settles add or take a fraction of a percent
- **[filleted-bracket-fillet-stress](../tests/oracle/filleted-bracket-fillet-stress/)** (theory): Filleted L-bracket under a side load: the peak von Mises stress on the R6 fillet, fine tet10 mesh. Source: mesh convergence of the finite element solution (P. J. Roache, Verification and Validation in Computational Science and Engineering, Hermosa, 1998, ch. 5): the bracket has no closed-form stress; the reference is the mesh-independent peak of a four-level study of quadratic tetrahedral meshes refined by √2 in size and in curvature resolution (README.md); equilibrium. Tolerances — fillet_peak: the four-level study gives 213.3, 210.6, 214.3, 213.3 MPa (2k to 13.5k elements): the bending stress is converged across the fillet, and the peak nodal value moves only with which of the fillet's tessellation lines (fixed angles, through every level) carries the largest node, by under 2%; reaction: equilibrium holds to rounding
- **[filleted-bracket-fillet-stress-coarse](../tests/oracle/filleted-bracket-fillet-stress-coarse/)** (theory): Filleted L-bracket under a side load: the peak von Mises stress on the R6 fillet, coarse tet10 mesh. Source: mesh convergence of the finite element solution (P. J. Roache, Verification and Validation in Computational Science and Engineering, Hermosa, 1998, ch. 5): the bracket has no closed-form stress; the reference is the mesh-independent peak of a four-level study of quadratic tetrahedral meshes refined by √2 in size and in curvature resolution (README.md); equilibrium. Tolerances — fillet_peak: the four-level study gives 213.3, 210.6, 214.3, 213.3 MPa (2k to 13.5k elements): the bending stress is converged across the fillet, and the peak nodal value moves only with which of the fillet's tessellation lines (fixed angles, through every level) carries the largest node, by under 2%; reaction: equilibrium holds to rounding
- **[free-beam-frequencies](../tests/oracle/free-beam-frequencies/)** (theory): Natural frequencies of a free beam: rigid-body modes and the first bending mode. Source: Euler–Bernoulli free–free beam, β₁L = 4.7300; Timoshenko, Young and Weaver, Vibration Problems in Engineering, 4th ed., Wiley 1974, §5.3. Tolerances — rigid_6: a free body has six zero frequencies; numerical rigid-body frequencies below 10⁻³ of the first elastic one (eigenvalues below 10⁻⁶ of it) are rounding of the shifted solve; f7: Euler–Bernoulli neglects shear and rotary inertia, about 0.8% at L/h = 20 for the free–free mode; mass: the mass matrix integrates the density exactly
@@ -259,6 +280,7 @@ Reference values already cited; each case gets its recipe when the capability it
| Case | Kind | Problem | Needs | Reference values | Source |
|---|---|---|---|---|---|
| [cylinder-channel-2d1](../tests/oracle/cylinder-channel-2d1/) | benchmark | Flow around a cylinder, steady 2D-1 (Re = 20) | lattice Boltzmann CFD (M12) | drag coefficient (published interval 5.57–5.59) = 5.58; lift coefficient (interval 0.0104–0.0110) = 0.0107 | Schäfer and Turek, 'Benchmark computations of laminar flow around a cylinder', Notes on Numerical Fluid Mechanics 52 (1996) 547–566, Table 4 (reference intervals) |
| [explicit-hertz-spheres](../tests/oracle/explicit-hertz-spheres/) | theory | Two elastic spheres in a head-on collision: Hertz's force and contact duration (explicit contact) | a graded sphere mesh from commands (a cubed-sphere hex mesher, or tet refinement towards a point); until then the explicit crate's tests `spheres_collide_as_hertz_says` (a graded cubed-sphere quarter of each sphere, 27 648 hex8: peak force +2.3%, duration −0.4%) and its coarse twin in the main gate check this case on a mesh generated in code | the largest contact force, two steel spheres R = 10 mm (E = 210 GPa, ν = 0.3, ρ = 7.85 t/m³) meeting at 1 m/s (N) = 1005.4; the contact duration (s) = 6.0163e-5 | Hertz's quasi-static impact: with R* = R/2, m* = m/2, E* = E/(2(1 − ν²)), the approach reaches δ = (15 m* v²/(16 E* √R*))^(2/5), the force (4/3) E* √R* δ^(3/2), and the contact lasts 2.9432 δ/v; Hertz, J. reine angew. Math. 92:156–171, 1882; K. L. Johnson, Contact Mechanics, Cambridge 1985, §11.4 |
| [lid-driven-cavity-re100](../tests/oracle/lid-driven-cavity-re100/) | benchmark | Lid-driven cavity, Re = 100 | lattice Boltzmann CFD (M12) | u/U at y = 0.4531 on the vertical centreline = -0.2109 | Ghia, Ghia and Shin, Journal of Computational Physics 48 (1982) 387–411, Table I (u along the vertical centreline) |
| [mh-twisted-beam](../tests/oracle/mh-twisted-beam/) | benchmark | MacNeal–Harder twisted beam | shell elements (M8) or mapped blocks with helical edges | tip displacement along the in-plane load = 0.005424; tip displacement along the out-of-plane load = 0.001754 | MacNeal and Harder, 'A proposed standard set of problems to test finite element accuracy', Finite Elements in Analysis and Design 1 (1985) 3–20, Fig. 6 (p. 8), Table 3 (p. 10) |
| [nafems-le11](../tests/oracle/nafems-le11/) | benchmark | NAFEMS LE11 solid cylinder/taper/sphere under a temperature field | thermal loads (M8 heat transfer) | σ_zz at A = -105 | NAFEMS, The Standard NAFEMS Benchmarks, TNSB Rev. 3, October 1990, test LE11 (target σ_zz = −105 MPa at A) |