From 0220e2d8bb1ef79de53f198ead4a7f276edd59ac Mon Sep 17 00:00:00 2001 From: jyviko <2501648+jyviko@users.noreply.github.com> Date: Wed, 14 Oct 2026 15:47:09 -0400 Subject: [PATCH] engine, docs: self-contact in nonlinear static steps Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo --- crates/engine/src/catalogue.rs | 2 +- crates/engine/src/cmd/contact.rs | 2 +- crates/model/src/contact.rs | 2 +- docs/features.md | 2 +- docs/fem.md | 8 ++++++-- 5 files changed, 10 insertions(+), 6 deletions(-) diff --git a/crates/engine/src/catalogue.rs b/crates/engine/src/catalogue.rs index 186efe0..7362ed3 100644 --- a/crates/engine/src/catalogue.rs +++ b/crates/engine/src/catalogue.rs @@ -427,7 +427,7 @@ pub static CATALOGUE: &[Capability] = &[ "General Contact", Interactions, "Contact", - "Contact between everything that may touch, or self contact of a surface, with friction (explicit dynamics)", + "Contact between everything that may touch, or self contact of a surface, with friction (explicit dynamics and nonlinear static steps)", &["interaction.contact.edit", "interaction.contact.delete"], ), ready_more( diff --git a/crates/engine/src/cmd/contact.rs b/crates/engine/src/cmd/contact.rs index 1086be7..3be40a8 100644 --- a/crates/engine/src/cmd/contact.rs +++ b/crates/engine/src/cmd/contact.rs @@ -59,7 +59,7 @@ pub const GENERAL: CommandSpec = CommandSpec { params: concat!( r#"{"name": "all", "surface": "skin" (optional: a set of element faces, each in contact with every other: self contact; default every exterior face of the solids), "#, r#""friction": {"static": 0.3, "kinetic": 0.2, "decay": 10} (Coulomb, μ = μk + (μs − μk) e^(−decay × slip rate); default frictionless), "penalty_scale": 1 (0 < scale ≤ 1: a factor on the penalty: explicit, the stiffest that leaves the time increment alone; nonlinear static, the augmented Lagrangian's), "initial_penetration": "adjust" (nodes that start inside: explicit moves them onto the surface, strain-free; nonlinear static takes the overlap out of their gap; both report them) | "refuse" (refuse the analysis, naming the first)"#, - r#"} — single-surface contact of everything that may touch (explicit dynamics; nonlinear static steps refuse it: use pairs; fails if the name is taken)"# + r#"} — single-surface contact of everything that may touch (explicit dynamics, and mortar self-contact in nonlinear static steps; fails if the name is taken)"# ), form: Some(super::forms::CONTACT_GENERAL), kind: CommandKind::Model, diff --git a/crates/model/src/contact.rs b/crates/model/src/contact.rs index ce8a051..38059c0 100644 --- a/crates/model/src/contact.rs +++ b/crates/model/src/contact.rs @@ -1,7 +1,7 @@ //! Contact: which surfaces may touch, and the friction between them. //! //! A contact is a model definition, active in every step that can take it (explicit dynamics, -//! and nonlinear static steps for pairs; the linear analyses refuse contact by name). Its +//! and nonlinear static steps; the linear analyses refuse contact by name). Its //! surfaces are sets with element //! faces, so they survive remeshing like a pressure load does: //! - a **pair**: the faces of `main` against those of `secondary`, both ways (each surface's diff --git a/docs/features.md b/docs/features.md index 55958fa..2188889 100644 --- a/docs/features.md +++ b/docs/features.md @@ -103,7 +103,7 @@ the control channel and AI agents over MCP (docs/mcp.md) run the same commands. | Constraints | Reference Point — A reference point for couplings, loads and boundary conditions | ready | `model.reference_point.create`, `model.reference_point.edit`, `model.reference_point.delete` | | Constraints | Coupling — Kinematic or distributing coupling of a set to a reference point | ready | `model.coupling.create`, `model.coupling.edit`, `model.coupling.delete` | | Constraints | Tie — Tie non-matching meshes together (dual mortar constraints) | ready | `interaction.tie`, `interaction.tie.edit`, `interaction.tie.delete` | -| Contact | General Contact — Contact between everything that may touch, or self contact of a surface, with friction (explicit dynamics) | ready | `interaction.contact.general`, `interaction.contact.edit`, `interaction.contact.delete` | +| Contact | General Contact — Contact between everything that may touch, or self contact of a surface, with friction (explicit dynamics and nonlinear static steps) | ready | `interaction.contact.general`, `interaction.contact.edit`, `interaction.contact.delete` | | Contact | Contact Pair — Contact between two surfaces: with friction in explicit dynamics, mortar contact with friction in nonlinear static steps | ready | `interaction.contact.pair`, `interaction.contact.edit`, `interaction.contact.delete` | | Contact | Find Contacts — Find the parts of the mesh that touch, and make contact pairs of them | ready | `interaction.contact.find` | | Contact | Rigid Wall — Rigid walls for explicit dynamics | coming soon (M10) | | diff --git a/docs/fem.md b/docs/fem.md index c48fd44..d026a15 100644 --- a/docs/fem.md +++ b/docs/fem.md @@ -460,8 +460,12 @@ weighted gap g̃_A = Σ ∫ Φ_A (x_m − x_s)·n dA over the overlaps of its fa facing them, Φ_A the secondary face's own shape functions; ĝ_A = g̃_A / A_A with A_A = ∫ Φ_A over the node's faces. The pressure field is interpolated like the displacements, so a uniform pressure crosses a non-matching interface as the consistent nodal forces of both meshes: the -contact patch test. Linear faces (tri3, quad4: tet4, wedge6, hex8); general contact, quadratic -faces, 2D models and arc-length steps are refused by name. +contact patch test. General (single-surface) contact uses one face list, a set's or every +exterior face of the solids, as both sides: each face against every other one facing it that +shares no node with its element (its neighbours) and that it does not reach through more than +half an element (the far side of a thin wall), paired both ways, so the folds of one body press +on each other symmetrically. Linear faces (tri3, quad4: tet4, wedge6, hex8); quadratic faces, 2D +models and arc-length steps are refused by name. **Segmentation** (`fieldcraft_fem::mortar`): both faces are projected along the secondary face's unit normal onto its plane, the main polygon is clipped by the secondary one