LCOV - code coverage report
Current view: top level - src/materials/lagrangian - ComputeLagrangianStressPK2.C (source / functions) Hit Total Coverage
Test: idaholab/moose solid_mechanics: #33390 (250e9c) with base 846a5c Lines: 43 43 100.0 %
Date: 2026-07-31 18:20:40 Functions: 4 4 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //* This file is part of the MOOSE framework
       2             : //* https://mooseframework.inl.gov
       3             : //*
       4             : //* All rights reserved, see COPYRIGHT for full restrictions
       5             : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
       6             : //*
       7             : //* Licensed under LGPL 2.1, please see LICENSE for details
       8             : //* https://www.gnu.org/licenses/lgpl-2.1.html
       9             : 
      10             : #include "ComputeLagrangianStressPK2.h"
      11             : 
      12             : InputParameters
      13         208 : ComputeLagrangianStressPK2::validParams()
      14             : {
      15         208 :   InputParameters params = ComputeLagrangianStressPK1::validParams();
      16         208 :   return params;
      17             : }
      18             : 
      19         156 : ComputeLagrangianStressPK2::ComputeLagrangianStressPK2(const InputParameters & parameters)
      20             :   : ComputeLagrangianStressPK1(parameters),
      21         156 :     _E(declareProperty<RankTwoTensor>(_base_name + "green_lagrange_strain")),
      22         156 :     _S(declareProperty<RankTwoTensor>(_base_name + "pk2_stress")),
      23         312 :     _C(declareProperty<RankFourTensor>(_base_name + "pk2_jacobian"))
      24             : {
      25         156 : }
      26             : 
      27             : void
      28     3519536 : ComputeLagrangianStressPK2::computeQpCauchyStress()
      29             : {
      30             :   // PK2 has its own sigma-wrap structure: sigma = (1/J_ust) F_ust * S * F_ust^T. The PK1 base's
      31             :   // sigma-chain (which assumes pk1_jacobian = constitutive dPK1/dF_stab + _d_F_stab_d_F_ust)
      32             :   // doesn't fit here, so compute sigma and cauchy_jacobian directly from S and dS/dE.
      33             :   //
      34             :   // The R4 chain for `_cauchy_jacobian` is Jacobian-only; the wrap to `_cauchy_stress` is
      35             :   // not. Gate accordingly.
      36     3519536 :   const bool need_jacobian = _fe_problem.currentlyComputingJacobian() ||
      37     3390440 :                              _fe_problem.currentlyComputingResidualAndJacobian();
      38     3519536 :   if (_large_kinematics)
      39             :   {
      40     1960512 :     const Real J_ust = _F_ust[_qp].det();
      41     1960512 :     _cauchy_stress[_qp] = _F_ust[_qp] * _S[_qp] * _F_ust[_qp].transpose() / J_ust;
      42             : 
      43     1960512 :     if (!need_jacobian)
      44     1837624 :       return;
      45             : 
      46             :     // cauchy_jacobian = dsigma/d(dL). sigma depends on dL only through S(E(F_stab(dL))); the
      47             :     // F_ust factors in the wrap are CONSTANT w.r.t. dL (F_ust does not depend on dL --
      48             :     // dL is computed from F_stab via the kinematic helper, and F-bar relates F_stab to
      49             :     // F_ust). So:
      50             :     //   dsigma/d(dL) = (1/J_ust) F_ust * dS/d(dL) * F_ust^T
      51             :     //            = (1/J_ust) F_ust * _C * dE/d(F_stab) * inverse(d(dL)/d(F_stab)) * F_ust^T.
      52             :     usingTensorIndices(i_, j_, k_, l_);
      53             :     const auto I2 = RankTwoTensor::Identity();
      54      122888 :     const RankFourTensor dE_dFstab = 0.5 * (I2.template times<i_, l_, j_, k_>(_F[_qp].transpose()) +
      55      245776 :                                             _F[_qp].transpose().template times<i_, k_, j_, l_>(I2));
      56      122888 :     const RankFourTensor dE_d_dL = dE_dFstab * _d_deformation_gradient_increment_d_F[_qp].inverse();
      57      122888 :     const RankFourTensor dS_d_dL = _C[_qp] * dE_d_dL;
      58      245776 :     _cauchy_jacobian[_qp] = dS_d_dL.singleProductI(_F_ust[_qp]).singleProductJ(_F_ust[_qp]) / J_ust;
      59             :   }
      60             :   else
      61             :   {
      62     1559024 :     _cauchy_stress[_qp] = _S[_qp];
      63     1559024 :     if (need_jacobian)
      64        6208 :       _cauchy_jacobian[_qp] = _C[_qp];
      65             :   }
      66             : }
      67             : 
      68             : void
      69     3519536 : ComputeLagrangianStressPK2::computeQpPK1Stress()
      70             : {
      71             :   // Green-Lagrange strain uses the F-bar-stabilized F (`_F` from the strain calc) so
      72             :   // the constitutive law receives the stabilized strain -- F-bar's purpose is precisely
      73             :   // to feed a volumetrically-corrected strain into the constitutive update.
      74     3519536 :   _E[_qp] = 0.5 * (_F[_qp].transpose() * _F[_qp] - RankTwoTensor::Identity());
      75             : 
      76             :   // PK2 update (constitutive). This populates `_S` (always needed) and `_C` (= dPK2/dE,
      77             :   // Jacobian-only). PK2-subclass implementers that want to skip `_C` on residual sweeps
      78             :   // can check `_fe_problem.currentlyComputingJacobian()` themselves; the wrap below
      79             :   // doesn't read `_C` in the residual path.
      80     3519536 :   computeQpPK2Stress();
      81             : 
      82     3519536 :   const bool need_jacobian = _fe_problem.currentlyComputingJacobian() ||
      83     3390440 :                              _fe_problem.currentlyComputingResidualAndJacobian();
      84             : 
      85             :   // PK2 -> PK1 wrap uses the *unstabilized* F so the residual matches OLD. The constitutive
      86             :   // PK2 still carries the F-bar effect via its dependence on E (Green-Lagrange of F_stab).
      87     3519536 :   if (_large_kinematics)
      88             :   {
      89     1960512 :     _pk1_stress[_qp] = _F_ust[_qp] * _S[_qp];
      90     1960512 :     if (!need_jacobian)
      91     1837624 :       return;
      92             : 
      93             :     usingTensorIndices(i_, j_, k_, l_);
      94             :     // dE/d(F_stab) (E is computed from F_stab).
      95             :     RankFourTensor dE_dFstab =
      96      122888 :         0.5 * (RankTwoTensor::Identity().times<i_, l_, j_, k_>(_F[_qp].transpose()) +
      97      368664 :                _F[_qp].transpose().times<i_, k_, j_, l_>(RankTwoTensor::Identity()));
      98             :     // Chain dE/d(F_ust) = dE/d(F_stab) * d(F_stab)/d(F_ust). With F-bar off
      99             :     // _d_F_stab_d_F_ust = IdentityFour and this collapses to dE_dFstab.
     100      122888 :     const RankFourTensor dE_dFust = dE_dFstab * _d_F_stab_d_F_ust[_qp];
     101             : 
     102             :     // dPK1/d(F_ust) = d(F_ust)/d(F_ust) * S + F_ust * dS/d(F_ust)
     103             :     //   d(F_ust)/d(F_ust)*S gives I x S^T (per the existing template, with S^T because
     104             :     //   PK1 = F*S and we differentiate F).
     105             :     //   F_ust * dS/d(F_ust) via dS/dE * dE/d(F_ust).
     106             :     const RankFourTensor termA =
     107      122888 :         RankTwoTensor::Identity().times<i_, k_, j_, l_>(_S[_qp].transpose());
     108      122888 :     _pk1_jacobian[_qp] = termA + (_C[_qp] * dE_dFust).singleProductI(_F_ust[_qp]);
     109             :     // Bypass-F-bar variant: same Term A; sigma chain uses dE_dFstab (without
     110             :     // _d_F_stab_d_F_ust). Used by specialty kernels whose coupled variable bypasses
     111             :     // F-bar.
     112      122888 :     _pk1_jacobian_bypass_fbar[_qp] = termA + (_C[_qp] * dE_dFstab).singleProductI(_F_ust[_qp]);
     113             :   }
     114             :   // Small deformations: PK1 = PK2 = sigma; PK2 chain to PK1 still needs the F-bar local
     115             :   // contribution through dE/d(F_stab) * d(F_stab)/d(F_ust). For specialty bypass paths,
     116             :   // skip the F-bar factor.
     117             :   else
     118             :   {
     119     1559024 :     _pk1_stress[_qp] = _S[_qp];
     120     1559024 :     if (!need_jacobian)
     121             :       return;
     122        6208 :     _pk1_jacobian[_qp] = _C[_qp] * _d_F_stab_d_F_ust[_qp];
     123        6208 :     _pk1_jacobian_bypass_fbar[_qp] = _C[_qp];
     124             :   }
     125             : }

Generated by: LCOV version 1.14