forked from 1b-agent/fieldcraft-upstream
Implicit solver: reference points, couplings, moments, wedge6 (M4) (#26)
* fem: wedge6 element (triangle × interval, 3 × 2 points), patch and cantilever tests Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm * solver: reference points, kinematic and distributing couplings, moments by constraint elimination Coupled reference points get six degrees of freedom; kinematic couplings are rigid links, distributing couplings least-squares interpolation constraints. Every constraint row and prescribed value is eliminated master-slave (Abel-Shephard pivot choice), so the reduced matrix stays SPD; no coupling gives the old elimination bit for bit. Verified: rigid motion of a coupled block, clamping through a point, distributing tension vs pressure, bending and tube torsion. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm * engine: reference point results in solve.static and solve.probe Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm * docs: couplings, moments and wedge6 in the solver docs, literature and roadmap Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm * solver: simplify constraint elimination and reference point plumbing Rows combine by one sort; T_f transposed once; K and M reduced in one pass on a shared pattern; prescribed motion computed once; reference point loads and BCs go through Resolved like node ones (Mesh::label_dofs); one dof-direction rule; StepResult::locate for probes; dead Csr::restrict removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm * solver: refuse oversized reductions before allocating them A held distributing coupling point makes a dense (3N)^2 block; estimate it from the constraint rows and refuse it against the factorization's memory budget with a clear message, before anything is built. Other reductions with dependents count their entries first (stopping at the budget) and reserve fallibly. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm --------- Co-authored-by: jyviko <2501648+jyviko@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
18 files changed
+1502
-199
No files matched your search
@@ -179,13 +179,14 @@ fn cantilever_tip_deflection_and_convergence() {
|
||||
let meshes = [[5, 1, 1], [10, 2, 2], [20, 4, 4], [40, 8, 8]];
|
||||
let hex8 = study(ElementKind::Hex8, full(), &meshes, "hex8");
|
||||
let tet4 = study(ElementKind::Tet4, full(), &meshes, "tet4");
|
||||
for (name, e) in [("hex8", &hex8), ("tet4", &tet4)] {
|
||||
let wedge6 = study(ElementKind::Wedge6, full(), &meshes, "wedge6");
|
||||
for (name, e) in [("hex8", &hex8), ("tet4", &tet4), ("wedge6", &wedge6)] {
|
||||
let rates: Vec<f64> = e.windows(2).map(|w| (w[0] / w[1]).log2()).collect();
|
||||
eprintln!(" {name} convergence rates {rates:.2?}");
|
||||
assert!(e.windows(2).all(|w| w[1] < w[0]), "{name} converges monotonically");
|
||||
assert!(*rates.last().unwrap() > 1.5, "{name} approaches second order: {rates:?}");
|
||||
}
|
||||
assert!(hex8[3] < 0.04 && tet4[3] < 0.12, "{hex8:?} {tet4:?}");
|
||||
assert!(hex8[3] < 0.04 && tet4[3] < 0.12 && wedge6[3] < 0.04, "{hex8:?} {tet4:?} {wedge6:?}");
|
||||
}
|
||||
|
||||
/// Lamé's thick cylinder under internal pressure, plane strain (u_z = 0 on both ends), quarter
|
||||
|
||||
Reference in new issue
Block a user