LCOV - code coverage report
Current view: top level - src/userobjects - BilinearMixedModeCohesiveZoneModel.C (source / functions) Hit Total Coverage
Test: idaholab/moose contact: #32971 (54bef8) with base c6cf66 Lines: 163 166 98.2 %
Date: 2026-05-29 20:36:03 Functions: 16 17 94.1 %
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 "BilinearMixedModeCohesiveZoneModel.h"
      11             : #include "MooseVariableFE.h"
      12             : #include "SystemBase.h"
      13             : #include "MortarUtils.h"
      14             : #include "MooseUtils.h"
      15             : #include "MathUtils.h"
      16             : 
      17             : #include "MortarContactUtils.h"
      18             : #include "FactorizedRankTwoTensor.h"
      19             : 
      20             : #include "ADReal.h"
      21             : #include "CohesiveZoneModelTools.h"
      22             : #include <Eigen/Core>
      23             : 
      24             : registerMooseObject("ContactApp", BilinearMixedModeCohesiveZoneModel);
      25             : 
      26             : InputParameters
      27          90 : BilinearMixedModeCohesiveZoneModel::validParams()
      28             : {
      29          90 :   InputParameters params = CohesiveZoneModelBase::validParams();
      30             : 
      31          90 :   params.addClassDescription("Computes the bilinear mixed mode cohesive zone model.");
      32             : 
      33             :   // Input parameters for bilinear mixed mode traction.
      34         180 :   params.addParam<MaterialPropertyName>("GI_c",
      35             :                                         "Critical energy release rate in normal direction.");
      36         180 :   params.addParam<MaterialPropertyName>("GII_c",
      37             :                                         "Critical energy release rate in shear direction.");
      38         180 :   params.addParam<MaterialPropertyName>("normal_strength", "Tensile strength in normal direction.");
      39         180 :   params.addParam<MaterialPropertyName>("shear_strength", "Tensile strength in shear direction.");
      40         180 :   params.addParam<Real>("power_law_parameter", "The power law parameter.");
      41         180 :   MooseEnum criterion("POWER_LAW BK", "BK");
      42         180 :   params.addParam<Real>("viscosity", 0.0, "Viscosity for damage model.");
      43         180 :   params.addParam<MooseEnum>(
      44             :       "mixed_mode_criterion", criterion, "Option for mixed mode propagation criterion.");
      45         180 :   params.addParam<bool>(
      46             :       "lag_displacement_jump",
      47         180 :       false,
      48             :       "Whether to use old displacement jumps to compute the effective displacement jump.");
      49         180 :   params.addParam<bool>("set_compressive_traction_to_zero",
      50         180 :                         false,
      51             :                         "Zero compressive traction (set to true, allowing the use of standard "
      52             :                         "zero-penetration mortar contact constraints in "
      53             :                         "the normal direction).");
      54         180 :   params.addParam<Real>(
      55         180 :       "regularization_alpha", 1e-10, "Regularization parameter for the Macaulay bracket.");
      56         180 :   params.addRangeCheckedParam<Real>(
      57             :       "penalty_stiffness", "penalty_stiffness > 0.0", "Penalty stiffness for CZM.");
      58         180 :   params.addParamNamesToGroup(
      59             :       "GI_c GII_c normal_strength shear_strength power_law_parameter viscosity "
      60             :       "mixed_mode_criterion lag_displacement_jump regularization_alpha "
      61             :       "penalty_stiffness",
      62             :       "Bilinear mixed mode traction");
      63             :   // End of input parameters for bilinear mixed mode traction.
      64             : 
      65          90 :   return params;
      66          90 : }
      67             : 
      68          45 : BilinearMixedModeCohesiveZoneModel::BilinearMixedModeCohesiveZoneModel(
      69          45 :     const InputParameters & parameters)
      70             :   : WeightedGapUserObject(parameters),
      71             :     PenaltyWeightedGapUserObject(parameters),
      72             :     WeightedVelocitiesUserObject(parameters),
      73             :     CohesiveZoneModelBase(parameters),
      74          45 :     _set_compressive_traction_to_zero(getParam<bool>("set_compressive_traction_to_zero")),
      75          90 :     _normal_strength(getMaterialProperty<Real>("normal_strength")),
      76          90 :     _shear_strength(getMaterialProperty<Real>("shear_strength")),
      77          90 :     _GI_c(getMaterialProperty<Real>("GI_c")),
      78          90 :     _GII_c(getMaterialProperty<Real>("GII_c")),
      79          90 :     _penalty_stiffness_czm(getParam<Real>("penalty_stiffness")),
      80          90 :     _mix_mode_criterion(getParam<MooseEnum>("mixed_mode_criterion").getEnum<MixedModeCriterion>()),
      81          90 :     _power_law_parameter(getParam<Real>("power_law_parameter")),
      82          90 :     _viscosity(getParam<Real>("viscosity")),
      83         135 :     _regularization_alpha(getParam<Real>("regularization_alpha"))
      84             : {
      85             : 
      86             :   // Checks for bilinear traction input.
      87         315 :   if (!isParamValid("GI_c") || !isParamValid("GII_c") || !isParamValid("normal_strength") ||
      88         315 :       !isParamValid("shear_strength") || !isParamValid("power_law_parameter") ||
      89         135 :       !isParamValid("penalty_stiffness"))
      90           0 :     paramError("GI_c",
      91             :                "The CZM bilinear mixed mode traction parameters GI_c, GII_c, normal_strength, "
      92             :                "shear_strength, and power_law_parameter are required. Revise your input and add "
      93             :                "those parameters if you want to use the bilinear mixed mode traction model. ");
      94          45 : }
      95             : 
      96             : void
      97       26886 : BilinearMixedModeCohesiveZoneModel::computeQpProperties()
      98             : {
      99       26886 :   CohesiveZoneModelBase::computeQpProperties();
     100             : 
     101       26886 :   _normal_strength_interpolation = _normal_strength[_qp] * _JxW_msm[_qp] * _coord[_qp];
     102       26886 :   _shear_strength_interpolation = _shear_strength[_qp] * _JxW_msm[_qp] * _coord[_qp];
     103       26886 :   _GI_c_interpolation = _GI_c[_qp] * _JxW_msm[_qp] * _coord[_qp];
     104       26886 :   _GII_c_interpolation = _GII_c[_qp] * _JxW_msm[_qp] * _coord[_qp];
     105       26886 : }
     106             : 
     107             : void
     108       53772 : BilinearMixedModeCohesiveZoneModel::computeQpIProperties()
     109             : {
     110       53772 :   CohesiveZoneModelBase::computeQpIProperties();
     111             : 
     112             :   // Get the _dof_to_weighted_gap map
     113       53772 :   const auto * const dof = static_cast<const DofObject *>(_lower_secondary_elem->node_ptr(_i));
     114             : 
     115             :   // TODO: Probably better to interpolate the deformation gradients.
     116      107544 :   _dof_to_normal_strength[dof] += (*_test)[_i][_qp] * _normal_strength_interpolation;
     117      107544 :   _dof_to_shear_strength[dof] += (*_test)[_i][_qp] * _shear_strength_interpolation;
     118             : 
     119      107544 :   _dof_to_GI_c[dof] += (*_test)[_i][_qp] * _GI_c_interpolation;
     120      107544 :   _dof_to_GII_c[dof] += (*_test)[_i][_qp] * _GII_c_interpolation;
     121       53772 : }
     122             : 
     123             : void
     124        7087 : BilinearMixedModeCohesiveZoneModel::initialize()
     125             : {
     126             :   // instead we call it explicitly here
     127        7087 :   CohesiveZoneModelBase::initialize();
     128             : 
     129             :   // Avoid accumulating interpolation over the time step
     130             :   _dof_to_mode_mixity_ratio.clear();
     131             :   _dof_to_normal_strength.clear();
     132             :   _dof_to_shear_strength.clear();
     133             :   _dof_to_GI_c.clear();
     134             :   _dof_to_GII_c.clear();
     135             :   _dof_to_delta_initial.clear();
     136             :   _dof_to_delta_final.clear();
     137             :   _dof_to_delta_max.clear();
     138        7087 : }
     139             : 
     140             : void
     141       26886 : BilinearMixedModeCohesiveZoneModel::computeCZMTraction(const Node * const node)
     142             : {
     143             :   using std::max, std::min;
     144             : 
     145             :   // First call does not have maps available
     146       26886 :   const bool return_boolean = _dof_to_weighted_gap.find(node) == _dof_to_weighted_gap.end();
     147       26886 :   if (return_boolean)
     148           0 :     return;
     149             : 
     150       26886 :   computeModeMixity(node);
     151       26886 :   computeCriticalDisplacementJump(node);
     152       26886 :   computeFinalDisplacementJump(node);
     153       26886 :   computeEffectiveDisplacementJump(node);
     154       26886 :   computeDamage(node);
     155             : 
     156             :   // Split displacement jump into active and inactive parts
     157             :   const auto interface_displacement_jump =
     158       26886 :       normalizeQuantity(_dof_to_interface_displacement_jump, node);
     159             : 
     160       26886 :   const ADRealVectorValue delta_active(max(interface_displacement_jump(0), 0.0),
     161             :                                        interface_displacement_jump(1),
     162             :                                        interface_displacement_jump(2));
     163       26886 :   const ADRealVectorValue delta_inactive(min(interface_displacement_jump(0), 0.0), 0.0, 0.0);
     164             : 
     165             :   // This traction vector is local at this point.
     166       53772 :   _dof_to_czm_traction[node] =
     167       53772 :       -(1.0 - libmesh_map_find(_dof_to_damage, node->id()).first) * _penalty_stiffness_czm *
     168       26886 :           delta_active -
     169       80658 :       _penalty_stiffness_czm * (_set_compressive_traction_to_zero ? 0.0 : delta_inactive);
     170             : }
     171             : 
     172             : void
     173       26886 : BilinearMixedModeCohesiveZoneModel::computeModeMixity(const Node * const node)
     174             : {
     175             :   using std::sqrt;
     176             : 
     177             :   const auto interface_displacement_jump =
     178       26886 :       normalizeQuantity(_dof_to_interface_displacement_jump, node);
     179             : 
     180       26886 :   if (interface_displacement_jump(0) > _epsilon_tolerance)
     181             :   {
     182             :     const auto delta_s =
     183       20525 :         sqrt(interface_displacement_jump(1) * interface_displacement_jump(1) +
     184       20525 :              interface_displacement_jump(2) * interface_displacement_jump(2) + _epsilon_tolerance);
     185             : 
     186       20525 :     _dof_to_mode_mixity_ratio[node] = delta_s / interface_displacement_jump(0);
     187             :   }
     188             :   else
     189        6361 :     _dof_to_mode_mixity_ratio[node] = 0;
     190       26886 : }
     191             : 
     192             : void
     193       26886 : BilinearMixedModeCohesiveZoneModel::computeCriticalDisplacementJump(const Node * const node)
     194             : {
     195             :   using std::sqrt;
     196             : 
     197             :   const auto interface_displacement_jump =
     198       26886 :       normalizeQuantity(_dof_to_interface_displacement_jump, node);
     199             : 
     200       26886 :   const auto mixity_ratio = libmesh_map_find(_dof_to_mode_mixity_ratio, node);
     201             : 
     202             :   const auto delta_normal_knot =
     203       26886 :       normalizeQuantity(_dof_to_normal_strength, node) / _penalty_stiffness_czm;
     204             :   const auto delta_shear_knot =
     205       26886 :       normalizeQuantity(_dof_to_shear_strength, node) / _penalty_stiffness_czm;
     206             : 
     207       26886 :   _dof_to_delta_initial[node] = delta_shear_knot;
     208             : 
     209       26886 :   if (interface_displacement_jump(0) > _epsilon_tolerance)
     210             :   {
     211       20525 :     const auto delta_mixed = sqrt(delta_shear_knot * delta_shear_knot +
     212       20525 :                                   Utility::pow<2>(mixity_ratio * delta_normal_knot));
     213             : 
     214       41050 :     _dof_to_delta_initial[node] = delta_normal_knot * delta_shear_knot *
     215       61575 :                                   sqrt(1.0 + mixity_ratio * mixity_ratio) / delta_mixed;
     216             :   }
     217       26886 : }
     218             : 
     219             : void
     220       26886 : BilinearMixedModeCohesiveZoneModel::computeFinalDisplacementJump(const Node * const node)
     221             : {
     222             :   using std::sqrt, std::pow;
     223             : 
     224             :   const auto interface_displacement_jump =
     225       26886 :       normalizeQuantity(_dof_to_interface_displacement_jump, node);
     226             : 
     227       26886 :   const auto mixity_ratio = libmesh_map_find(_dof_to_mode_mixity_ratio, node);
     228             : 
     229       26886 :   const auto normalized_GI_c = normalizeQuantity(_dof_to_GI_c, node);
     230       26886 :   const auto normalized_GII_c = normalizeQuantity(_dof_to_GII_c, node);
     231             : 
     232       53772 :   _dof_to_delta_final[node] =
     233       53772 :       sqrt(2.0) * 2.0 * normalized_GII_c / normalizeQuantity(_dof_to_shear_strength, node);
     234             : 
     235       26886 :   if (interface_displacement_jump(0) > _epsilon_tolerance)
     236             :   {
     237       20525 :     if (_mix_mode_criterion == MixedModeCriterion::BK)
     238             :     {
     239       14842 :       _dof_to_delta_final[node] =
     240        7421 :           2.0 / _penalty_stiffness_czm / libmesh_map_find(_dof_to_delta_initial, node) *
     241        7421 :           (normalized_GI_c +
     242        7421 :            (normalized_GII_c - normalized_GI_c) *
     243       22263 :                pow(mixity_ratio * mixity_ratio / (1 + mixity_ratio * mixity_ratio),
     244       14842 :                    _power_law_parameter));
     245             :     }
     246       13104 :     else if (_mix_mode_criterion == MixedModeCriterion::POWER_LAW)
     247             :     {
     248             :       const auto Gc_mixed =
     249       26208 :           pow(1.0 / normalized_GI_c, _power_law_parameter) +
     250       26208 :           pow(mixity_ratio * mixity_ratio / normalized_GII_c, _power_law_parameter);
     251       39312 :       _dof_to_delta_final[node] = (2.0 + 2.0 * mixity_ratio * mixity_ratio) /
     252       13104 :                                   _penalty_stiffness_czm /
     253       13104 :                                   libmesh_map_find(_dof_to_delta_initial, node) *
     254       26208 :                                   pow(Gc_mixed, -1.0 / _power_law_parameter);
     255             :     }
     256             :   }
     257       26886 : }
     258             : 
     259             : void
     260       26886 : BilinearMixedModeCohesiveZoneModel::computeEffectiveDisplacementJump(const Node * const node)
     261             : {
     262             :   using std::sqrt;
     263             : 
     264             :   const auto interface_displacement_jump =
     265       26886 :       normalizeQuantity(_dof_to_interface_displacement_jump, node);
     266             : 
     267             :   const auto delta_normal_pos =
     268       26886 :       MathUtils::regularizedHeavyside(interface_displacement_jump(0), _regularization_alpha) *
     269             :       interface_displacement_jump(0);
     270             : 
     271       26886 :   _dof_to_delta_max[node] = sqrt(Utility::pow<2>(interface_displacement_jump(1)) +
     272       26886 :                                  Utility::pow<2>(interface_displacement_jump(2)) +
     273       53772 :                                  Utility::pow<2>(delta_normal_pos) + _epsilon_tolerance);
     274       26886 : }
     275             : 
     276             : void
     277       26886 : BilinearMixedModeCohesiveZoneModel::computeDamage(const Node * const node)
     278             : {
     279       26886 :   const auto delta_max = libmesh_map_find(_dof_to_delta_max, node);
     280       26886 :   const auto delta_initial = libmesh_map_find(_dof_to_delta_initial, node);
     281       26886 :   const auto delta_final = libmesh_map_find(_dof_to_delta_final, node);
     282             : 
     283       26886 :   auto & [damage, damage_old] = _dof_to_damage[node->id()];
     284       26886 :   if (delta_max < delta_initial)
     285       22976 :     damage = 0;
     286        3910 :   else if (delta_max > delta_final)
     287           0 :     damage = 1.0;
     288             :   else
     289        3910 :     damage = delta_final * (delta_max - delta_initial) / delta_max / (delta_final - delta_initial);
     290             : 
     291       26886 :   if (damage < damage_old)
     292             :     // Irreversibility
     293         491 :     damage = damage_old;
     294             : 
     295             :   // Viscous regularization
     296       53772 :   damage = (damage + _viscosity * damage_old / _dt) / (_viscosity / _dt + 1.0);
     297       26886 : }
     298             : 
     299             : void
     300        7087 : BilinearMixedModeCohesiveZoneModel::finalize()
     301             : {
     302        7087 :   CohesiveZoneModelBase::finalize();
     303             : 
     304        7087 :   const bool send_data_back = !constrainedByOwner();
     305             : 
     306       14174 :   Moose::Mortar::Contact::communicateRealObject(
     307        7087 :       _dof_to_normal_strength, _subproblem.mesh(), _nodal, _communicator, send_data_back);
     308             : 
     309       14174 :   Moose::Mortar::Contact::communicateRealObject(
     310        7087 :       _dof_to_shear_strength, _subproblem.mesh(), _nodal, _communicator, send_data_back);
     311             : 
     312       14174 :   Moose::Mortar::Contact::communicateRealObject(
     313        7087 :       _dof_to_GI_c, _subproblem.mesh(), _nodal, _communicator, send_data_back);
     314             : 
     315       14174 :   Moose::Mortar::Contact::communicateRealObject(
     316        7087 :       _dof_to_GII_c, _subproblem.mesh(), _nodal, _communicator, send_data_back);
     317        7087 : }
     318             : 
     319             : Real
     320        1890 : BilinearMixedModeCohesiveZoneModel::getModeMixityRatio(const Node * const node) const
     321             : {
     322        1890 :   const auto it = _dof_to_mode_mixity_ratio.find(_subproblem.mesh().nodePtr(node->id()));
     323             : 
     324        1890 :   if (it != _dof_to_mode_mixity_ratio.end())
     325        1114 :     return MetaPhysicL::raw_value(it->second);
     326             :   else
     327             :     return 0.0;
     328             : }
     329             : 
     330             : Real
     331        1890 : BilinearMixedModeCohesiveZoneModel::getCohesiveDamage(const Node * const node) const
     332             : {
     333        1890 :   const auto it = _dof_to_damage.find(node->id());
     334             : 
     335        1890 :   if (it != _dof_to_damage.end())
     336        1114 :     return MetaPhysicL::raw_value(it->second.first);
     337             :   else
     338             :     return 0.0;
     339             : }
     340             : 
     341             : Real
     342        1890 : BilinearMixedModeCohesiveZoneModel::getLocalDisplacementNormal(const Node * const node) const
     343             : {
     344        1890 :   const auto it = _dof_to_interface_displacement_jump.find(_subproblem.mesh().nodePtr(node->id()));
     345        1890 :   const auto it2 = _dof_to_weighted_gap.find(_subproblem.mesh().nodePtr(node->id()));
     346             : 
     347        1890 :   if (it != _dof_to_interface_displacement_jump.end() && it2 != _dof_to_weighted_gap.end())
     348        2228 :     return MetaPhysicL::raw_value(it->second(0) / it2->second.second);
     349             :   else
     350             :     return 0.0;
     351             : }
     352             : 
     353             : Real
     354        1890 : BilinearMixedModeCohesiveZoneModel::getLocalDisplacementTangential(const Node * const node) const
     355             : {
     356        1890 :   const auto it = _dof_to_interface_displacement_jump.find(_subproblem.mesh().nodePtr(node->id()));
     357        1890 :   const auto it2 = _dof_to_weighted_gap.find(_subproblem.mesh().nodePtr(node->id()));
     358             : 
     359        1890 :   if (it != _dof_to_interface_displacement_jump.end() && it2 != _dof_to_weighted_gap.end())
     360        2228 :     return MetaPhysicL::raw_value(it->second(1) / it2->second.second);
     361             :   else
     362             :     return 0.0;
     363             : }

Generated by: LCOV version 1.14