LCOV - code coverage report
Current view: top level - src/userobjects - SolidMechanicsPlasticTensile.C (source / functions) Hit Total Coverage
Test: idaholab/moose solid_mechanics: f45d79 Lines: 148 151 98.0 %
Date: 2025-07-25 05:00:39 Functions: 13 14 92.9 %
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 "SolidMechanicsPlasticTensile.h"
      11             : #include "RankFourTensor.h"
      12             : #include "libmesh/utility.h"
      13             : 
      14             : registerMooseObject("SolidMechanicsApp", SolidMechanicsPlasticTensile);
      15             : registerMooseObjectRenamed("SolidMechanicsApp",
      16             :                            TensorMechanicsPlasticTensile,
      17             :                            "01/01/2025 00:00",
      18             :                            SolidMechanicsPlasticTensile);
      19             : 
      20             : InputParameters
      21         244 : SolidMechanicsPlasticTensile::validParams()
      22             : {
      23         244 :   InputParameters params = SolidMechanicsPlasticModel::validParams();
      24         488 :   params.addRequiredParam<UserObjectName>(
      25             :       "tensile_strength",
      26             :       "A SolidMechanicsHardening UserObject that defines hardening of the tensile strength");
      27         732 :   params.addRangeCheckedParam<Real>(
      28             :       "tensile_edge_smoother",
      29         488 :       25.0,
      30             :       "tensile_edge_smoother>=0 & tensile_edge_smoother<=30",
      31             :       "Smoothing parameter: the edges of the cone are smoothed by the given amount.");
      32         488 :   MooseEnum tip_scheme("hyperbolic cap", "hyperbolic");
      33         488 :   params.addParam<MooseEnum>(
      34             :       "tip_scheme", tip_scheme, "Scheme by which the pyramid's tip will be smoothed.");
      35         488 :   params.addRequiredRangeCheckedParam<Real>("tensile_tip_smoother",
      36             :                                             "tensile_tip_smoother>=0",
      37             :                                             "For the 'hyperbolic' tip_scheme, the pyramid vertex "
      38             :                                             "will be smoothed by the given amount.  For the 'cap' "
      39             :                                             "tip_scheme, additional smoothing will occur.  Typical "
      40             :                                             "value is 0.1*tensile_strength");
      41         488 :   params.addParam<Real>(
      42             :       "cap_start",
      43         488 :       0.0,
      44             :       "For the 'cap' tip_scheme, smoothing is performed in the stress_mean > cap_start region");
      45         732 :   params.addRangeCheckedParam<Real>("cap_rate",
      46         488 :                                     0.0,
      47             :                                     "cap_rate>=0",
      48             :                                     "For the 'cap' tip_scheme, this controls how quickly the cap "
      49             :                                     "degenerates to a hemisphere: small values mean a slow "
      50             :                                     "degeneration to a hemisphere (and zero means the 'cap' will "
      51             :                                     "be totally inactive).  Typical value is 1/tensile_strength");
      52         488 :   params.addParam<Real>("tensile_lode_cutoff",
      53             :                         "If the second invariant of stress is less than "
      54             :                         "this amount, the Lode angle is assumed to be zero. "
      55             :                         "This is to guard against precision-loss problems, "
      56             :                         "and this parameter should be set small.  Default = "
      57             :                         "0.00001*((yield_Function_tolerance)^2)");
      58         244 :   params.addClassDescription(
      59             :       "Associative tensile plasticity with hardening/softening, and tensile_strength = 1");
      60             : 
      61         244 :   return params;
      62         244 : }
      63             : 
      64         122 : SolidMechanicsPlasticTensile::SolidMechanicsPlasticTensile(const InputParameters & parameters)
      65             :   : SolidMechanicsPlasticModel(parameters),
      66         122 :     _strength(getUserObject<SolidMechanicsHardeningModel>("tensile_strength")),
      67         244 :     _tip_scheme(getParam<MooseEnum>("tip_scheme")),
      68         244 :     _small_smoother2(Utility::pow<2>(getParam<Real>("tensile_tip_smoother"))),
      69         244 :     _cap_start(getParam<Real>("cap_start")),
      70         244 :     _cap_rate(getParam<Real>("cap_rate")),
      71         244 :     _tt(getParam<Real>("tensile_edge_smoother") * libMesh::pi / 180.0),
      72         122 :     _sin3tt(std::sin(3.0 * _tt)),
      73         122 :     _lode_cutoff(parameters.isParamValid("tensile_lode_cutoff")
      74         122 :                      ? getParam<Real>("tensile_lode_cutoff")
      75         122 :                      : 1.0e-5 * Utility::pow<2>(_f_tol))
      76             : 
      77             : {
      78         122 :   if (_lode_cutoff < 0)
      79           0 :     mooseError("tensile_lode_cutoff must not be negative");
      80         122 :   _ccc = (-std::cos(3.0 * _tt) * (std::cos(_tt) - std::sin(_tt) / std::sqrt(3.0)) -
      81         122 :           3.0 * _sin3tt * (std::sin(_tt) + std::cos(_tt) / std::sqrt(3.0))) /
      82         122 :          (18.0 * Utility::pow<3>(std::cos(3.0 * _tt)));
      83         122 :   _bbb = (std::sin(6.0 * _tt) * (std::cos(_tt) - std::sin(_tt) / std::sqrt(3.0)) -
      84         122 :           6.0 * std::cos(6.0 * _tt) * (std::sin(_tt) + std::cos(_tt) / std::sqrt(3.0))) /
      85             :          (18.0 * Utility::pow<3>(std::cos(3.0 * _tt)));
      86         122 :   _aaa = -std::sin(_tt) / std::sqrt(3.0) - _bbb * _sin3tt - _ccc * Utility::pow<2>(_sin3tt) +
      87             :          std::cos(_tt);
      88         122 : }
      89             : 
      90             : Real
      91      243312 : SolidMechanicsPlasticTensile::yieldFunction(const RankTwoTensor & stress, Real intnl) const
      92             : {
      93      243312 :   Real mean_stress = stress.trace() / 3.0;
      94      243312 :   Real sin3Lode = stress.sin3Lode(_lode_cutoff, 0);
      95      243312 :   if (sin3Lode <= _sin3tt)
      96             :   {
      97             :     // the non-edge-smoothed version
      98             :     std::vector<Real> eigvals;
      99      166368 :     stress.symmetricEigenvalues(eigvals);
     100      166368 :     return mean_stress + std::sqrt(smooth(stress) + Utility::pow<2>(eigvals[2] - mean_stress)) -
     101      166368 :            tensile_strength(intnl);
     102             :   }
     103             :   else
     104             :   {
     105             :     // the edge-smoothed version
     106       76944 :     Real kk = _aaa + _bbb * sin3Lode + _ccc * Utility::pow<2>(sin3Lode);
     107       76944 :     Real sibar2 = stress.secondInvariant();
     108       76944 :     return mean_stress + std::sqrt(smooth(stress) + sibar2 * Utility::pow<2>(kk)) -
     109       76944 :            tensile_strength(intnl);
     110             :   }
     111             : }
     112             : 
     113             : RankTwoTensor
     114      392016 : SolidMechanicsPlasticTensile::dyieldFunction_dstress(const RankTwoTensor & stress,
     115             :                                                      Real /*intnl*/) const
     116             : {
     117      392016 :   Real mean_stress = stress.trace() / 3.0;
     118      392016 :   RankTwoTensor dmean_stress = stress.dtrace() / 3.0;
     119      392016 :   Real sin3Lode = stress.sin3Lode(_lode_cutoff, 0);
     120      392016 :   if (sin3Lode <= _sin3tt)
     121             :   {
     122             :     // the non-edge-smoothed version
     123             :     std::vector<Real> eigvals;
     124             :     std::vector<RankTwoTensor> deigvals;
     125      267440 :     stress.dsymmetricEigenvalues(eigvals, deigvals);
     126      267440 :     Real denom = std::sqrt(smooth(stress) + Utility::pow<2>(eigvals[2] - mean_stress));
     127      267440 :     return dmean_stress + (0.5 * dsmooth(stress) * dmean_stress +
     128      267440 :                            (eigvals[2] - mean_stress) * (deigvals[2] - dmean_stress)) /
     129      267440 :                               denom;
     130             :   }
     131             :   else
     132             :   {
     133             :     // the edge-smoothed version
     134      124576 :     Real kk = _aaa + _bbb * sin3Lode + _ccc * Utility::pow<2>(sin3Lode);
     135      124576 :     RankTwoTensor dkk = (_bbb + 2.0 * _ccc * sin3Lode) * stress.dsin3Lode(_lode_cutoff);
     136      124576 :     Real sibar2 = stress.secondInvariant();
     137      124576 :     RankTwoTensor dsibar2 = stress.dsecondInvariant();
     138      124576 :     Real denom = std::sqrt(smooth(stress) + sibar2 * Utility::pow<2>(kk));
     139      124576 :     return dmean_stress + (0.5 * dsmooth(stress) * dmean_stress +
     140      124576 :                            0.5 * dsibar2 * Utility::pow<2>(kk) + sibar2 * kk * dkk) /
     141      124576 :                               denom;
     142             :   }
     143             : }
     144             : 
     145             : Real
     146       93552 : SolidMechanicsPlasticTensile::dyieldFunction_dintnl(const RankTwoTensor & /*stress*/,
     147             :                                                     Real intnl) const
     148             : {
     149       93552 :   return -dtensile_strength(intnl);
     150             : }
     151             : 
     152             : RankTwoTensor
     153      298464 : SolidMechanicsPlasticTensile::flowPotential(const RankTwoTensor & stress, Real intnl) const
     154             : {
     155             :   // This plasticity is associative so
     156      298464 :   return dyieldFunction_dstress(stress, intnl);
     157             : }
     158             : 
     159             : RankFourTensor
     160       93552 : SolidMechanicsPlasticTensile::dflowPotential_dstress(const RankTwoTensor & stress,
     161             :                                                      Real /*intnl*/) const
     162             : {
     163       93552 :   Real mean_stress = stress.trace() / 3.0;
     164       93552 :   RankTwoTensor dmean_stress = stress.dtrace() / 3.0;
     165       93552 :   Real sin3Lode = stress.sin3Lode(_lode_cutoff, 0);
     166       93552 :   if (sin3Lode <= _sin3tt)
     167             :   {
     168             :     // the non-edge-smoothed version
     169             :     std::vector<Real> eigvals;
     170             :     std::vector<RankTwoTensor> deigvals;
     171             :     std::vector<RankFourTensor> d2eigvals;
     172       63856 :     stress.dsymmetricEigenvalues(eigvals, deigvals);
     173       63856 :     stress.d2symmetricEigenvalues(d2eigvals);
     174             : 
     175       63856 :     Real denom = std::sqrt(smooth(stress) + Utility::pow<2>(eigvals[2] - mean_stress));
     176             :     Real denom3 = Utility::pow<3>(denom);
     177       63856 :     RankTwoTensor numer_part = deigvals[2] - dmean_stress;
     178             :     RankTwoTensor numer_full =
     179       63856 :         0.5 * dsmooth(stress) * dmean_stress + (eigvals[2] - mean_stress) * numer_part;
     180       63856 :     Real d2smooth_over_denom = d2smooth(stress) / denom;
     181             : 
     182       63856 :     RankFourTensor dr_dstress = (eigvals[2] - mean_stress) * d2eigvals[2] / denom;
     183      255424 :     for (unsigned i = 0; i < 3; ++i)
     184      766272 :       for (unsigned j = 0; j < 3; ++j)
     185     2298816 :         for (unsigned k = 0; k < 3; ++k)
     186     6896448 :           for (unsigned l = 0; l < 3; ++l)
     187             :           {
     188     5172336 :             dr_dstress(i, j, k, l) +=
     189     5172336 :                 0.5 * d2smooth_over_denom * dmean_stress(i, j) * dmean_stress(k, l);
     190     5172336 :             dr_dstress(i, j, k, l) += numer_part(i, j) * numer_part(k, l) / denom;
     191     5172336 :             dr_dstress(i, j, k, l) -= numer_full(i, j) * numer_full(k, l) / denom3;
     192             :           }
     193       63856 :     return dr_dstress;
     194             :   }
     195             :   else
     196             :   {
     197             :     // the edge-smoothed version
     198       29696 :     RankTwoTensor dsin3Lode = stress.dsin3Lode(_lode_cutoff);
     199       29696 :     Real kk = _aaa + _bbb * sin3Lode + _ccc * Utility::pow<2>(sin3Lode);
     200       29696 :     RankTwoTensor dkk = (_bbb + 2.0 * _ccc * sin3Lode) * dsin3Lode;
     201       29696 :     RankFourTensor d2kk = (_bbb + 2.0 * _ccc * sin3Lode) * stress.d2sin3Lode(_lode_cutoff);
     202      118784 :     for (unsigned i = 0; i < 3; ++i)
     203      356352 :       for (unsigned j = 0; j < 3; ++j)
     204     1069056 :         for (unsigned k = 0; k < 3; ++k)
     205     3207168 :           for (unsigned l = 0; l < 3; ++l)
     206     2405376 :             d2kk(i, j, k, l) += 2.0 * _ccc * dsin3Lode(i, j) * dsin3Lode(k, l);
     207             : 
     208       29696 :     Real sibar2 = stress.secondInvariant();
     209       29696 :     RankTwoTensor dsibar2 = stress.dsecondInvariant();
     210       29696 :     RankFourTensor d2sibar2 = stress.d2secondInvariant();
     211             : 
     212       29696 :     Real denom = std::sqrt(smooth(stress) + sibar2 * Utility::pow<2>(kk));
     213             :     Real denom3 = Utility::pow<3>(denom);
     214       29696 :     Real d2smooth_over_denom = d2smooth(stress) / denom;
     215             :     RankTwoTensor numer_full =
     216       29696 :         0.5 * dsmooth(stress) * dmean_stress + 0.5 * dsibar2 * kk * kk + sibar2 * kk * dkk;
     217             : 
     218       29696 :     RankFourTensor dr_dstress = (0.5 * d2sibar2 * Utility::pow<2>(kk) + sibar2 * kk * d2kk) / denom;
     219      118784 :     for (unsigned i = 0; i < 3; ++i)
     220      356352 :       for (unsigned j = 0; j < 3; ++j)
     221     1069056 :         for (unsigned k = 0; k < 3; ++k)
     222     3207168 :           for (unsigned l = 0; l < 3; ++l)
     223             :           {
     224     2405376 :             dr_dstress(i, j, k, l) +=
     225     2405376 :                 0.5 * d2smooth_over_denom * dmean_stress(i, j) * dmean_stress(k, l);
     226     2405376 :             dr_dstress(i, j, k, l) +=
     227     2405376 :                 (dsibar2(i, j) * dkk(k, l) * kk + dkk(i, j) * dsibar2(k, l) * kk +
     228     2405376 :                  sibar2 * dkk(i, j) * dkk(k, l)) /
     229             :                 denom;
     230     2405376 :             dr_dstress(i, j, k, l) -= numer_full(i, j) * numer_full(k, l) / denom3;
     231             :           }
     232       29696 :     return dr_dstress;
     233             :   }
     234             : }
     235             : 
     236             : RankTwoTensor
     237       93552 : SolidMechanicsPlasticTensile::dflowPotential_dintnl(const RankTwoTensor & /*stress*/,
     238             :                                                     Real /*intnl*/) const
     239             : {
     240       93552 :   return RankTwoTensor();
     241             : }
     242             : 
     243             : Real
     244      243312 : SolidMechanicsPlasticTensile::tensile_strength(const Real internal_param) const
     245             : {
     246      243312 :   return _strength.value(internal_param);
     247             : }
     248             : 
     249             : Real
     250       93552 : SolidMechanicsPlasticTensile::dtensile_strength(const Real internal_param) const
     251             : {
     252       93552 :   return _strength.derivative(internal_param);
     253             : }
     254             : 
     255             : Real
     256      728880 : SolidMechanicsPlasticTensile::smooth(const RankTwoTensor & stress) const
     257             : {
     258      728880 :   Real smoother2 = _small_smoother2;
     259      728880 :   if (_tip_scheme == "cap")
     260             :   {
     261       66048 :     Real x = stress.trace() / 3.0 - _cap_start;
     262             :     Real p = 0;
     263       66048 :     if (x > 0)
     264       56640 :       p = x * (1 - std::exp(-_cap_rate * x));
     265       66048 :     smoother2 += Utility::pow<2>(p);
     266             :   }
     267      728880 :   return smoother2;
     268             : }
     269             : 
     270             : Real
     271      485568 : SolidMechanicsPlasticTensile::dsmooth(const RankTwoTensor & stress) const
     272             : {
     273             :   Real dsmoother2 = 0;
     274      485568 :   if (_tip_scheme == "cap")
     275             :   {
     276       46080 :     Real x = stress.trace() / 3.0 - _cap_start;
     277             :     Real p = 0;
     278             :     Real dp_dx = 0;
     279       46080 :     if (x > 0)
     280             :     {
     281       39360 :       p = x * (1 - std::exp(-_cap_rate * x));
     282       39360 :       dp_dx = (1 - std::exp(-_cap_rate * x)) + x * _cap_rate * std::exp(-_cap_rate * x);
     283             :     }
     284       46080 :     dsmoother2 += 2.0 * p * dp_dx;
     285             :   }
     286      485568 :   return dsmoother2;
     287             : }
     288             : 
     289             : Real
     290       93552 : SolidMechanicsPlasticTensile::d2smooth(const RankTwoTensor & stress) const
     291             : {
     292             :   Real d2smoother2 = 0;
     293       93552 :   if (_tip_scheme == "cap")
     294             :   {
     295        9984 :     Real x = stress.trace() / 3.0 - _cap_start;
     296             :     Real p = 0;
     297             :     Real dp_dx = 0;
     298             :     Real d2p_dx2 = 0;
     299        9984 :     if (x > 0)
     300             :     {
     301        8640 :       p = x * (1 - std::exp(-_cap_rate * x));
     302        8640 :       dp_dx = (1 - std::exp(-_cap_rate * x)) + x * _cap_rate * std::exp(-_cap_rate * x);
     303        8640 :       d2p_dx2 = 2.0 * _cap_rate * std::exp(-_cap_rate * x) -
     304        8640 :                 x * Utility::pow<2>(_cap_rate) * std::exp(-_cap_rate * x);
     305             :     }
     306        9984 :     d2smoother2 += 2.0 * Utility::pow<2>(dp_dx) + 2.0 * p * d2p_dx2;
     307             :   }
     308       93552 :   return d2smoother2;
     309             : }
     310             : 
     311             : std::string
     312           0 : SolidMechanicsPlasticTensile::modelName() const
     313             : {
     314           0 :   return "Tensile";
     315             : }

Generated by: LCOV version 1.14