LCOV - code coverage report
Current view: top level - src/materials/crystal_plasticity - ComputeMultipleCrystalPlasticityStress.C (source / functions) Hit Total Coverage
Test: idaholab/moose solid_mechanics: f45d79 Lines: 305 359 85.0 %
Date: 2025-07-25 05:00:39 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        1438 : ComputeMultipleCrystalPlasticityStress::validParams()
      21             : {
      22        1438 :   InputParameters params = ComputeFiniteStrainElasticStress::validParams();
      23             : 
      24        1438 :   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        2876 :   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        2876 :   params.addRequiredParam<std::vector<MaterialName>>(
      34             :       "crystal_plasticity_models",
      35             :       "The material objects to use to calculate crystal plasticity stress and strains.");
      36        2876 :   params.addParam<std::vector<MaterialName>>(
      37             :       "eigenstrain_names", {}, "The material objects to calculate eigenstrains.");
      38        2876 :   params.addParam<MooseEnum>("tan_mod_type",
      39        4314 :                              MooseEnum("exact none", "none"),
      40             :                              "Type of tangent moduli for preconditioner: default elastic");
      41        2876 :   params.addParam<Real>("rtol", 1e-6, "Constitutive stress residual relative tolerance");
      42        2876 :   params.addParam<Real>("abs_tol", 1e-6, "Constitutive stress residual absolute tolerance");
      43        2876 :   params.addParam<unsigned int>("maxiter", 100, "Maximum number of iterations for stress update");
      44        2876 :   params.addParam<unsigned int>(
      45        2876 :       "maxiter_state_variable", 100, "Maximum number of iterations for state variable update");
      46        2876 :   params.addParam<unsigned int>(
      47        2876 :       "maximum_substep_iteration", 1, "Maximum number of substep iteration");
      48        2876 :   params.addParam<bool>("use_line_search", false, "Use line search in constitutive update");
      49        2876 :   params.addParam<Real>("min_line_search_step_size", 0.01, "Minimum line search step size");
      50        2876 :   params.addParam<Real>("line_search_tol", 0.5, "Line search bisection method tolerance");
      51        2876 :   params.addParam<unsigned int>(
      52        2876 :       "line_search_maxiter", 20, "Line search bisection method maximum number of iteration");
      53        2876 :   params.addParam<MooseEnum>("line_search_method",
      54        4314 :                              MooseEnum("CUT_HALF BISECTION", "CUT_HALF"),
      55             :                              "The method used in line search");
      56        2876 :   params.addParam<bool>(
      57             :       "print_state_variable_convergence_error_messages",
      58        2876 :       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        1438 :   return params;
      62           0 : }
      63             : 
      64        1074 : ComputeMultipleCrystalPlasticityStress::ComputeMultipleCrystalPlasticityStress(
      65        1074 :     const InputParameters & parameters)
      66             :   : ComputeFiniteStrainElasticStress(parameters),
      67        1074 :     _num_models(getParam<std::vector<MaterialName>>("crystal_plasticity_models").size()),
      68        2148 :     _num_eigenstrains(getParam<std::vector<MaterialName>>("eigenstrain_names").size()),
      69        2292 :     _base_name(isParamValid("base_name") ? getParam<std::string>("base_name") + "_" : ""),
      70        2148 :     _elasticity_tensor(getMaterialPropertyByName<RankFourTensor>(_base_name + "elasticity_tensor")),
      71        2148 :     _rtol(getParam<Real>("rtol")),
      72        2148 :     _abs_tol(getParam<Real>("abs_tol")),
      73        2148 :     _maxiter(getParam<unsigned int>("maxiter")),
      74        2148 :     _maxiterg(getParam<unsigned int>("maxiter_state_variable")),
      75        2148 :     _tan_mod_type(getParam<MooseEnum>("tan_mod_type").getEnum<TangentModuliType>()),
      76        2148 :     _max_substep_iter(getParam<unsigned int>("maximum_substep_iteration")),
      77        2148 :     _use_line_search(getParam<bool>("use_line_search")),
      78        2148 :     _min_line_search_step_size(getParam<Real>("min_line_search_step_size")),
      79        2148 :     _line_search_tolerance(getParam<Real>("line_search_tol")),
      80        2148 :     _line_search_max_iterations(getParam<unsigned int>("line_search_maxiter")),
      81        2148 :     _line_search_method(getParam<MooseEnum>("line_search_method").getEnum<LineSearchMethod>()),
      82        1074 :     _plastic_deformation_gradient(declareProperty<RankTwoTensor>("plastic_deformation_gradient")),
      83        1074 :     _plastic_deformation_gradient_old(
      84        1074 :         getMaterialPropertyOld<RankTwoTensor>("plastic_deformation_gradient")),
      85        1074 :     _eigenstrain_deformation_gradient(
      86        1074 :         _num_eigenstrains ? &declareProperty<RankTwoTensor>("eigenstrain_deformation_gradient")
      87             :                           : nullptr),
      88        1074 :     _eigenstrain_deformation_gradient_old(
      89        1074 :         _num_eigenstrains
      90        1248 :             ? &getMaterialPropertyOld<RankTwoTensor>("eigenstrain_deformation_gradient")
      91             :             : nullptr),
      92        2148 :     _deformation_gradient(getMaterialProperty<RankTwoTensor>(_base_name + "deformation_gradient")),
      93        1074 :     _deformation_gradient_old(
      94        1074 :         getMaterialPropertyOld<RankTwoTensor>(_base_name + "deformation_gradient")),
      95        1074 :     _pk2(declareProperty<RankTwoTensor>("second_piola_kirchhoff_stress")),
      96        2148 :     _pk2_old(getMaterialPropertyOld<RankTwoTensor>("second_piola_kirchhoff_stress")),
      97        1074 :     _total_lagrangian_strain(
      98        1074 :         declareProperty<RankTwoTensor>("total_lagrangian_strain")), // Lagrangian strain
      99        1074 :     _updated_rotation(declareProperty<RankTwoTensor>("updated_rotation")),
     100        1074 :     _crysrot(getMaterialProperty<RankTwoTensor>(
     101        1074 :         _base_name + "crysrot")), // defined in the elasticity tensor classes for crystal plasticity
     102        4296 :     _print_convergence_message(getParam<bool>("print_state_variable_convergence_error_messages"))
     103             : {
     104        1074 :   _convergence_failed = false;
     105        1074 : }
     106             : 
     107             : void
     108       22848 : ComputeMultipleCrystalPlasticityStress::initQpStatefulProperties()
     109             : {
     110       22848 :   _plastic_deformation_gradient[_qp].zero();
     111       22848 :   _plastic_deformation_gradient[_qp].addIa(1.0);
     112             : 
     113       22848 :   if (_num_eigenstrains)
     114             :   {
     115        6400 :     (*_eigenstrain_deformation_gradient)[_qp].zero();
     116        6400 :     (*_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       16448 :     _inverse_eigenstrain_deformation_grad.addIa(1.0);
     123             :   }
     124             : 
     125       22848 :   _pk2[_qp].zero();
     126             : 
     127       22848 :   _total_lagrangian_strain[_qp].zero();
     128             : 
     129       22848 :   _updated_rotation[_qp].zero();
     130       22848 :   _updated_rotation[_qp].addIa(1.0);
     131             : 
     132       48256 :   for (unsigned int i = 0; i < _num_models; ++i)
     133             :   {
     134       25408 :     _models[i]->setQp(_qp);
     135       25408 :     _models[i]->initQpStatefulProperties();
     136             :   }
     137             : 
     138       29312 :   for (unsigned int i = 0; i < _num_eigenstrains; ++i)
     139             :   {
     140        6464 :     _eigenstrains[i]->setQp(_qp);
     141        6464 :     _eigenstrains[i]->initQpStatefulProperties();
     142             :   }
     143       22848 : }
     144             : 
     145             : void
     146         990 : ComputeMultipleCrystalPlasticityStress::initialSetup()
     147             : {
     148             :   // get crystal plasticity models
     149             :   std::vector<MaterialName> model_names =
     150        1980 :       getParam<std::vector<MaterialName>>("crystal_plasticity_models");
     151             : 
     152        2106 :   for (unsigned int i = 0; i < _num_models; ++i)
     153             :   {
     154             :     CrystalPlasticityStressUpdateBase * model =
     155        1116 :         dynamic_cast<CrystalPlasticityStressUpdateBase *>(&getMaterialByName(model_names[i]));
     156             : 
     157        1116 :     if (model)
     158             :     {
     159        1116 :       _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        1980 :       getParam<std::vector<MaterialName>>("eigenstrain_names");
     170             : 
     171        1182 :   for (unsigned int i = 0; i < _num_eigenstrains; ++i)
     172             :   {
     173             :     ComputeCrystalPlasticityEigenstrainBase * eigenstrain =
     174         192 :         dynamic_cast<ComputeCrystalPlasticityEigenstrainBase *>(
     175         192 :             &getMaterialByName(eigenstrain_names[i]));
     176             : 
     177         192 :     if (eigenstrain)
     178         192 :       _eigenstrains.push_back(eigenstrain);
     179             :     else
     180           0 :       mooseError("Eigenstrain" + eigenstrain_names[i] +
     181             :                  " is not compatible with ComputeMultipleCrystalPlasticityStress");
     182             :   }
     183         990 : }
     184             : 
     185             : void
     186     1803382 : ComputeMultipleCrystalPlasticityStress::computeQpStress()
     187             : {
     188     3833836 :   for (unsigned int i = 0; i < _num_models; ++i)
     189             :   {
     190     2030454 :     _models[i]->setQp(_qp);
     191     2030454 :     _models[i]->setMaterialVectorSize();
     192             :   }
     193             : 
     194     2457162 :   for (unsigned int i = 0; i < _num_eigenstrains; ++i)
     195      653780 :     _eigenstrains[i]->setQp(_qp);
     196             : 
     197     1803382 :   updateStress(_stress[_qp], _Jacobian_mult[_qp]); // This is NOT the exact jacobian
     198     1803118 : }
     199             : 
     200             : void
     201     1803382 : ComputeMultipleCrystalPlasticityStress::updateStress(RankTwoTensor & cauchy_stress,
     202             :                                                      RankFourTensor & jacobian_mult)
     203             : {
     204             :   // Does not support face/boundary material property calculation
     205     1803382 :   if (isBoundaryMaterial())
     206             :     return;
     207             : 
     208             :   // Initialize substepping variables
     209             :   unsigned int substep_iter = 1;
     210             :   unsigned int num_substep = 1;
     211             : 
     212     1800822 :   _temporary_deformation_gradient_old = _deformation_gradient_old[_qp];
     213     1800822 :   if (_temporary_deformation_gradient_old.det() == 0)
     214           0 :     _temporary_deformation_gradient_old.addIa(1.0);
     215             : 
     216     1800822 :   _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     3828716 :   for (unsigned int i = 0; i < _num_models; ++i)
     223     2027894 :     _models[i]->calculateFlowDirection(_crysrot[_qp]);
     224             : 
     225             :   do
     226             :   {
     227     1967074 :     _convergence_failed = false;
     228     1967074 :     preSolveQp();
     229             : 
     230     1967074 :     _substep_dt = _dt / num_substep;
     231     4161220 :     for (unsigned int i = 0; i < _num_models; ++i)
     232     2194146 :       _models[i]->setSubstepDt(_substep_dt);
     233             : 
     234             :     // calculate F^{eigen} only when we have eigenstrain
     235             :     _inverse_eigenstrain_deformation_grad.zero();
     236     1967074 :     _inverse_eigenstrain_deformation_grad.addIa(1.0);
     237     1967074 :     if (_num_eigenstrains)
     238      726276 :       calculateEigenstrainDeformationGrad();
     239             : 
     240     4177180 :     for (unsigned int istep = 0; istep < num_substep; ++istep)
     241             :     {
     242     2376622 :       _temporary_deformation_gradient =
     243     2376622 :           (static_cast<Real>(istep) + 1) / num_substep * _delta_deformation_gradient;
     244     2376622 :       _temporary_deformation_gradient += _temporary_deformation_gradient_old;
     245             : 
     246     2376622 :       solveQp();
     247             : 
     248     2376614 :       if (_convergence_failed)
     249             :       {
     250      166488 :         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      166488 :         substep_iter++;
     256      166488 :         num_substep *= 2;
     257      166488 :         break;
     258             :       }
     259             :     }
     260             : 
     261     1967046 :     if (substep_iter > _max_substep_iter && _convergence_failed)
     262         236 :       mooseException("ComputeMultipleCrystalPlasticityStress: Constitutive failure");
     263     1966810 :   } while (_convergence_failed);
     264             : 
     265     1800558 :   postSolveQp(cauchy_stress, jacobian_mult);
     266             : }
     267             : 
     268             : void
     269     1967074 : ComputeMultipleCrystalPlasticityStress::preSolveQp()
     270             : {
     271     4161220 :   for (unsigned int i = 0; i < _num_models; ++i)
     272     2194146 :     _models[i]->setInitialConstitutiveVariableValues();
     273             : 
     274     1967074 :   _pk2[_qp] = _pk2_old[_qp];
     275     1967074 :   _inverse_plastic_deformation_grad_old = _plastic_deformation_gradient_old[_qp].inverse();
     276     1967074 : }
     277             : 
     278             : void
     279     2376622 : ComputeMultipleCrystalPlasticityStress::solveQp()
     280             : {
     281     4980316 :   for (unsigned int i = 0; i < _num_models; ++i)
     282             :   {
     283     2603694 :     _models[i]->setSubstepConstitutiveVariableValues();
     284     2603694 :     _models[i]->calculateSlipResistance();
     285             :   }
     286             : 
     287     2376622 :   _inverse_plastic_deformation_grad = _inverse_plastic_deformation_grad_old;
     288             : 
     289     2376622 :   solveStateVariables();
     290     2376614 :   if (_convergence_failed)
     291             :     return; // pop back up and take a smaller substep
     292             : 
     293     4647324 :   for (unsigned int i = 0; i < _num_models; ++i)
     294     2437198 :     _models[i]->updateSubstepConstitutiveVariableValues();
     295             : 
     296             :   // save off the old F^{p} inverse now that have converged on the stress and state variables
     297     2210126 :   _inverse_plastic_deformation_grad_old = _inverse_plastic_deformation_grad;
     298             : }
     299             : 
     300             : void
     301     1800558 : ComputeMultipleCrystalPlasticityStress::postSolveQp(RankTwoTensor & cauchy_stress,
     302             :                                                     RankFourTensor & jacobian_mult)
     303             : {
     304     1800558 :   cauchy_stress = _elastic_deformation_gradient * _pk2[_qp] *
     305     1800558 :                   _elastic_deformation_gradient.transpose() / _elastic_deformation_gradient.det();
     306             : 
     307     1800558 :   calcTangentModuli(jacobian_mult);
     308             : 
     309     1800558 :   _total_lagrangian_strain[_qp] =
     310     1800558 :       _deformation_gradient[_qp].transpose() * _deformation_gradient[_qp] -
     311     1800558 :       RankTwoTensor::Identity();
     312     1800558 :   _total_lagrangian_strain[_qp] = _total_lagrangian_strain[_qp] * 0.5;
     313             : 
     314             :   // Calculate crystal rotation to track separately
     315     1800558 :   RankTwoTensor rot;
     316     1800558 :   _elastic_deformation_gradient.getRUDecompositionRotation(rot);
     317     1800558 :   _updated_rotation[_qp] = rot * _crysrot[_qp];
     318     1800558 : }
     319             : 
     320             : void
     321     2376622 : 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     3564184 :     solveStress();
     331     3564178 :     if (_convergence_failed)
     332             :       return;
     333             : 
     334     3400174 :     _plastic_deformation_gradient[_qp] =
     335     3400174 :         _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     7252544 :     for (unsigned int i = 0; i < _num_models; ++i)
     342     3852370 :       _models[i]->cacheStateVariablesBeforeUpdate();
     343             : 
     344     7252544 :     for (unsigned int i = 0; i < _num_models; ++i)
     345     3852370 :       _models[i]->calculateStateVariableEvolutionRateComponent();
     346             : 
     347     7252542 :     for (unsigned int i = 0; i < _num_models; ++i)
     348     3852370 :       if (!_models[i]->updateStateVariables())
     349         116 :         _convergence_failed = true;
     350             : 
     351     7252540 :     for (unsigned int i = 0; i < _num_models; ++i)
     352     3852368 :       _models[i]->calculateSlipResistance();
     353             : 
     354     3400172 :     if (_convergence_failed)
     355             :       return;
     356             : 
     357     5839602 :     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     3629432 :       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     3400056 :     if (iter_flag)
     371             :     {
     372     1189886 :       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     2210170 :     iteration++;
     381     1189886 :   } while (iter_flag && iteration < _maxiterg);
     382             : 
     383     2212494 :   if (iteration == _maxiterg)
     384             :   {
     385        2368 :     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        2368 :     _convergence_failed = true;
     395             :   }
     396             : }
     397             : 
     398             : void
     399     3564184 : ComputeMultipleCrystalPlasticityStress::solveStress()
     400             : {
     401             :   unsigned int iteration = 0;
     402     3564184 :   RankTwoTensor dpk2;
     403             :   Real rnorm, rnorm0, rnorm_prev;
     404             : 
     405             :   // Calculate stress residual
     406     3564184 :   calculateResidualAndJacobian();
     407     3564184 :   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     3564184 :   rnorm = _residual_tensor.L2norm();
     420     3564184 :   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    17837254 :   while (rnorm > _rtol * rnorm0 && rnorm > _abs_tol && iteration < _maxiter)
     425             :   {
     426             :     // Calculate stress increment
     427    14431868 :     dpk2 = -_jacobian.invSymm() * _residual_tensor;
     428    14431868 :     _pk2[_qp] = _pk2[_qp] + dpk2;
     429             : 
     430    14431868 :     calculateResidualAndJacobian();
     431             : 
     432    14431864 :     if (_convergence_failed)
     433             :     {
     434      158794 :       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      158794 :       return;
     442             :     }
     443             : 
     444    14273070 :     rnorm_prev = rnorm;
     445    14273070 :     rnorm = _residual_tensor.L2norm();
     446             : 
     447    14273070 :     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    14273070 :     if (_use_line_search)
     457      757088 :       rnorm = _residual_tensor.L2norm();
     458             : 
     459    14273070 :     iteration++;
     460             :   }
     461             : 
     462     3405386 :   if (iteration >= _maxiter)
     463             :   {
     464        5212 :     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        5210 :     _convergence_failed = true;
     477             :   }
     478             : }
     479             : 
     480             : // Calculates stress residual equation and jacobian
     481             : void
     482    17996052 : ComputeMultipleCrystalPlasticityStress::calculateResidualAndJacobian()
     483             : {
     484    17996052 :   calculateResidual();
     485    17996048 :   if (_convergence_failed)
     486             :     return;
     487    17837254 :   calculateJacobian();
     488             : }
     489             : 
     490             : void
     491    18047892 : ComputeMultipleCrystalPlasticityStress::calculateResidual()
     492             : {
     493    18047892 :   RankTwoTensor ce, elastic_strain, ce_pk2, equivalent_slip_increment_per_model,
     494    18047892 :       equivalent_slip_increment, pk2_new;
     495             : 
     496             :   equivalent_slip_increment.zero();
     497             : 
     498             :   // calculate slip rate in order to compute F^{p-1}
     499    38413994 :   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    20524900 :     _models[i]->calculateShearStress(
     505    20524900 :         _pk2[_qp], _inverse_eigenstrain_deformation_grad, _num_eigenstrains);
     506             : 
     507    20524900 :     _convergence_failed = !_models[i]->calculateSlipRate();
     508             : 
     509    20524896 :     if (_convergence_failed)
     510             :       return;
     511             : 
     512    20366102 :     _models[i]->calculateEquivalentSlipIncrement(equivalent_slip_increment_per_model);
     513    20366102 :     equivalent_slip_increment += equivalent_slip_increment_per_model;
     514             :   }
     515             : 
     516             :   RankTwoTensor residual_equivalent_slip_increment =
     517    17889094 :       RankTwoTensor::Identity() - equivalent_slip_increment;
     518    17889094 :   _inverse_plastic_deformation_grad =
     519    17889094 :       _inverse_plastic_deformation_grad_old * residual_equivalent_slip_increment;
     520             : 
     521    17889094 :   _elastic_deformation_gradient = _temporary_deformation_gradient *
     522    17889094 :                                   _inverse_eigenstrain_deformation_grad *
     523             :                                   _inverse_plastic_deformation_grad;
     524             : 
     525    17889094 :   ce = _elastic_deformation_gradient.transpose() * _elastic_deformation_gradient;
     526             : 
     527    17889094 :   elastic_strain = ce - RankTwoTensor::Identity();
     528    17889094 :   elastic_strain *= 0.5;
     529             : 
     530    17889094 :   pk2_new = _elasticity_tensor[_qp] * elastic_strain;
     531    17889094 :   _residual_tensor = _pk2[_qp] - pk2_new;
     532             : }
     533             : 
     534             : void
     535    17837254 : ComputeMultipleCrystalPlasticityStress::calculateJacobian()
     536             : {
     537             :   // may not need to cache the dfpinvdpk2 here. need to double check
     538    17837254 :   RankFourTensor dfedfpinv, deedfe, dfpinvdpk2, dfpinvdpk2_per_model;
     539             : 
     540    17837254 :   RankTwoTensor ffeiginv = _temporary_deformation_gradient * _inverse_eigenstrain_deformation_grad;
     541             : 
     542    71349016 :   for (const auto i : make_range(Moose::dim))
     543   214047048 :     for (const auto j : make_range(Moose::dim))
     544   642141144 :       for (const auto k : make_range(Moose::dim))
     545   481605858 :         dfedfpinv(i, j, k, j) = ffeiginv(i, k);
     546             : 
     547    71349016 :   for (const auto i : make_range(Moose::dim))
     548   214047048 :     for (const auto j : make_range(Moose::dim))
     549   642141144 :       for (const auto k : make_range(Moose::dim))
     550             :       {
     551   481605858 :         deedfe(i, j, k, i) = deedfe(i, j, k, i) + _elastic_deformation_gradient(k, j) * 0.5;
     552   481605858 :         deedfe(i, j, k, j) = deedfe(i, j, k, j) + _elastic_deformation_gradient(k, i) * 0.5;
     553             :       }
     554             : 
     555    38151516 :   for (unsigned int i = 0; i < _num_models; ++i)
     556             :   {
     557    20314262 :     _models[i]->calculateTotalPlasticDeformationGradientDerivative(
     558             :         dfpinvdpk2_per_model,
     559    20314262 :         _inverse_plastic_deformation_grad_old,
     560    20314262 :         _inverse_eigenstrain_deformation_grad,
     561    20314262 :         _num_eigenstrains);
     562    20314262 :     dfpinvdpk2 += dfpinvdpk2_per_model;
     563             :   }
     564             : 
     565             :   _jacobian =
     566    35674508 :       RankFourTensor::IdentityFour() - (_elasticity_tensor[_qp] * deedfe * dfedfpinv * dfpinvdpk2);
     567    17837254 : }
     568             : 
     569             : void
     570     1800558 : ComputeMultipleCrystalPlasticityStress::calcTangentModuli(RankFourTensor & jacobian_mult)
     571             : {
     572     1800558 :   switch (_tan_mod_type)
     573             :   {
     574     1800558 :     case TangentModuliType::EXACT:
     575     1800558 :       elastoPlasticTangentModuli(jacobian_mult);
     576     1800558 :       break;
     577           0 :     default:
     578           0 :       elasticTangentModuli(jacobian_mult);
     579             :   }
     580     1800558 : }
     581             : 
     582             : void
     583     1800558 : ComputeMultipleCrystalPlasticityStress::elastoPlasticTangentModuli(RankFourTensor & jacobian_mult)
     584             : {
     585     1800558 :   RankFourTensor tan_mod;
     586     1800558 :   RankTwoTensor pk2fet, fepk2, feiginvfpinv;
     587     1800558 :   RankFourTensor deedfe, dsigdpk2dfe, dfedf;
     588             : 
     589             :   // Fill in the matrix stiffness material property
     590     7202232 :   for (const auto i : make_range(Moose::dim))
     591    21606696 :     for (const auto j : make_range(Moose::dim))
     592    64820088 :       for (const auto k : make_range(Moose::dim))
     593             :       {
     594    48615066 :         deedfe(i, j, k, i) = deedfe(i, j, k, i) + _elastic_deformation_gradient(k, j) * 0.5;
     595    48615066 :         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     1800558 :   dsigdpk2dfe = _elastic_deformation_gradient.times<i_, k_, j_, l_>(_elastic_deformation_gradient) *
     600     1800558 :                 _elasticity_tensor[_qp] * deedfe;
     601             : 
     602     1800558 :   pk2fet = _pk2[_qp] * _elastic_deformation_gradient.transpose();
     603     1800558 :   fepk2 = _elastic_deformation_gradient * _pk2[_qp];
     604             : 
     605     7202232 :   for (const auto i : make_range(Moose::dim))
     606    21606696 :     for (const auto j : make_range(Moose::dim))
     607    64820088 :       for (const auto l : make_range(Moose::dim))
     608             :       {
     609    48615066 :         tan_mod(i, j, i, l) += pk2fet(l, j);
     610    48615066 :         tan_mod(i, j, j, l) += fepk2(i, l);
     611             :       }
     612             : 
     613     1800558 :   tan_mod += dsigdpk2dfe;
     614             : 
     615     1800558 :   const auto je = _elastic_deformation_gradient.det();
     616     1800558 :   if (je > 0.0)
     617     1800558 :     tan_mod /= je;
     618             : 
     619     1800558 :   feiginvfpinv = _inverse_eigenstrain_deformation_grad * _inverse_plastic_deformation_grad;
     620     7202232 :   for (const auto i : make_range(Moose::dim))
     621    21606696 :     for (const auto j : make_range(Moose::dim))
     622    64820088 :       for (const auto l : make_range(Moose::dim))
     623    48615066 :         dfedf(i, j, i, l) = feiginvfpinv(l, j);
     624             : 
     625     1800558 :   jacobian_mult = tan_mod * dfedf;
     626     1800558 : }
     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       51840 : ComputeMultipleCrystalPlasticityStress::lineSearchUpdate(const Real & rnorm_prev,
     637             :                                                          const RankTwoTensor & dpk2)
     638             : {
     639       51840 :   if (_line_search_method == LineSearchMethod::CutHalf)
     640             :   {
     641             :     Real rnorm;
     642       51840 :     Real step = 1.0;
     643             : 
     644             :     do
     645             :     {
     646       51840 :       _pk2[_qp] = _pk2[_qp] - step * dpk2;
     647       51840 :       step /= 2.0;
     648       51840 :       _pk2[_qp] = _pk2[_qp] + step * dpk2;
     649             : 
     650       51840 :       calculateResidual();
     651       51840 :       rnorm = _residual_tensor.L2norm();
     652       51840 :     } 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       51840 :     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      726276 : ComputeMultipleCrystalPlasticityStress::calculateEigenstrainDeformationGrad()
     712             : {
     713             :   _inverse_eigenstrain_deformation_grad.zero();
     714      726276 :   _inverse_eigenstrain_deformation_grad.addIa(1.0);
     715             : 
     716     1541940 :   for (unsigned int i = 0; i < _num_eigenstrains; ++i)
     717             :   {
     718      815684 :     _eigenstrains[i]->setSubstepDt(_substep_dt);
     719      815684 :     _eigenstrains[i]->computeQpProperties();
     720      815664 :     _inverse_eigenstrain_deformation_grad *= _eigenstrains[i]->getDeformationGradientInverse();
     721             :   }
     722      726256 :   (*_eigenstrain_deformation_gradient)[_qp] = _inverse_eigenstrain_deformation_grad.inverse();
     723      726256 : }

Generated by: LCOV version 1.14