LCOV - code coverage report
Current view: top level - src/materials - ComputeSmearedCrackingStress.C (source / functions) Hit Total Coverage
Test: idaholab/moose tensor_mechanics: d6b47a Lines: 261 291 89.7 %
Date: 2024-02-27 11:53:14 Functions: 11 11 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //* This file is part of the MOOSE framework
       2             : //* https://www.mooseframework.org
       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 "ComputeSmearedCrackingStress.h"
      11             : #include "ElasticityTensorTools.h"
      12             : #include "StressUpdateBase.h"
      13             : #include "Conversion.h"
      14             : 
      15             : registerMooseObject("TensorMechanicsApp", ComputeSmearedCrackingStress);
      16             : 
      17             : InputParameters
      18         145 : ComputeSmearedCrackingStress::validParams()
      19             : {
      20         145 :   InputParameters params = ComputeMultipleInelasticStress::validParams();
      21         145 :   params.addClassDescription("Compute stress using a fixed smeared cracking model");
      22         290 :   params.addRequiredParam<std::vector<MaterialName>>(
      23             :       "softening_models",
      24             :       "The material objects used to compute softening behavior for loading a crack."
      25             :       "Either 1 or 3 models must be specified. If a single model is specified, it is"
      26             :       "used for all directions. If 3 models are specified, they will be used for the"
      27             :       "3 crack directions in sequence");
      28         290 :   params.addRequiredCoupledVar(
      29             :       "cracking_stress",
      30             :       "The stress threshold beyond which cracking occurs. Negative values prevent cracking.");
      31         290 :   MultiMooseEnum direction("x y z");
      32         290 :   params.addParam<MultiMooseEnum>(
      33             :       "prescribed_crack_directions", direction, "Prescribed directions of first cracks");
      34         290 :   params.addParam<unsigned int>(
      35         290 :       "max_cracks", 3, "The maximum number of cracks allowed at a material point.");
      36         290 :   params.addRangeCheckedParam<Real>("cracking_neg_fraction",
      37             :                                     0,
      38             :                                     "cracking_neg_fraction <= 1 & cracking_neg_fraction >= 0",
      39             :                                     "The fraction of the cracking strain at which "
      40             :                                     "a transition begins during decreasing "
      41             :                                     "strain to the original stiffness.");
      42         290 :   params.addParam<Real>(
      43             :       "max_stress_correction",
      44         290 :       1.0,
      45             :       "Maximum permitted correction to the predicted stress as a ratio of the "
      46             :       "stress change to the predicted stress from the previous step's damage level. "
      47             :       "Values less than 1 will improve robustness, but not be as accurate.");
      48             : 
      49         435 :   params.addRangeCheckedParam<Real>(
      50             :       "shear_retention_factor",
      51         290 :       0.0,
      52             :       "shear_retention_factor>=0 & shear_retention_factor<=1.0",
      53             :       "Fraction of original shear stiffness to be retained after cracking");
      54         145 :   params.set<std::vector<MaterialName>>("inelastic_models") = {};
      55             : 
      56         290 :   MooseEnum crackedElasticityType("DIAGONAL FULL", "DIAGONAL");
      57         290 :   crackedElasticityType.addDocumentation(
      58             :       "DIAGONAL", "Zero out terms coupling with directions orthogonal to a crack (legacy)");
      59         290 :   crackedElasticityType.addDocumentation(
      60             :       "FULL", "Consistently scale all entries based on damage (recommended)");
      61         290 :   params.addParam<MooseEnum>(
      62             :       "cracked_elasticity_type",
      63             :       crackedElasticityType,
      64             :       "Method to modify the local elasticity tensor to account for cracking");
      65             : 
      66         145 :   return params;
      67         145 : }
      68             : 
      69         109 : ComputeSmearedCrackingStress::ComputeSmearedCrackingStress(const InputParameters & parameters)
      70             :   : ComputeMultipleInelasticStress(parameters),
      71         109 :     _cracking_stress(coupledValue("cracking_stress")),
      72         218 :     _max_cracks(getParam<unsigned int>("max_cracks")),
      73         218 :     _cracking_neg_fraction(getParam<Real>("cracking_neg_fraction")),
      74         218 :     _shear_retention_factor(getParam<Real>("shear_retention_factor")),
      75         218 :     _max_stress_correction(getParam<Real>("max_stress_correction")),
      76         109 :     _cracked_elasticity_type(
      77         109 :         getParam<MooseEnum>("cracked_elasticity_type").getEnum<CrackedElasticityType>()),
      78         109 :     _crack_damage(declareProperty<RealVectorValue>(_base_name + "crack_damage")),
      79         218 :     _crack_damage_old(getMaterialPropertyOld<RealVectorValue>(_base_name + "crack_damage")),
      80         109 :     _crack_flags(declareProperty<RealVectorValue>(_base_name + "crack_flags")),
      81         109 :     _crack_rotation(declareProperty<RankTwoTensor>(_base_name + "crack_rotation")),
      82         218 :     _crack_rotation_old(getMaterialPropertyOld<RankTwoTensor>(_base_name + "crack_rotation")),
      83         109 :     _crack_initiation_strain(
      84         109 :         declareProperty<RealVectorValue>(_base_name + "crack_initiation_strain")),
      85         109 :     _crack_initiation_strain_old(
      86         109 :         getMaterialPropertyOld<RealVectorValue>(_base_name + "crack_initiation_strain")),
      87         109 :     _crack_max_strain(declareProperty<RealVectorValue>(_base_name + "crack_max_strain")),
      88         436 :     _crack_max_strain_old(getMaterialPropertyOld<RealVectorValue>(_base_name + "crack_max_strain"))
      89             : {
      90             :   MultiMooseEnum prescribed_crack_directions =
      91         218 :       getParam<MultiMooseEnum>("prescribed_crack_directions");
      92         109 :   if (prescribed_crack_directions.size() > 0)
      93             :   {
      94          27 :     if (prescribed_crack_directions.size() > 3)
      95           0 :       mooseError("A maximum of three crack directions may be specified");
      96          78 :     for (unsigned int i = 0; i < prescribed_crack_directions.size(); ++i)
      97             :     {
      98          84 :       for (unsigned int j = 0; j < i; ++j)
      99          33 :         if (prescribed_crack_directions[i] == prescribed_crack_directions[j])
     100           0 :           mooseError("Entries in 'prescribed_crack_directions' cannot be repeated");
     101             :       _prescribed_crack_directions.push_back(
     102          51 :           static_cast<unsigned int>(prescribed_crack_directions.get(i)));
     103             :     }
     104             : 
     105             :     // Fill in the last remaining direction if 2 are specified
     106          27 :     if (_prescribed_crack_directions.size() == 2)
     107             :     {
     108           6 :       std::set<unsigned int> available_dirs = {0, 1, 2};
     109          18 :       for (auto dir : _prescribed_crack_directions)
     110          12 :         if (available_dirs.erase(dir) != 1)
     111           0 :           mooseError("Invalid prescribed crack direction:" + Moose::stringify(dir));
     112           6 :       if (available_dirs.size() != 1)
     113           0 :         mooseError("Error in finding remaining available crack direction");
     114           6 :       _prescribed_crack_directions.push_back(*available_dirs.begin());
     115             :     }
     116             :   }
     117         218 :   if (!isParamSetByUser("cracked_elasticity_type"))
     118          25 :     paramWarning(
     119             :         "cracked_elasticity_type",
     120             :         "Defaulting to the legacy option of 'DIAGONAL', but the 'FULL' option is preferred");
     121             : 
     122         108 :   _local_elastic_vector.resize(9);
     123         108 : }
     124             : 
     125             : void
     126         416 : ComputeSmearedCrackingStress::initQpStatefulProperties()
     127             : {
     128         416 :   ComputeMultipleInelasticStress::initQpStatefulProperties();
     129             : 
     130         416 :   _crack_damage[_qp] = 0.0;
     131             : 
     132         416 :   _crack_initiation_strain[_qp] = 0.0;
     133         416 :   _crack_max_strain[_qp](0) = 0.0;
     134             : 
     135         416 :   switch (_prescribed_crack_directions.size())
     136             :   {
     137         288 :     case 0:
     138             :     {
     139         288 :       _crack_rotation[_qp] = RankTwoTensor::Identity();
     140         288 :       break;
     141             :     }
     142          64 :     case 1:
     143             :     {
     144          64 :       _crack_rotation[_qp].zero();
     145          64 :       switch (_prescribed_crack_directions[0])
     146             :       {
     147          32 :         case 0:
     148             :         {
     149          32 :           _crack_rotation[_qp](0, 0) = 1.0;
     150          32 :           _crack_rotation[_qp](1, 1) = 1.0;
     151          32 :           _crack_rotation[_qp](2, 2) = 1.0;
     152          32 :           break;
     153             :         }
     154           0 :         case 1:
     155             :         {
     156           0 :           _crack_rotation[_qp](1, 0) = 1.0;
     157           0 :           _crack_rotation[_qp](0, 1) = 1.0;
     158           0 :           _crack_rotation[_qp](2, 2) = 1.0;
     159           0 :           break;
     160             :         }
     161          32 :         case 2:
     162             :         {
     163          32 :           _crack_rotation[_qp](2, 0) = 1.0;
     164          32 :           _crack_rotation[_qp](0, 1) = 1.0;
     165          32 :           _crack_rotation[_qp](1, 2) = 1.0;
     166          32 :           break;
     167             :         }
     168             :       }
     169             :       break;
     170             :     }
     171           0 :     case 2:
     172             :     {
     173           0 :       mooseError("Number of prescribed crack directions cannot be 2");
     174             :       break;
     175             :     }
     176             :     case 3:
     177             :     {
     178         256 :       for (unsigned int i = 0; i < _prescribed_crack_directions.size(); ++i)
     179             :       {
     180             :         RealVectorValue crack_dir_vec;
     181         192 :         crack_dir_vec(_prescribed_crack_directions[i]) = 1.0;
     182         192 :         _crack_rotation[_qp].fillColumn(i, crack_dir_vec);
     183             :       }
     184             :     }
     185             :   }
     186         416 : }
     187             : 
     188             : void
     189         106 : ComputeSmearedCrackingStress::initialSetup()
     190             : {
     191         106 :   ComputeMultipleInelasticStress::initialSetup();
     192             : 
     193         212 :   if (!hasGuaranteedMaterialProperty(_elasticity_tensor_name, Guarantee::ISOTROPIC))
     194           0 :     mooseError("ComputeSmearedCrackingStress requires that the elasticity tensor be "
     195             :                "guaranteed isotropic");
     196             : 
     197         318 :   std::vector<MaterialName> soft_matls = getParam<std::vector<MaterialName>>("softening_models");
     198         231 :   for (auto soft_matl : soft_matls)
     199             :   {
     200             :     SmearedCrackSofteningBase * scsb =
     201         125 :         dynamic_cast<SmearedCrackSofteningBase *>(&getMaterialByName(soft_matl));
     202         125 :     if (scsb)
     203         125 :       _softening_models.push_back(scsb);
     204             :     else
     205           0 :       paramError("softening_models", "Model " + soft_matl + " is not a softening model");
     206             :   }
     207         106 :   if (_softening_models.size() == 1)
     208             :   {
     209             :     // Reuse the same model in all 3 directions
     210          96 :     _softening_models.push_back(_softening_models[0]);
     211          96 :     _softening_models.push_back(_softening_models[0]);
     212             :   }
     213          10 :   else if (_softening_models.size() != 3)
     214           1 :     paramError("softening_models", "Either 1 or 3 softening models must be specified");
     215         105 : }
     216             : 
     217             : void
     218      547072 : ComputeSmearedCrackingStress::computeQpStress()
     219             : {
     220             :   bool force_elasticity_rotation = false;
     221             : 
     222      547072 :   if (!previouslyCracked())
     223       28240 :     computeQpStressIntermediateConfiguration();
     224             :   else
     225             :   {
     226      518832 :     _elastic_strain[_qp] = _elastic_strain_old[_qp] + _strain_increment[_qp];
     227             : 
     228             :     // Propagate behavior from the (now inactive) inelastic models
     229      518832 :     _inelastic_strain[_qp] = _inelastic_strain_old[_qp];
     230      518832 :     for (auto model : _models)
     231             :     {
     232           0 :       model->setQp(_qp);
     233           0 :       model->propagateQpStatefulProperties();
     234             :     }
     235             : 
     236             :     // Since the other inelastic models are inactive, they will not limit the time step
     237      518832 :     _material_timestep_limit[_qp] = std::numeric_limits<Real>::max();
     238             : 
     239             :     // update _local_elasticity_tensor based on cracking state in previous time step
     240      518832 :     updateLocalElasticityTensor();
     241             : 
     242             :     // Calculate stress in intermediate configuration
     243      518832 :     _stress[_qp] = _local_elasticity_tensor * _elastic_strain[_qp];
     244             : 
     245      518832 :     _Jacobian_mult[_qp] = _local_elasticity_tensor;
     246             :     force_elasticity_rotation = true;
     247             :   }
     248             : 
     249             :   // compute crack status and adjust stress
     250      547072 :   updateCrackingStateAndStress();
     251             : 
     252      547072 :   if (_perform_finite_strain_rotations)
     253             :   {
     254      547072 :     finiteStrainRotation(force_elasticity_rotation);
     255      547072 :     _crack_rotation[_qp] = _rotation_increment[_qp] * _crack_rotation[_qp];
     256             :   }
     257      547072 : }
     258             : 
     259             : void
     260      518832 : ComputeSmearedCrackingStress::updateLocalElasticityTensor()
     261             : {
     262             :   const Real youngs_modulus =
     263      518832 :       ElasticityTensorTools::getIsotropicYoungsModulus(_elasticity_tensor[_qp]);
     264             : 
     265             :   bool cracking_locally_active = false;
     266             : 
     267      518832 :   const Real cracking_stress = _cracking_stress[_qp];
     268             : 
     269      518832 :   if (cracking_stress > 0)
     270             :   {
     271             :     RealVectorValue stiffness_ratio_local(1.0, 1.0, 1.0);
     272      518832 :     const RankTwoTensor & R = _crack_rotation_old[_qp];
     273      518832 :     RankTwoTensor ePrime(_elastic_strain_old[_qp]);
     274      518832 :     ePrime.rotate(R.transpose());
     275             : 
     276     2075328 :     for (unsigned int i = 0; i < 3; ++i)
     277             :     {
     278             :       // Update elasticity tensor based on crack status of the end of last time step
     279     1556496 :       if (_crack_damage_old[_qp](i) > 0.0)
     280             :       {
     281      549648 :         if (_cracking_neg_fraction == 0.0 && MooseUtils::absoluteFuzzyLessThan(ePrime(i, i), 0.0))
     282       43816 :           stiffness_ratio_local(i) = 1.0;
     283           0 :         else if (_cracking_neg_fraction > 0.0 &&
     284      505832 :                  ePrime(i, i) < _crack_initiation_strain_old[_qp](i) * _cracking_neg_fraction &&
     285             :                  ePrime(i, i) > -_crack_initiation_strain_old[_qp](i) * _cracking_neg_fraction)
     286             :         {
     287             :           const Real etr = _cracking_neg_fraction * _crack_initiation_strain_old[_qp](i);
     288           0 :           const Real Eo = cracking_stress / _crack_initiation_strain_old[_qp](i);
     289           0 :           const Real Ec = Eo * (1.0 - _crack_damage_old[_qp](i));
     290           0 :           const Real a = (Ec - Eo) / (4 * etr);
     291           0 :           const Real b = (Ec + Eo) / 2;
     292             :           // Compute the ratio of the current transition stiffness to the original stiffness
     293           0 :           stiffness_ratio_local(i) = (2.0 * a * etr + b) / Eo;
     294             :           cracking_locally_active = true;
     295             :         }
     296             :         else
     297             :         {
     298      505832 :           stiffness_ratio_local(i) = (1.0 - _crack_damage_old[_qp](i));
     299             :           cracking_locally_active = true;
     300             :         }
     301             :       }
     302             :     }
     303             : 
     304      518832 :     if (cracking_locally_active)
     305             :     {
     306             :       // Update the elasticity tensor in the crack coordinate system
     307      475640 :       if (_cracked_elasticity_type == CrackedElasticityType::DIAGONAL)
     308             :       {
     309             :         const bool c0_coupled = MooseUtils::absoluteFuzzyEqual(stiffness_ratio_local(0), 1.0);
     310             :         const bool c1_coupled = MooseUtils::absoluteFuzzyEqual(stiffness_ratio_local(1), 1.0);
     311             :         const bool c2_coupled = MooseUtils::absoluteFuzzyEqual(stiffness_ratio_local(2), 1.0);
     312             : 
     313        1504 :         const Real c01 = (c0_coupled && c1_coupled ? 1.0 : 0.0);
     314        1504 :         const Real c02 = (c0_coupled && c2_coupled ? 1.0 : 0.0);
     315        1504 :         const Real c12 = (c1_coupled && c2_coupled ? 1.0 : 0.0);
     316             : 
     317        1504 :         const Real c01_shear_retention = (c0_coupled && c1_coupled ? 1.0 : _shear_retention_factor);
     318        1504 :         const Real c02_shear_retention = (c0_coupled && c2_coupled ? 1.0 : _shear_retention_factor);
     319        1504 :         const Real c12_shear_retention = (c1_coupled && c2_coupled ? 1.0 : _shear_retention_factor);
     320             : 
     321        1504 :         _local_elastic_vector[0] = (c0_coupled ? _elasticity_tensor[_qp](0, 0, 0, 0)
     322             :                                                : stiffness_ratio_local(0) * youngs_modulus);
     323        1504 :         _local_elastic_vector[1] = _elasticity_tensor[_qp](0, 0, 1, 1) * c01;
     324        1504 :         _local_elastic_vector[2] = _elasticity_tensor[_qp](0, 0, 2, 2) * c02;
     325        1504 :         _local_elastic_vector[3] = (c1_coupled ? _elasticity_tensor[_qp](1, 1, 1, 1)
     326             :                                                : stiffness_ratio_local(1) * youngs_modulus);
     327        1504 :         _local_elastic_vector[4] = _elasticity_tensor[_qp](1, 1, 2, 2) * c12;
     328        1504 :         _local_elastic_vector[5] = (c2_coupled ? _elasticity_tensor[_qp](2, 2, 2, 2)
     329             :                                                : stiffness_ratio_local(2) * youngs_modulus);
     330        1504 :         _local_elastic_vector[6] = _elasticity_tensor[_qp](1, 2, 1, 2) * c12_shear_retention;
     331        1504 :         _local_elastic_vector[7] = _elasticity_tensor[_qp](0, 2, 0, 2) * c02_shear_retention;
     332        1504 :         _local_elastic_vector[8] = _elasticity_tensor[_qp](0, 1, 0, 1) * c01_shear_retention;
     333             :       }
     334             :       else // _cracked_elasticity_type == CrackedElasticityType::FULL
     335             :       {
     336             :         const Real & c0 = stiffness_ratio_local(0);
     337             :         const Real & c1 = stiffness_ratio_local(1);
     338             :         const Real & c2 = stiffness_ratio_local(2);
     339             : 
     340      474136 :         const Real c01 = c0 * c1;
     341      474136 :         const Real c02 = c0 * c2;
     342      474136 :         const Real c12 = c1 * c2;
     343             : 
     344      474616 :         const Real c01_shear_retention = std::max(c01, _shear_retention_factor);
     345      474136 :         const Real c02_shear_retention = std::max(c02, _shear_retention_factor);
     346      474136 :         const Real c12_shear_retention = std::max(c12, _shear_retention_factor);
     347             : 
     348      474136 :         _local_elastic_vector[0] = _elasticity_tensor[_qp](0, 0, 0, 0) * c0;
     349      474136 :         _local_elastic_vector[1] = _elasticity_tensor[_qp](0, 0, 1, 1) * c01;
     350      474136 :         _local_elastic_vector[2] = _elasticity_tensor[_qp](0, 0, 2, 2) * c02;
     351      474136 :         _local_elastic_vector[3] = _elasticity_tensor[_qp](1, 1, 1, 1) * c1;
     352      474136 :         _local_elastic_vector[4] = _elasticity_tensor[_qp](1, 1, 2, 2) * c12;
     353      474136 :         _local_elastic_vector[5] = _elasticity_tensor[_qp](2, 2, 2, 2) * c2;
     354      474136 :         _local_elastic_vector[6] = _elasticity_tensor[_qp](1, 2, 1, 2) * c12_shear_retention;
     355      474136 :         _local_elastic_vector[7] = _elasticity_tensor[_qp](0, 2, 0, 2) * c02_shear_retention;
     356      474136 :         _local_elastic_vector[8] = _elasticity_tensor[_qp](0, 1, 0, 1) * c01_shear_retention;
     357             :       }
     358             : 
     359             :       // Filling with 9 components is sufficient because these are the only nonzero entries
     360             :       // for isotropic or orthotropic materials.
     361      475640 :       _local_elasticity_tensor.fillFromInputVector(_local_elastic_vector,
     362             :                                                    RankFourTensor::symmetric9);
     363             : 
     364             :       // Rotate the modified elasticity tensor back into global coordinates
     365      475640 :       _local_elasticity_tensor.rotate(R);
     366             :     }
     367             :   }
     368             :   if (!cracking_locally_active)
     369       43192 :     _local_elasticity_tensor = _elasticity_tensor[_qp];
     370      518832 : }
     371             : 
     372             : void
     373      547072 : ComputeSmearedCrackingStress::updateCrackingStateAndStress()
     374             : {
     375             :   const Real youngs_modulus =
     376      547072 :       ElasticityTensorTools::getIsotropicYoungsModulus(_elasticity_tensor[_qp]);
     377             : 
     378      547072 :   Real cracking_stress = _cracking_stress[_qp];
     379             : 
     380      547072 :   if (cracking_stress > 0)
     381             :   {
     382             :     // Initializing crack states
     383      547048 :     _crack_rotation[_qp] = _crack_rotation_old[_qp];
     384             : 
     385     2188192 :     for (unsigned i = 0; i < 3; ++i)
     386             :     {
     387     1641144 :       _crack_max_strain[_qp](i) = _crack_max_strain_old[_qp](i);
     388     1641144 :       _crack_initiation_strain[_qp](i) = _crack_initiation_strain_old[_qp](i);
     389     1641144 :       _crack_damage[_qp](i) = _crack_damage_old[_qp](i);
     390             :     }
     391             : 
     392             :     // Compute crack orientations: updated _crack_rotation[_qp] based on current strain
     393             :     RealVectorValue strain_in_crack_dir;
     394      547048 :     computeCrackStrainAndOrientation(strain_in_crack_dir);
     395             : 
     396     2188192 :     for (unsigned i = 0; i < 3; ++i)
     397             :     {
     398     1641144 :       if (strain_in_crack_dir(i) > _crack_max_strain[_qp](i))
     399      540688 :         _crack_max_strain[_qp](i) = strain_in_crack_dir(i);
     400             :     }
     401             : 
     402             :     // Check for new cracks.
     403             :     // Rotate stress to cracked orientation.
     404      547048 :     const RankTwoTensor & R = _crack_rotation[_qp];
     405      547048 :     RankTwoTensor sigmaPrime(_stress[_qp]);
     406      547048 :     sigmaPrime.rotate(R.transpose()); // stress in crack coordinates
     407             : 
     408             :     unsigned int num_cracks = 0;
     409     2188192 :     for (unsigned int i = 0; i < 3; ++i)
     410             :     {
     411     1641144 :       if (_crack_damage_old[_qp](i) > 0.0)
     412      549648 :         ++num_cracks;
     413             :     }
     414             : 
     415             :     bool cracked(false);
     416             :     RealVectorValue sigma;
     417             :     mooseAssert(_softening_models.size() == 3, "Must have 3 softening models");
     418     2188192 :     for (unsigned int i = 0; i < 3; ++i)
     419             :     {
     420     1641144 :       sigma(i) = sigmaPrime(i, i);
     421             : 
     422     1641144 :       Real stiffness_ratio = 1.0 - _crack_damage[_qp](i);
     423             : 
     424     1641144 :       const bool pre_existing_crack = (_crack_damage_old[_qp](i) > 0.0);
     425     1641144 :       const bool met_stress_criterion = (sigma(i) > cracking_stress);
     426     1641144 :       const bool loading_existing_crack = (strain_in_crack_dir(i) >= _crack_max_strain[_qp](i));
     427     1641144 :       const bool allowed_to_crack = (pre_existing_crack || num_cracks < _max_cracks);
     428             :       bool new_crack = false;
     429             : 
     430     1641144 :       cracked |= pre_existing_crack;
     431             : 
     432             :       // Adjustments for newly created cracks
     433     1641144 :       if (met_stress_criterion && !pre_existing_crack && allowed_to_crack)
     434             :       {
     435             :         new_crack = true;
     436        2944 :         ++num_cracks;
     437             : 
     438             :         // Assume Poisson's ratio drops to zero for this direction.  Stiffness is then Young's
     439             :         // modulus.
     440        2944 :         _crack_initiation_strain[_qp](i) = cracking_stress / youngs_modulus;
     441             : 
     442        2944 :         if (_crack_max_strain[_qp](i) < _crack_initiation_strain[_qp](i))
     443         352 :           _crack_max_strain[_qp](i) = _crack_initiation_strain[_qp](i);
     444             :       }
     445             : 
     446             :       // Update stress and stiffness ratio according to specified crack release model
     447     1638200 :       if (new_crack || (pre_existing_crack && loading_existing_crack))
     448             :       {
     449             :         cracked = true;
     450      125800 :         _softening_models[i]->computeCrackingRelease(sigma(i),
     451             :                                                      stiffness_ratio,
     452             :                                                      strain_in_crack_dir(i),
     453      125800 :                                                      _crack_initiation_strain[_qp](i),
     454             :                                                      _crack_max_strain[_qp](i),
     455             :                                                      cracking_stress,
     456             :                                                      youngs_modulus);
     457      125800 :         _crack_damage[_qp](i) = 1.0 - stiffness_ratio;
     458             :       }
     459             : 
     460     1094648 :       else if (cracked && _cracking_neg_fraction > 0 &&
     461     1515344 :                _crack_initiation_strain[_qp](i) * _cracking_neg_fraction > strain_in_crack_dir(i) &&
     462             :                -_crack_initiation_strain[_qp](i) * _cracking_neg_fraction < strain_in_crack_dir(i))
     463             :       {
     464             :         const Real etr = _cracking_neg_fraction * _crack_initiation_strain[_qp](i);
     465           0 :         const Real Eo = cracking_stress / _crack_initiation_strain[_qp](i);
     466           0 :         const Real Ec = Eo * (1.0 - _crack_damage_old[_qp](i));
     467           0 :         const Real a = (Ec - Eo) / (4.0 * etr);
     468           0 :         const Real b = 0.5 * (Ec + Eo);
     469           0 :         const Real c = 0.25 * (Ec - Eo) * etr;
     470           0 :         sigma(i) = (a * strain_in_crack_dir(i) + b) * strain_in_crack_dir(i) + c;
     471             :       }
     472             :     }
     473             : 
     474      547048 :     if (cracked)
     475      519744 :       updateStressTensorForCracking(_stress[_qp], sigma);
     476             :   }
     477             : 
     478      547072 :   _crack_flags[_qp](0) = 1.0 - _crack_damage[_qp](2);
     479      547072 :   _crack_flags[_qp](1) = 1.0 - _crack_damage[_qp](1);
     480      547072 :   _crack_flags[_qp](2) = 1.0 - _crack_damage[_qp](0);
     481      547072 : }
     482             : 
     483             : void
     484      547048 : ComputeSmearedCrackingStress::computeCrackStrainAndOrientation(
     485             :     RealVectorValue & strain_in_crack_dir)
     486             : {
     487             :   // The rotation tensor is ordered such that directions for pre-existing cracks appear first
     488             :   // in the list of columns.  For example, if there is one existing crack, its direction is in the
     489             :   // first column in the rotation tensor.
     490      547048 :   const unsigned int num_known_dirs = getNumKnownCrackDirs();
     491             : 
     492      547048 :   if (num_known_dirs == 0)
     493             :   {
     494       26920 :     std::vector<Real> eigval(3, 0.0);
     495       26920 :     RankTwoTensor eigvec;
     496             : 
     497       26920 :     _elastic_strain[_qp].symmetricEigenvaluesEigenvectors(eigval, eigvec);
     498             : 
     499             :     // If the elastic strain is beyond the cracking strain, save the eigen vectors as
     500             :     // the rotation tensor. Reverse their order so that the third principal strain
     501             :     // (most tensile) will correspond to the first crack.
     502       26920 :     _crack_rotation[_qp].fillColumn(0, eigvec.column(2));
     503       26920 :     _crack_rotation[_qp].fillColumn(1, eigvec.column(1));
     504       26920 :     _crack_rotation[_qp].fillColumn(2, eigvec.column(0));
     505             : 
     506       26920 :     strain_in_crack_dir(0) = eigval[2];
     507       26920 :     strain_in_crack_dir(1) = eigval[1];
     508       26920 :     strain_in_crack_dir(2) = eigval[0];
     509             :   }
     510      520128 :   else if (num_known_dirs == 1)
     511             :   {
     512             :     // This is easily the most complicated case.
     513             :     // 1.  Rotate the elastic strain to the orientation associated with the known
     514             :     //     crack.
     515             :     // 2.  Extract the lower 2x2 block into a separate tensor.
     516             :     // 3.  Run the eigen solver on the result.
     517             :     // 4.  Update the rotation tensor to reflect the effect of the 2 eigenvectors.
     518             : 
     519             :     // 1.
     520      237136 :     const RankTwoTensor & R = _crack_rotation[_qp];
     521      237136 :     RankTwoTensor ePrime(_elastic_strain[_qp]);
     522      237136 :     ePrime.rotate(R.transpose()); // elastic strain in crack coordinates
     523             : 
     524             :     // 2.
     525      237136 :     ColumnMajorMatrix e2x2(2, 2);
     526      237136 :     e2x2(0, 0) = ePrime(1, 1);
     527      237136 :     e2x2(1, 0) = ePrime(2, 1);
     528      237136 :     e2x2(0, 1) = ePrime(1, 2);
     529      237136 :     e2x2(1, 1) = ePrime(2, 2);
     530             : 
     531             :     // 3.
     532      237136 :     ColumnMajorMatrix e_val2x1(2, 1);
     533      237136 :     ColumnMajorMatrix e_vec2x2(2, 2);
     534      237136 :     e2x2.eigen(e_val2x1, e_vec2x2);
     535             : 
     536             :     // 4.
     537             :     RankTwoTensor eigvec(
     538      237136 :         1.0, 0.0, 0.0, 0.0, e_vec2x2(0, 1), e_vec2x2(1, 1), 0.0, e_vec2x2(0, 0), e_vec2x2(1, 0));
     539             : 
     540      237136 :     _crack_rotation[_qp] = _crack_rotation_old[_qp] * eigvec; // Roe implementation
     541             : 
     542      237136 :     strain_in_crack_dir(0) = ePrime(0, 0);
     543      237136 :     strain_in_crack_dir(1) = e_val2x1(1, 0);
     544      237136 :     strain_in_crack_dir(2) = e_val2x1(0, 0);
     545             :   }
     546      282992 :   else if (num_known_dirs == 2 || num_known_dirs == 3)
     547             :   {
     548             :     // Rotate to cracked orientation and pick off the strains in the rotated
     549             :     // coordinate directions.
     550      282992 :     const RankTwoTensor & R = _crack_rotation[_qp];
     551      282992 :     RankTwoTensor ePrime(_elastic_strain[_qp]);
     552      282992 :     ePrime.rotate(R.transpose()); // elastic strain in crack coordinates
     553             : 
     554      282992 :     strain_in_crack_dir(0) = ePrime(0, 0);
     555      282992 :     strain_in_crack_dir(1) = ePrime(1, 1);
     556      282992 :     strain_in_crack_dir(2) = ePrime(2, 2);
     557             :   }
     558             :   else
     559           0 :     mooseError("Invalid number of known crack directions");
     560      547048 : }
     561             : 
     562             : unsigned int
     563      547048 : ComputeSmearedCrackingStress::getNumKnownCrackDirs() const
     564             : {
     565             :   unsigned int num_known_dirs = 0;
     566     2188192 :   for (unsigned int i = 0; i < 3; ++i)
     567             :   {
     568     1641144 :     if (_crack_damage_old[_qp](i) > 0.0 || _prescribed_crack_directions.size() >= i + 1)
     569      905248 :       ++num_known_dirs;
     570             :   }
     571      547048 :   return num_known_dirs;
     572             : }
     573             : 
     574             : void
     575      519744 : ComputeSmearedCrackingStress::updateStressTensorForCracking(RankTwoTensor & tensor,
     576             :                                                             const RealVectorValue & sigma)
     577             : {
     578             :   // Get transformation matrix
     579      519744 :   const RankTwoTensor & R = _crack_rotation[_qp];
     580             :   // Rotate to crack frame
     581      519744 :   tensor.rotate(R.transpose());
     582             : 
     583             :   // Reset stress if cracked
     584     2078976 :   for (unsigned int i = 0; i < 3; ++i)
     585     1559232 :     if (_crack_damage[_qp](i) > 0.0)
     586             :     {
     587      550912 :       const Real stress_correction_ratio = (tensor(i, i) - sigma(i)) / tensor(i, i);
     588      550912 :       if (stress_correction_ratio > _max_stress_correction)
     589           0 :         tensor(i, i) *= (1.0 - _max_stress_correction);
     590      550912 :       else if (stress_correction_ratio < -_max_stress_correction)
     591           0 :         tensor(i, i) *= (1.0 + _max_stress_correction);
     592             :       else
     593      550912 :         tensor(i, i) = sigma(i);
     594             :     }
     595             : 
     596             :   // Rotate back to global frame
     597      519744 :   tensor.rotate(R);
     598      519744 : }
     599             : 
     600             : bool
     601      547072 : ComputeSmearedCrackingStress::previouslyCracked()
     602             : {
     603      970384 :   for (unsigned int i = 0; i < 3; ++i)
     604      942144 :     if (_crack_damage_old[_qp](i) > 0.0)
     605             :       return true;
     606             :   return false;
     607             : }

Generated by: LCOV version 1.14