forked from 1b-agent/fieldcraft-upstream
solver: mortar contact in nonlinear static steps
Frictionless contact pairs enforced by an augmented Lagrangian: nodal pressures from the mortar weighted gaps, Uzawa updates after each converged increment until the gaps are within 1e-5 of the element thickness, and the consistent tangent (outer products of the weighted gap gradients and the pressure-weighted Hessians from the automatic differentiation of the mortar integrals). Finite sliding searches and integrates on the current configuration every evaluation; without nonlinear geometry the pairs and their mortar integrals are fixed in the reference configuration (small sliding, linear and exact). The tangent's pattern takes the face pairs' blocks; the step cuts back when the active set chatters. Initial overclosure is offset or refused; general contact, 2D models and arc length are refused by name; the linear analyses refuse contact by name instead of the mesh. With contact the convergence force scale comes from the converged states, the loads and the current state. The loads-and-reactions balance check takes the nodal reactions into its scale (no spurious warning for a part squeezed between held faces). Tests: the contact patch test on non-matching hex8/tet4 meshes (exact with small sliding, to 1e-4 with finite sliding), Hertz cylinder on a flat (peak pressure within 3%, half-width bracketed) with quadratic Newton convergence, overclosure, thread-count determinism and the refusals; Hertz sphere on a flat (heavy). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
This commit is contained in:
1 parent
37f338c9e8
commit
8871f6721d
8 files changed
+1392
-25
No files matched your search
@@ -105,6 +105,30 @@ impl NodeGraph {
|
||||
NodeGraph { adjacency }
|
||||
}
|
||||
|
||||
/// The graph with more blocks, each coupling all its slots (contact: the slots a contact
|
||||
/// element couples change with the deformation).
|
||||
pub fn with_blocks<'a>(&self, blocks: impl Iterator<Item = &'a [usize]>) -> NodeGraph {
|
||||
let mut adjacency = self.adjacency.clone();
|
||||
let mut touched = Vec::new();
|
||||
for b in blocks {
|
||||
for &a in b {
|
||||
if let Some(row) = adjacency.get_mut(a) {
|
||||
row.extend_from_slice(b);
|
||||
touched.push(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
touched.sort_unstable();
|
||||
touched.dedup();
|
||||
for a in touched {
|
||||
if let Some(row) = adjacency.get_mut(a) {
|
||||
row.sort_unstable();
|
||||
row.dedup();
|
||||
}
|
||||
}
|
||||
NodeGraph { adjacency }
|
||||
}
|
||||
|
||||
/// Nonzeros of the dof-level matrix: a dense block per node pair.
|
||||
pub fn entries(&self, layout: &DofLayout) -> usize {
|
||||
self.adjacency.iter().enumerate().map(|(a, row)| layout.range(a).len() * row.iter().map(|b| layout.range(*b).len()).sum::<usize>()).sum()
|
||||
|
||||
Reference in new issue
Block a user