linearElasticMisesPlastic
This page documents the small-strain elasto-plastic mechanical law with Hookean elasticity and von Mises (J2) plasticity. The runtime type is:
linearElasticMisesPlastic
The return-mapping algorithm is the radial return of Box 3.2 in Simo and Hughes, Computational Inelasticity (1998). The implementation is described in P. Cardiff, Z. Tuković, P. De Jaeger, M. Clancy and A. Ivanković (2017), A Lagrangian cell-centred finite volume method for metal forming simulation, 10.1002/nme.5345.
User Guide
What it computes
For each cell and each boundary face the law performs an elastic trial followed by a radial return:
sTrial = 2*mu*(dev(epsilon) - dev(epsilonP.oldTime()))
fTrial = mag(sTrial) - sqrt(2/3)*sigmaY.oldTime()
If fTrial is below SMALL the step is elastic. Otherwise the return direction is plasticN = sTrial/mag(sTrial) and a plastic multiplier increment DLambda is computed. The deviatoric and hydrostatic parts are then recombined:
DEpsilonP = DLambda*plasticN
s = sTrial - 2*mu*DEpsilonP
sigmaHyd = K*tr(epsilon)
sigma = sigmaHyd*I + s
sigmaHyd is routed through updateSigmaHyd(), so it comes from the smoothed pressure equation when solvePressureEqn is enabled.
Hardening input
The post-yield behaviour is supplied as a table of equivalent plastic strain versus yield stress, read by an interpolationTable. The number of rows in that table decides the algorithm:
| Rows | Behaviour | Solution method |
|---|---|---|
| 1 | Perfect plasticity | Closed form |
| 2 | Linear hardening | Closed form, modulus Hp |
| 3 or more | Nonlinear hardening | Newton iteration per cell |
With one or two rows, DLambda = fTrial/(2*mu), divided by 1 + Hp/(3*mu) when the linear plastic modulus Hp is non-zero. With three or more rows a local Newton loop solves the yield function to a relative tolerance of 1e-8 in at most 100 iterations, using a first-order finite difference derivative with a step of 1e-6; a warning is printed if it fails to converge.
Model options
| Entry | Required | Description |
|---|---|---|
E | with nu | Young's modulus, [1 -1 -2 0 0 0 0] |
nu | with E | Poisson's ratio, dimensionless |
mu | with K | Shear modulus, [1 -1 -2 0 0 0 0] |
K | with mu | Bulk modulus, [1 -1 -2 0 0 0 0] |
rho | yes | Density, [1 -3 0 0 0 0 0] |
file or fileName | yes | Hardening table file |
outOfBounds | yes | interpolationTable bounds handling |
As for linearElastic, the elastic constants are given as either the E/nu pair or the mu/K pair, and a missing pair is a fatal error.
The hardening table entries are those of the standard OpenFOAM interpolationTable constructed from a dictionary. Tutorials write the file key as "file|fileName" so that the same dictionary works across forks, and set outOfBounds clamp. The referenced file contains a list of (plasticStrain yieldStress) pairs.
Two further entries are read outside the material sub-dictionary or in a way worth flagging:
| Entry | Where | Description |
|---|---|---|
maxDeltaErr | controlDict | Target plastic-strain integration error |
tangentEps | material dict | Perturbation for the numerical tangent |
maxDeltaErr defaults to 0.01 and is only consulted when the solid model requests adaptive time-stepping through newDeltaT(). tangentEps is read with lookup() — that is, it is required, with no default — but only inside materialTangentField(), so it is needed only by the block-coupled and PETSc SNES solid models.
The constructor also reads a solvePressureEquation switch (default no),but that member is never used anywhere else in the class. The switch thatactually takes effect is the base-class solvePressureEqn. Do not rely onsolvePressureEquation.
planeStress yes is a fatal error. The header suggests the workaround of solving in 3-D with a symmetryPlane back patch and a traction-free front patch.
Recommended dictionary setup
planeStress no;
mechanical
(
aluminium
{
type linearElasticMisesPlastic;
rho rho [1 -3 0 0 0 0 0] 2700;
E E [1 -1 -2 0 0 0 0] 70e9;
nu nu [0 0 0 0 0 0 0] 0.3;
"file|fileName" "$FOAM_CASE/constant/plasticStrainVsYieldStress";
outOfBounds clamp;
solvePressureEqn no;
}
);
with constant/plasticStrainVsYieldStress containing, for example:
(
(0 250e6)
(0.1 300e6)
(0.5 400e6)
)
Field glossary
Written to the time directory (AUTO_WRITE):
sigmaY,sigmaYf,pSigmaY: current yield stress at cells, faces and points. All three areREAD_IF_PRESENT, so a restart picks up the hardened state.epsilonP,epsilonPf,pEpsilonP: accumulated plastic strain tensor.epsilonPEq,epsilonPEqf,pEpsilonPEq: accumulated equivalent plastic strain.DEpsilonP,DEpsilonPf: plastic strain increment for the current step.DEpsilonPEq,DEpsilonPEqf: equivalent plastic strain increment.activeYield:1in cells that yielded in the current step,0elsewhere.
Internal only: plasticN, plasticNf, pPlasticN (return direction), DLambda, DLambdaf, pDLambda (plastic multiplier increment) and DSigmaY, DSigmaYf, pDSigmaY (yield-stress increment).
updateTotalFields() prints the maximum DEpsilonPEq, the maximum epsilonPEq and the number of actively yielding cells at the end of each time step; those three lines are the quickest health check on a plastic run.
Developer Notes
Class role
linearElasticMisesPlastic derives from mechanicalLaw and maintains a complete triple of state fields — cell, face and point — for every plastic quantity. This is what allows it to serve the cell-centred, face-based (uns) and vertex-centred solid models from one class. It is compiled for all three forks, appearing in both Make/files.openfoam and Make/files.foamextend.
Note that the class is registered with a debug level of 1, unlike the other laws in this subsection which use 0.
Construction
The initialiser list builds the interpolationTable first, because the initial yield stress stressPlasticStrainSeries_(0.0) is needed as the uniform value of sigmaY, sigmaYf and pSigmaY. The body then forces old-time storage for every state field, reads the elastic pair, and classifies the hardening as perfect, linear or nonlinear, computing Hp_ in the linear case.
Key methods
updatePlasticity(): the per-point kernel. It is called once per cell and once per boundary face fromcorrect(), and decides between the elastic branch and the return mapping.newtonLoop(): local Newton solve forDLambdain the nonlinear hardening case, callingyieldFunction()twice per iteration.correct(volSymmTensorField&): the full cell-centred update, ending withupdateSigmaHyd(). The surface overload delegates to a sharedepsilon-taking implementation.residual(): relative change inDEpsilonP(orDEpsilonPf, if a face gradient field exists) between outer iterations. This feeds the solid model'smaterialTolerancecheck.newDeltaT(): estimates the plastic-strain time integration error from the rotation of the return direction over the step, following Lee and Bathe (1994), and scalesdeltaTso that the error matchesmaxDeltaErr. It warns if the error exceeds 50 times the target.impK(),impKdiagTensor(): scalar and diagonal-tensor implicit stiffnesses.materialTangentField(): builds a per-face 6x6 tangent by numerical perturbation ofgrad(D)f, one symmetric-tensor component at a time. The branch is preceded by a commented-outnumericalTangentlookup; there is currently no analytic alternative.
Extension points
- Replacing the
interpolationTablewith a run-time selectable hardening law would remove the row-count-based dispatch in the constructor. - The Newton loop constants (
LoopTol_,MaxNewtonIter_,finiteDiff_) are compile-time members rather than dictionary entries; exposing them would help for materials with steep hardening curves. - Kinematic hardening would require a back-stress field alongside
sigmaYand a modifiedsTrial.
The source is at linearElasticMisesPlastic.C.
Tutorials
Cases that select linearElasticMisesPlastic:
solids/elastoplasticity/perforatedPlate