LCOV - code coverage report
Current view: top level - src/materials - TensileStressUpdate.C (source / functions) Hit Total Coverage
Test: idaholab/moose solid_mechanics: #32971 (54bef8) with base c6cf66 Lines: 128 133 96.2 %
Date: 2026-05-29 20:40:07 Functions: 16 16 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 "TensileStressUpdate.h"
      11             : #include "libmesh/utility.h"
      12             : 
      13             : registerMooseObject("SolidMechanicsApp", TensileStressUpdate);
      14             : 
      15             : InputParameters
      16         320 : TensileStressUpdate::validParams()
      17             : {
      18         320 :   InputParameters params = MultiParameterPlasticityStressUpdate::validParams();
      19         640 :   params.addRequiredParam<UserObjectName>(
      20             :       "tensile_strength",
      21             :       "A SolidMechanicsHardening UserObject that defines hardening of the tensile strength");
      22         640 :   params.addParam<bool>("perfect_guess",
      23         640 :                         true,
      24             :                         "Provide a guess to the Newton-Raphson procedure "
      25             :                         "that is the result from perfect plasticity.  With "
      26             :                         "severe hardening/softening this may be "
      27             :                         "suboptimal.");
      28         320 :   params.addClassDescription(
      29             :       "Associative, smoothed, tensile (Rankine) plasticity with hardening/softening");
      30         320 :   return params;
      31           0 : }
      32             : 
      33         240 : TensileStressUpdate::TensileStressUpdate(const InputParameters & parameters)
      34             :   : MultiParameterPlasticityStressUpdate(parameters, 3, 3, 1),
      35         240 :     _strength(getUserObject<SolidMechanicsHardeningModel>("tensile_strength")),
      36         480 :     _perfect_guess(getParam<bool>("perfect_guess")),
      37         240 :     _eigvecs(RankTwoTensor()),
      38         240 :     _dsp_trial_scratch(3),
      39         480 :     _eigvals_scratch(_tensor_dimensionality)
      40             : {
      41         240 : }
      42             : 
      43             : void
      44       12152 : TensileStressUpdate::computeStressParams(const RankTwoTensor & stress,
      45             :                                          std::vector<Real> & stress_params) const
      46             : {
      47             :   // stress_params[0] = smallest eigenvalue, stress_params[2] = largest eigenvalue
      48       12152 :   stress.symmetricEigenvalues(stress_params);
      49       12152 : }
      50             : 
      51             : void
      52       10360 : TensileStressUpdate::dstressparam_dstress(const RankTwoTensor & stress,
      53             :                                           std::vector<RankTwoTensor> & dsp) const
      54             : {
      55             :   mooseAssert(dsp.size() == 3,
      56             :               "TensileStressUpdate: dsp incorrectly sized in dstressparam_dstress");
      57             :   mooseAssert(_eigvals_scratch.size() == _tensor_dimensionality,
      58             :               "_eigvals_scratch incorrectly sized in TensileStressUpdate:dstressparam_dstress");
      59       10360 :   stress.dsymmetricEigenvalues(_eigvals_scratch, dsp);
      60       10360 : }
      61             : 
      62             : void
      63         128 : TensileStressUpdate::d2stressparam_dstress(const RankTwoTensor & stress,
      64             :                                            std::vector<RankFourTensor> & d2sp) const
      65             : {
      66             :   /*
      67             :    * This function is not used but is included here in case a derived class needs it.
      68             :    * The reason it is unused is because consistentTangentOperatorV is optimised
      69             :    */
      70             :   mooseAssert(d2sp.size() == 3,
      71             :               "TensileStressUpdate: d2sp incorrectly sized in d2stressparam_dstress");
      72         128 :   stress.d2symmetricEigenvalues(d2sp);
      73         128 : }
      74             : 
      75             : void
      76        9976 : TensileStressUpdate::preReturnMapV(const std::vector<Real> & /*trial_stress_params*/,
      77             :                                    const RankTwoTensor & stress_trial,
      78             :                                    const std::vector<Real> & /*intnl_old*/,
      79             :                                    const std::vector<Real> & /*yf*/,
      80             :                                    const RankFourTensor & /*Eijkl*/)
      81             : {
      82             :   mooseAssert(_eigvals_scratch.size() == _tensor_dimensionality,
      83             :               "_eigvals_scratch incorrectly sized in TensileStressUpdate:preReturnMapV");
      84        9976 :   stress_trial.symmetricEigenvaluesEigenvectors(_eigvals_scratch, _eigvecs);
      85        9976 : }
      86             : 
      87             : void
      88        9976 : TensileStressUpdate::setStressAfterReturnV(const RankTwoTensor & /*stress_trial*/,
      89             :                                            const std::vector<Real> & stress_params,
      90             :                                            Real /*gaE*/,
      91             :                                            const std::vector<Real> & /*intnl*/,
      92             :                                            const yieldAndFlow & /*smoothed_q*/,
      93             :                                            const RankFourTensor & /*Eijkl*/,
      94             :                                            RankTwoTensor & stress) const
      95             : {
      96             :   // form the diagonal stress
      97        9976 :   stress = RankTwoTensor(stress_params[0], stress_params[1], stress_params[2], 0.0, 0.0, 0.0);
      98             :   // rotate to the original frame
      99        9976 :   stress = _eigvecs * stress * (_eigvecs.transpose());
     100        9976 : }
     101             : 
     102             : void
     103       20112 : TensileStressUpdate::yieldFunctionValuesV(const std::vector<Real> & stress_params,
     104             :                                           const std::vector<Real> & intnl,
     105             :                                           std::vector<Real> & yf) const
     106             : {
     107       20112 :   const Real ts = tensile_strength(intnl[0]);
     108             :   // The smoothing strategy means that the last yield function
     109             :   // gives the smallest value when returning to a line/point where,
     110             :   // without smoothing, the yield functions are equal.
     111             :   // Therefore, i use the smallest eigenvalue in this yield function
     112       20112 :   yf[0] = stress_params[2] - ts; // use largest eigenvalue
     113       20112 :   yf[1] = stress_params[1] - ts;
     114       20112 :   yf[2] = stress_params[0] - ts; // use smallest eigenvalue
     115       20112 : }
     116             : 
     117             : void
     118       49496 : TensileStressUpdate::computeAllQV(const std::vector<Real> & stress_params,
     119             :                                   const std::vector<Real> & intnl,
     120             :                                   std::vector<yieldAndFlow> & all_q) const
     121             : {
     122       49496 :   const Real ts = tensile_strength(intnl[0]);
     123       49496 :   const Real dts = dtensile_strength(intnl[0]);
     124             : 
     125             :   // yield functions.  See comment in yieldFunctionValuesV
     126       49496 :   all_q[0].f = stress_params[2] - ts;
     127       49496 :   all_q[1].f = stress_params[1] - ts;
     128       49496 :   all_q[2].f = stress_params[0] - ts;
     129             : 
     130             :   // d(yield function)/d(stress_params)
     131      197984 :   for (unsigned yf = 0; yf < _num_yf; ++yf)
     132      593952 :     for (unsigned a = 0; a < _num_sp; ++a)
     133      445464 :       all_q[yf].df[a] = 0.0;
     134       49496 :   all_q[0].df[2] = 1.0;
     135       49496 :   all_q[1].df[1] = 1.0;
     136       49496 :   all_q[2].df[0] = 1.0;
     137             : 
     138             :   // d(yield function)/d(intnl)
     139      197984 :   for (unsigned yf = 0; yf < _num_yf; ++yf)
     140      148488 :     all_q[yf].df_di[0] = -dts;
     141             : 
     142             :   // the flow potential is just the yield function
     143             :   // d(flow potential)/d(stress_params)
     144      197984 :   for (unsigned yf = 0; yf < _num_yf; ++yf)
     145      593952 :     for (unsigned a = 0; a < _num_sp; ++a)
     146      445464 :       all_q[yf].dg[a] = all_q[yf].df[a];
     147             : 
     148             :   // d(flow potential)/d(stress_params)/d(intnl)
     149      197984 :   for (unsigned yf = 0; yf < _num_yf; ++yf)
     150      593952 :     for (unsigned a = 0; a < _num_sp; ++a)
     151      445464 :       all_q[yf].d2g_di[a][0] = 0.0;
     152             : 
     153             :   // d(flow potential)/d(stress_params)/d(stress_params)
     154      197984 :   for (unsigned yf = 0; yf < _num_yf; ++yf)
     155      593952 :     for (unsigned a = 0; a < _num_sp; ++a)
     156     1781856 :       for (unsigned b = 0; b < _num_sp; ++b)
     157     1336392 :         all_q[yf].d2g[a][b] = 0.0;
     158       49496 : }
     159             : 
     160             : void
     161        9976 : TensileStressUpdate::setEffectiveElasticity(const RankFourTensor & Eijkl)
     162             : {
     163             :   // Eijkl is required to be isotropic, so we can use the
     164             :   // frame where stress is diagonal
     165       39904 :   for (unsigned a = 0; a < _num_sp; ++a)
     166      119712 :     for (unsigned b = 0; b < _num_sp; ++b)
     167       89784 :       _Eij[a][b] = Eijkl(a, a, b, b);
     168        9976 :   _En = _Eij[2][2];
     169        9976 :   const Real denom = _Eij[0][0] * (_Eij[0][0] + _Eij[0][1]) - 2 * Utility::pow<2>(_Eij[0][1]);
     170       39904 :   for (unsigned a = 0; a < _num_sp; ++a)
     171             :   {
     172       29928 :     _Cij[a][a] = (_Eij[0][0] + _Eij[0][1]) / denom;
     173       59856 :     for (unsigned b = 0; b < a; ++b)
     174       29928 :       _Cij[a][b] = _Cij[b][a] = -_Eij[0][1] / denom;
     175             :   }
     176        9976 : }
     177             : 
     178             : void
     179        9976 : TensileStressUpdate::initializeVarsV(const std::vector<Real> & trial_stress_params,
     180             :                                      const std::vector<Real> & intnl_old,
     181             :                                      std::vector<Real> & stress_params,
     182             :                                      Real & gaE,
     183             :                                      std::vector<Real> & intnl) const
     184             : {
     185        9976 :   if (!_perfect_guess)
     186             :   {
     187           0 :     for (unsigned i = 0; i < _num_sp; ++i)
     188           0 :       stress_params[i] = trial_stress_params[i];
     189           0 :     gaE = 0.0;
     190             :   }
     191             :   else
     192             :   {
     193        9976 :     const Real ts = tensile_strength(intnl_old[0]);
     194        9976 :     stress_params[2] = ts; // largest eigenvalue
     195        9976 :     stress_params[1] = std::min(stress_params[1], ts);
     196        9976 :     stress_params[0] = std::min(stress_params[0], ts);
     197        9976 :     gaE = trial_stress_params[2] - stress_params[2];
     198             :   }
     199        9976 :   setIntnlValuesV(trial_stress_params, stress_params, intnl_old, intnl);
     200        9976 : }
     201             : 
     202             : void
     203       59472 : TensileStressUpdate::setIntnlValuesV(const std::vector<Real> & trial_stress_params,
     204             :                                      const std::vector<Real> & current_stress_params,
     205             :                                      const std::vector<Real> & intnl_old,
     206             :                                      std::vector<Real> & intnl) const
     207             : {
     208       59472 :   intnl[0] = intnl_old[0] + (trial_stress_params[2] - current_stress_params[2]) / _Eij[2][2];
     209       59472 : }
     210             : 
     211             : void
     212       38880 : TensileStressUpdate::setIntnlDerivativesV(const std::vector<Real> & /*trial_stress_params*/,
     213             :                                           const std::vector<Real> & /*current_stress_params*/,
     214             :                                           const std::vector<Real> & /*intnl*/,
     215             :                                           std::vector<std::vector<Real>> & dintnl) const
     216             : {
     217       38880 :   dintnl[0][0] = 0.0;
     218       38880 :   dintnl[0][1] = 0.0;
     219       38880 :   dintnl[0][2] = -1.0 / _Eij[2][2];
     220       38880 : }
     221             : 
     222             : Real
     223       79584 : TensileStressUpdate::tensile_strength(const Real internal_param) const
     224             : {
     225       79584 :   return _strength.value(internal_param);
     226             : }
     227             : 
     228             : Real
     229       49496 : TensileStressUpdate::dtensile_strength(const Real internal_param) const
     230             : {
     231       49496 :   return _strength.derivative(internal_param);
     232             : }
     233             : 
     234             : void
     235         128 : TensileStressUpdate::consistentTangentOperatorV(const RankTwoTensor & stress_trial,
     236             :                                                 const std::vector<Real> & trial_stress_params,
     237             :                                                 const RankTwoTensor & /*stress*/,
     238             :                                                 const std::vector<Real> & stress_params,
     239             :                                                 Real /*gaE*/,
     240             :                                                 const yieldAndFlow & /*smoothed_q*/,
     241             :                                                 const RankFourTensor & elasticity_tensor,
     242             :                                                 bool compute_full_tangent_operator,
     243             :                                                 const std::vector<std::vector<Real>> & dvar_dtrial,
     244             :                                                 RankFourTensor & cto)
     245             : {
     246         128 :   cto = elasticity_tensor;
     247         128 :   if (!compute_full_tangent_operator)
     248           0 :     return;
     249             : 
     250             :   // dvar_dtrial has been computed already, so
     251             :   // d(stress)/d(trial_stress) = d(eigvecs * stress_params * eigvecs.transpose())/d(trial_stress)
     252             :   // eigvecs is a rotation matrix, rot(i, j) = e_j(i) = i^th component of j^th eigenvector
     253             :   // d(rot_ij)/d(stress_kl) = d(e_j(i))/d(stress_kl)
     254             :   // = sum_a 0.5 * e_a(i) * (e_a(k)e_j(l) + e_a(l)e_j(k)) / (la_j - la_a)
     255             :   // = sum_a 0.5 * rot(i,a) * (rot(k,a)rot(l,j) + rot(l,a)*rot(k,j)) / (la_j - la_a)
     256         128 :   RankFourTensor drot_dstress;
     257         512 :   for (unsigned i = 0; i < _tensor_dimensionality; ++i)
     258        1536 :     for (unsigned j = 0; j < _tensor_dimensionality; ++j)
     259        4608 :       for (unsigned k = 0; k < _tensor_dimensionality; ++k)
     260       13824 :         for (unsigned l = 0; l < _tensor_dimensionality; ++l)
     261       41472 :           for (unsigned a = 0; a < _num_sp; ++a)
     262             :           {
     263       31104 :             if (trial_stress_params[a] == trial_stress_params[j])
     264       10368 :               continue;
     265       20736 :             drot_dstress(i, j, k, l) +=
     266       20736 :                 0.5 * _eigvecs(i, a) *
     267       20736 :                 (_eigvecs(k, a) * _eigvecs(l, j) + _eigvecs(l, a) * _eigvecs(k, j)) /
     268       20736 :                 (trial_stress_params[j] - trial_stress_params[a]);
     269             :           }
     270             : 
     271         128 :   const RankTwoTensor eT = _eigvecs.transpose();
     272             : 
     273         128 :   RankFourTensor dstress_dtrial;
     274         512 :   for (unsigned i = 0; i < _tensor_dimensionality; ++i)
     275        1536 :     for (unsigned j = 0; j < _tensor_dimensionality; ++j)
     276        4608 :       for (unsigned k = 0; k < _tensor_dimensionality; ++k)
     277       13824 :         for (unsigned l = 0; l < _tensor_dimensionality; ++l)
     278       41472 :           for (unsigned a = 0; a < _num_sp; ++a)
     279       31104 :             dstress_dtrial(i, j, k, l) +=
     280       31104 :                 drot_dstress(i, a, k, l) * stress_params[a] * eT(a, j) +
     281       31104 :                 _eigvecs(i, a) * stress_params[a] * drot_dstress(j, a, k, l);
     282             : 
     283         128 :   dstressparam_dstress(stress_trial, _dsp_trial_scratch);
     284         512 :   for (unsigned i = 0; i < _tensor_dimensionality; ++i)
     285        1536 :     for (unsigned j = 0; j < _tensor_dimensionality; ++j)
     286        4608 :       for (unsigned k = 0; k < _tensor_dimensionality; ++k)
     287       13824 :         for (unsigned l = 0; l < _tensor_dimensionality; ++l)
     288       41472 :           for (unsigned a = 0; a < _num_sp; ++a)
     289      124416 :             for (unsigned b = 0; b < _num_sp; ++b)
     290       93312 :               dstress_dtrial(i, j, k, l) +=
     291       93312 :                   _eigvecs(i, a) * dvar_dtrial[a][b] * _dsp_trial_scratch[b](k, l) * eT(a, j);
     292             : 
     293         128 :   cto = dstress_dtrial * elasticity_tensor;
     294             : }

Generated by: LCOV version 1.14