solver: mortar contact in 2D models

Plane strain, plane stress and axisymmetric models take contact pairs and
general (self) contact on the linear edges of tri3 and quad4 elements:
edges oriented out of their elements, the edge mortar of fem with the
thickness or 2 pi r in the weights, the element's area over the edge's
length as the thickness under it, and the in-plane rows of the tangent
blocks. Verified by the contact patch test in plane strain and
axisymmetric (to 1e-9 small sliding, 1e-4 finite), Hertz's line contact
on quad4 edges (Johnson 1985, 4.3; equal to the hex8 model's to 1e-5),
and a hybrid rubber C-ring closing on itself that moves node for node as
the one-layer solid ring.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
This commit is contained in:
jyvikoandClaude Opus 5.5 authored and Irakli Kourtis committed 2026-10-14 16:30:44 -04:00
1 parent 6baa189231
commit 227c4544ed
20 files changed
+1579 -81

No files matched your search

+6 -3
View File
@@ -388,13 +388,16 @@ impl Model {
}
}
// Contacts: their surfaces are element faces of solids.
// Contacts: their surfaces are element faces of solids, or edges of 2D elements.
for (name, c) in &self.contacts {
for set in c.surfaces.sets() {
let faces = &set_of(set).faces;
let solid = |f: &crate::ElementFace| self.elements.get(&f.element).is_some_and(|e| e.kind.dimension() == 3);
if faces.is_empty() {
d.error(format!("contact `{name}`"), format!("set `{set}` has no element faces (a contact surface is a set of faces)"));
if faces.is_empty() && resolved.planar_edges(set).is_empty() {
d.error(
format!("contact `{name}`"),
format!("set `{set}` has no element faces (a contact surface is a set of faces, or of 2D element edges)"),
);
} else if !faces.iter().all(solid) {
d.error(
format!("contact `{name}`"),
+2 -2
View File
@@ -3,12 +3,12 @@
//! A contact is a model definition, active in every step that can take it (explicit dynamics,
//! 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:
//! faces (in a 2D model, element edges), so they survive remeshing like a pressure load does:
//! - a **pair**: the faces of `main` against those of `secondary`, both ways (each surface's
//! nodes are kept out of the other's faces, so neither surface is privileged);
//! - **general** contact: every face against every other face of one surface (single-surface or
//! self contact, for folding and buckling), or of every exterior face of the model's solid
//! elements when no surface is named.
//! elements (in a 2D model every exterior edge of its 2D elements) when no surface is named.
//!
//! **Friction** is Coulomb's law with a coefficient that falls from its static to its kinetic
//! value with the slip rate γ̇: μ = μ_k + (μ_s − μ_k) e^{−d γ̇} (the exponential decay of