White box / Analysis methods / Composed nonlinear routes

Corotational J2

Composed formulation · assumptions, essential equations, full derivation, algorithm, code and verification references.

Browse another sheet Analysis methods / Composed nonlinear routes
Analysis methodsComposed nonlinear routesSheet 1 / 2
Composed formulationQUALIFIED_BOUNDED · formal acceptance is HEX8-only

Large rigid rotation is separated from a small-local-strain additive J2 law; this is not multiplicative finite-strain plasticity.

01 Model and scope

At each integration point, the deformation gradient is split into a proper rotation R and a right stretch U. The rotation is removed before a small-strain J2 update on U−I; tensor history is transported into the new corotated frame. This supports large rigid rotation with bounded local strain, not arbitrary finite-strain plasticity.

Read the kinematics, constitutive law and solution lifecycle together. A component's evidence does not qualify their combination.

Route assumptions and calculation checks

  1. Polar decomposition removes rigid rotation before evaluating the bounded Biot-like local strain U−I; tensor history is transported between frames.
  2. The element tangent is a symmetrized central difference at a fixed committed state, not an exact analytical consistent tangent.
  3. Formal acceptance is owner-accepted bounded HEX8 only. TET10/HEX20 extensions have limited evidence; no multiplicative finite-strain plasticity is implemented.

02 Essential equations and symbols

F=RU,RTR=I,det⁡R=1\mathbf F=\mathbf R\mathbf U,\quad\mathbf R^T\mathbf R=\mathbf I,\quad\det\mathbf R=1εcorot=U−I,∥εcorot∥F≤0.05  by default\boldsymbol{\varepsilon}_{corot}=\mathbf U-\mathbf I,\quad\|\boldsymbol{\varepsilon}_{corot}\|_F\le0.05\;\text{by default}P=Rσlocal,fint,a=∑gwgdet⁡(J0,g)Pg∇XNa\mathbf P=\mathbf R\boldsymbol{\sigma}_{local},\quad\mathbf f_{int,a}=\sum_gw_g\det(\mathbf J_{0,g})\mathbf P_g\nabla_XN_aKFD[:,j]=fint(u+hej;Sn)−fint(u−hej;Sn)2h\mathbf K_{FD}[:,j]=\frac{\mathbf f_{int}(\mathbf u+h\mathbf e_j;S_n)-\mathbf f_{int}(\mathbf u-h\mathbf e_j;S_n)}{2h}

Definitions and conventions

F=RUF = RU
Right polar decomposition; R is proper rotation and U is symmetric positive stretch.
εcorot=U−I\varepsilon{}corot = U-I
Biot-like corotated strain used by this implementation; limited by a configured norm bound.
Sₙ, Rₙ
Accepted constitutive history and corotation frame at the prior increment.
P=RσlocalP = R\sigma{}local
First Piola stress used to assemble internal force in the reference configuration.
KFD
Central-difference force tangent evaluated from the same committed material state.
RUreferencerotated framePolar frame → bounded J2 update → global forceF = R U separates rotation and stretchEvaluate J2 on sym(U − I), with the documented strain boundRotate stress back; finite-difference the element tangent
Separate rigid-body rotation from local stretchThe corotational step handles large rigid rotation while the local constitutive strain remains bounded and small. This is not a multiplicative finite-strain plasticity model.
6 detailed steps

03 Step by step derivation

Follow the assumptions, equations and discrete operations in order. The full explanation stays visible.

The current implementation forms internal force from P=Rσlocal and reference shape gradients. It computes a central-difference tangent at a fixed committed state, then symmetrizes that numerical matrix. Formal acceptance is bounded to HEX8; TET10 and HEX20 extension evidence does not inherit that maturity.

1 · Start from the reference-to-current deformation gradient

With reference coordinates X and displacement u, F maps infinitesimal reference line elements to current line elements. A pure rigid motion may make F far from I even when the material is not strained; using the small-strain tensor sym(∇u) directly would mistake that rotation for deformation.

x=X+u(X)\mathbf x=\mathbf X+\mathbf u(\mathbf X)F=∂x∂X=I+∇ ⁣Xu\mathbf F=\frac{\partial\mathbf x}{\partial\mathbf X}=\mathbf I+\nabla_{\!X}\mathbf udet⁡F>0\det\mathbf F>0

A non-positive determinant is rejected. The implementation also rejects determinants at or below its numerical threshold 10⁻¹⁰.

2 · Factor rigid rotation from material stretch

The right polar decomposition F=RU separates a proper rotation R from the symmetric positive-definite right stretch U. The implementation obtains this factorization with an SVD and verifies that R is finite and orientation-preserving. For a pure rotation, U=I.

F=RU,RTR=I,det⁡R=+1\mathbf F=\mathbf R\mathbf U,\qquad \mathbf R^T\mathbf R=\mathbf I,\quad\det\mathbf R=+1U=UT≻0\mathbf U=\mathbf U^T\succ0F=R⟹U=I\mathbf F=\mathbf R\quad\Longrightarrow\quad\mathbf U=\mathbf I

This decomposition is kinematic. It does not introduce the multiplicative plastic split F=FeFp or a finite-strain yield law.

3 · Apply the small-strain constitutive update in the rotating frame

The local measure is εcorot=U−I, a Biot-like stretch strain. It is symmetrized and converted to engineering Voigt form before calling the material model. The configured default maximum Frobenius norm is 0.05; exceeding it raises an error instead of silently extending the model.

εcorot=sym⁡(U−I)=U−I\boldsymbol{\varepsilon}_{corot}=\operatorname{sym}(\mathbf U-\mathbf I)=\mathbf U-\mathbf I∥εcorot∥F≤εmax,εmax=0.05  by default\|\boldsymbol{\varepsilon}_{corot}\|_F\le\varepsilon_{max},\qquad \varepsilon_{max}=0.05\;\text{by default}(σlocal,Clocal,S∗)=J2Update⁡(εcorot,transport⁡(Sn,R))\left(\boldsymbol{\sigma}_{local},\mathbb C_{local},S^*\right)=\operatorname{J2Update}\left(\boldsymbol{\varepsilon}_{corot},\operatorname{transport}(S_n,\mathbf R)\right)

A constitutive call returns a trial state S*. The global nonlinear lifecycle decides whether it is committed after equilibrium convergence or discarded after rejection.

4 · Transport history between successive corotated frames

Plastic strain, stress, and stored strain are tensors expressed in the last local frame. When R changes, the code rotates these second-order tensors through the relative frame rotation before the next J2 update. Equivalent plastic strain and scalar history remain unchanged by this coordinate change.

Qrel=Rn+1TRn\mathbf Q_{rel}=\mathbf R_{n+1}^T\mathbf R_nAn+1local=QrelAnlocalQrelT\mathbf A_{n+1}^{local}=\mathbf Q_{rel}\mathbf A_n^{local}\mathbf Q_{rel}^Tαn+1transport=αn\alpha_{n+1}^{transport}=\alpha_n

A non-zero restart state without its committed corotation metadata is rejected because its tensor components cannot be interpreted safely in a new frame.

5 · Rotate stress back and assemble internal force

The local stress is rotated into a first Piola stress, then multiplied by reference gradients and integrated over the reference element. This is the virtual-work path used by the current kernel. It is not the same operation as simply rotating a final plotted stress field.

P=Rσlocal\mathbf P=\mathbf R\boldsymbol{\sigma}_{local}fint,a=∑gwgdet⁡(J0,g) Pg∇ ⁣XNa\mathbf f_{int,a}=\sum_g w_g\det(\mathbf J_{0,g})\,\mathbf P_g\nabla_{\!X}N_aσCauchy=1JPFT,J=det⁡F\boldsymbol{\sigma}_{Cauchy}=\frac1J\mathbf P\mathbf F^T,\qquad J=\det\mathbf F

Post-processing reports several stress measures. Compare only matching measures and configurations when correlating results.

6 · Understand the numerical tangent and accepted scope

For each element displacement component, the code perturbs the displacement by ±h, reevaluates force from the same committed state, and forms a central difference. It symmetrizes the result. This exposes frame and geometric effects to Newton but costs two force evaluations per DOF and can depend on the perturbation scale.

KFD[:,j]=fint(u+hej;Sn)−fint(u−hej;Sn)2h\mathbf K_{FD}[:,j]=\frac{\mathbf f_{int}(\mathbf u+h\mathbf e_j;S_n)-\mathbf f_{int}(\mathbf u-h\mathbf e_j;S_n)}{2h}h=10−7max⁡(1,∥u∥∞,∥X∥∞)h=10^{-7}\max\left(1,\|\mathbf u\|_{\infty},\|\mathbf X\|_{\infty}\right)Kused=sym⁡(KFD)\mathbf K_{used}=\operatorname{sym}(\mathbf K_{FD})

The v0.2.10 V&V summary records owner-accepted bounded HEX8 scope, with large rotations and small local strain. TET10/HEX20 extensions are accepted with limitations, not formally promoted. This is not general finite-strain plasticity, arbitrary local strain, contact, or dynamic qualification.

04 Algorithm and implementation

Source excerpt · v0.2.11

The kernel extracts rotation and stretch at each integration point, bounds U−I, transports the accepted state, evaluates J2, and forms P=Rσlocal. Its tangent is computed separately by central differences.

Code
rotation, stretch, determinant = _polar_decomposition(deformation)
corotated_strain = symmetrize(stretch - identity)
local_strain_norm = float(np.linalg.norm(corotated_strain))
if local_strain_norm > self.max_corotational_strain:
    raise ValueError('Corotational small-strain bound exceeded.')
transported = _transport_state(committed, rotation)
response = evaluate_constitutive(self.material, strain_voigt(corotated_strain), transported)
first_piola = rotation @ stress_tensor(response.stress)
internal += measure * np.einsum('iJ,aJ->ai', first_piola, gradients).reshape(-1)
force_plus, _, _ = self._force_and_states(coords, plus, states)
force_minus, _, _ = self._force_and_states(coords, minus, states)
tangent[:, column] = (force_plus - force_minus) / (2.0 * scale)
Read the complete versioned implementation →

05 Verification and limitations

QUALIFIED_BOUNDED · formal acceptance is HEX8-only

Each reference supports its own model, observable and analysis route. Read the original contract and limitations before transferring a conclusion.

06 Sources and related sheets

Continue the reasoning

Back to sheet contents ↑