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}`"),