WIP (parked): folding robustness, stabilization, mesh.revolve, boot-seal profile

Parked work for #182/#185 (not for merge as is):
- contact: held active set with primal-dual updates replaces the
  inconsistent ENGAGED_BAND tangent after chattering (moves the
  nl-friction-sliding-blocks fixture by 4.5e-8; not re-blessed)
- nonlinear: opt-in viscous stabilization (step 'stabilization',
  calibrated on the first increment), Abaqus STABILIZE, LS-DYNA refusal
- ordering: graph (level-structure) nested dissection, chosen when it
  fills less: half the fill on the revolved boot, factor time 62 s -> 25 s
- engine: mesh.revolve command (2D profile -> hex8/wedge6, tags kept)
- engine: sample/boot.rs boot-seal profile, axisymmetric and 3D scripts
Scratch still in the code: FC_TRACE/TIMES timing prints, NO_BAND/STAB/
SQUEEZE env hooks in tests, boot_axisymmetric_scratch test.

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 committed 2026-10-14 17:54:43 -04:00
1 parent 227c4544ed
commit 98eaede2dd
18 files changed
+1111 -57

No files matched your search

+19
View File
@@ -155,6 +155,13 @@ pub struct NonlinearStatic {
/// lengths in proportion. `None`: load control.
#[serde(skip_serializing_if = "Option::is_none")]
pub arc_length: Option<ArcLength>,
/// Viscous stabilization of local instabilities (wrinkling, folding, snap-through of a
/// part under displacement control): damping forces α D (u − uₙ)/Δt against each
/// increment's motion, with D the diagonal of the step's first tangent and Δt the increment
/// as a fraction of the step, so α is about the fraction of the forces the damping takes
/// where the motion is smooth. `None`: none.
#[serde(skip_serializing_if = "Option::is_none")]
pub stabilization: Option<f64>,
}
/// The constraint of an arc-length step.
@@ -242,6 +249,7 @@ impl Default for NonlinearStatic {
load_path: None,
imperfection: None,
arc_length: None,
stabilization: None,
}
}
}
@@ -273,6 +281,14 @@ impl NonlinearStatic {
}
finite("imperfection scale", imp.scale)?;
}
if let Some(a) = self.stabilization {
if !(a > 0.0 && a <= MAX_STABILIZATION) {
return Err(Error::Invalid(format!("the stabilization is a damping fraction in (0, {MAX_STABILIZATION}], got {a}")));
}
if self.arc_length.is_some() {
return Err(Error::Invalid("an arc-length step follows instabilities along its path; it takes no stabilization".into()));
}
}
let initial = fraction("initial increment", self.initial_increment)?;
let min = fraction("minimum increment", self.min_increment)?;
let max = fraction("maximum increment", self.max_increment)?;
@@ -331,6 +347,9 @@ impl NonlinearStatic {
}
}
/// The largest damping fraction of a nonlinear step's stabilization.
pub const MAX_STABILIZATION: f64 = 1.0;
/// Most time increments of a transient heat transfer step.
pub const MAX_HEAT_INCREMENTS: f64 = 100_000.0;