Constitutive model (UMAT) catalog
Every constitutive law is selected by its 5-character umat_name. Since the
modular UMAT framework, four kinds of implementation coexist behind those
names — the calling convention is identical for all of them (same
umat_name, same props, same solver/FEA usage):
modular (native): the composable
MODULengine, configured from a props stream (seesimcoon.modularfor the Python builder).modular (adapter): a legacy name whose dedicated kernel was removed after its equivalence with a
MODULconfiguration was proven against the retained reference kernels — bit-identical for the elastic, power-law and Hill families; within 2e-3 relative for the Voce/Chaboche families, whose legacy incrementalHpupdate differs from the modular closed form (tests intest_modular.pyandTreference_umats); a translator maps the legacy props to the modular configuration at each call.legacy (kept): a dedicated, self-contained implementation kept either for pedagogy (readable single-file reference of the CCP return mapping) or because no modular equivalent exists.
Python (external): the
PYEXTname serves a law written in Python (simcoon.PythonUMAT) through a registered callback; see Constitutive laws in Python (PYEXT).
Small-strain mechanical models
Name |
Physics |
Engine |
Props (in order) |
Notes |
|---|---|---|---|---|
ELISO |
Isotropic elasticity |
modular (adapter) |
E, nu, alpha |
|
ELIST |
Transversely isotropic elasticity |
modular (adapter) |
axis, EL, ET, nuTL, nuTT, GLT, alpha_L, alpha_T |
|
ELORT |
Orthotropic elasticity |
modular (adapter) |
E1, E2, E3, nu12, nu13, nu23, G12, G13, G23, alpha1, alpha2, alpha3 |
|
EPICP |
Von Mises + power-law isotropic hardening |
legacy (kept) |
E, nu, alpha, sigmaY, k, m |
Pedagogical reference of the CCP return mapping |
EPKCP |
Von Mises + power-law isotropic + Prager kinematic |
modular (adapter) |
E, nu, alpha, sigmaY, k, m, kX |
Legacy Prager writes X = kX·a; the modular twin uses X = (2/3)C·a, i.e. C = 1.5·kX (handled by the adapter) |
EPCHA |
Von Mises + Voce + 2x Armstrong-Frederick |
legacy (kept) |
E, nu, alpha, sigmaY, Q, b, C1, D1, C2, D2 |
Pedagogical reference of kinematic hardening in CCP |
EPHIL / EPTRI |
Hill yield + power-law isotropic hardening |
modular (adapter) |
E, nu, alpha, sigmaY, k, m, F, G, H, L, M, N |
Bit-identical to the modular twin (machine precision) |
EPHAC |
Cubic elasticity + Hill + Voce + 2x AF |
modular (adapter) |
E, nu, G, alpha, sigmaY, Q, b, C1, D1, C2, D2, F, G, H, L, M, N |
statev columns beyond the modular layout are unused (see below) |
EPANI |
Cubic elasticity + 9-parameter anisotropic yield + Voce + 2x AF |
modular (adapter) |
E, nu, G, alpha, sigmaY, Q, b, C1, D1, C2, D2, P11, P22, P33, P12, P13, P23, P44, P55, P66 |
P must be an admissible (convex) quadratic form: symmetric with zero row sums on the normal block; an indefinite P yields sqrt(<0) = NaN |
EPDFA |
Cubic elasticity + Deshpande-Fleck-Ashby yield + Voce + 2x AF |
modular (adapter) |
E, nu, G, alpha, sigmaY, Q, b, C1, D1, C2, D2, F, G, H, L, M, N, K |
|
EPCHG |
Cubic elasticity + selectable yield + N-term “Voce” + N-term Chaboche |
modular (adapter) |
E, nu, G, alpha, sigmaY, N_iso, N_kin, criteria(0=Mises, 1=Hill, 2=DFA, 3=anisotropic), (Q_i, b_i) x N_iso, (C_i, D_i) x N_kin, criterion parameters |
The legacy N-term isotropic hardening couples all terms through a single Hp (dHp/dp = sum b_i (Q_i - Hp)): mathematically ONE effective Voce with b_eff = sum(b_i), Q_eff = sum(b_i Q_i)/sum(b_i) — not the standard combined-Voce sum. The adapter maps accordingly. |
EPHIN |
N Hill yield surfaces, each with power-law isotropic hardening |
modular (adapter) |
E, nu, alpha, N, then per surface: sigmaY, k, m, F, G, H, L, M, N |
The removed legacy kernel was defective for N >= 2 (NaN even for identical or inactive second surfaces); the modular engine handles multiple surfaces correctly, so N >= 2 is now functional. |
ZENER |
Generalized KELVIN chain, 1 branch (standard solid) |
legacy (kept) |
E0, nu0, alpha, E1, nu1, etaB1, etaS1 |
No modular equivalent (Kelvin branches in series; the modular viscoelasticity is a generalized Maxwell/Prony model) |
ZENNK |
Generalized KELVIN chain, N branches |
legacy (kept) |
E0, nu0, alpha, N, then per branch: E_i, nu_i, etaB_i, etaS_i |
Same rheology note as ZENER — NOT equivalent to PRONK despite the identical props layout (measured 86% response difference) |
PRONK |
Generalized Maxwell (Prony series), N branches |
legacy (kept) |
E0, nu0, alpha, N, then per branch: E_i, nu_i, etaB_i, etaS_i |
Pedagogical reference; the modular Viscoelasticity mechanism takes the same closed-form step and is identical to it (round-off) |
LLDM0 |
Ductile damage (Lemaitre-Ladeveze-Dufailly) |
legacy (kept) |
see header |
Modular equivalence not yet established (audit pending) |
MODUL |
Composable modular UMAT (elasticity + N mechanisms) |
modular (native) |
self-describing stream — build it with
|
Also available under finite strain (NLGEOM control types 2-6), where
the composition is a Hencky hyperelastic law on the logarithmic
strain; requires |
Shape memory alloys, finite strain, multiscale, plugins
Unchanged dedicated implementations (out of the modular scope):
SMA: SMADI/SMADC/SMAAI/SMAAC (unified), SMRDI/SMRDC/SMRAI/SMRAC (unified with reorientation), SMAMO/SMAMC (monocrystal).
Finite strain: HYPOO (hypoelastic orthotropic), SNTVE (Saint-Venant), NEOHI/NEOHC (Neo-Hookean), MOORI, YEOHH, ISHAH, GETHH, SWANH, HOLZA (invariant-based hyperelasticity); OGDEN (isochoric principal stretches, props =
N, kappa, mu_1, alpha_1, ...). The compressible ones take one optional trailing prop selecting the volumetric term \(U(J)\): absent or 0 for \(\kappa (J \ln J - J + 1)\), 1 for \(\frac{\kappa}{2} (J - 1)^2\) (NEOHI has the latter form built in, with \(\kappa = 2 / D_1\)).HOLZA is the Gasser-Ogden-Holzapfel model, the only anisotropic one of the set: an isotropic neo-Hookean matrix reinforced by \(n\) families of dispersed fibres,
\[W = C_{10} \left(\bar{I}_1 - 3\right) + \sum_i \frac{k_1}{2 k_2} \left[ \exp\left(k_2 \left(\bar{I}^{*}_{4,i} - 1\right)^2\right) - 1 \right] + U(J),\]with \(\bar{I}^{*}_{4,i} = \kappa_d \bar{I}_1 + (1 - 3 \kappa_d) \bar{I}_{4,i}\) and \(\bar{I}_{4,i} = \mathbf{a}_{0,i} \cdot \bar{\mathbf{C}} \, \mathbf{a}_{0,i}\). The dispersion \(\kappa_d \in [0, 1/3]\) interpolates between perfectly aligned fibres (\(\kappa_d = 0\), the Holzapfel-Gasser-Ogden 2000 model) and an isotropic distribution (\(\kappa_d = 1/3\)). The fibre term is inactive wherever \(\bar{I}^{*}_{4,i} < 1\), which is the switch of the original Gasser-Ogden-Holzapfel formulation. Note it is a condition on the generalized invariant, not on fibre compression: once \(\kappa_d > 0\) the term picks up a \(\kappa_d \bar{I}_1\) contribution, so a fibre with \(\bar{I}_{4,i} < 1\) can still be active (at \(\kappa_d = 0.2\) a fibre shortened to 0.39 of its length gives \(\bar{I}^{*}_4 = 1.12\)).
props =
C10, k1, k2, kappa_d, n_fam, a0x_1, a0y_1, a0z_1, ..., kappa, where each \(\mathbf{a}_{0,i}\) is a unit direction in the local material frame (the solver’s material orientation places it globally, as for ELIST/ELORT). From Python the directions are given as asimcoon.Rotationapplied to \(\mathbf{e}_1\), one entry per family, which keeps Euler angles and their gimbal lock off the path to the kernel:sim.modular.HolzapfelElasticity( C10=0.0354, k1=0.0107, k2=7.48, kappa_d=0.0, fibres=sim.Rotation.from_euler('zxz', [[0, 0, 40], [0, 0, -40]], degrees=True), kappa=1000.)
The same potential is available as a MODUL elasticity block, and may be composed with any mechanism. Composed with damage – anisotropic tissue with softening – the kinematics are exact: damage subtracts no inelastic strain (it scales the stiffness instead), so the elastic stretch is the total one and the fibres follow it. Its driving force is the thermodynamic force \(Y = -\partial\psi/\partial D = \psi_0\), the undamaged energy, evaluated as \(\tfrac12\,\boldsymbol{\tau}_{eff} : \mathbf{M}_t : \boldsymbol{\tau}_{eff}\) on the effective stress \(\boldsymbol{\tau}/(1-D)\): exact for a linear block, an approximation of \(\psi_0\) through the tangent compliance for this nonlinear potential.
Warning
Composed with a mechanism that does subtract an inelastic strain (plasticity, viscoelasticity), the fibre convection is approximate. The block carries \(\mathbf{a}_{0,i}\) from the reference configuration and pushes it forward with the elastic stretch, so the inelastic strain does not reorient the fibres. The composition is well posed and converges – the return mapping is handed the anisotropic tangent and its consistency condition holds exactly – but the response is only as good as that assumption: exact while the inelastic strain is small or leaves the fibre directions fixed, degrading as it reorients them. Representing the convection exactly would require the convected directions as state variables, which the additive corotational kinematics of the modular UMAT cannot express (there is no plastic deformation gradient to convect with).
A second, separate caveat applies to viscoelasticity only: every Prony branch is built as an isotropic \(\mathbf{L}_i(E_i, \nu_i)\), so the viscous response carries none of the fibre anisotropy while the equilibrium response does. That is a property of the viscoelastic mechanism’s \((E_i, \nu_i)\) parameterization rather than of HOLZA – a Prony branch cannot follow an ELORT or ELIST block’s symmetry either.
Neither is rejected at run time; both are modelling choices left to the user.
A single scalar damage variable, finally, degrades matrix and fibres at the same rate. The Holzapfel damage literature instead carries separate variables – one on the isotropic term and one per fibre family – since collagen and ground substance damage very differently. simcoon’s damage mechanism is a single scalar, so the composition models uniform softening, not anisotropic damage.
Multiscale: MIHEN, MIMTN, MISCN, MIPLN. Their sub-phases are passed in memory (
phases=, see In-memory Python solver) and theirpropshold only the scheme’s settings:[mp, np]for MIHEN,[mp, np, n_matrix]for MIMTN,[mp, np, n_matrix]or[mp, np, n_matrix, start]for MISCN, nothing for MIPLN (mp,np: integration points of the Eshelby integrals;n_matrix: index of the matrix phase in the list;start: first guess of the self-consistent iteration, 1 Mori-Tanaka (default) or 0 homogeneous strain withn_matrix < 0). The length is checked, so the pre-2.0 layout with its leadingnphasesand file-number slots is refused rather than misread.Plugins: UMEXT (external dylib), UMABA (Abaqus wrapper).
Python: PYEXT (registered Python law;
props/nstatevfrom the object).
State variable (statev) layout for adapter-served names
The modular engine claims the FIRST required_nstatev slots of the caller’s
statev array — always within the legacy allocation, so array sizes never
change. For ELISO/ELIST/ELORT (T_init) and EPHIL/EPTRI
(T_init, p, EP(6)) the column meaning is identical to the removed kernels.
For the Chaboche-family names and EPKCP the columns re-mean: the layout is
T_init | p, EP(6) | back-strains a_i(6) ... in mechanism registration
order; trailing legacy slots are left untouched. Code that read specific
legacy statev columns (e.g. the stored X_i of EPHAC) must be updated to the
modular layout.
Stress measure and tangent rate
Every native simcoon kernel is Kirchhoff-native. In the logarithmic framework an isotropic stored energy per reference volume gives \(\boldsymbol{\tau} = \partial W / \partial \ln \mathbf{V}\) (for an anisotropic one the identity needs \(\boldsymbol{\tau}\) coaxial with \(\mathbf{V}\)), so \(\boldsymbol{\tau}\) is the route stress, and the Cauchy stress is the derived output \(\boldsymbol{\sigma} = \boldsymbol{\tau}/J\), formed only at the boundaries – the solver’s output sinks and the Python wrapper. Nothing on the route carries Cauchy.
The stress measure a kernel writes into sigma is declared, one entry per kernel, in
output_convention_of (umat_smart.cpp). A kernel that fails to declare it is
rejected rather than given a default – a missing declaration is an error of exactly
\(J\), and invisible near \(J = 1\):
kirchhoff– every native kernel.cauchy– only theUMEXT/UMABAplugin adapters, whose contract belongs to the host code (AbaqusDDSDDEis Cauchy-based).select_umat_M_finiteconverts those to \(\boldsymbol{\tau}\) on the way out.
HYPOO is native too: it integrates the corotational Kirchhoff rate,
\(\boldsymbol{\tau}_{n+1} = \boldsymbol{\tau}_n + \mathbf{L} : \Delta\boldsymbol{\varepsilon}^{el}\),
and is the rate counterpart of ELORT (total form
\(\boldsymbol{\tau} = \mathbf{L} : \boldsymbol{\varepsilon}^{el}\)). With the same
\(\mathbf{L}\), isotropic or anisotropic, the two are identical on any path for corates
0 to 3: with the material axes following the body, the transported strain and stress satisfy
the same recursion (a ~74 % orthotropic shear gap measured before 2.1 came from lab-fixed
axes, not from the rate form). They differ under corate 4 even for an isotropic
\(\mathbf{L}\): ELORT is then the total Almansi law
\(\boldsymbol{\tau} = \lambda\,\mathrm{tr}(\mathbf{e}_A)\mathbf{I} + 2\mu\,\mathbf{e}_A\), HYPOO
integrates the Oldroyd rate of \(\boldsymbol{\tau}\), whose isochoric solution is
\(\boldsymbol{\tau} = \mu(\mathbf{b} - \mathbf{I})\). In simple shear both give
\(\tau_{12} = \mu\gamma\); the normal stresses differ, \(\tau_{11} = \mu\gamma^2\),
\(\tau_{22} = \tau_{33} = 0\) for HYPOO against \(\tau_{11} = \tau_{33} = -\lambda\gamma^2/2\),
\(\tau_{22} = -(\lambda/2 + \mu)\gamma^2\) for ELORT. Under corate 5 they differ for an
anisotropic \(\mathbf{L}\) only (about 6 % measured in orthotropic shear): the similarity
transport by a rotation-free stretch does not commute with it. For an
anisotropic \(\mathbf{L}\) the common law \(\boldsymbol{\tau} = \mathbf{L}_R :
\ln\mathbf{V}\) is Cauchy-elastic, not hyperelastic.
Material frame. On the finite route the kernels fed the logarithmic strain (ELISO, ELIST,
ELORT, HYPOO, the plasticity names, MODUL, PYEXT) run in a frame that follows the
material: the accumulated corate rotation for corates 0 to 3, the polar rotation of
\(\mathbf{F}\) for 4 and 5. Their anisotropy axes (orthotropic and transversely isotropic
stiffness, Hill-type criteria, HOLZA fibres in MODUL) therefore rotate with the body, as with
Abaqus *ORIENTATION under NLGEOM, and their tensorial Statev are material-frame
components. The kernels built from \(\mathbf{F}\) (SNTVE, the Neo-Hookean and invariant
family, OGDEN, HOLZA) are objective by construction and keep the lab frame.
The tangent rate is not declared, it is deduced from the solver’s ``corate_type``. Every
kernel receives the solver’s corate_type and must return \(\mathbf{L}_t\) expressed in
it. A kernel that builds its tangent from \(\mathbf{F}\) – the finite hyperelastic family –
converts the spatial (Lie/Oldroyd) closed form of the potential in one step, with
Dtau_LieDD_2_DtauDe_corate; a kernel handed the solver’s already-corotated strain
increment is in that rate for free. Per corate: 0 Jaumann and 1 Green-Naghdi are spin/rate
corrections, 2 (XBM) and 3 (log_R) share the exact spectral map, and 4 (Truesdell) is the
convected box, which is the spatial (Lie) tangent – an identity: the Kirchhoff stress is
transported upper-convected and the strain lower-convected, so the strain is the Almansi strain
\(\mathbf{e}_A = \tfrac12(\mathbf{I} - \mathbf{b}^{-1})\) (the Strain output; see
Read the results). Logarithmic control (control type 3) still prescribes \(\ln\mathbf{V}\)
under corate 4: the solver rebuilds it from the stored strain,
\(\ln\mathbf{V} = -\tfrac12\ln(\mathbf{I} - 2\mathbf{e}_A)\).
5 (log_F) is the chain rule through its own increment \(\mathbf{D}_e = \mathbb{A}^F :
\mathbf{D}\,\Delta t\), \(\mathbb{C}^J : (\mathbb{A}^F)^{-1}\), equal to the log box for
isotropic laws (both finite-difference verified).
Note
The solver transports the total strain, the start stress and the tensorial internal
variables with the variance each corate requires: rotation for 0-3 (in the material frame the
frame-relative increment is the identity, so a kernel is called with
\(\Delta\mathbf{R} = \mathbf{I}\)); for 4, lower-convected strain-like and upper-convected
stress-like quantities; for 5, similarity. For 4 and 5 the dispatcher applies it to the
internal variables each kernel declares in umat_conventions (umat_smart.cpp: EPICP,
EPCHA, the elastic and hyperelastic kernels); a kernel that has not declared them (the
plasticity names served by the modular engine, PYEXT) is refused under corates 4 and 5,
and MODUL under any corate but 3. EPCHA is also refused under corate 4: it stores
\(\mathbf{X}_i = \tfrac23 C_i\,\mathbf{a}_i\), and the Truesdell rate convects the
back-strain and the back-stress differently.
Mechanical work. Wm is the work per reference volume,
\(\int \mathbf{P} : \mathrm{d}\mathbf{F}\). A kernel accumulates
\(\tfrac12(\hat{\boldsymbol{\tau}}_n + \boldsymbol{\tau}_{n+1}) : \Delta\mathbf{e}\) on the strain
increment it is handed, \(\hat{\boldsymbol{\tau}}_n\) being the start stress transported to the
end configuration. Per corate:
0, 1 (Jaumann, Green-Naghdi): \(\Delta\mathbf{e} = \mathbf{D}\,\Delta t\), the kernel work converges to the true work at second order.
2 (XBM): the rate is conjugate, \(\mathbf{D} = (\ln\mathbf{V})^{\circ\log}\), so there is no continuum gap.
3, 5 (log_R, log_F): \(\boldsymbol{\tau} : \dot{\mathbf{e}} \neq \boldsymbol{\tau} : \mathbf{D}\) as soon as \(\boldsymbol{\tau}\) is not coaxial with \(\mathbf{V}\) (anisotropy, plasticity).
4 (Truesdell): the kernel work is exactly the trapezoid \(\tfrac12(\mathbf{S}_n + \mathbf{S}_{n+1}) : \Delta\mathbf{E}\).
Under 2, 3 and 5 the solver replaces the kernel work by the midpoint stress power with both
stresses in the lab frame, \(\tfrac12(\boldsymbol{\tau}_n + \boldsymbol{\tau}_{n+1}) :
\mathrm{sym}\big(2(\mathbf{F}_1 - \mathbf{F}_0)(\mathbf{F}_1 + \mathbf{F}_0)^{-1}\big)\), which is the
trapezoid of \(\mathbf{P} : \mathrm{d}\mathbf{F}\) itself and zero under a rigid rotation (Delta_work_conjugacy).
The difference is added to \(W_m\) and \(W_m^r\), so \(W_m^r\) then holds the stored
energy plus the work the rate does not conjugate: under 3 and 5, in non-coaxial states, it is not
a state function. simcoon.umat() does the same when it is given
\(\mathbf{F}_0, \mathbf{F}_1\), recovering the lab start stress from the one it is passed
(transported by the caller) as \(\mathrm{sym}(\Delta\mathbf{R}^{-1}\hat{\boldsymbol{\tau}}_n\Delta\mathbf{R})\).
Note
MODUL passes corate 3 unconditionally rather than the solver’s value, because it
evaluates its potential at \(\mathbf{V}^{el}\) in the corotated frame
(\(\mathbf{R} = \mathbf{I}\)), where the log box with respect to
\(\ln \mathbf{V}^{el}\) is
\(\partial \boldsymbol{\tau} / \partial \boldsymbol{\varepsilon}^{el}\). Any other
corate is already refused upstream under NLGEOM, so passing one down would not be more
general – it would be wrong.
The Python contract. sim.umat returns Cauchy stress and the Kirchhoff box
tangent \(\partial \hat{\boldsymbol{\tau}} / \partial \mathbf{D}_e\) with no \(J\),
and takes corate= (default 3, log_R) selecting the rate that tangent is expressed
in. The default is contract-preserving: corates 2 and 3 resolve to the same exact map, so it
returns precisely the box the finite kernels used to produce unconditionally. Rescaling that
tangent by \(1/J\) at the boundary would break Lt_convert by exactly \(J\).
Tangent-operator mode
All models receive the solver’s tangent_mode (named constants in
parameter.hpp / sim.tangent_*): 0 = none (Lt = elastic L, explicit
integration), 1 = continuum, 2 = algorithmic/Simo-Hughes (default),
3 = closest-point (reserved). Pre-2.0 numbering was 0 = continuum,
1 = algorithmic — see Use the solver for the migration note. The
finite-strain hyperelastic models ignore the mode (their tangent is always
the exact one of the hyperelastic law). So do the linear viscoelastic models (ZENER,
ZENNK, PRONK and their thermomechanical versions) except for mode 0: their
backward-Euler step is solved in closed form, so the tangent, and for the thermomechanical
versions dSdT and the heat-source derivatives drdE, drdT, are the exact
derivatives of the discrete update. For plasticity, the algorithmic operator is exact with a
von Mises criterion and isotropic hardening only; with kinematic hardening or a Hill, DFA,
Drucker or Tresca criterion the cutting-plane update is path dependent and the operator is
approximate (see the note on the scope of the algorithmic tangent in Use the solver).
Validation and performance
Each adapter-served name is validated at two levels:
Translator correctness: a pytest equivalence test (
simcoon-python-builder/test/test_core/test_modular.py, the*_matches_modulfamily) proves the legacy name and the explicitMODULconfiguration are bit-identical through the solver.Independent physics: the removed legacy kernels are retained VERBATIM as test-only reference oracles under
test/Libraries/Umat/reference_kernels/(compiled only into theTreference_umatsgtest, never intolibsimcoon, not dispatchable by name). Every adapter is driven side by side with its reference kernel on a cyclic strain path each test run — machine precision for the elastic/power-law families, < 2e-3 for the Voce/Chaboche family (legacy incremental vs modular closed-form Voce integration).
A benchmark row per family lives in bench/bench_legacy_vs_modular.py:
results show no measurable adapter overhead, and the modular
engine runs at 0.8-1.2x the speed of the removed kernels on all families.