forked from 1b-agent/fieldcraft-upstream
FEM foundation A: DofKind/DofLayout, shape-function library with Hessians, solvers on DofLayout (#35)
* fem: DofKind/DofLayout and the shape-function library with second derivatives DofKind (Ux..Rz, T, P), DofSet, ElementDofs (per-node kinds and condensed internal unknowns) and DofLayout: mesh nodes by label, kinds in order, then reference points. basis::Basis covers line2/3, tri3/6, quad4/8/9, tet4/10, wedge6/15, pyramid5, hex8/20/27 with values, first and second natural derivatives (second-order forward AD, fem::jet) and the physical gradients, Hessians and Laplacians with the map's second-derivative term. Tested for Kronecker delta, partition of unity, polynomial completeness, finite differences, affine and curved maps. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm * solver, explicit: number degrees of freedom with DofLayout The implicit mesh numbers its unknowns with a DofLayout (mesh nodes by label with the kinds their elements declare, then six per coupled reference point); assembly adds element blocks by (node, DofKind), so a node may carry any mix of kinds; couplings, boundary conditions, loads and results address (node, kind). The explicit system keeps node-major translations, now checked against its layout (NODE_DOFS). Solid formulations declare their ElementDofs. Every static, frequency and explicit result of the solver, explicit, engine and io test suites hashes bit-identically before and after (957 results). docs/fem.md describes the DOF model and the shape-function conventions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm * fem, solver: simplify after review Block offsets resolved once per node pair; add_scalar/add_diagonal take the kinds like add_block; one checked Jacobian inverse (dense::positive_inverse) for the solid kernels and the basis library; static natural-node tables; the Hessian path inverts the Jacobian once. 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:
16 files changed
+1805
-192
No files matched your search
@@ -38,7 +38,7 @@ use modelcraft_fem::material::stress;
|
||||
use modelcraft_fem::uniform::UniformStrain;
|
||||
use modelcraft_model::{BulkViscosity, HourglassKind};
|
||||
|
||||
use crate::system::{Material, System};
|
||||
use crate::system::{Material, NODE_DOFS, System};
|
||||
|
||||
/// Scratch vectors and the element state of the latest evaluation.
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -82,13 +82,13 @@ impl Workspace {
|
||||
}
|
||||
|
||||
pub(crate) fn gather<const N: usize>(x: &[f64], nodes: &[usize; N]) -> [[f64; 3]; N] {
|
||||
nodes.map(|n| [0, 1, 2].map(|k| x.get(3 * n + k).copied().unwrap_or(0.0)))
|
||||
nodes.map(|n| [0, 1, 2].map(|k| x.get(NODE_DOFS * n + k).copied().unwrap_or(0.0)))
|
||||
}
|
||||
|
||||
/// Add a node's vector into a per-degree-of-freedom vector.
|
||||
pub(crate) fn add_at(f: &mut [f64], node: usize, v: &[f64; 3]) {
|
||||
for (k, c) in v.iter().enumerate() {
|
||||
if let Some(x) = f.get_mut(3 * node + k) {
|
||||
if let Some(x) = f.get_mut(NODE_DOFS * node + k) {
|
||||
*x += c;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user