LCOV - code coverage report
Current view: top level - src/constraints - ComputeDynamicFrictionalForceLMMechanicalContact.C (source / functions) Hit Total Coverage
Test: idaholab/moose contact: #33358 (34476d) with base 4fcf7b Lines: 182 193 94.3 %
Date: 2026-07-17 19:51:21 Functions: 11 12 91.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 "ComputeDynamicFrictionalForceLMMechanicalContact.h"
      11             : #include "DisplacedProblem.h"
      12             : #include "Assembly.h"
      13             : #include "Function.h"
      14             : #include "MortarContactUtils.h"
      15             : #include "ContactFrictionUtils.h"
      16             : #include "AutomaticMortarGeneration.h"
      17             : 
      18             : #include "metaphysicl/metaphysicl_version.h"
      19             : #include "metaphysicl/dualsemidynamicsparsenumberarray.h"
      20             : #include "metaphysicl/parallel_dualnumber.h"
      21             : #if METAPHYSICL_MAJOR_VERSION < 2
      22             : #include "metaphysicl/parallel_dynamic_std_array_wrapper.h"
      23             : #else
      24             : #include "metaphysicl/parallel_dynamic_array_wrapper.h"
      25             : #endif
      26             : #include "metaphysicl/parallel_semidynamicsparsenumberarray.h"
      27             : #include "timpi/parallel_sync.h"
      28             : 
      29             : #include <limits>
      30             : 
      31             : registerMooseObject("ContactApp", ComputeDynamicFrictionalForceLMMechanicalContact);
      32             : 
      33             : InputParameters
      34         208 : ComputeDynamicFrictionalForceLMMechanicalContact::validParams()
      35             : {
      36         208 :   InputParameters params = ComputeDynamicWeightedGapLMMechanicalContact::validParams();
      37         208 :   params.addClassDescription("Computes the tangential frictional forces for dynamic simulations");
      38         416 :   params.addRequiredCoupledVar("friction_lm", "The frictional Lagrange's multiplier");
      39         416 :   params.addCoupledVar("friction_lm_dir",
      40             :                        "The frictional Lagrange's multiplier for an addtional direction.");
      41         416 :   params.addParam<FunctionName>(
      42             :       "function_friction",
      43             :       "Coupled function to evaluate friction with values from contact pressure and relative "
      44             :       "tangential velocities (from the previous step).");
      45         416 :   params.addParam<Real>("c_t", 1e0, "Numerical parameter for tangential constraints");
      46         624 :   params.addRangeCheckedParam<Real>(
      47             :       "epsilon",
      48         416 :       1.0e-7,
      49             :       "epsilon > 0",
      50             :       "Minimum value of contact pressure that will trigger frictional enforcement");
      51         416 :   params.addRangeCheckedParam<Real>(
      52             :       "mu", "mu >= 0", "The friction coefficient for the Coulomb friction law");
      53         416 :   params.addParam<MooseEnum>("friction_coefficient_regularization",
      54         416 :                              Moose::Contact::frictionCoefficientRegularizationOptions(),
      55             :                              "The regularization applied to the Coulomb friction coefficient.");
      56         624 :   params.addRangeCheckedParam<Real>(
      57             :       "friction_reference_slip",
      58         416 :       0.0,
      59             :       "friction_reference_slip >= 0",
      60             :       "Reference slip increment used by friction coefficient regularization.");
      61         624 :   params.addRangeCheckedParam<Real>(
      62             :       "friction_elastic_slip",
      63         416 :       0.0,
      64             :       "friction_elastic_slip >= 0",
      65             :       "Tangential elastic slip distance over which the Coulomb friction bound is reached.");
      66         208 :   return params;
      67           0 : }
      68             : 
      69         104 : ComputeDynamicFrictionalForceLMMechanicalContact::ComputeDynamicFrictionalForceLMMechanicalContact(
      70         104 :     const InputParameters & parameters)
      71             :   : ComputeDynamicWeightedGapLMMechanicalContact(parameters),
      72         208 :     _c_t(getParam<Real>("c_t")),
      73         104 :     _secondary_x_dot(_secondary_var.adUDot()),
      74         104 :     _primary_x_dot(_primary_var.adUDotNeighbor()),
      75         104 :     _secondary_y_dot(adCoupledDot("disp_y")),
      76         104 :     _primary_y_dot(adCoupledNeighborValueDot("disp_y")),
      77         104 :     _secondary_z_dot(_has_disp_z ? &adCoupledDot("disp_z") : nullptr),
      78         104 :     _primary_z_dot(_has_disp_z ? &adCoupledNeighborValueDot("disp_z") : nullptr),
      79         208 :     _epsilon(getParam<Real>("epsilon")),
      80         404 :     _mu(isParamValid("mu") ? getParam<Real>("mu") : std::numeric_limits<double>::quiet_NaN()),
      81         104 :     _friction_coefficient_regularization(
      82         104 :         getParam<MooseEnum>("friction_coefficient_regularization")
      83             :             .getEnum<Moose::Contact::FrictionCoefficientRegularization>()),
      84         208 :     _friction_reference_slip(getParam<Real>("friction_reference_slip")),
      85         208 :     _friction_elastic_slip(getParam<Real>("friction_elastic_slip")),
      86         214 :     _function_friction(isParamValid("function_friction") ? &getFunction("function_friction")
      87             :                                                          : nullptr),
      88         208 :     _has_friction_function(isParamValid("function_friction")),
      89         104 :     _3d(_has_disp_z)
      90             : {
      91         398 :   if (!_has_friction_function && !isParamValid("mu"))
      92           0 :     paramError("mu",
      93             :                "A coefficient of friction needs to be provided as a constant value or via a "
      94             :                "function.");
      95             : 
      96         116 :   if (_has_friction_function && isParamValid("mu"))
      97           0 :     paramError("mu",
      98             :                "Either provide a constant coefficient of friction or a function defining the "
      99             :                "coefficient of friction. Both inputs cannot be provided simultaneously.");
     100             : 
     101         208 :   if (!getParam<bool>("use_displaced_mesh"))
     102           0 :     paramError("use_displaced_mesh",
     103             :                "'use_displaced_mesh' must be true for the "
     104             :                "ComputeFrictionalForceLMMechanicalContact object");
     105             : 
     106         182 :   if (_3d && !isParamValid("friction_lm_dir"))
     107           0 :     paramError("friction_lm_dir",
     108             :                "Three-dimensional mortar frictional contact simulations require an additional "
     109             :                "frictional Lagrange's multiplier to enforce a second tangential pressure");
     110             : 
     111         104 :   if (_friction_coefficient_regularization !=
     112          26 :           Moose::Contact::FrictionCoefficientRegularization::NONE &&
     113          26 :       _friction_reference_slip <= 0.0)
     114           0 :     paramError("friction_reference_slip",
     115             :                "A positive friction_reference_slip is required when "
     116             :                "friction_coefficient_regularization is not NONE.");
     117             : 
     118         104 :   _friction_vars.push_back(getVar("friction_lm", 0));
     119             : 
     120         104 :   if (_3d)
     121          52 :     _friction_vars.push_back(getVar("friction_lm_dir", 0));
     122             : 
     123         104 :   if (!_friction_vars[0]->isNodal())
     124           0 :     if (_friction_vars[0]->feType().order != static_cast<Order>(0))
     125           0 :       paramError(
     126             :           "friction_lm",
     127             :           "Frictional contact constraints only support elemental variables of CONSTANT order");
     128             : 
     129             :   // Request the old solution state in unison
     130         104 :   _sys.solutionOld();
     131         104 : }
     132             : 
     133             : void
     134      565044 : ComputeDynamicFrictionalForceLMMechanicalContact::computeQpProperties()
     135             : {
     136             :   // Compute the value of _qp_gap
     137      565044 :   ComputeDynamicWeightedGapLMMechanicalContact::computeQpProperties();
     138             : 
     139             :   // It appears that the relative velocity between weighted gap and this class have a sign
     140             :   // difference
     141      565044 :   _qp_tangential_velocity_nodal = -_relative_velocity * (_JxW_msm[_qp] * _coord[_qp]);
     142      565044 :   _qp_real_tangential_velocity_nodal = -_relative_velocity;
     143      565044 : }
     144             : 
     145             : void
     146     1986576 : ComputeDynamicFrictionalForceLMMechanicalContact::computeQpIProperties()
     147             : {
     148             :   // Get the _dof_to_weighted_gap map
     149     1986576 :   ComputeDynamicWeightedGapLMMechanicalContact::computeQpIProperties();
     150             : 
     151     1986576 :   const auto & nodal_tangents = amg().getNodalTangents(*_lower_secondary_elem);
     152             : 
     153             :   // Get the _dof_to_weighted_tangential_velocity map
     154             :   const DofObject * const dof =
     155     1986576 :       _friction_vars[0]->isNodal()
     156     1986576 :           ? static_cast<const DofObject *>(_lower_secondary_elem->node_ptr(_i))
     157           0 :           : static_cast<const DofObject *>(_lower_secondary_elem);
     158             : 
     159             :   _dof_to_weighted_tangential_velocity[dof][0] +=
     160     3973152 :       _test[_i][_qp] * _qp_tangential_velocity_nodal * nodal_tangents[0][_i];
     161             : 
     162             :   _dof_to_real_tangential_velocity[dof][0] +=
     163     3973152 :       _test[_i][_qp] * _qp_real_tangential_velocity_nodal * nodal_tangents[0][_i];
     164             : 
     165             :   // Get the _dof_to_weighted_tangential_velocity map for a second direction
     166     1986576 :   if (_3d)
     167             :   {
     168             :     _dof_to_weighted_tangential_velocity[dof][1] +=
     169     3425952 :         _test[_i][_qp] * _qp_tangential_velocity_nodal * nodal_tangents[1][_i];
     170             : 
     171             :     _dof_to_real_tangential_velocity[dof][1] +=
     172     3425952 :         _test[_i][_qp] * _qp_real_tangential_velocity_nodal * nodal_tangents[1][_i];
     173             :   }
     174     1986576 : }
     175             : 
     176             : void
     177        6122 : ComputeDynamicFrictionalForceLMMechanicalContact::residualSetup()
     178             : {
     179             :   // Clear both maps
     180        6122 :   ComputeDynamicWeightedGapLMMechanicalContact::residualSetup();
     181             :   _dof_to_weighted_tangential_velocity.clear();
     182             :   _dof_to_real_tangential_velocity.clear();
     183        6122 : }
     184             : 
     185             : void
     186         317 : ComputeDynamicFrictionalForceLMMechanicalContact::timestepSetup()
     187             : {
     188             : 
     189         317 :   ComputeDynamicWeightedGapLMMechanicalContact::timestepSetup();
     190             : 
     191             :   _dof_to_old_real_tangential_velocity.clear();
     192             : 
     193        2087 :   for (const auto & [dof, real_tangential_velocity] : _dof_to_real_tangential_velocity)
     194             :     _dof_to_old_real_tangential_velocity.emplace(
     195             :         dof,
     196        1770 :         std::array<Real, 2>{{MetaPhysicL::raw_value(real_tangential_velocity[0]),
     197             :                              MetaPhysicL::raw_value(real_tangential_velocity[1])}});
     198         317 : }
     199             : 
     200             : void
     201         451 : ComputeDynamicFrictionalForceLMMechanicalContact::post()
     202             : {
     203         451 :   ComputeDynamicWeightedGapLMMechanicalContact::post();
     204             : 
     205         451 :   Moose::Mortar::Contact::communicateVelocities(
     206         451 :       _dof_to_weighted_tangential_velocity, _mesh, _nodal, _communicator, false);
     207             : 
     208         451 :   Moose::Mortar::Contact::communicateVelocities(
     209         451 :       _dof_to_real_tangential_velocity, _mesh, _nodal, _communicator, false);
     210             : 
     211             :   // Enforce frictional complementarity constraints
     212        3430 :   for (const auto & pr : _dof_to_weighted_tangential_velocity)
     213             :   {
     214        2979 :     const DofObject * const dof = pr.first;
     215             : 
     216        2979 :     if (dof->processor_id() != this->processor_id())
     217           0 :       continue;
     218             : 
     219             :     // Use always weighted gap for dynamic PDASS. Omit the dynamic weighted gap approach that is
     220             :     // used in normal contact where the discretized gap velocity is enforced if a node has
     221             :     // identified to be into contact.
     222             : 
     223        2979 :     _weighted_gap_ptr = &_dof_to_weighted_gap[dof].first;
     224        2979 :     _normalization_ptr = &_dof_to_weighted_gap[dof].second;
     225        2979 :     _tangential_vel_ptr[0] = &(pr.second[0]);
     226             : 
     227        2979 :     if (_3d)
     228             :     {
     229        2979 :       _tangential_vel_ptr[1] = &(pr.second[1]);
     230        2979 :       enforceConstraintOnDof3d(dof);
     231             :     }
     232             :     else
     233           0 :       enforceConstraintOnDof(dof);
     234             :   }
     235         451 : }
     236             : 
     237             : void
     238        5671 : ComputeDynamicFrictionalForceLMMechanicalContact::incorrectEdgeDroppingPost(
     239             :     const std::unordered_set<const Node *> & inactive_lm_nodes)
     240             : {
     241        5671 :   ComputeDynamicWeightedGapLMMechanicalContact::incorrectEdgeDroppingPost(inactive_lm_nodes);
     242             : 
     243        5671 :   Moose::Mortar::Contact::communicateVelocities(
     244        5671 :       _dof_to_weighted_tangential_velocity, _mesh, _nodal, _communicator, false);
     245             : 
     246        5671 :   Moose::Mortar::Contact::communicateVelocities(
     247        5671 :       _dof_to_real_tangential_velocity, _mesh, _nodal, _communicator, false);
     248             : 
     249             :   // Enforce frictional complementarity constraints
     250       51352 :   for (const auto & pr : _dof_to_weighted_tangential_velocity)
     251             :   {
     252       45681 :     const DofObject * const dof = pr.first;
     253             : 
     254             :     // If node inactive, skip
     255       45681 :     if ((inactive_lm_nodes.find(static_cast<const Node *>(dof)) != inactive_lm_nodes.end()) ||
     256       45327 :         (dof->processor_id() != this->processor_id()))
     257         726 :       continue;
     258             : 
     259             :     // Use always weighted gap for dynamic PDASS
     260       44955 :     _weighted_gap_ptr = &_dof_to_weighted_gap[dof].first;
     261       44955 :     _normalization_ptr = &_dof_to_weighted_gap[dof].second;
     262       44955 :     _tangential_vel_ptr[0] = &pr.second[0];
     263             : 
     264       44955 :     if (_3d)
     265             :     {
     266        7689 :       _tangential_vel_ptr[1] = &pr.second[1];
     267        7689 :       enforceConstraintOnDof3d(dof);
     268             :     }
     269             :     else
     270       37266 :       enforceConstraintOnDof(dof);
     271             :   }
     272        5671 : }
     273             : 
     274             : void
     275       10668 : ComputeDynamicFrictionalForceLMMechanicalContact::enforceConstraintOnDof3d(
     276             :     const DofObject * const dof)
     277             : {
     278             :   using std::max, std::sqrt;
     279             : 
     280             :   // Get normal LM
     281       10668 :   const auto normal_dof_index = dof->dof_number(_sys.number(), _var->number(), 0);
     282       10668 :   const ADReal & weighted_gap = *_weighted_gap_ptr;
     283       10668 :   ADReal contact_pressure = (*_sys.currentSolution())(normal_dof_index);
     284             :   Moose::derivInsert(contact_pressure.derivatives(), normal_dof_index, 1.);
     285             : 
     286             :   // Get friction LMs
     287             :   std::array<const ADReal *, 2> & tangential_vel = _tangential_vel_ptr;
     288             :   std::array<dof_id_type, 2> friction_dof_indices;
     289             :   std::array<ADReal, 2> friction_lm_values;
     290             : 
     291             :   const unsigned int num_tangents = 2;
     292       32004 :   for (const auto i : make_range(num_tangents))
     293             :   {
     294       21336 :     friction_dof_indices[i] = dof->dof_number(_sys.number(), _friction_vars[i]->number(), 0);
     295       21336 :     friction_lm_values[i] = (*_sys.currentSolution())(friction_dof_indices[i]);
     296             :     Moose::derivInsert(friction_lm_values[i].derivatives(), friction_dof_indices[i], 1.);
     297             :   }
     298             : 
     299             :   // Get normalized c and c_t values (if normalization specified
     300       10668 :   const Real c = _normalize_c ? _c / *_normalization_ptr : _c;
     301       10668 :   const Real c_t = _normalize_c ? _c_t / *_normalization_ptr : _c_t;
     302             : 
     303       10668 :   const Real contact_pressure_old = _sys.solutionOld()(normal_dof_index);
     304             : 
     305             :   // Compute the friction coefficient (constant or function)
     306             :   const auto & current_real_tangential_velocity =
     307       10668 :       libmesh_map_find(_dof_to_real_tangential_velocity, dof);
     308             :   const auto old_real_tangential_velocity_it = _dof_to_old_real_tangential_velocity.find(dof);
     309             :   const std::array<Real, 2> current_function_real_tangential_velocity{
     310             :       {MetaPhysicL::raw_value(current_real_tangential_velocity[0]),
     311       10668 :        MetaPhysicL::raw_value(current_real_tangential_velocity[1])}};
     312             :   const auto & function_real_tangential_velocity =
     313             :       old_real_tangential_velocity_it != _dof_to_old_real_tangential_velocity.end()
     314       12432 :           ? old_real_tangential_velocity_it->second
     315             :           : current_function_real_tangential_velocity;
     316             :   const ADReal slip_increment =
     317       10668 :       sqrt(current_real_tangential_velocity[0] * current_real_tangential_velocity[0] +
     318       10668 :            current_real_tangential_velocity[1] * current_real_tangential_velocity[1] + 1.0e-24) *
     319       10668 :       _dt;
     320             :   ADReal mu_ad = computeFrictionValue(contact_pressure_old,
     321             :                                       function_real_tangential_velocity[0],
     322             :                                       function_real_tangential_velocity[1],
     323       10668 :                                       slip_increment);
     324             : 
     325             :   ADReal dof_residual;
     326             :   ADReal dof_residual_dir;
     327             : 
     328             :   // Primal-dual active set strategy (PDASS)
     329       10668 :   if (contact_pressure < _epsilon)
     330             :   {
     331        2899 :     dof_residual = friction_lm_values[0];
     332        2899 :     dof_residual_dir = friction_lm_values[1];
     333             :   }
     334             :   else
     335             :   {
     336             :     const Real epsilon_sqrt = 1.0e-48;
     337             : 
     338        7769 :     const auto lamdba_plus_cg = contact_pressure + c * weighted_gap;
     339        7769 :     const auto normal_bound = max(0.0, lamdba_plus_cg);
     340             :     const auto friction_bound = mu_ad * normal_bound;
     341             :     const auto tangential_compliance =
     342        7769 :         _friction_elastic_slip > 0.0 ? _friction_elastic_slip / (friction_bound + _epsilon) : 0.0;
     343             : 
     344             :     std::array<ADReal, 2> lambda_t_plus_ctu;
     345             :     lambda_t_plus_ctu[0] =
     346        7769 :         friction_lm_values[0] +
     347       15538 :         c_t * (*tangential_vel[0] * _dt - tangential_compliance * friction_lm_values[0]);
     348             :     lambda_t_plus_ctu[1] =
     349        7769 :         friction_lm_values[1] +
     350       15538 :         c_t * (*tangential_vel[1] * _dt - tangential_compliance * friction_lm_values[1]);
     351             : 
     352             :     const auto tangential_trial_norm =
     353        7769 :         sqrt(lambda_t_plus_ctu[0] * lambda_t_plus_ctu[0] +
     354        7769 :              lambda_t_plus_ctu[1] * lambda_t_plus_ctu[1] + epsilon_sqrt);
     355             : 
     356        7769 :     const auto term_1_x = max(friction_bound, tangential_trial_norm) * friction_lm_values[0];
     357             : 
     358       15538 :     const auto term_1_y = max(friction_bound, tangential_trial_norm) * friction_lm_values[1];
     359             : 
     360             :     const auto term_2_x = friction_bound * lambda_t_plus_ctu[0];
     361             : 
     362             :     const auto term_2_y = friction_bound * lambda_t_plus_ctu[1];
     363             : 
     364        7769 :     dof_residual = term_1_x - term_2_x;
     365        7769 :     dof_residual_dir = term_1_y - term_2_y;
     366             :   }
     367             : 
     368       10668 :   addResidualsAndJacobian(_assembly,
     369       21336 :                           std::array<ADReal, 1>{{dof_residual}},
     370       21336 :                           std::array<dof_id_type, 1>{{friction_dof_indices[0]}},
     371             :                           _friction_vars[0]->scalingFactor());
     372       10668 :   addResidualsAndJacobian(_assembly,
     373       21336 :                           std::array<ADReal, 1>{{dof_residual_dir}},
     374       21336 :                           std::array<dof_id_type, 1>{{friction_dof_indices[1]}},
     375             :                           _friction_vars[1]->scalingFactor());
     376       10668 : }
     377             : 
     378             : void
     379       37266 : ComputeDynamicFrictionalForceLMMechanicalContact::enforceConstraintOnDof(
     380             :     const DofObject * const dof)
     381             : {
     382             :   using std::max, std::abs, std::sqrt;
     383             : 
     384             :   // Get friction LM
     385       37266 :   const auto friction_dof_index = dof->dof_number(_sys.number(), _friction_vars[0]->number(), 0);
     386       37266 :   const ADReal & tangential_vel = *_tangential_vel_ptr[0];
     387       37266 :   ADReal friction_lm_value = (*_sys.currentSolution())(friction_dof_index);
     388             :   Moose::derivInsert(friction_lm_value.derivatives(), friction_dof_index, 1.);
     389             : 
     390             :   // Get normal LM
     391       37266 :   const auto normal_dof_index = dof->dof_number(_sys.number(), _var->number(), 0);
     392       37266 :   const ADReal & weighted_gap = *_weighted_gap_ptr;
     393       37266 :   ADReal contact_pressure = (*_sys.currentSolution())(normal_dof_index);
     394             :   Moose::derivInsert(contact_pressure.derivatives(), normal_dof_index, 1.);
     395             : 
     396       37266 :   const Real contact_pressure_old = _sys.solutionOld()(normal_dof_index);
     397             : 
     398             :   // Get normalized c and c_t values (if normalization specified
     399       37266 :   const Real c = _normalize_c ? _c / *_normalization_ptr : _c;
     400       37266 :   const Real c_t = _normalize_c ? _c_t / *_normalization_ptr : _c_t;
     401             : 
     402             :   // Compute the friction coefficient (constant or function)
     403             :   const auto & current_real_tangential_velocity =
     404       37266 :       libmesh_map_find(_dof_to_real_tangential_velocity, dof);
     405             :   const auto old_real_tangential_velocity_it = _dof_to_old_real_tangential_velocity.find(dof);
     406             :   const std::array<Real, 2> current_function_real_tangential_velocity{
     407             :       {MetaPhysicL::raw_value(current_real_tangential_velocity[0]),
     408       37266 :        MetaPhysicL::raw_value(current_real_tangential_velocity[1])}};
     409             :   const auto & function_real_tangential_velocity =
     410             :       old_real_tangential_velocity_it != _dof_to_old_real_tangential_velocity.end()
     411       69190 :           ? old_real_tangential_velocity_it->second
     412             :           : current_function_real_tangential_velocity;
     413             :   const ADReal slip_increment =
     414       37266 :       sqrt(current_real_tangential_velocity[0] * current_real_tangential_velocity[0] + 1.0e-24) *
     415       37266 :       _dt;
     416             :   ADReal mu_ad = computeFrictionValue(
     417       37266 :       contact_pressure_old, function_real_tangential_velocity[0], 0.0, slip_increment);
     418             : 
     419             :   ADReal dof_residual;
     420             :   // Primal-dual active set strategy (PDASS)
     421       37266 :   if (contact_pressure < _epsilon)
     422       22933 :     dof_residual = friction_lm_value;
     423             :   else
     424             :   {
     425       14333 :     const auto lambda_plus_cg = contact_pressure + c * weighted_gap;
     426       14333 :     const auto normal_bound = max(0.0, lambda_plus_cg);
     427             :     const auto friction_bound = mu_ad * normal_bound;
     428             :     const auto tangential_compliance =
     429       18469 :         _friction_elastic_slip > 0.0 ? _friction_elastic_slip / (friction_bound + _epsilon) : 0.0;
     430             :     const auto lambda_t_plus_ctu =
     431             :         friction_lm_value +
     432       14333 :         c_t * (tangential_vel * _dt - tangential_compliance * friction_lm_value);
     433             : 
     434       28666 :     const auto term_1 = max(friction_bound, abs(lambda_t_plus_ctu)) * friction_lm_value;
     435             :     const auto term_2 = friction_bound * lambda_t_plus_ctu;
     436             : 
     437       14333 :     dof_residual = term_1 - term_2;
     438             :   }
     439             : 
     440       37266 :   addResidualsAndJacobian(_assembly,
     441       74532 :                           std::array<ADReal, 1>{{dof_residual}},
     442       74532 :                           std::array<dof_id_type, 1>{{friction_dof_index}},
     443             :                           _friction_vars[0]->scalingFactor());
     444       37266 : }
     445             : 
     446             : ADReal
     447       47934 : ComputeDynamicFrictionalForceLMMechanicalContact::computeFrictionValue(
     448             :     const ADReal & contact_pressure,
     449             :     const Real & function_tangential_vel,
     450             :     const Real & function_tangential_vel_dir,
     451             :     const ADReal & slip_increment)
     452             : {
     453             :   using std::sqrt;
     454             : 
     455             :   // TODO: Introduce temperature dependence in the function. Do this when we have an example.
     456             :   ADReal mu_ad;
     457             : 
     458       47934 :   if (!_has_friction_function)
     459       46710 :     mu_ad = _mu;
     460             :   else
     461             :   {
     462             :     ADReal tangential_vel_magnitude =
     463        2448 :         sqrt(function_tangential_vel * function_tangential_vel +
     464        1224 :              function_tangential_vel_dir * function_tangential_vel_dir + 1.0e-24);
     465             : 
     466        1224 :     mu_ad = _function_friction->value<ADReal>(0.0, contact_pressure, tangential_vel_magnitude, 0.0);
     467             :   }
     468             : 
     469             :   return Moose::Contact::regularizedFrictionCoefficient(
     470       47934 :       mu_ad, slip_increment, _friction_coefficient_regularization, _friction_reference_slip);
     471             : }

Generated by: LCOV version 1.14