forked from 1b-agent/fieldcraft-upstream
fem: J2 plasticity at the implicit material point, finite and small strain
The radial return of the explicit update is now J2::radial_return, called by both solvers, with the consistent tangent J2::tangent (Simo & Hughes 1998, Box 3.2). The new elastoplastic module gives the implicit material point: Simo's multiplicative plasticity with the exponential return map in the principal logarithmic strains (CMAME 99, 1992) and its spatial tangent through the Daleckii-Krein divided differences of the logarithm, and the additive radial return of small strain with kinematic hardening. MaterialModel::Plastic carries it, decoupled (deviatoric return, Hencky volume) so hybrid elements take it. The element loops of finite.rs gain small-strain kinematics for inelastic materials and pass history through the mixed path. Every tangent is checked against central differences, element by element, from a plastic history. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm
This commit is contained in:
1 parent
3ecb7c6883
commit
72940fe78f
8 files changed
+908
-137
No files matched your search
@@ -62,6 +62,7 @@
|
||||
use fieldcraft_fem::constitutive::MaterialModel;
|
||||
use fieldcraft_fem::dense::Matrix;
|
||||
use fieldcraft_fem::element::{Extrapolation, extrapolation};
|
||||
use fieldcraft_fem::finite::Kinematics;
|
||||
use fieldcraft_fem::quadrature::Rule;
|
||||
use fieldcraft_fem::{DofKind, DofSet, ElementType, PointStress, face, von_mises};
|
||||
use fieldcraft_model::{Extent, Load, Model, NonlinearStatic, Procedure, Step};
|
||||
@@ -250,7 +251,7 @@ impl Problem<'_> {
|
||||
}
|
||||
let material = self.materials.get(e).ok_or_else(|| Error::Internal("element material".into()))?;
|
||||
let mut updated = committed.to_vec();
|
||||
let r = kernel.finite_strain(material, &ue, committed, &mut updated, tangent).map_err(at)?;
|
||||
let r = kernel.nonlinear(material, &ue, Kinematics::Finite, committed, &mut updated, tangent).map_err(at)?;
|
||||
Ok((r.force, r.tangent, updated))
|
||||
}
|
||||
|
||||
@@ -833,7 +834,7 @@ fn finish(
|
||||
let kernel = el.kernel()?;
|
||||
let points = if problem.finite {
|
||||
let material = problem.materials.get(i).ok_or_else(|| Error::Internal("element material".into()))?;
|
||||
kernel.finite_strain_stresses(material, &ue, committed.get(i).map(Vec::as_slice).unwrap_or_default())
|
||||
kernel.nonlinear_stresses(material, &ue, Kinematics::Finite, committed.get(i).map(Vec::as_slice).unwrap_or_default())
|
||||
} else {
|
||||
let per_node: Vec<[f64; 3]> = el.nodes.iter().map(|n| displacement.get(*n).copied().unwrap_or_default()).collect();
|
||||
kernel.stresses_with(&el.d, &per_node, None)
|
||||
|
||||
@@ -11,6 +11,7 @@ use fieldcraft_fem::beam::{Beam, BeamSection};
|
||||
use fieldcraft_fem::constitutive::MaterialModel;
|
||||
use fieldcraft_fem::dense::Matrix;
|
||||
use fieldcraft_fem::element::{Formulation, Solid, ThermalStrain};
|
||||
use fieldcraft_fem::finite::Kinematics;
|
||||
use fieldcraft_fem::plane::{Plane, Theory};
|
||||
use fieldcraft_fem::shell::{Shell, ShellSection};
|
||||
use fieldcraft_fem::truss::{Truss, young_modulus};
|
||||
@@ -113,27 +114,30 @@ impl Kernel<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Finite-strain internal forces and tangent ([`fieldcraft_fem::finite`]) for the element's
|
||||
/// displacements `u` (its degrees of freedom in order: 3 per node, or 2 for 2D elements).
|
||||
pub fn finite_strain(
|
||||
/// Nonlinear internal forces and tangent ([`fieldcraft_fem::finite`]) for the element's
|
||||
/// displacements `u` (its degrees of freedom in order: 3 per node, or 2 for 2D elements),
|
||||
/// total Lagrangian or with small strain.
|
||||
pub fn nonlinear(
|
||||
&self,
|
||||
m: &MaterialModel,
|
||||
u: &[f64],
|
||||
kin: Kinematics,
|
||||
committed: &[f64],
|
||||
updated: &mut [f64],
|
||||
tangent: bool,
|
||||
) -> fieldcraft_fem::Result<fieldcraft_fem::finite::Finite> {
|
||||
match self {
|
||||
Kernel::Solid(s) => s.finite_strain(m, u.as_chunks::<3>().0, committed, updated, tangent),
|
||||
Kernel::Plane(p) => p.finite_strain(m, u.as_chunks::<2>().0, committed, updated, tangent),
|
||||
Kernel::Solid(s) => s.nonlinear(m, u.as_chunks::<3>().0, kin, committed, updated, tangent),
|
||||
Kernel::Plane(p) => p.nonlinear(m, u.as_chunks::<2>().0, kin, committed, updated, tangent),
|
||||
}
|
||||
}
|
||||
|
||||
/// Cauchy stress and logarithmic strain at the integration points, as [`Self::finite_strain`].
|
||||
pub fn finite_strain_stresses(&self, m: &MaterialModel, u: &[f64], committed: &[f64]) -> fieldcraft_fem::Result<Vec<PointStress>> {
|
||||
/// Cauchy stress and strain (logarithmic at finite strain) at the integration points, as
|
||||
/// [`Self::nonlinear`].
|
||||
pub fn nonlinear_stresses(&self, m: &MaterialModel, u: &[f64], kin: Kinematics, committed: &[f64]) -> fieldcraft_fem::Result<Vec<PointStress>> {
|
||||
match self {
|
||||
Kernel::Solid(s) => s.finite_strain_stresses(m, u.as_chunks::<3>().0, committed),
|
||||
Kernel::Plane(p) => p.finite_strain_stresses(m, u.as_chunks::<2>().0, committed),
|
||||
Kernel::Solid(s) => s.nonlinear_stresses(m, u.as_chunks::<3>().0, kin, committed),
|
||||
Kernel::Plane(p) => p.nonlinear_stresses(m, u.as_chunks::<2>().0, kin, committed),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user