LCOV - code coverage report
Current view: top level - src/materials/crystal_plasticity - ComputeMultipleCrystalPlasticityStress.C (source / functions) Hit Total Coverage
Test: idaholab/moose solid_mechanics: #31405 (292dce) with base fef103 Lines: 305 359 85.0 %
Date: 2025-09-04 07:57:23 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        1630 : ComputeMultipleCrystalPlasticityStress::validParams()
      21             : {
      22        1630 :   InputParameters params = ComputeFiniteStrainElasticStress::validParams();
      23             : 
      24        1630 :   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        3260 :   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        3260 :   params.addRequiredParam<std::vector<MaterialName>>(
      34             :       "crystal_plasticity_models",
      35             :       "The material objects to use to calculate crystal plasticity stress and strains.");
      36        3260 :   params.addParam<std::vector<MaterialName>>(
      37             :       "eigenstrain_names", {}, "The material objects to calculate eigenstrains.");
      38        3260 :   params.addParam<MooseEnum>("tan_mod_type",
      39        4890 :                              MooseEnum("exact none", "none"),
      40             :                              "Type of tangent moduli for preconditioner: default elastic");
      41        3260 :   params.addParam<Real>("rtol", 1e-6, "Constitutive stress residual relative tolerance");
      42        3260 :   params.addParam<Real>("abs_tol", 1e-6, "Constitutive stress residual absolute tolerance");
      43        3260 :   params.addParam<unsigned int>("maxiter", 100, "Maximum number of iterations for stress update");
      44        3260 :   params.addParam<unsigned int>(
      45        3260 :       "maxiter_state_variable", 100, "Maximum number of iterations for state variable update");
      46        3260 :   params.addParam<unsigned int>(
      47        3260 :       "maximum_substep_iteration", 1, "Maximum number of substep iteration");
      48        3260 :   params.addParam<bool>("use_line_search", false, "Use line search in constitutive update");
      49        3260 :   params.addParam<Real>("min_line_search_step_size", 0.01, "Minimum line search step size");
      50        3260 :   params.addParam<Real>("line_search_tol", 0.5, "Line search bisection method tolerance");
      51        3260 :   params.addParam<unsigned int>(
      52        3260 :       "line_search_maxiter", 20, "Line search bisection method maximum number of iteration");
      53        3260 :   params.addParam<MooseEnum>("line_search_method",
      54        4890 :                              MooseEnum("CUT_HALF BISECTION", "CUT_HALF"),
      55             :                              "The method used in line search");
      56        3260 :   params.addParam<bool>(
      57             :       "print_state_variable_convergence_error_messages",
      58        3260 :       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        1630 :   return params;
      62           0 : }
      63             : 
      64        1218 : ComputeMultipleCrystalPlasticityStress::ComputeMultipleCrystalPlasticityStress(
      65        1218 :     const InputParameters & parameters)
      66             :   : ComputeFiniteStrainElasticStress(parameters),
      67        1218 :     _num_models(getParam<std::vector<MaterialName>>("crystal_plasticity_models").size()),
      68        2436 :     _num_eigenstrains(getParam<std::vector<MaterialName>>("eigenstrain_names").size()),
      69        2604 :     _base_name(isParamValid("base_name") ? getParam<std::string>("base_name") + "_" : ""),
      70        2436 :     _elasticity_tensor(getMaterialPropertyByName<RankFourTensor>(_base_name + "elasticity_tensor")),
      71        2436 :     _rtol(getParam<Real>("rtol")),
      72        2436 :     _abs_tol(getParam<Real>("abs_tol")),
      73        2436 :     _maxiter(getParam<unsigned int>("maxiter")),
      74        2436 :     _maxiterg(getParam<unsigned int>("maxiter_state_variable")),
      75        2436 :     _tan_mod_type(getParam<MooseEnum>("tan_mod_type").getEnum<TangentModuliType>()),
      76        2436 :     _max_substep_iter(getParam<unsigned int>("maximum_substep_iteration")),
      77        2436 :     _use_line_search(getParam<bool>("use_line_search")),
      78        2436 :     _min_line_search_step_size(getParam<Real>("min_line_search_step_size")),
      79        2436 :     _line_search_tolerance(getParam<Real>("line_search_tol")),
      80        2436 :     _line_search_max_iterations(getParam<unsigned int>("line_search_maxiter")),
      81        2436 :     _line_search_method(getParam<MooseEnum>("line_search_method").getEnum<LineSearchMethod>()),
      82        1218 :     _plastic_deformation_gradient(declareProperty<RankTwoTensor>("plastic_deformation_gradient")),
      83        1218 :     _plastic_deformation_gradient_old(
      84        1218 :         getMaterialPropertyOld<RankTwoTensor>("plastic_deformation_gradient")),
      85        1218 :     _eigenstrain_deformation_gradient(
      86        1218 :         _num_eigenstrains ? &declareProperty<RankTwoTensor>("eigenstrain_deformation_gradient")
      87             :                           : nullptr),
      88        1218 :     _eigenstrain_deformation_gradient_old(
      89        1218 :         _num_eigenstrains
      90        1413 :             ? &getMaterialPropertyOld<RankTwoTensor>("eigenstrain_deformation_gradient")
      91             :             : nullptr),
      92        2436 :     _deformation_gradient(getMaterialProperty<RankTwoTensor>(_base_name + "deformation_gradient")),
      93        1218 :     _deformation_gradient_old(
      94        1218 :         getMaterialPropertyOld<RankTwoTensor>(_base_name + "deformation_gradient")),
      95        1218 :     _pk2(declareProperty<RankTwoTensor>("second_piola_kirchhoff_stress")),
      96        2436 :     _pk2_old(getMaterialPropertyOld<RankTwoTensor>("second_piola_kirchhoff_stress")),
      97        1218 :     _total_lagrangian_strain(
      98        1218 :         declareProperty<RankTwoTensor>("total_lagrangian_strain")), // Lagrangian strain
      99        1218 :     _updated_rotation(declareProperty<RankTwoTensor>("updated_rotation")),
     100        1218 :     _crysrot(getMaterialProperty<RankTwoTensor>(
     101        1218 :         _base_name + "crysrot")), // defined in the elasticity tensor classes for crystal plasticity
     102        4872 :     _print_convergence_message(getParam<bool>("print_state_variable_convergence_error_messages"))
     103             : {
     104        1218 :   _convergence_failed = false;
     105        1218 : }
     106             : 
     107             : void
     108       27984 : ComputeMultipleCrystalPlasticityStress::initQpStatefulProperties()
     109             : {
     110       27984 :   _plastic_deformation_gradient[_qp].zero();
     111       27984 :   _plastic_deformation_gradient[_qp].addIa(1.0);
     112             : 
     113       27984 :   if (_num_eigenstrains)
     114             :   {
     115        7568 :     (*_eigenstrain_deformation_gradient)[_qp].zero();
     116        7568 :     (*_eigenstrain_deformation_gradient)[_qp].addIa(1.0);
     117             :   }
     118             :   else
     119             :   {
     120             :     // set to identity if no eigenstrain is added
     121             :     _inverse_eigenstrain_deformation_grad.zero();
     122       20416 :     _inverse_eigenstrain_deformation_grad.addIa(1.0);
     123             :   }
     124             : 
     125       27984 :   _pk2[_qp].zero();
     126             : 
     127       27984 :   _total_lagrangian_strain[_qp].zero();
     128             : 
     129       27984 :   _updated_rotation[_qp].zero();
     130       27984 :   _updated_rotation[_qp].addIa(1.0);
     131             : 
     132       59168 :   for (unsigned int i = 0; i < _num_models; ++i)
     133             :   {
     134       31184 :     _models[i]->setQp(_qp);
     135       31184 :     _models[i]->initQpStatefulProperties();
     136             :   }
     137             : 
     138       35632 :   for (unsigned int i = 0; i < _num_eigenstrains; ++i)
     139             :   {
     140        7648 :     _eigenstrains[i]->setQp(_qp);
     141        7648 :     _eigenstrains[i]->initQpStatefulProperties();
     142             :   }
     143       27984 : }
     144             : 
     145             : void
     146        1134 : ComputeMultipleCrystalPlasticityStress::initialSetup()
     147             : {
     148             :   // get crystal plasticity models
     149             :   std::vector<MaterialName> model_names =
     150        2268 :       getParam<std::vector<MaterialName>>("crystal_plasticity_models");
     151             : 
     152        2412 :   for (unsigned int i = 0; i < _num_models; ++i)
     153             :   {
     154             :     CrystalPlasticityStressUpdateBase * model =
     155        1278 :         dynamic_cast<CrystalPlasticityStressUpdateBase *>(&getMaterialByName(model_names[i]));
     156             : 
     157        1278 :     if (model)
     158             :     {
     159        1278 :       _models.push_back(model);
     160             :       // TODO: check to make sure that the material model is compatible with this class
     161             :     }
     162             :     else
     163           0 :       mooseError("Model " + model_names[i] +
     164             :                  " is not compatible with ComputeMultipleCrystalPlasticityStress");
     165             :   }
     166             : 
     167             :   // get crystal plasticity eigenstrains
     168             :   std::vector<MaterialName> eigenstrain_names =
     169        2268 :       getParam<std::vector<MaterialName>>("eigenstrain_names");
     170             : 
     171        1350 :   for (unsigned int i = 0; i < _num_eigenstrains; ++i)
     172             :   {
     173             :     ComputeCrystalPlasticityEigenstrainBase * eigenstrain =
     174         216 :         dynamic_cast<ComputeCrystalPlasticityEigenstrainBase *>(
     175         216 :             &getMaterialByName(eigenstrain_names[i]));
     176             : 
     177         216 :     if (eigenstrain)
     178         216 :       _eigenstrains.push_back(eigenstrain);
     179             :     else
     180           0 :       mooseError("Eigenstrain" + eigenstrain_names[i] +
     181             :                  " is not compatible with ComputeMultipleCrystalPlasticityStress");
     182             :   }
     183        1134 : }
     184             : 
     185             : void
     186     2255745 : ComputeMultipleCrystalPlasticityStress::computeQpStress()
     187             : {
     188     4797442 :   for (unsigned int i = 0; i < _num_models; ++i)
     189             :   {
     190     2541697 :     _models[i]->setQp(_qp);
     191     2541697 :     _models[i]->setMaterialVectorSize();
     192             :   }
     193             : 
     194     3061781 :   for (unsigned int i = 0; i < _num_eigenstrains; ++i)
     195      806036 :     _eigenstrains[i]->setQp(_qp);
     196             : 
     197     2255745 :   updateStress(_stress[_qp], _Jacobian_mult[_qp]); // This is NOT the exact jacobian
     198     2255425 : }
     199             : 
     200             : void
     201     2255745 : ComputeMultipleCrystalPlasticityStress::updateStress(RankTwoTensor & cauchy_stress,
     202             :                                                      RankFourTensor & jacobian_mult)
     203             : {
     204             :   // Does not support face/boundary material property calculation
     205     2255745 :   if (isBoundaryMaterial())
     206             :     return;
     207             : 
     208             :   // Initialize substepping variables
     209             :   unsigned int substep_iter = 1;
     210             :   unsigned int num_substep = 1;
     211             : 
     212     2252545 :   _temporary_deformation_gradient_old = _deformation_gradient_old[_qp];
     213     2252545 :   if (_temporary_deformation_gradient_old.det() == 0)
     214           0 :     _temporary_deformation_gradient_old.addIa(1.0);
     215             : 
     216     2252545 :   _delta_deformation_gradient = _deformation_gradient[_qp] - _temporary_deformation_gradient_old;
     217             : 
     218             :   // Loop through all models and calculate the schmid tensor for the current state of the crystal
     219             :   // lattice
     220             :   // Not sure if we should pass in the updated or the original rotation here
     221             :   // If not, then we should not need to compute the flow direction every iteration here
     222     4791042 :   for (unsigned int i = 0; i < _num_models; ++i)
     223     2538497 :     _models[i]->calculateFlowDirection(_crysrot[_qp]);
     224             : 
     225             :   do
     226             :   {
     227     2463776 :     _convergence_failed = false;
     228     2463776 :     preSolveQp();
     229             : 
     230     2463776 :     _substep_dt = _dt / num_substep;
     231     5213504 :     for (unsigned int i = 0; i < _num_models; ++i)
     232     2749728 :       _models[i]->setSubstepDt(_substep_dt);
     233             : 
     234             :     // calculate F^{eigen} only when we have eigenstrain
     235             :     _inverse_eigenstrain_deformation_grad.zero();
     236     2463776 :     _inverse_eigenstrain_deformation_grad.addIa(1.0);
     237     2463776 :     if (_num_eigenstrains)
     238      899824 :       calculateEigenstrainDeformationGrad();
     239             : 
     240     5235133 :     for (unsigned int istep = 0; istep < num_substep; ++istep)
     241             :     {
     242     2982908 :       _temporary_deformation_gradient =
     243     2982908 :           (static_cast<Real>(istep) + 1) / num_substep * _delta_deformation_gradient;
     244     2982908 :       _temporary_deformation_gradient += _temporary_deformation_gradient_old;
     245             : 
     246     2982908 :       solveQp();
     247             : 
     248     2982900 :       if (_convergence_failed)
     249             :       {
     250      211523 :         if (_print_convergence_message)
     251           0 :           mooseWarning(
     252             :               "The crystal plasticity constitutive model has failed to converge. Increasing "
     253             :               "the number of substeps.");
     254             : 
     255      211523 :         substep_iter++;
     256      211523 :         num_substep *= 2;
     257      211523 :         break;
     258             :       }
     259             :     }
     260             : 
     261     2463748 :     if (substep_iter > _max_substep_iter && _convergence_failed)
     262         292 :       mooseException("ComputeMultipleCrystalPlasticityStress: Constitutive failure");
     263     2463456 :   } while (_convergence_failed);
     264             : 
     265     2252225 :   postSolveQp(cauchy_stress, jacobian_mult);
     266             : }
     267             : 
     268             : void
     269     2463776 : ComputeMultipleCrystalPlasticityStress::preSolveQp()
     270             : {
     271     5213504 :   for (unsigned int i = 0; i < _num_models; ++i)
     272     2749728 :     _models[i]->setInitialConstitutiveVariableValues();
     273             : 
     274     2463776 :   _pk2[_qp] = _pk2_old[_qp];
     275     2463776 :   _inverse_plastic_deformation_grad_old = _plastic_deformation_gradient_old[_qp].inverse();
     276     2463776 : }
     277             : 
     278             : void
     279     2982908 : ComputeMultipleCrystalPlasticityStress::solveQp()
     280             : {
     281     6251768 :   for (unsigned int i = 0; i < _num_models; ++i)
     282             :   {
     283     3268860 :     _models[i]->setSubstepConstitutiveVariableValues();
     284     3268860 :     _models[i]->calculateSlipResistance();
     285             :   }
     286             : 
     287     2982908 :   _inverse_plastic_deformation_grad = _inverse_plastic_deformation_grad_old;
     288             : 
     289     2982908 :   solveStateVariables();
     290     2982900 :   if (_convergence_failed)
     291             :     return; // pop back up and take a smaller substep
     292             : 
     293     5828706 :   for (unsigned int i = 0; i < _num_models; ++i)
     294     3057329 :     _models[i]->updateSubstepConstitutiveVariableValues();
     295             : 
     296             :   // save off the old F^{p} inverse now that have converged on the stress and state variables
     297     2771377 :   _inverse_plastic_deformation_grad_old = _inverse_plastic_deformation_grad;
     298             : }
     299             : 
     300             : void
     301     2252225 : ComputeMultipleCrystalPlasticityStress::postSolveQp(RankTwoTensor & cauchy_stress,
     302             :                                                     RankFourTensor & jacobian_mult)
     303             : {
     304     2252225 :   cauchy_stress = _elastic_deformation_gradient * _pk2[_qp] *
     305     2252225 :                   _elastic_deformation_gradient.transpose() / _elastic_deformation_gradient.det();
     306             : 
     307     2252225 :   calcTangentModuli(jacobian_mult);
     308             : 
     309     2252225 :   _total_lagrangian_strain[_qp] =
     310     2252225 :       _deformation_gradient[_qp].transpose() * _deformation_gradient[_qp] -
     311     2252225 :       RankTwoTensor::Identity();
     312     2252225 :   _total_lagrangian_strain[_qp] = _total_lagrangian_strain[_qp] * 0.5;
     313             : 
     314             :   // Calculate crystal rotation to track separately
     315     2252225 :   RankTwoTensor rot;
     316     2252225 :   _elastic_deformation_gradient.getRUDecompositionRotation(rot);
     317     2252225 :   _updated_rotation[_qp] = rot * _crysrot[_qp];
     318     2252225 : }
     319             : 
     320             : void
     321     2982908 : ComputeMultipleCrystalPlasticityStress::solveStateVariables()
     322             : {
     323             :   unsigned int iteration;
     324             :   bool iter_flag = true;
     325             : 
     326             :   iteration = 0;
     327             :   // Check for slip system resistance update tolerance
     328             :   do
     329             :   {
     330     4463042 :     solveStress();
     331     4463036 :     if (_convergence_failed)
     332             :       return;
     333             : 
     334     4254619 :     _plastic_deformation_gradient[_qp] =
     335     4254619 :         _inverse_plastic_deformation_grad.inverse(); // the postSoveStress
     336             : 
     337             :     // Update slip system resistance and state variable after the stress has been finalized
     338             :     // We loop through all the models for each calculation
     339             :     // in order to make sure that when coupling appears, the state variables are updated based on
     340             :     // the same components
     341     9073759 :     for (unsigned int i = 0; i < _num_models; ++i)
     342     4819140 :       _models[i]->cacheStateVariablesBeforeUpdate();
     343             : 
     344     9073759 :     for (unsigned int i = 0; i < _num_models; ++i)
     345     4819140 :       _models[i]->calculateStateVariableEvolutionRateComponent();
     346             : 
     347     9073757 :     for (unsigned int i = 0; i < _num_models; ++i)
     348     4819140 :       if (!_models[i]->updateStateVariables())
     349         146 :         _convergence_failed = true;
     350             : 
     351     9073755 :     for (unsigned int i = 0; i < _num_models; ++i)
     352     4819138 :       _models[i]->calculateSlipResistance();
     353             : 
     354     4254617 :     if (_convergence_failed)
     355             :       return;
     356             : 
     357     7314543 :     for (unsigned int i = 0; i < _num_models; ++i)
     358             :     {
     359             :       // iter_flag = false, stop iteration if all values are converged and good to go
     360             :       // iter_flag = true, continue iteration if any value is not converged
     361     4543111 :       if (!_models[i]->areConstitutiveStateVariablesConverged())
     362             :       {
     363             :         iter_flag = true;
     364             :         break;
     365             :       }
     366             :       else
     367             :         iter_flag = false; // iter_flag = false, stop iteration only when all models returns true
     368             :     }
     369             : 
     370     4254471 :     if (iter_flag)
     371             :     {
     372     1483039 :       if (_print_convergence_message)
     373           0 :         mooseWarning("ComputeMultipleCrystalPlasticityStress: State variables (or the system "
     374             :                      "resistance) did not converge at element ",
     375           0 :                      _current_elem->id(),
     376             :                      " and qp ",
     377           0 :                      _qp,
     378             :                      "\n");
     379             :     }
     380     2771432 :     iteration++;
     381     1483039 :   } while (iter_flag && iteration < _maxiterg);
     382             : 
     383     2774337 :   if (iteration == _maxiterg)
     384             :   {
     385        2960 :     if (_print_convergence_message)
     386           0 :       mooseWarning(
     387             :           "ComputeMultipleCrystalPlasticityStress: Hardness Integration error. Reached the "
     388             :           "maximum number of iterations to solve for the state variables at element ",
     389           0 :           _current_elem->id(),
     390             :           " and qp ",
     391           0 :           _qp,
     392             :           "\n");
     393             : 
     394        2960 :     _convergence_failed = true;
     395             :   }
     396             : }
     397             : 
     398             : void
     399     4463042 : ComputeMultipleCrystalPlasticityStress::solveStress()
     400             : {
     401             :   unsigned int iteration = 0;
     402     4463042 :   RankTwoTensor dpk2;
     403             :   Real rnorm, rnorm0, rnorm_prev;
     404             : 
     405             :   // Calculate stress residual
     406     4463042 :   calculateResidualAndJacobian();
     407     4463042 :   if (_convergence_failed)
     408             :   {
     409           0 :     if (_print_convergence_message)
     410           0 :       mooseWarning("ComputeMultipleCrystalPlasticityStress: the slip increment exceeds tolerance "
     411             :                    "at element ",
     412           0 :                    _current_elem->id(),
     413             :                    " and Gauss point ",
     414           0 :                    _qp);
     415             : 
     416           0 :     return;
     417             :   }
     418             : 
     419     4463042 :   rnorm = _residual_tensor.L2norm();
     420     4463042 :   rnorm0 = rnorm;
     421             : 
     422             :   // Check for stress residual tolerance; different from user object version which
     423             :   // compares the absolute tolerance of only the original rnorm value
     424    22005899 :   while (rnorm > _rtol * rnorm0 && rnorm > _abs_tol && iteration < _maxiter)
     425             :   {
     426             :     // Calculate stress increment
     427    17744616 :     dpk2 = -_jacobian.invSymm() * _residual_tensor;
     428    17744616 :     _pk2[_qp] = _pk2[_qp] + dpk2;
     429             : 
     430    17744616 :     calculateResidualAndJacobian();
     431             : 
     432    17744612 :     if (_convergence_failed)
     433             :     {
     434      201755 :       if (_print_convergence_message)
     435           0 :         mooseWarning("ComputeMultipleCrystalPlasticityStress: the slip increment exceeds tolerance "
     436             :                      "at element ",
     437           0 :                      _current_elem->id(),
     438             :                      " and Gauss point ",
     439           0 :                      _qp);
     440             : 
     441      201755 :       return;
     442             :     }
     443             : 
     444    17542857 :     rnorm_prev = rnorm;
     445    17542857 :     rnorm = _residual_tensor.L2norm();
     446             : 
     447    17542857 :     if (_use_line_search && rnorm > rnorm_prev && !lineSearchUpdate(rnorm_prev, dpk2))
     448             :     {
     449           0 :       if (_print_convergence_message)
     450           0 :         mooseWarning("ComputeMultipleCrystalPlasticityStress: Failed with line search");
     451             : 
     452           0 :       _convergence_failed = true;
     453           0 :       return;
     454             :     }
     455             : 
     456    17542857 :     if (_use_line_search)
     457      945728 :       rnorm = _residual_tensor.L2norm();
     458             : 
     459    17542857 :     iteration++;
     460             :   }
     461             : 
     462     4261283 :   if (iteration >= _maxiter)
     463             :   {
     464        6664 :     if (_print_convergence_message)
     465           2 :       mooseWarning("ComputeMultipleCrystalPlasticityStress: Stress Integration error rmax = ",
     466             :                    rnorm,
     467             :                    " and the tolerance is ",
     468           2 :                    _rtol * rnorm0,
     469             :                    " when the rnorm0 value is ",
     470             :                    rnorm0,
     471             :                    " for element ",
     472           0 :                    _current_elem->id(),
     473             :                    " and qp ",
     474           2 :                    _qp);
     475             : 
     476        6662 :     _convergence_failed = true;
     477             :   }
     478             : }
     479             : 
     480             : // Calculates stress residual equation and jacobian
     481             : void
     482    22207658 : ComputeMultipleCrystalPlasticityStress::calculateResidualAndJacobian()
     483             : {
     484    22207658 :   calculateResidual();
     485    22207654 :   if (_convergence_failed)
     486             :     return;
     487    22005899 :   calculateJacobian();
     488             : }
     489             : 
     490             : void
     491    22272458 : ComputeMultipleCrystalPlasticityStress::calculateResidual()
     492             : {
     493    22272458 :   RankTwoTensor ce, elastic_strain, ce_pk2, equivalent_slip_increment_per_model,
     494    22272458 :       equivalent_slip_increment, pk2_new;
     495             : 
     496             :   equivalent_slip_increment.zero();
     497             : 
     498             :   // calculate slip rate in order to compute F^{p-1}
     499    47318982 :   for (unsigned int i = 0; i < _num_models; ++i)
     500             :   {
     501             :     equivalent_slip_increment_per_model.zero();
     502             : 
     503             :     // calculate shear stress with consideration of contribution from other physics
     504    25248283 :     _models[i]->calculateShearStress(
     505    25248283 :         _pk2[_qp], _inverse_eigenstrain_deformation_grad, _num_eigenstrains);
     506             : 
     507    25248283 :     _convergence_failed = !_models[i]->calculateSlipRate();
     508             : 
     509    25248279 :     if (_convergence_failed)
     510             :       return;
     511             : 
     512    25046524 :     _models[i]->calculateEquivalentSlipIncrement(equivalent_slip_increment_per_model);
     513    25046524 :     equivalent_slip_increment += equivalent_slip_increment_per_model;
     514             :   }
     515             : 
     516             :   RankTwoTensor residual_equivalent_slip_increment =
     517    22070699 :       RankTwoTensor::Identity() - equivalent_slip_increment;
     518    22070699 :   _inverse_plastic_deformation_grad =
     519    22070699 :       _inverse_plastic_deformation_grad_old * residual_equivalent_slip_increment;
     520             : 
     521    22070699 :   _elastic_deformation_gradient = _temporary_deformation_gradient *
     522    22070699 :                                   _inverse_eigenstrain_deformation_grad *
     523             :                                   _inverse_plastic_deformation_grad;
     524             : 
     525    22070699 :   ce = _elastic_deformation_gradient.transpose() * _elastic_deformation_gradient;
     526             : 
     527    22070699 :   elastic_strain = ce - RankTwoTensor::Identity();
     528    22070699 :   elastic_strain *= 0.5;
     529             : 
     530    22070699 :   pk2_new = _elasticity_tensor[_qp] * elastic_strain;
     531    22070699 :   _residual_tensor = _pk2[_qp] - pk2_new;
     532             : }
     533             : 
     534             : void
     535    22005899 : ComputeMultipleCrystalPlasticityStress::calculateJacobian()
     536             : {
     537             :   // may not need to cache the dfpinvdpk2 here. need to double check
     538    22005899 :   RankFourTensor dfedfpinv, deedfe, dfpinvdpk2, dfpinvdpk2_per_model;
     539             : 
     540    22005899 :   RankTwoTensor ffeiginv = _temporary_deformation_gradient * _inverse_eigenstrain_deformation_grad;
     541             : 
     542    88023596 :   for (const auto i : make_range(Moose::dim))
     543   264070788 :     for (const auto j : make_range(Moose::dim))
     544   792212364 :       for (const auto k : make_range(Moose::dim))
     545   594159273 :         dfedfpinv(i, j, k, j) = ffeiginv(i, k);
     546             : 
     547    88023596 :   for (const auto i : make_range(Moose::dim))
     548   264070788 :     for (const auto j : make_range(Moose::dim))
     549   792212364 :       for (const auto k : make_range(Moose::dim))
     550             :       {
     551   594159273 :         deedfe(i, j, k, i) = deedfe(i, j, k, i) + _elastic_deformation_gradient(k, j) * 0.5;
     552   594159273 :         deedfe(i, j, k, j) = deedfe(i, j, k, j) + _elastic_deformation_gradient(k, i) * 0.5;
     553             :       }
     554             : 
     555    46987623 :   for (unsigned int i = 0; i < _num_models; ++i)
     556             :   {
     557    24981724 :     _models[i]->calculateTotalPlasticDeformationGradientDerivative(
     558             :         dfpinvdpk2_per_model,
     559    24981724 :         _inverse_plastic_deformation_grad_old,
     560    24981724 :         _inverse_eigenstrain_deformation_grad,
     561    24981724 :         _num_eigenstrains);
     562    24981724 :     dfpinvdpk2 += dfpinvdpk2_per_model;
     563             :   }
     564             : 
     565             :   _jacobian =
     566    44011798 :       RankFourTensor::IdentityFour() - (_elasticity_tensor[_qp] * deedfe * dfedfpinv * dfpinvdpk2);
     567    22005899 : }
     568             : 
     569             : void
     570     2252225 : ComputeMultipleCrystalPlasticityStress::calcTangentModuli(RankFourTensor & jacobian_mult)
     571             : {
     572     2252225 :   switch (_tan_mod_type)
     573             :   {
     574     2252225 :     case TangentModuliType::EXACT:
     575     2252225 :       elastoPlasticTangentModuli(jacobian_mult);
     576     2252225 :       break;
     577           0 :     default:
     578           0 :       elasticTangentModuli(jacobian_mult);
     579             :   }
     580     2252225 : }
     581             : 
     582             : void
     583     2252225 : ComputeMultipleCrystalPlasticityStress::elastoPlasticTangentModuli(RankFourTensor & jacobian_mult)
     584             : {
     585     2252225 :   RankFourTensor tan_mod;
     586     2252225 :   RankTwoTensor pk2fet, fepk2, feiginvfpinv;
     587     2252225 :   RankFourTensor deedfe, dsigdpk2dfe, dfedf;
     588             : 
     589             :   // Fill in the matrix stiffness material property
     590     9008900 :   for (const auto i : make_range(Moose::dim))
     591    27026700 :     for (const auto j : make_range(Moose::dim))
     592    81080100 :       for (const auto k : make_range(Moose::dim))
     593             :       {
     594    60810075 :         deedfe(i, j, k, i) = deedfe(i, j, k, i) + _elastic_deformation_gradient(k, j) * 0.5;
     595    60810075 :         deedfe(i, j, k, j) = deedfe(i, j, k, j) + _elastic_deformation_gradient(k, i) * 0.5;
     596             :       }
     597             : 
     598             :   usingTensorIndices(i_, j_, k_, l_);
     599     2252225 :   dsigdpk2dfe = _elastic_deformation_gradient.times<i_, k_, j_, l_>(_elastic_deformation_gradient) *
     600     2252225 :                 _elasticity_tensor[_qp] * deedfe;
     601             : 
     602     2252225 :   pk2fet = _pk2[_qp] * _elastic_deformation_gradient.transpose();
     603     2252225 :   fepk2 = _elastic_deformation_gradient * _pk2[_qp];
     604             : 
     605     9008900 :   for (const auto i : make_range(Moose::dim))
     606    27026700 :     for (const auto j : make_range(Moose::dim))
     607    81080100 :       for (const auto l : make_range(Moose::dim))
     608             :       {
     609    60810075 :         tan_mod(i, j, i, l) += pk2fet(l, j);
     610    60810075 :         tan_mod(i, j, j, l) += fepk2(i, l);
     611             :       }
     612             : 
     613     2252225 :   tan_mod += dsigdpk2dfe;
     614             : 
     615     2252225 :   const auto je = _elastic_deformation_gradient.det();
     616     2252225 :   if (je > 0.0)
     617     2252225 :     tan_mod /= je;
     618             : 
     619     2252225 :   feiginvfpinv = _inverse_eigenstrain_deformation_grad * _inverse_plastic_deformation_grad;
     620     9008900 :   for (const auto i : make_range(Moose::dim))
     621    27026700 :     for (const auto j : make_range(Moose::dim))
     622    81080100 :       for (const auto l : make_range(Moose::dim))
     623    60810075 :         dfedf(i, j, i, l) = feiginvfpinv(l, j);
     624             : 
     625     2252225 :   jacobian_mult = tan_mod * dfedf;
     626     2252225 : }
     627             : 
     628             : void
     629           0 : ComputeMultipleCrystalPlasticityStress::elasticTangentModuli(RankFourTensor & jacobian_mult)
     630             : {
     631             :   // update jacobian_mult
     632           0 :   jacobian_mult = _elasticity_tensor[_qp];
     633           0 : }
     634             : 
     635             : bool
     636       64800 : ComputeMultipleCrystalPlasticityStress::lineSearchUpdate(const Real & rnorm_prev,
     637             :                                                          const RankTwoTensor & dpk2)
     638             : {
     639       64800 :   if (_line_search_method == LineSearchMethod::CutHalf)
     640             :   {
     641             :     Real rnorm;
     642       64800 :     Real step = 1.0;
     643             : 
     644             :     do
     645             :     {
     646       64800 :       _pk2[_qp] = _pk2[_qp] - step * dpk2;
     647       64800 :       step /= 2.0;
     648       64800 :       _pk2[_qp] = _pk2[_qp] + step * dpk2;
     649             : 
     650       64800 :       calculateResidual();
     651       64800 :       rnorm = _residual_tensor.L2norm();
     652       64800 :     } while (rnorm > rnorm_prev && step > _min_line_search_step_size);
     653             : 
     654             :     // has norm improved or is the step still above minumum search step size?
     655       64800 :     return (rnorm <= rnorm_prev || step > _min_line_search_step_size);
     656             :   }
     657           0 :   else if (_line_search_method == LineSearchMethod::Bisection)
     658             :   {
     659             :     unsigned int count = 0;
     660             :     Real step_a = 0.0;
     661             :     Real step_b = 1.0;
     662           0 :     Real step = 1.0;
     663             :     Real s_m = 1000.0;
     664             :     Real rnorm = 1000.0;
     665             : 
     666           0 :     calculateResidual();
     667           0 :     auto s_b = _residual_tensor.doubleContraction(dpk2);
     668           0 :     const auto rnorm1 = _residual_tensor.L2norm();
     669           0 :     _pk2[_qp] = _pk2[_qp] - dpk2;
     670           0 :     calculateResidual();
     671           0 :     auto s_a = _residual_tensor.doubleContraction(dpk2);
     672           0 :     const auto rnorm0 = _residual_tensor.L2norm();
     673           0 :     _pk2[_qp] = _pk2[_qp] + dpk2;
     674             : 
     675           0 :     if ((rnorm1 / rnorm0) < _line_search_tolerance || s_a * s_b > 0)
     676             :     {
     677           0 :       calculateResidual();
     678           0 :       return true;
     679             :     }
     680             : 
     681           0 :     while ((rnorm / rnorm0) > _line_search_tolerance && count < _line_search_max_iterations)
     682             :     {
     683           0 :       _pk2[_qp] = _pk2[_qp] - step * dpk2;
     684           0 :       step = 0.5 * (step_b + step_a);
     685           0 :       _pk2[_qp] = _pk2[_qp] + step * dpk2;
     686           0 :       calculateResidual();
     687           0 :       s_m = _residual_tensor.doubleContraction(dpk2);
     688           0 :       rnorm = _residual_tensor.L2norm();
     689             : 
     690           0 :       if (s_m * s_a < 0.0)
     691             :       {
     692             :         step_b = step;
     693             :         s_b = s_m;
     694             :       }
     695           0 :       if (s_m * s_b < 0.0)
     696             :       {
     697             :         step_a = step;
     698             :         s_a = s_m;
     699             :       }
     700           0 :       count++;
     701             :     }
     702             : 
     703             :     // below tolerance and max iterations?
     704           0 :     return ((rnorm / rnorm0) < _line_search_tolerance && count < _line_search_max_iterations);
     705             :   }
     706             :   else
     707           0 :     mooseError("Line search method is not provided.");
     708             : }
     709             : 
     710             : void
     711      899824 : ComputeMultipleCrystalPlasticityStress::calculateEigenstrainDeformationGrad()
     712             : {
     713             :   _inverse_eigenstrain_deformation_grad.zero();
     714      899824 :   _inverse_eigenstrain_deformation_grad.addIa(1.0);
     715             : 
     716     1911612 :   for (unsigned int i = 0; i < _num_eigenstrains; ++i)
     717             :   {
     718     1011808 :     _eigenstrains[i]->setSubstepDt(_substep_dt);
     719     1011808 :     _eigenstrains[i]->computeQpProperties();
     720     1011788 :     _inverse_eigenstrain_deformation_grad *= _eigenstrains[i]->getDeformationGradientInverse();
     721             :   }
     722      899804 :   (*_eigenstrain_deformation_gradient)[_qp] = _inverse_eigenstrain_deformation_grad.inverse();
     723      899804 : }

Generated by: LCOV version 1.14