LCOV - code coverage report
Current view: top level - src/materials - TensileStressUpdate.C (source / functions) Hit Total Coverage
Test: idaholab/moose solid_mechanics: f45d79 Lines: 123 131 93.9 %
Date: 2025-07-25 05:00:39 Functions: 15 16 93.8 %
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         384 : TensileStressUpdate::validParams()
      17             : {
      18         384 :   InputParameters params = MultiParameterPlasticityStressUpdate::validParams();
      19         768 :   params.addRequiredParam<UserObjectName>(
      20             :       "tensile_strength",
      21             :       "A SolidMechanicsHardening UserObject that defines hardening of the tensile strength");
      22         768 :   params.addParam<bool>("perfect_guess",
      23         768 :                         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         384 :   params.addClassDescription(
      29             :       "Associative, smoothed, tensile (Rankine) plasticity with hardening/softening");
      30         384 :   return params;
      31           0 : }
      32             : 
      33         288 : TensileStressUpdate::TensileStressUpdate(const InputParameters & parameters)
      34             :   : MultiParameterPlasticityStressUpdate(parameters, 3, 3, 1),
      35         288 :     _strength(getUserObject<SolidMechanicsHardeningModel>("tensile_strength")),
      36         576 :     _perfect_guess(getParam<bool>("perfect_guess")),
      37         576 :     _eigvecs(RankTwoTensor())
      38             : {
      39         288 : }
      40             : 
      41             : void
      42       13376 : TensileStressUpdate::computeStressParams(const RankTwoTensor & stress,
      43             :                                          std::vector<Real> & stress_params) const
      44             : {
      45             :   // stress_params[0] = smallest eigenvalue, stress_params[2] = largest eigenvalue
      46       13376 :   stress.symmetricEigenvalues(stress_params);
      47       13376 : }
      48             : 
      49             : std::vector<RankTwoTensor>
      50       10880 : TensileStressUpdate::dstress_param_dstress(const RankTwoTensor & stress) const
      51             : {
      52             :   std::vector<Real> sp;
      53             :   std::vector<RankTwoTensor> dsp;
      54       10880 :   stress.dsymmetricEigenvalues(sp, dsp);
      55       10880 :   return dsp;
      56             : }
      57             : 
      58             : std::vector<RankFourTensor>
      59           0 : TensileStressUpdate::d2stress_param_dstress(const RankTwoTensor & stress) const
      60             : {
      61             :   std::vector<RankFourTensor> d2;
      62           0 :   stress.d2symmetricEigenvalues(d2);
      63           0 :   return d2;
      64             : }
      65             : 
      66             : void
      67       10624 : TensileStressUpdate::preReturnMapV(const std::vector<Real> & /*trial_stress_params*/,
      68             :                                    const RankTwoTensor & stress_trial,
      69             :                                    const std::vector<Real> & /*intnl_old*/,
      70             :                                    const std::vector<Real> & /*yf*/,
      71             :                                    const RankFourTensor & /*Eijkl*/)
      72             : {
      73             :   std::vector<Real> eigvals;
      74       10624 :   stress_trial.symmetricEigenvaluesEigenvectors(eigvals, _eigvecs);
      75       10624 : }
      76             : 
      77             : void
      78       10624 : TensileStressUpdate::setStressAfterReturnV(const RankTwoTensor & /*stress_trial*/,
      79             :                                            const std::vector<Real> & stress_params,
      80             :                                            Real /*gaE*/,
      81             :                                            const std::vector<Real> & /*intnl*/,
      82             :                                            const yieldAndFlow & /*smoothed_q*/,
      83             :                                            const RankFourTensor & /*Eijkl*/,
      84             :                                            RankTwoTensor & stress) const
      85             : {
      86             :   // form the diagonal stress
      87       10624 :   stress = RankTwoTensor(stress_params[0], stress_params[1], stress_params[2], 0.0, 0.0, 0.0);
      88             :   // rotate to the original frame
      89       10624 :   stress = _eigvecs * stress * (_eigvecs.transpose());
      90       10624 : }
      91             : 
      92             : void
      93       21408 : TensileStressUpdate::yieldFunctionValuesV(const std::vector<Real> & stress_params,
      94             :                                           const std::vector<Real> & intnl,
      95             :                                           std::vector<Real> & yf) const
      96             : {
      97       21408 :   const Real ts = tensile_strength(intnl[0]);
      98             :   // The smoothing strategy means that the last yield function
      99             :   // gives the smallest value when returning to a line/point where,
     100             :   // without smoothing, the yield functions are equal.
     101             :   // Therefore, i use the smallest eigenvalue in this yield function
     102       21408 :   yf[0] = stress_params[2] - ts; // use largest eigenvalue
     103       21408 :   yf[1] = stress_params[1] - ts;
     104       21408 :   yf[2] = stress_params[0] - ts; // use smallest eigenvalue
     105       21408 : }
     106             : 
     107             : void
     108       52064 : TensileStressUpdate::computeAllQV(const std::vector<Real> & stress_params,
     109             :                                   const std::vector<Real> & intnl,
     110             :                                   std::vector<yieldAndFlow> & all_q) const
     111             : {
     112       52064 :   const Real ts = tensile_strength(intnl[0]);
     113       52064 :   const Real dts = dtensile_strength(intnl[0]);
     114             : 
     115             :   // yield functions.  See comment in yieldFunctionValuesV
     116       52064 :   all_q[0].f = stress_params[2] - ts;
     117       52064 :   all_q[1].f = stress_params[1] - ts;
     118       52064 :   all_q[2].f = stress_params[0] - ts;
     119             : 
     120             :   // d(yield function)/d(stress_params)
     121      208256 :   for (unsigned yf = 0; yf < _num_yf; ++yf)
     122      624768 :     for (unsigned a = 0; a < _num_sp; ++a)
     123      468576 :       all_q[yf].df[a] = 0.0;
     124       52064 :   all_q[0].df[2] = 1.0;
     125       52064 :   all_q[1].df[1] = 1.0;
     126       52064 :   all_q[2].df[0] = 1.0;
     127             : 
     128             :   // d(yield function)/d(intnl)
     129      208256 :   for (unsigned yf = 0; yf < _num_yf; ++yf)
     130      156192 :     all_q[yf].df_di[0] = -dts;
     131             : 
     132             :   // the flow potential is just the yield function
     133             :   // d(flow potential)/d(stress_params)
     134      208256 :   for (unsigned yf = 0; yf < _num_yf; ++yf)
     135      624768 :     for (unsigned a = 0; a < _num_sp; ++a)
     136      468576 :       all_q[yf].dg[a] = all_q[yf].df[a];
     137             : 
     138             :   // d(flow potential)/d(stress_params)/d(intnl)
     139      208256 :   for (unsigned yf = 0; yf < _num_yf; ++yf)
     140      624768 :     for (unsigned a = 0; a < _num_sp; ++a)
     141      468576 :       all_q[yf].d2g_di[a][0] = 0.0;
     142             : 
     143             :   // d(flow potential)/d(stress_params)/d(stress_params)
     144      208256 :   for (unsigned yf = 0; yf < _num_yf; ++yf)
     145      624768 :     for (unsigned a = 0; a < _num_sp; ++a)
     146     1874304 :       for (unsigned b = 0; b < _num_sp; ++b)
     147     1405728 :         all_q[yf].d2g[a][b] = 0.0;
     148       52064 : }
     149             : 
     150             : void
     151       10624 : TensileStressUpdate::setEffectiveElasticity(const RankFourTensor & Eijkl)
     152             : {
     153             :   // Eijkl is required to be isotropic, so we can use the
     154             :   // frame where stress is diagonal
     155       42496 :   for (unsigned a = 0; a < _num_sp; ++a)
     156      127488 :     for (unsigned b = 0; b < _num_sp; ++b)
     157       95616 :       _Eij[a][b] = Eijkl(a, a, b, b);
     158       10624 :   _En = _Eij[2][2];
     159       10624 :   const Real denom = _Eij[0][0] * (_Eij[0][0] + _Eij[0][1]) - 2 * Utility::pow<2>(_Eij[0][1]);
     160       42496 :   for (unsigned a = 0; a < _num_sp; ++a)
     161             :   {
     162       31872 :     _Cij[a][a] = (_Eij[0][0] + _Eij[0][1]) / denom;
     163       63744 :     for (unsigned b = 0; b < a; ++b)
     164       31872 :       _Cij[a][b] = _Cij[b][a] = -_Eij[0][1] / denom;
     165             :   }
     166       10624 : }
     167             : 
     168             : void
     169       10624 : TensileStressUpdate::initializeVarsV(const std::vector<Real> & trial_stress_params,
     170             :                                      const std::vector<Real> & intnl_old,
     171             :                                      std::vector<Real> & stress_params,
     172             :                                      Real & gaE,
     173             :                                      std::vector<Real> & intnl) const
     174             : {
     175       10624 :   if (!_perfect_guess)
     176             :   {
     177           0 :     for (unsigned i = 0; i < _num_sp; ++i)
     178           0 :       stress_params[i] = trial_stress_params[i];
     179           0 :     gaE = 0.0;
     180             :   }
     181             :   else
     182             :   {
     183       10624 :     const Real ts = tensile_strength(intnl_old[0]);
     184       10624 :     stress_params[2] = ts; // largest eigenvalue
     185       10624 :     stress_params[1] = std::min(stress_params[1], ts);
     186       10624 :     stress_params[0] = std::min(stress_params[0], ts);
     187       10624 :     gaE = trial_stress_params[2] - stress_params[2];
     188             :   }
     189       10624 :   setIntnlValuesV(trial_stress_params, stress_params, intnl_old, intnl);
     190       10624 : }
     191             : 
     192             : void
     193       62688 : TensileStressUpdate::setIntnlValuesV(const std::vector<Real> & trial_stress_params,
     194             :                                      const std::vector<Real> & current_stress_params,
     195             :                                      const std::vector<Real> & intnl_old,
     196             :                                      std::vector<Real> & intnl) const
     197             : {
     198       62688 :   intnl[0] = intnl_old[0] + (trial_stress_params[2] - current_stress_params[2]) / _Eij[2][2];
     199       62688 : }
     200             : 
     201             : void
     202       40800 : TensileStressUpdate::setIntnlDerivativesV(const std::vector<Real> & /*trial_stress_params*/,
     203             :                                           const std::vector<Real> & /*current_stress_params*/,
     204             :                                           const std::vector<Real> & /*intnl*/,
     205             :                                           std::vector<std::vector<Real>> & dintnl) const
     206             : {
     207       40800 :   dintnl[0][0] = 0.0;
     208       40800 :   dintnl[0][1] = 0.0;
     209       40800 :   dintnl[0][2] = -1.0 / _Eij[2][2];
     210       40800 : }
     211             : 
     212             : Real
     213       84096 : TensileStressUpdate::tensile_strength(const Real internal_param) const
     214             : {
     215       84096 :   return _strength.value(internal_param);
     216             : }
     217             : 
     218             : Real
     219       52064 : TensileStressUpdate::dtensile_strength(const Real internal_param) const
     220             : {
     221       52064 :   return _strength.derivative(internal_param);
     222             : }
     223             : 
     224             : void
     225         256 : TensileStressUpdate::consistentTangentOperatorV(const RankTwoTensor & stress_trial,
     226             :                                                 const std::vector<Real> & trial_stress_params,
     227             :                                                 const RankTwoTensor & /*stress*/,
     228             :                                                 const std::vector<Real> & stress_params,
     229             :                                                 Real /*gaE*/,
     230             :                                                 const yieldAndFlow & /*smoothed_q*/,
     231             :                                                 const RankFourTensor & elasticity_tensor,
     232             :                                                 bool compute_full_tangent_operator,
     233             :                                                 const std::vector<std::vector<Real>> & dvar_dtrial,
     234             :                                                 RankFourTensor & cto)
     235             : {
     236         256 :   cto = elasticity_tensor;
     237         256 :   if (!compute_full_tangent_operator)
     238           0 :     return;
     239             : 
     240             :   // dvar_dtrial has been computed already, so
     241             :   // d(stress)/d(trial_stress) = d(eigvecs * stress_params * eigvecs.transpose())/d(trial_stress)
     242             :   // eigvecs is a rotation matrix, rot(i, j) = e_j(i) = i^th component of j^th eigenvector
     243             :   // d(rot_ij)/d(stress_kl) = d(e_j(i))/d(stress_kl)
     244             :   // = sum_a 0.5 * e_a(i) * (e_a(k)e_j(l) + e_a(l)e_j(k)) / (la_j - la_a)
     245             :   // = sum_a 0.5 * rot(i,a) * (rot(k,a)rot(l,j) + rot(l,a)*rot(k,j)) / (la_j - la_a)
     246         256 :   RankFourTensor drot_dstress;
     247        1024 :   for (unsigned i = 0; i < _tensor_dimensionality; ++i)
     248        3072 :     for (unsigned j = 0; j < _tensor_dimensionality; ++j)
     249        9216 :       for (unsigned k = 0; k < _tensor_dimensionality; ++k)
     250       27648 :         for (unsigned l = 0; l < _tensor_dimensionality; ++l)
     251       82944 :           for (unsigned a = 0; a < _num_sp; ++a)
     252             :           {
     253       62208 :             if (trial_stress_params[a] == trial_stress_params[j])
     254       20736 :               continue;
     255       41472 :             drot_dstress(i, j, k, l) +=
     256       41472 :                 0.5 * _eigvecs(i, a) *
     257       41472 :                 (_eigvecs(k, a) * _eigvecs(l, j) + _eigvecs(l, a) * _eigvecs(k, j)) /
     258       41472 :                 (trial_stress_params[j] - trial_stress_params[a]);
     259             :           }
     260             : 
     261         256 :   const RankTwoTensor eT = _eigvecs.transpose();
     262             : 
     263         256 :   RankFourTensor dstress_dtrial;
     264        1024 :   for (unsigned i = 0; i < _tensor_dimensionality; ++i)
     265        3072 :     for (unsigned j = 0; j < _tensor_dimensionality; ++j)
     266        9216 :       for (unsigned k = 0; k < _tensor_dimensionality; ++k)
     267       27648 :         for (unsigned l = 0; l < _tensor_dimensionality; ++l)
     268       82944 :           for (unsigned a = 0; a < _num_sp; ++a)
     269       62208 :             dstress_dtrial(i, j, k, l) +=
     270       62208 :                 drot_dstress(i, a, k, l) * stress_params[a] * eT(a, j) +
     271       62208 :                 _eigvecs(i, a) * stress_params[a] * drot_dstress(j, a, k, l);
     272             : 
     273         256 :   const std::vector<RankTwoTensor> dsp_trial = dstress_param_dstress(stress_trial);
     274        1024 :   for (unsigned i = 0; i < _tensor_dimensionality; ++i)
     275        3072 :     for (unsigned j = 0; j < _tensor_dimensionality; ++j)
     276        9216 :       for (unsigned k = 0; k < _tensor_dimensionality; ++k)
     277       27648 :         for (unsigned l = 0; l < _tensor_dimensionality; ++l)
     278       82944 :           for (unsigned a = 0; a < _num_sp; ++a)
     279      248832 :             for (unsigned b = 0; b < _num_sp; ++b)
     280      186624 :               dstress_dtrial(i, j, k, l) +=
     281      186624 :                   _eigvecs(i, a) * dvar_dtrial[a][b] * dsp_trial[b](k, l) * eT(a, j);
     282             : 
     283         256 :   cto = dstress_dtrial * elasticity_tensor;
     284             : }

Generated by: LCOV version 1.14