LCOV - code coverage report
Current view: top level - src/materials - ComputeFiniteStrain.C (source / functions) Hit Total Coverage
Test: idaholab/moose solid_mechanics: f45d79 Lines: 125 130 96.2 %
Date: 2025-07-25 05:00:39 Functions: 6 6 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 "ComputeFiniteStrain.h"
      11             : #include "Assembly.h"
      12             : 
      13             : #include "libmesh/quadrature.h"
      14             : #include "libmesh/utility.h"
      15             : 
      16             : MooseEnum
      17       24776 : ComputeFiniteStrain::decompositionType()
      18             : {
      19       49552 :   return MooseEnum("TaylorExpansion EigenSolution HughesWinget", "TaylorExpansion");
      20             : }
      21             : 
      22             : registerMooseObject("SolidMechanicsApp", ComputeFiniteStrain);
      23             : 
      24             : InputParameters
      25       11896 : ComputeFiniteStrain::validParams()
      26             : {
      27       11896 :   InputParameters params = ComputeIncrementalStrainBase::validParams();
      28       11896 :   params.addClassDescription(
      29             :       "Compute a strain increment and rotation increment for finite strains.");
      30       23792 :   params.addParam<MooseEnum>("decomposition_method",
      31       23792 :                              ComputeFiniteStrain::decompositionType(),
      32             :                              "Methods to calculate the strain and rotation increments");
      33       11896 :   return params;
      34           0 : }
      35             : 
      36        8916 : ComputeFiniteStrain::ComputeFiniteStrain(const InputParameters & parameters)
      37             :   : ComputeIncrementalStrainBase(parameters),
      38        8916 :     _Fhat(_fe_problem.getMaxQps()),
      39       17832 :     _decomposition_method(getParam<MooseEnum>("decomposition_method").getEnum<DecompMethod>()),
      40        8916 :     _use_hw(_decomposition_method == DecompMethod::HughesWinget),
      41        8916 :     _def_grad_mid(_use_hw ? &declareProperty<RankTwoTensor>(_base_name + "def_grad_mid") : nullptr),
      42       17832 :     _f_bar(_use_hw ? &declareProperty<RankTwoTensor>(_base_name + "f_bar") : nullptr)
      43             : {
      44        8916 : }
      45             : 
      46             : void
      47     4922260 : ComputeFiniteStrain::computeProperties()
      48             : {
      49     4922260 :   RankTwoTensor ave_Fhat;
      50             :   Real ave_dfgrd_det = 0.0;
      51    40690014 :   for (_qp = 0; _qp < _qrule->n_points(); ++_qp)
      52             :   {
      53             :     // Deformation gradient
      54             :     auto A = RankTwoTensor::initializeFromRows(
      55    35767754 :         (*_grad_disp[0])[_qp], (*_grad_disp[1])[_qp], (*_grad_disp[2])[_qp]);
      56             : 
      57             :     // Old Deformation gradient
      58             :     auto Fbar = RankTwoTensor::initializeFromRows(
      59    35767754 :         (*_grad_disp_old[0])[_qp], (*_grad_disp_old[1])[_qp], (*_grad_disp_old[2])[_qp]);
      60             : 
      61             :     // Gauss point deformation gradient
      62    35767754 :     _deformation_gradient[_qp] = A;
      63    35767754 :     _deformation_gradient[_qp].addIa(1.0);
      64             : 
      65             :     // deformation gradient midpoint (for Hughes-Winget kinematics)
      66    35767754 :     if (_use_hw)
      67             :     {
      68       40288 :       (*_def_grad_mid)[_qp].setToIdentity();
      69       40288 :       (*_def_grad_mid)[_qp] += 0.5 * (A + Fbar);
      70             :     }
      71             : 
      72             :     // A = gradU - gradUold
      73    35767754 :     A -= Fbar;
      74             : 
      75             :     //_f_bar = dDu/Dx_o (for Hughes-Winget kinematics)
      76    35767754 :     if (_use_hw)
      77       40288 :       (*_f_bar)[_qp] = A;
      78             : 
      79             :     // Fbar = ( I + gradUold)
      80    35767754 :     Fbar.addIa(1.0);
      81             : 
      82             :     // Incremental deformation gradient _Fhat = I + A Fbar^-1
      83    35767754 :     _Fhat[_qp] = A * Fbar.inverse();
      84    35767754 :     _Fhat[_qp].addIa(1.0);
      85             : 
      86    35767754 :     if (_volumetric_locking_correction)
      87             :     {
      88             :       // Calculate average _Fhat for volumetric locking correction
      89    23506144 :       ave_Fhat += _Fhat[_qp] * _JxW[_qp] * _coord[_qp];
      90             : 
      91             :       // Average deformation gradient
      92    23506144 :       ave_dfgrd_det += _deformation_gradient[_qp].det() * _JxW[_qp] * _coord[_qp];
      93             :     }
      94             :   }
      95             : 
      96     4922260 :   if (_volumetric_locking_correction)
      97             :   {
      98             :     // needed for volumetric locking correction
      99     2959548 :     ave_Fhat /= _current_elem_volume;
     100             :     // average deformation gradient
     101     2959548 :     ave_dfgrd_det /= _current_elem_volume;
     102             :   }
     103             : 
     104    40689358 :   for (_qp = 0; _qp < _qrule->n_points(); ++_qp)
     105             :   {
     106    35767180 :     if (_volumetric_locking_correction)
     107             :     {
     108             :       // Finalize volumetric locking correction
     109    23506144 :       _Fhat[_qp] *= std::cbrt(ave_Fhat.det() / _Fhat[_qp].det());
     110    23506144 :       _deformation_gradient[_qp] *= std::cbrt(ave_dfgrd_det / _deformation_gradient[_qp].det());
     111             :     }
     112             : 
     113    35767180 :     computeQpStrain();
     114             :   }
     115     4922178 : }
     116             : 
     117             : void
     118    44147832 : ComputeFiniteStrain::computeQpStrain()
     119             : {
     120    44147832 :   RankTwoTensor total_strain_increment;
     121             : 
     122             :   // three ways to calculate these increments: TaylorExpansion(default), EigenSolution, or
     123             :   // HughesWinget
     124    44147832 :   computeQpIncrements(total_strain_increment, _rotation_increment[_qp]);
     125             : 
     126    44147750 :   _strain_increment[_qp] = total_strain_increment;
     127             : 
     128             :   // Remove the eigenstrain increment
     129    44147750 :   subtractEigenstrainIncrementFromStrain(_strain_increment[_qp]);
     130             : 
     131    44147750 :   if (_dt > 0)
     132    44088326 :     _strain_rate[_qp] = _strain_increment[_qp] / _dt;
     133             :   else
     134       59424 :     _strain_rate[_qp].zero();
     135             : 
     136             :   // if HughesWinget, rotate old strains here
     137    44147750 :   RankTwoTensor mechanical_strain_old = _mechanical_strain_old[_qp];
     138    44147750 :   RankTwoTensor total_strain_old = _total_strain_old[_qp];
     139    44147750 :   if (_use_hw)
     140             :   {
     141       40288 :     mechanical_strain_old = _rotation_increment[_qp] * _mechanical_strain_old[_qp] *
     142       40288 :                             _rotation_increment[_qp].transpose();
     143       40288 :     total_strain_old =
     144       40288 :         _rotation_increment[_qp] * _total_strain_old[_qp] * _rotation_increment[_qp].transpose();
     145             :   }
     146             : 
     147             :   // Update strain in intermediate configuration
     148    44147750 :   _mechanical_strain[_qp] = mechanical_strain_old + _strain_increment[_qp];
     149    44147750 :   _total_strain[_qp] = total_strain_old + total_strain_increment;
     150             : 
     151             :   // Rotate strain to current configuration, unless HughesWinget
     152    44147750 :   if (!_use_hw)
     153             :   {
     154    44107462 :     _mechanical_strain[_qp] =
     155    44107462 :         _rotation_increment[_qp] * _mechanical_strain[_qp] * _rotation_increment[_qp].transpose();
     156    44107462 :     _total_strain[_qp] =
     157    44107462 :         _rotation_increment[_qp] * _total_strain[_qp] * _rotation_increment[_qp].transpose();
     158             :   }
     159             : 
     160    44147750 :   if (_global_strain)
     161           0 :     _total_strain[_qp] += (*_global_strain)[_qp];
     162    44147750 : }
     163             : 
     164             : void
     165    44145444 : ComputeFiniteStrain::computeQpIncrements(RankTwoTensor & total_strain_increment,
     166             :                                          RankTwoTensor & rotation_increment)
     167             : {
     168    44145444 :   switch (_decomposition_method)
     169             :   {
     170    43527060 :     case DecompMethod::TaylorExpansion:
     171             :     {
     172             :       // inverse of _Fhat
     173    43527060 :       const RankTwoTensor invFhat = _Fhat[_qp].inverse();
     174             : 
     175             :       // A = I - _Fhat^-1
     176    43527060 :       RankTwoTensor A(RankTwoTensor::initIdentity);
     177    43527060 :       A -= invFhat;
     178             : 
     179             :       // Cinv - I = A A^T - A - A^T;
     180    43527060 :       RankTwoTensor Cinv_I = A * A.transpose() - A - A.transpose();
     181             : 
     182             :       // strain rate D from Taylor expansion, Chat = (-1/2(Chat^-1 - I) + 1/4*(Chat^-1 - I)^2 + ...
     183    43527060 :       total_strain_increment = -Cinv_I * 0.5 + Cinv_I * Cinv_I * 0.25;
     184             : 
     185    43527060 :       const Real a[3] = {invFhat(1, 2) - invFhat(2, 1),
     186    43527060 :                          invFhat(2, 0) - invFhat(0, 2),
     187    43527060 :                          invFhat(0, 1) - invFhat(1, 0)};
     188             : 
     189    43527060 :       Real q = (a[0] * a[0] + a[1] * a[1] + a[2] * a[2]) / 4.0;
     190    43527060 :       Real trFhatinv_1 = invFhat.trace() - 1.0;
     191    43527060 :       const Real p = trFhatinv_1 * trFhatinv_1 / 4.0;
     192             : 
     193             :       // cos theta_a
     194    43527060 :       const Real C1_squared = p +
     195    43527060 :                               3.0 * Utility::pow<2>(p) * (1.0 - (p + q)) / Utility::pow<2>(p + q) -
     196    43527060 :                               2.0 * Utility::pow<3>(p) * (1.0 - (p + q)) / Utility::pow<3>(p + q);
     197    43527060 :       if (C1_squared <= 0.0)
     198          82 :         mooseException(
     199             :             "Cannot take square root of a number less than or equal to zero in the calculation of "
     200             :             "C1 for the Rashid approximation for the rotation tensor. This zero or negative number "
     201             :             "may occur when elements become heavily distorted.");
     202             : 
     203    43526978 :       const Real C1 = std::sqrt(C1_squared);
     204             : 
     205             :       Real C2;
     206    43526978 :       if (q > 0.01)
     207             :         // (1-cos theta_a)/4q
     208      248680 :         C2 = (1.0 - C1) / (4.0 * q);
     209             :       else
     210             :         // alternate form for small q
     211    43278298 :         C2 = 0.125 + q * 0.03125 * (Utility::pow<2>(p) - 12.0 * (p - 1.0)) / Utility::pow<2>(p) +
     212    43278298 :              Utility::pow<2>(q) * (p - 2.0) * (Utility::pow<2>(p) - 10.0 * p + 32.0) /
     213             :                  Utility::pow<3>(p) +
     214    43278298 :              Utility::pow<3>(q) *
     215    43278298 :                  (1104.0 - 992.0 * p + 376.0 * Utility::pow<2>(p) - 72.0 * Utility::pow<3>(p) +
     216    43278298 :                   5.0 * Utility::pow<4>(p)) /
     217    43278298 :                  (512.0 * Utility::pow<4>(p));
     218             : 
     219             :       const Real C3_test =
     220    43526978 :           (p * q * (3.0 - q) + Utility::pow<3>(p) + Utility::pow<2>(q)) / Utility::pow<3>(p + q);
     221             : 
     222    43526978 :       if (C3_test <= 0.0)
     223           0 :         mooseException(
     224             :             "Cannot take square root of a number less than or equal to zero in the calculation of "
     225             :             "C3_test for the Rashid approximation for the rotation tensor. This zero or negative "
     226             :             "number may occur when elements become heavily distorted.");
     227             : 
     228    43526978 :       const Real C3 = 0.5 * std::sqrt(C3_test); // sin theta_a/(2 sqrt(q))
     229             : 
     230             :       // Calculate incremental rotation. Note that this value is the transpose of that from Rashid,
     231             :       // 93, so we transpose it before storing
     232    43526978 :       RankTwoTensor R_incr;
     233    43526978 :       R_incr.addIa(C1);
     234   174107912 :       for (unsigned int i = 0; i < 3; ++i)
     235   522323736 :         for (unsigned int j = 0; j < 3; ++j)
     236   391742802 :           R_incr(i, j) += C2 * a[i] * a[j];
     237             : 
     238    43526978 :       R_incr(0, 1) += C3 * a[2];
     239    43526978 :       R_incr(0, 2) -= C3 * a[1];
     240    43526978 :       R_incr(1, 0) -= C3 * a[2];
     241    43526978 :       R_incr(1, 2) += C3 * a[0];
     242    43526978 :       R_incr(2, 0) += C3 * a[1];
     243    43526978 :       R_incr(2, 1) -= C3 * a[0];
     244             : 
     245    43526978 :       rotation_increment = R_incr.transpose();
     246             :       break;
     247             :     }
     248             : 
     249      578096 :     case DecompMethod::EigenSolution:
     250             :     {
     251      578096 :       FactorizedRankTwoTensor Chat = RankTwoTensor::transposeTimes(_Fhat[_qp]);
     252      578096 :       FactorizedRankTwoTensor Uhat = MathUtils::sqrt(Chat);
     253     1156192 :       rotation_increment = _Fhat[_qp] * Uhat.inverse().get();
     254     1156192 :       total_strain_increment = MathUtils::log(Uhat).get();
     255             :       break;
     256             :     }
     257             : 
     258       40288 :     case DecompMethod::HughesWinget:
     259             :     {
     260       40288 :       const RankTwoTensor G = (*_f_bar)[_qp] * (*_def_grad_mid)[_qp].inverse();
     261             : 
     262       40288 :       total_strain_increment = 0.5 * (G + G.transpose());
     263       40288 :       const RankTwoTensor W = 0.5 * (G - G.transpose());
     264             : 
     265       40288 :       RankTwoTensor Q_1(RankTwoTensor::initIdentity);
     266       40288 :       RankTwoTensor Q_2(RankTwoTensor::initIdentity);
     267             : 
     268       40288 :       Q_1 -= 0.5 * W;
     269       40288 :       Q_2 += 0.5 * W;
     270             : 
     271       40288 :       rotation_increment = Q_1.inverse() * Q_2;
     272             : 
     273             :       break;
     274             :     }
     275             : 
     276           0 :     default:
     277           0 :       mooseError("ComputeFiniteStrain Error: Pass valid decomposition type: TaylorExpansion, "
     278             :                  "EigenSolution, or HughesWinget.");
     279             :   }
     280    44145362 : }

Generated by: LCOV version 1.14