LCOV - code coverage report
Current view: top level - src/materials/crystal_plasticity - ComputeMultipleCrystalPlasticityStress.C (source / functions) Hit Total Coverage
Test: idaholab/moose solid_mechanics: #32971 (54bef8) with base c6cf66 Lines: 313 368 85.1 %
Date: 2026-05-29 20:40:07 Functions: 18 19 94.7 %
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 "ComputeMultipleCrystalPlasticityStress.h"
      11             : 
      12             : #include "CrystalPlasticityStressUpdateBase.h"
      13             : #include "libmesh/utility.h"
      14             : #include "Conversion.h"
      15             : #include "MooseException.h"
      16             : 
      17             : registerMooseObject("SolidMechanicsApp", ComputeMultipleCrystalPlasticityStress);
      18             : 
      19             : InputParameters
      20         943 : ComputeMultipleCrystalPlasticityStress::validParams()
      21             : {
      22         943 :   InputParameters params = ComputeFiniteStrainElasticStress::validParams();
      23             : 
      24         943 :   params.addClassDescription(
      25             :       "Crystal Plasticity base class: handles the Newton iteration over the stress residual and "
      26             :       "calculates the Jacobian based on constitutive laws from multiple material classes "
      27             :       "that are inherited from CrystalPlasticityStressUpdateBase");
      28        1886 :   params.addParam<std::string>(
      29             :       "base_name",
      30             :       "Optional parameter that allows the user to define multiple mechanics material systems on "
      31             :       "the same block, i.e. for multiple phases");
      32             : 
      33        1886 :   params.addRequiredParam<std::vector<MaterialName>>(
      34             :       "crystal_plasticity_models",
      35             :       "The material objects to use to calculate crystal plasticity stress and strains.");
      36        1886 :   params.addParam<std::vector<MaterialName>>(
      37             :       "eigenstrain_names", {}, "The material objects to calculate eigenstrains.");
      38        1886 :   params.addParam<MooseEnum>("tan_mod_type",
      39        2829 :                              MooseEnum("exact none", "none"),
      40             :                              "Type of tangent moduli for preconditioner: default elastic");
      41        1886 :   params.addParam<Real>("rtol", 1e-6, "Constitutive stress residual relative tolerance");
      42        1886 :   params.addParam<Real>("abs_tol", 1e-6, "Constitutive stress residual absolute tolerance");
      43        1886 :   params.addParam<unsigned int>("maxiter", 100, "Maximum number of iterations for stress update");
      44        1886 :   params.addParam<unsigned int>(
      45        1886 :       "maxiter_state_variable", 100, "Maximum number of iterations for state variable update");
      46        1886 :   params.addParam<unsigned int>(
      47        1886 :       "maximum_substep_iteration", 1, "Maximum number of substep iteration");
      48        1886 :   params.addParam<bool>("use_line_search", false, "Use line search in constitutive update");
      49        1886 :   params.addParam<Real>("min_line_search_step_size", 0.01, "Minimum line search step size");
      50        1886 :   params.addParam<Real>("line_search_tol", 0.5, "Line search bisection method tolerance");
      51        1886 :   params.addParam<unsigned int>(
      52        1886 :       "line_search_maxiter", 20, "Line search bisection method maximum number of iteration");
      53        1886 :   params.addParam<MooseEnum>("line_search_method",
      54        2829 :                              MooseEnum("CUT_HALF BISECTION", "CUT_HALF"),
      55             :                              "The method used in line search");
      56        1886 :   params.addParam<bool>(
      57             :       "print_state_variable_convergence_error_messages",
      58        1886 :       false,
      59             :       "Whether or not to print warning messages from the crystal plasticity specific convergence "
      60             :       "checks on the stress measure and general constitutive model quantinties.");
      61         943 :   return params;
      62           0 : }
      63             : 
      64         705 : ComputeMultipleCrystalPlasticityStress::ComputeMultipleCrystalPlasticityStress(
      65         705 :     const InputParameters & parameters)
      66             :   : ComputeFiniteStrainElasticStress(parameters),
      67         705 :     _num_models(getParam<std::vector<MaterialName>>("crystal_plasticity_models").size()),
      68        1410 :     _num_eigenstrains(getParam<std::vector<MaterialName>>("eigenstrain_names").size()),
      69        1506 :     _base_name(isParamValid("base_name") ? getParam<std::string>("base_name") + "_" : ""),
      70        1410 :     _elasticity_tensor(getMaterialPropertyByName<RankFourTensor>(_base_name + "elasticity_tensor")),
      71        1410 :     _rtol(getParam<Real>("rtol")),
      72        1410 :     _abs_tol(getParam<Real>("abs_tol")),
      73        1410 :     _maxiter(getParam<unsigned int>("maxiter")),
      74        1410 :     _maxiterg(getParam<unsigned int>("maxiter_state_variable")),
      75        1410 :     _tan_mod_type(getParam<MooseEnum>("tan_mod_type").getEnum<TangentModuliType>()),
      76        1410 :     _max_substep_iter(getParam<unsigned int>("maximum_substep_iteration")),
      77        1410 :     _use_line_search(getParam<bool>("use_line_search")),
      78        1410 :     _min_line_search_step_size(getParam<Real>("min_line_search_step_size")),
      79        1410 :     _line_search_tolerance(getParam<Real>("line_search_tol")),
      80        1410 :     _line_search_max_iterations(getParam<unsigned int>("line_search_maxiter")),
      81        1410 :     _line_search_method(getParam<MooseEnum>("line_search_method").getEnum<LineSearchMethod>()),
      82         705 :     _plastic_deformation_gradient(declareProperty<RankTwoTensor>("plastic_deformation_gradient")),
      83         705 :     _plastic_deformation_gradient_old(
      84         705 :         getMaterialPropertyOld<RankTwoTensor>("plastic_deformation_gradient")),
      85         705 :     _eigenstrain_deformation_gradient(
      86         705 :         _num_eigenstrains ? &declareProperty<RankTwoTensor>("eigenstrain_deformation_gradient")
      87             :                           : nullptr),
      88         705 :     _eigenstrain_deformation_gradient_old(
      89         705 :         _num_eigenstrains
      90         813 :             ? &getMaterialPropertyOld<RankTwoTensor>("eigenstrain_deformation_gradient")
      91             :             : nullptr),
      92        1410 :     _deformation_gradient(getMaterialProperty<RankTwoTensor>(_base_name + "deformation_gradient")),
      93         705 :     _deformation_gradient_old(
      94         705 :         getMaterialPropertyOld<RankTwoTensor>(_base_name + "deformation_gradient")),
      95         705 :     _pk2(declareProperty<RankTwoTensor>("second_piola_kirchhoff_stress")),
      96        1410 :     _pk2_old(getMaterialPropertyOld<RankTwoTensor>("second_piola_kirchhoff_stress")),
      97         705 :     _total_lagrangian_strain(
      98         705 :         declareProperty<RankTwoTensor>("total_lagrangian_strain")), // Lagrangian strain
      99         705 :     _updated_rotation(declareProperty<RankTwoTensor>("updated_rotation")),
     100        1410 :     _updated_rotation_old(getMaterialPropertyOld<RankTwoTensor>("updated_rotation")),
     101         705 :     _misorientation(declareProperty<Real>("misorientation")),
     102         705 :     _crysrot(getMaterialProperty<RankTwoTensor>(
     103         705 :         _base_name + "crysrot")), // defined in the elasticity tensor classes for crystal plasticity
     104        2820 :     _print_convergence_message(getParam<bool>("print_state_variable_convergence_error_messages"))
     105             : {
     106         705 :   _convergence_failed = false;
     107         705 : }
     108             : 
     109             : void
     110       19632 : ComputeMultipleCrystalPlasticityStress::initQpStatefulProperties()
     111             : {
     112       19632 :   _plastic_deformation_gradient[_qp].zero();
     113       19632 :   _plastic_deformation_gradient[_qp].addIa(1.0);
     114             : 
     115       19632 :   if (_num_eigenstrains)
     116             :   {
     117        4368 :     (*_eigenstrain_deformation_gradient)[_qp].zero();
     118        4368 :     (*_eigenstrain_deformation_gradient)[_qp].addIa(1.0);
     119             :   }
     120             :   else
     121             :   {
     122             :     // set to identity if no eigenstrain is added
     123             :     _inverse_eigenstrain_deformation_grad.zero();
     124       15264 :     _inverse_eigenstrain_deformation_grad.addIa(1.0);
     125             :   }
     126             : 
     127       19632 :   _pk2[_qp].zero();
     128             : 
     129       19632 :   _total_lagrangian_strain[_qp].zero();
     130             : 
     131       19632 :   _updated_rotation[_qp].zero();
     132       19632 :   _updated_rotation[_qp].addIa(1.0);
     133             : 
     134       41184 :   for (unsigned int i = 0; i < _num_models; ++i)
     135             :   {
     136       21552 :     _models[i]->setQp(_qp);
     137       21552 :     _models[i]->initQpStatefulProperties();
     138             :   }
     139             : 
     140       24048 :   for (unsigned int i = 0; i < _num_eigenstrains; ++i)
     141             :   {
     142        4416 :     _eigenstrains[i]->setQp(_qp);
     143        4416 :     _eigenstrains[i]->initQpStatefulProperties();
     144             :   }
     145       19632 : }
     146             : 
     147             : void
     148         663 : ComputeMultipleCrystalPlasticityStress::initialSetup()
     149             : {
     150             :   // get crystal plasticity models
     151             :   std::vector<MaterialName> model_names =
     152        1326 :       getParam<std::vector<MaterialName>>("crystal_plasticity_models");
     153             : 
     154        1407 :   for (unsigned int i = 0; i < _num_models; ++i)
     155             :   {
     156             :     CrystalPlasticityStressUpdateBase * model =
     157         744 :         dynamic_cast<CrystalPlasticityStressUpdateBase *>(&getMaterialByName(model_names[i]));
     158             : 
     159         744 :     if (model)
     160             :     {
     161         744 :       _models.push_back(model);
     162             :       // TODO: check to make sure that the material model is compatible with this class
     163             :     }
     164             :     else
     165           0 :       mooseError("Model " + model_names[i] +
     166             :                  " is not compatible with ComputeMultipleCrystalPlasticityStress");
     167             :   }
     168             : 
     169             :   // get crystal plasticity eigenstrains
     170             :   std::vector<MaterialName> eigenstrain_names =
     171        1326 :       getParam<std::vector<MaterialName>>("eigenstrain_names");
     172             : 
     173         783 :   for (unsigned int i = 0; i < _num_eigenstrains; ++i)
     174             :   {
     175             :     ComputeCrystalPlasticityEigenstrainBase * eigenstrain =
     176         120 :         dynamic_cast<ComputeCrystalPlasticityEigenstrainBase *>(
     177         120 :             &getMaterialByName(eigenstrain_names[i]));
     178             : 
     179         120 :     if (eigenstrain)
     180         120 :       _eigenstrains.push_back(eigenstrain);
     181             :     else
     182           0 :       mooseError("Eigenstrain" + eigenstrain_names[i] +
     183             :                  " is not compatible with ComputeMultipleCrystalPlasticityStress");
     184             :   }
     185         663 : }
     186             : 
     187             : void
     188     1475310 : ComputeMultipleCrystalPlasticityStress::computeQpStress()
     189             : {
     190     3123036 :   for (unsigned int i = 0; i < _num_models; ++i)
     191             :   {
     192     1647726 :     _models[i]->setQp(_qp);
     193     1647726 :     _models[i]->setMaterialVectorSize();
     194             :   }
     195             : 
     196     1954880 :   for (unsigned int i = 0; i < _num_eigenstrains; ++i)
     197      479570 :     _eigenstrains[i]->setQp(_qp);
     198             : 
     199     1475310 :   updateStress(_stress[_qp], _Jacobian_mult[_qp]); // This is NOT the exact jacobian
     200     1475122 : }
     201             : 
     202             : void
     203     1475310 : ComputeMultipleCrystalPlasticityStress::updateStress(RankTwoTensor & cauchy_stress,
     204             :                                                      RankFourTensor & jacobian_mult)
     205             : {
     206             :   // Does not support face/boundary material property calculation
     207     1475310 :   if (isBoundaryMaterial())
     208             :     return;
     209             : 
     210             :   // Initialize substepping variables
     211             :   unsigned int substep_iter = 1;
     212             :   unsigned int num_substep = 1;
     213             : 
     214     1473390 :   _temporary_deformation_gradient_old = _deformation_gradient_old[_qp];
     215     1473390 :   if (_temporary_deformation_gradient_old.det() == 0)
     216           0 :     _temporary_deformation_gradient_old.addIa(1.0);
     217             : 
     218     1473390 :   _delta_deformation_gradient = _deformation_gradient[_qp] - _temporary_deformation_gradient_old;
     219             : 
     220             :   // Loop through all models and calculate the schmid tensor for the current state of the crystal
     221             :   // lattice
     222             :   // Not sure if we should pass in the updated or the original rotation here
     223             :   // If not, then we should not need to compute the flow direction every iteration here
     224     3119196 :   for (unsigned int i = 0; i < _num_models; ++i)
     225     1645806 :     _models[i]->calculateFlowDirection(_crysrot[_qp]);
     226             : 
     227             :   do
     228             :   {
     229     1601495 :     _convergence_failed = false;
     230     1601495 :     preSolveQp();
     231             : 
     232     1601495 :     _substep_dt = _dt / num_substep;
     233     3375406 :     for (unsigned int i = 0; i < _num_models; ++i)
     234     1773911 :       _models[i]->setSubstepDt(_substep_dt);
     235             : 
     236             :     // calculate F^{eigen} only when we have eigenstrain
     237             :     _inverse_eigenstrain_deformation_grad.zero();
     238     1601495 :     _inverse_eigenstrain_deformation_grad.addIa(1.0);
     239     1601495 :     if (_num_eigenstrains)
     240      537022 :       calculateEigenstrainDeformationGrad();
     241             : 
     242     3389055 :     for (unsigned int istep = 0; istep < num_substep; ++istep)
     243             :     {
     244     1915853 :       _temporary_deformation_gradient =
     245     1915853 :           (static_cast<Real>(istep) + 1) / num_substep * _delta_deformation_gradient;
     246     1915853 :       _temporary_deformation_gradient += _temporary_deformation_gradient_old;
     247             : 
     248     1915853 :       solveQp();
     249             : 
     250     1915849 :       if (_convergence_failed)
     251             :       {
     252      128279 :         if (_print_convergence_message)
     253           0 :           mooseWarning(
     254             :               "The crystal plasticity constitutive model has failed to converge. Increasing "
     255             :               "the number of substeps.");
     256             : 
     257      128279 :         substep_iter++;
     258      128279 :         num_substep *= 2;
     259      128279 :         break;
     260             :       }
     261             :     }
     262             : 
     263     1601481 :     if (substep_iter > _max_substep_iter && _convergence_failed)
     264         174 :       mooseException("ComputeMultipleCrystalPlasticityStress: Constitutive failure");
     265     1601307 :   } while (_convergence_failed);
     266             : 
     267     1473202 :   postSolveQp(cauchy_stress, jacobian_mult);
     268             : }
     269             : 
     270             : void
     271     1601495 : ComputeMultipleCrystalPlasticityStress::preSolveQp()
     272             : {
     273     3375406 :   for (unsigned int i = 0; i < _num_models; ++i)
     274     1773911 :     _models[i]->setInitialConstitutiveVariableValues();
     275             : 
     276     1601495 :   _pk2[_qp] = _pk2_old[_qp];
     277     1601495 :   _inverse_plastic_deformation_grad_old = _plastic_deformation_gradient_old[_qp].inverse();
     278     1601495 : }
     279             : 
     280             : void
     281     1915853 : ComputeMultipleCrystalPlasticityStress::solveQp()
     282             : {
     283     4004122 :   for (unsigned int i = 0; i < _num_models; ++i)
     284             :   {
     285     2088269 :     _models[i]->setSubstepConstitutiveVariableValues();
     286     2088269 :     _models[i]->calculateSlipResistance();
     287             :   }
     288             : 
     289     1915853 :   _inverse_plastic_deformation_grad = _inverse_plastic_deformation_grad_old;
     290             : 
     291     1915853 :   solveStateVariables();
     292     1915849 :   if (_convergence_failed)
     293             :     return; // pop back up and take a smaller substep
     294             : 
     295     3747556 :   for (unsigned int i = 0; i < _num_models; ++i)
     296     1959986 :     _models[i]->updateSubstepConstitutiveVariableValues();
     297             : 
     298             :   // save off the old F^{p} inverse now that have converged on the stress and state variables
     299     1787570 :   _inverse_plastic_deformation_grad_old = _inverse_plastic_deformation_grad;
     300             : }
     301             : 
     302             : void
     303     1473202 : ComputeMultipleCrystalPlasticityStress::postSolveQp(RankTwoTensor & cauchy_stress,
     304             :                                                     RankFourTensor & jacobian_mult)
     305             : {
     306     1473202 :   cauchy_stress = _elastic_deformation_gradient * _pk2[_qp] *
     307     1473202 :                   _elastic_deformation_gradient.transpose() / _elastic_deformation_gradient.det();
     308             : 
     309     1473202 :   calcTangentModuli(jacobian_mult);
     310             : 
     311     1473202 :   _total_lagrangian_strain[_qp] =
     312     1473202 :       _deformation_gradient[_qp].transpose() * _deformation_gradient[_qp] -
     313     1473202 :       RankTwoTensor::Identity();
     314     1473202 :   _total_lagrangian_strain[_qp] = _total_lagrangian_strain[_qp] * 0.5;
     315             : 
     316             :   // Calculate crystal rotation to track separately
     317     1473202 :   RankTwoTensor rot;
     318     1473202 :   _elastic_deformation_gradient.getRUDecompositionRotation(rot);
     319     1473202 :   _updated_rotation[_qp] = rot * _crysrot[_qp];
     320             : 
     321             :   // Calculate the misorientation
     322     1473202 :   auto _delta_misorientation_mat = _updated_rotation[_qp] * _updated_rotation_old[_qp].inverse();
     323     1473202 :   auto cos_val = (_delta_misorientation_mat.trace() - 1.0) / 2.0;
     324             :   // Mathematically, the values should lie in the range of [-1, 1]. However, there maybe numerical
     325             :   // errors during calculation. Let's guard small numerical errors here and throw an error when the
     326             :   // numerical error is too big, which indicates other issues.
     327     1473202 :   if (cos_val > 1.0 || cos_val < -1.0)
     328             :   {
     329      256666 :     if (MooseUtils::absoluteFuzzyEqual(cos_val, -1.0))
     330             :       cos_val = -1.0;
     331      256666 :     else if (MooseUtils::absoluteFuzzyEqual(cos_val, 1.0))
     332             :       cos_val = 1.0;
     333             :     else
     334           0 :       mooseError("Misorientation value is undefined. This should not happen.");
     335             :   }
     336     1473202 :   _misorientation[_qp] = std::acos(cos_val);
     337     1473202 : }
     338             : 
     339             : void
     340     1915853 : ComputeMultipleCrystalPlasticityStress::solveStateVariables()
     341             : {
     342             :   unsigned int iteration;
     343             :   bool iter_flag = true;
     344             : 
     345             :   iteration = 0;
     346             :   // Check for slip system resistance update tolerance
     347             :   do
     348             :   {
     349     2802150 :     solveStress();
     350     2802147 :     if (_convergence_failed)
     351             :       return;
     352             : 
     353     2675732 :     _plastic_deformation_gradient[_qp] =
     354     2675732 :         _inverse_plastic_deformation_grad.inverse(); // the postSoveStress
     355             : 
     356             :     // Update slip system resistance and state variable after the stress has been finalized
     357             :     // We loop through all the models for each calculation
     358             :     // in order to make sure that when coupling appears, the state variables are updated based on
     359             :     // the same components
     360     5689887 :     for (unsigned int i = 0; i < _num_models; ++i)
     361     3014155 :       _models[i]->cacheStateVariablesBeforeUpdate();
     362             : 
     363     5689887 :     for (unsigned int i = 0; i < _num_models; ++i)
     364     3014155 :       _models[i]->calculateStateVariableEvolutionRateComponent();
     365             : 
     366     5689886 :     for (unsigned int i = 0; i < _num_models; ++i)
     367     3014155 :       if (!_models[i]->updateStateVariables())
     368          88 :         _convergence_failed = true;
     369             : 
     370     5689885 :     for (unsigned int i = 0; i < _num_models; ++i)
     371     3014154 :       _models[i]->calculateSlipResistance();
     372             : 
     373     2675731 :     if (_convergence_failed)
     374             :       return;
     375             : 
     376     4637198 :     for (unsigned int i = 0; i < _num_models; ++i)
     377             :     {
     378             :       // iter_flag = false, stop iteration if all values are converged and good to go
     379             :       // iter_flag = true, continue iteration if any value is not converged
     380     2849595 :       if (!_models[i]->areConstitutiveStateVariablesConverged())
     381             :       {
     382             :         iter_flag = true;
     383             :         break;
     384             :       }
     385             :       else
     386             :         iter_flag = false; // iter_flag = false, stop iteration only when all models returns true
     387             :     }
     388             : 
     389     2675643 :     if (iter_flag)
     390             :     {
     391      888040 :       if (_print_convergence_message)
     392           0 :         mooseWarning("ComputeMultipleCrystalPlasticityStress: State variables (or the system "
     393             :                      "resistance) did not converge at element ",
     394           0 :                      _current_elem->id(),
     395             :                      " and qp ",
     396           0 :                      _qp,
     397             :                      "\n");
     398             :     }
     399     1787603 :     iteration++;
     400      888040 :   } while (iter_flag && iteration < _maxiterg);
     401             : 
     402     1789346 :   if (iteration == _maxiterg)
     403             :   {
     404        1776 :     if (_print_convergence_message)
     405           0 :       mooseWarning(
     406             :           "ComputeMultipleCrystalPlasticityStress: Hardness Integration error. Reached the "
     407             :           "maximum number of iterations to solve for the state variables at element ",
     408           0 :           _current_elem->id(),
     409             :           " and qp ",
     410           0 :           _qp,
     411             :           "\n");
     412             : 
     413        1776 :     _convergence_failed = true;
     414             :   }
     415             : }
     416             : 
     417             : void
     418     2802150 : ComputeMultipleCrystalPlasticityStress::solveStress()
     419             : {
     420             :   unsigned int iteration = 0;
     421     2802150 :   RankTwoTensor dpk2;
     422             :   Real rnorm, rnorm0, rnorm_prev;
     423             : 
     424             :   // Calculate stress residual
     425     2802150 :   calculateResidualAndJacobian();
     426     2802150 :   if (_convergence_failed)
     427             :   {
     428           0 :     if (_print_convergence_message)
     429           0 :       mooseWarning("ComputeMultipleCrystalPlasticityStress: the slip increment exceeds tolerance "
     430             :                    "at element ",
     431           0 :                    _current_elem->id(),
     432             :                    " and Gauss point ",
     433           0 :                    _qp);
     434             : 
     435           0 :     return;
     436             :   }
     437             : 
     438     2802150 :   rnorm = _residual_tensor.L2norm();
     439     2802150 :   rnorm0 = rnorm;
     440             : 
     441             :   // Check for stress residual tolerance; different from user object version which
     442             :   // compares the absolute tolerance of only the original rnorm value
     443    13383986 :   while (rnorm > _rtol * rnorm0 && rnorm > _abs_tol && iteration < _maxiter)
     444             :   {
     445             :     // Calculate stress increment
     446    10704196 :     dpk2 = -_jacobian.invSymm() * _residual_tensor;
     447    10704196 :     _pk2[_qp] = _pk2[_qp] + dpk2;
     448             : 
     449    10704196 :     calculateResidualAndJacobian();
     450             : 
     451    10704194 :     if (_convergence_failed)
     452             :     {
     453      122358 :       if (_print_convergence_message)
     454           0 :         mooseWarning("ComputeMultipleCrystalPlasticityStress: the slip increment exceeds tolerance "
     455             :                      "at element ",
     456           0 :                      _current_elem->id(),
     457             :                      " and Gauss point ",
     458           0 :                      _qp);
     459             : 
     460      122358 :       return;
     461             :     }
     462             : 
     463    10581836 :     rnorm_prev = rnorm;
     464    10581836 :     rnorm = _residual_tensor.L2norm();
     465             : 
     466    10581836 :     if (_use_line_search && rnorm > rnorm_prev && !lineSearchUpdate(rnorm_prev, dpk2))
     467             :     {
     468           0 :       if (_print_convergence_message)
     469           0 :         mooseWarning("ComputeMultipleCrystalPlasticityStress: Failed with line search");
     470             : 
     471           0 :       _convergence_failed = true;
     472           0 :       return;
     473             :     }
     474             : 
     475    10581836 :     if (_use_line_search)
     476      567184 :       rnorm = _residual_tensor.L2norm();
     477             : 
     478    10581836 :     iteration++;
     479             :   }
     480             : 
     481     2679790 :   if (iteration >= _maxiter)
     482             :   {
     483        4058 :     if (_print_convergence_message)
     484           1 :       mooseWarning("ComputeMultipleCrystalPlasticityStress: Stress Integration error rmax = ",
     485             :                    rnorm,
     486             :                    " and the tolerance is ",
     487           1 :                    _rtol * rnorm0,
     488             :                    " when the rnorm0 value is ",
     489             :                    rnorm0,
     490             :                    " for element ",
     491           0 :                    _current_elem->id(),
     492             :                    " and qp ",
     493           1 :                    _qp);
     494             : 
     495        4057 :     _convergence_failed = true;
     496             :   }
     497             : }
     498             : 
     499             : // Calculates stress residual equation and jacobian
     500             : void
     501    13506346 : ComputeMultipleCrystalPlasticityStress::calculateResidualAndJacobian()
     502             : {
     503    13506346 :   calculateResidual();
     504    13506344 :   if (_convergence_failed)
     505             :     return;
     506    13383986 :   calculateJacobian();
     507             : }
     508             : 
     509             : void
     510    13545226 : ComputeMultipleCrystalPlasticityStress::calculateResidual()
     511             : {
     512    13545226 :   RankTwoTensor ce, elastic_strain, ce_pk2, equivalent_slip_increment_per_model,
     513    13545226 :       equivalent_slip_increment, pk2_new;
     514             : 
     515             :   equivalent_slip_increment.zero();
     516             : 
     517             :   // calculate slip rate in order to compute F^{p-1}
     518    28705414 :   for (unsigned int i = 0; i < _num_models; ++i)
     519             :   {
     520             :     equivalent_slip_increment_per_model.zero();
     521             : 
     522             :     // calculate shear stress with consideration of contribution from other physics
     523    15282548 :     _models[i]->calculateShearStress(
     524    15282548 :         _pk2[_qp], _inverse_eigenstrain_deformation_grad, _num_eigenstrains);
     525             : 
     526    15282548 :     _convergence_failed = !_models[i]->calculateSlipRate();
     527             : 
     528    15282546 :     if (_convergence_failed)
     529             :       return;
     530             : 
     531    15160188 :     _models[i]->calculateEquivalentSlipIncrement(equivalent_slip_increment_per_model);
     532    15160188 :     equivalent_slip_increment += equivalent_slip_increment_per_model;
     533             :   }
     534             : 
     535             :   RankTwoTensor residual_equivalent_slip_increment =
     536    13422866 :       RankTwoTensor::Identity() - equivalent_slip_increment;
     537    13422866 :   _inverse_plastic_deformation_grad =
     538    13422866 :       _inverse_plastic_deformation_grad_old * residual_equivalent_slip_increment;
     539             : 
     540    13422866 :   _elastic_deformation_gradient = _temporary_deformation_gradient *
     541    13422866 :                                   _inverse_eigenstrain_deformation_grad *
     542             :                                   _inverse_plastic_deformation_grad;
     543             : 
     544    13422866 :   ce = _elastic_deformation_gradient.transpose() * _elastic_deformation_gradient;
     545             : 
     546    13422866 :   elastic_strain = ce - RankTwoTensor::Identity();
     547    13422866 :   elastic_strain *= 0.5;
     548             : 
     549    13422866 :   pk2_new = _elasticity_tensor[_qp] * elastic_strain;
     550    13422866 :   _residual_tensor = _pk2[_qp] - pk2_new;
     551             : }
     552             : 
     553             : void
     554    13383986 : ComputeMultipleCrystalPlasticityStress::calculateJacobian()
     555             : {
     556             :   // may not need to cache the dfpinvdpk2 here. need to double check
     557    13383986 :   RankFourTensor dfedfpinv, deedfe, dfpinvdpk2, dfpinvdpk2_per_model;
     558             : 
     559    13383986 :   RankTwoTensor ffeiginv = _temporary_deformation_gradient * _inverse_eigenstrain_deformation_grad;
     560             : 
     561    53535944 :   for (const auto i : make_range(Moose::dim))
     562   160607832 :     for (const auto j : make_range(Moose::dim))
     563   481823496 :       for (const auto k : make_range(Moose::dim))
     564   361367622 :         dfedfpinv(i, j, k, j) = ffeiginv(i, k);
     565             : 
     566    53535944 :   for (const auto i : make_range(Moose::dim))
     567   160607832 :     for (const auto j : make_range(Moose::dim))
     568   481823496 :       for (const auto k : make_range(Moose::dim))
     569             :       {
     570   361367622 :         deedfe(i, j, k, i) = deedfe(i, j, k, i) + _elastic_deformation_gradient(k, j) * 0.5;
     571   361367622 :         deedfe(i, j, k, j) = deedfe(i, j, k, j) + _elastic_deformation_gradient(k, i) * 0.5;
     572             :       }
     573             : 
     574    28505294 :   for (unsigned int i = 0; i < _num_models; ++i)
     575             :   {
     576    15121308 :     _models[i]->calculateTotalPlasticDeformationGradientDerivative(
     577             :         dfpinvdpk2_per_model,
     578    15121308 :         _inverse_plastic_deformation_grad_old,
     579    15121308 :         _inverse_eigenstrain_deformation_grad,
     580    15121308 :         _num_eigenstrains);
     581    15121308 :     dfpinvdpk2 += dfpinvdpk2_per_model;
     582             :   }
     583             : 
     584             :   _jacobian =
     585    26767972 :       RankFourTensor::IdentityFour() - (_elasticity_tensor[_qp] * deedfe * dfedfpinv * dfpinvdpk2);
     586    13383986 : }
     587             : 
     588             : void
     589     1473202 : ComputeMultipleCrystalPlasticityStress::calcTangentModuli(RankFourTensor & jacobian_mult)
     590             : {
     591     1473202 :   switch (_tan_mod_type)
     592             :   {
     593     1473202 :     case TangentModuliType::EXACT:
     594     1473202 :       elastoPlasticTangentModuli(jacobian_mult);
     595     1473202 :       break;
     596           0 :     default:
     597           0 :       elasticTangentModuli(jacobian_mult);
     598             :   }
     599     1473202 : }
     600             : 
     601             : void
     602     1473202 : ComputeMultipleCrystalPlasticityStress::elastoPlasticTangentModuli(RankFourTensor & jacobian_mult)
     603             : {
     604     1473202 :   RankFourTensor tan_mod;
     605     1473202 :   RankTwoTensor pk2fet, fepk2, feiginvfpinv;
     606     1473202 :   RankFourTensor deedfe, dsigdpk2dfe, dfedf;
     607             : 
     608             :   // Fill in the matrix stiffness material property
     609     5892808 :   for (const auto i : make_range(Moose::dim))
     610    17678424 :     for (const auto j : make_range(Moose::dim))
     611    53035272 :       for (const auto k : make_range(Moose::dim))
     612             :       {
     613    39776454 :         deedfe(i, j, k, i) = deedfe(i, j, k, i) + _elastic_deformation_gradient(k, j) * 0.5;
     614    39776454 :         deedfe(i, j, k, j) = deedfe(i, j, k, j) + _elastic_deformation_gradient(k, i) * 0.5;
     615             :       }
     616             : 
     617             :   usingTensorIndices(i_, j_, k_, l_);
     618     1473202 :   dsigdpk2dfe = _elastic_deformation_gradient.times<i_, k_, j_, l_>(_elastic_deformation_gradient) *
     619     1473202 :                 _elasticity_tensor[_qp] * deedfe;
     620             : 
     621     1473202 :   pk2fet = _pk2[_qp] * _elastic_deformation_gradient.transpose();
     622     1473202 :   fepk2 = _elastic_deformation_gradient * _pk2[_qp];
     623             : 
     624     5892808 :   for (const auto i : make_range(Moose::dim))
     625    17678424 :     for (const auto j : make_range(Moose::dim))
     626    53035272 :       for (const auto l : make_range(Moose::dim))
     627             :       {
     628    39776454 :         tan_mod(i, j, i, l) += pk2fet(l, j);
     629    39776454 :         tan_mod(i, j, j, l) += fepk2(i, l);
     630             :       }
     631             : 
     632     1473202 :   tan_mod += dsigdpk2dfe;
     633             : 
     634     1473202 :   const auto je = _elastic_deformation_gradient.det();
     635     1473202 :   if (je > 0.0)
     636     1473202 :     tan_mod /= je;
     637             : 
     638     1473202 :   feiginvfpinv = _inverse_eigenstrain_deformation_grad * _inverse_plastic_deformation_grad;
     639     5892808 :   for (const auto i : make_range(Moose::dim))
     640    17678424 :     for (const auto j : make_range(Moose::dim))
     641    53035272 :       for (const auto l : make_range(Moose::dim))
     642    39776454 :         dfedf(i, j, i, l) = feiginvfpinv(l, j);
     643             : 
     644     1473202 :   jacobian_mult = tan_mod * dfedf;
     645     1473202 : }
     646             : 
     647             : void
     648           0 : ComputeMultipleCrystalPlasticityStress::elasticTangentModuli(RankFourTensor & jacobian_mult)
     649             : {
     650             :   // update jacobian_mult
     651           0 :   jacobian_mult = _elasticity_tensor[_qp];
     652           0 : }
     653             : 
     654             : bool
     655       38880 : ComputeMultipleCrystalPlasticityStress::lineSearchUpdate(const Real & rnorm_prev,
     656             :                                                          const RankTwoTensor & dpk2)
     657             : {
     658       38880 :   if (_line_search_method == LineSearchMethod::CutHalf)
     659             :   {
     660             :     Real rnorm;
     661       38880 :     Real step = 1.0;
     662             : 
     663             :     do
     664             :     {
     665       38880 :       _pk2[_qp] = _pk2[_qp] - step * dpk2;
     666       38880 :       step /= 2.0;
     667       38880 :       _pk2[_qp] = _pk2[_qp] + step * dpk2;
     668             : 
     669       38880 :       calculateResidual();
     670       38880 :       rnorm = _residual_tensor.L2norm();
     671       38880 :     } while (rnorm > rnorm_prev && step > _min_line_search_step_size);
     672             : 
     673             :     // has norm improved or is the step still above minumum search step size?
     674       38880 :     return (rnorm <= rnorm_prev || step > _min_line_search_step_size);
     675             :   }
     676           0 :   else if (_line_search_method == LineSearchMethod::Bisection)
     677             :   {
     678             :     unsigned int count = 0;
     679             :     Real step_a = 0.0;
     680             :     Real step_b = 1.0;
     681           0 :     Real step = 1.0;
     682             :     Real s_m = 1000.0;
     683             :     Real rnorm = 1000.0;
     684             : 
     685           0 :     calculateResidual();
     686           0 :     auto s_b = _residual_tensor.doubleContraction(dpk2);
     687           0 :     const auto rnorm1 = _residual_tensor.L2norm();
     688           0 :     _pk2[_qp] = _pk2[_qp] - dpk2;
     689           0 :     calculateResidual();
     690           0 :     auto s_a = _residual_tensor.doubleContraction(dpk2);
     691           0 :     const auto rnorm0 = _residual_tensor.L2norm();
     692           0 :     _pk2[_qp] = _pk2[_qp] + dpk2;
     693             : 
     694           0 :     if ((rnorm1 / rnorm0) < _line_search_tolerance || s_a * s_b > 0)
     695             :     {
     696           0 :       calculateResidual();
     697           0 :       return true;
     698             :     }
     699             : 
     700           0 :     while ((rnorm / rnorm0) > _line_search_tolerance && count < _line_search_max_iterations)
     701             :     {
     702           0 :       _pk2[_qp] = _pk2[_qp] - step * dpk2;
     703           0 :       step = 0.5 * (step_b + step_a);
     704           0 :       _pk2[_qp] = _pk2[_qp] + step * dpk2;
     705           0 :       calculateResidual();
     706           0 :       s_m = _residual_tensor.doubleContraction(dpk2);
     707           0 :       rnorm = _residual_tensor.L2norm();
     708             : 
     709           0 :       if (s_m * s_a < 0.0)
     710             :       {
     711             :         step_b = step;
     712             :         s_b = s_m;
     713             :       }
     714           0 :       if (s_m * s_b < 0.0)
     715             :       {
     716             :         step_a = step;
     717             :         s_a = s_m;
     718             :       }
     719           0 :       count++;
     720             :     }
     721             : 
     722             :     // below tolerance and max iterations?
     723           0 :     return ((rnorm / rnorm0) < _line_search_tolerance && count < _line_search_max_iterations);
     724             :   }
     725             :   else
     726           0 :     mooseError("Line search method is not provided.");
     727             : }
     728             : 
     729             : void
     730      537022 : ComputeMultipleCrystalPlasticityStress::calculateEigenstrainDeformationGrad()
     731             : {
     732             :   _inverse_eigenstrain_deformation_grad.zero();
     733      537022 :   _inverse_eigenstrain_deformation_grad.addIa(1.0);
     734             : 
     735     1141402 :   for (unsigned int i = 0; i < _num_eigenstrains; ++i)
     736             :   {
     737      604390 :     _eigenstrains[i]->setSubstepDt(_substep_dt);
     738      604390 :     _eigenstrains[i]->computeQpProperties();
     739      604380 :     _inverse_eigenstrain_deformation_grad *= _eigenstrains[i]->getDeformationGradientInverse();
     740             :   }
     741      537012 :   (*_eigenstrain_deformation_gradient)[_qp] = _inverse_eigenstrain_deformation_grad.inverse();
     742      537012 : }

Generated by: LCOV version 1.14