LCOV - code coverage report
Current view: top level - src/constraints - MechanicalContactConstraint.C (source / functions) Hit Total Coverage
Test: idaholab/moose contact: 8601ad Lines: 783 932 84.0 %
Date: 2025-07-18 13:27:36 Functions: 22 22 100.0 %
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             : // MOOSE includes
      11             : #include "MechanicalContactConstraint.h"
      12             : #include "FEProblem.h"
      13             : #include "DisplacedProblem.h"
      14             : #include "AuxiliarySystem.h"
      15             : #include "PenetrationLocator.h"
      16             : #include "NearestNodeLocator.h"
      17             : #include "SystemBase.h"
      18             : #include "Assembly.h"
      19             : #include "MooseMesh.h"
      20             : #include "MathUtils.h"
      21             : #include "AugmentedLagrangianContactProblem.h"
      22             : #include "Executioner.h"
      23             : #include "AddVariableAction.h"
      24             : #include "ContactLineSearchBase.h"
      25             : #include "ContactAction.h"
      26             : 
      27             : #include "libmesh/string_to_enum.h"
      28             : #include "libmesh/sparse_matrix.h"
      29             : 
      30             : registerMooseObject("ContactApp", MechanicalContactConstraint);
      31             : 
      32             : const unsigned int MechanicalContactConstraint::_no_iterations = 0;
      33             : 
      34             : InputParameters
      35        6433 : MechanicalContactConstraint::validParams()
      36             : {
      37        6433 :   InputParameters params = NodeFaceConstraint::validParams();
      38        6433 :   params += ContactAction::commonParameters();
      39             : 
      40       12866 :   params.addRequiredParam<BoundaryName>("boundary", "The primary boundary");
      41       12866 :   params.addParam<BoundaryName>("secondary", "The secondary boundary");
      42       12866 :   params.addRequiredParam<unsigned int>("component",
      43             :                                         "An integer corresponding to the direction "
      44             :                                         "the variable this constraint acts on. (0 for x, "
      45             :                                         "1 for y, 2 for z)");
      46             : 
      47       12866 :   params.addCoupledVar(
      48             :       "displacements",
      49             :       "The displacements appropriate for the simulation geometry and coordinate system");
      50             : 
      51       12866 :   params.addCoupledVar("secondary_gap_offset", "offset to the gap distance from secondary side");
      52       12866 :   params.addCoupledVar("mapped_primary_gap_offset",
      53             :                        "offset to the gap distance mapped from primary side");
      54       12866 :   params.addRequiredCoupledVar("nodal_area", "The nodal area");
      55             : 
      56        6433 :   params.set<bool>("use_displaced_mesh") = true;
      57       12866 :   params.addParam<Real>(
      58             :       "penalty",
      59       12866 :       1e8,
      60             :       "The penalty to apply.  This can vary depending on the stiffness of your materials");
      61       12866 :   params.addParam<Real>("penalty_multiplier",
      62       12866 :                         1.0,
      63             :                         "The growth factor for the penalty applied at the end of each augmented "
      64             :                         "Lagrange update iteration");
      65       12866 :   params.addParam<Real>("friction_coefficient", 0, "The friction coefficient");
      66       12866 :   params.addParam<Real>("tangential_tolerance",
      67             :                         "Tangential distance to extend edges of contact surfaces");
      68       12866 :   params.addParam<Real>(
      69       12866 :       "capture_tolerance", 0, "Normal distance from surface within which nodes are captured");
      70             : 
      71       12866 :   params.addParam<Real>("tension_release",
      72       12866 :                         0.0,
      73             :                         "Tension release threshold.  A node in contact "
      74             :                         "will not be released if its tensile load is below "
      75             :                         "this value.  No tension release if negative.");
      76             : 
      77       12866 :   params.addParam<bool>(
      78             :       "normalize_penalty",
      79       12866 :       false,
      80             :       "Whether to normalize the penalty parameter with the nodal area for penalty contact.");
      81       12866 :   params.addParam<bool>(
      82             :       "primary_secondary_jacobian",
      83       12866 :       true,
      84             :       "Whether to include jacobian entries coupling primary and secondary nodes.");
      85       12866 :   params.addParam<bool>(
      86             :       "connected_secondary_nodes_jacobian",
      87       12866 :       true,
      88             :       "Whether to include jacobian entries coupling nodes connected to secondary nodes.");
      89       12866 :   params.addParam<bool>("non_displacement_variables_jacobian",
      90       12866 :                         true,
      91             :                         "Whether to include jacobian entries coupling with variables that are not "
      92             :                         "displacement variables.");
      93       12866 :   params.addParam<unsigned int>("stick_lock_iterations",
      94       12866 :                                 std::numeric_limits<unsigned int>::max(),
      95             :                                 "Number of times permitted to switch between sticking and slipping "
      96             :                                 "in a solution before locking node in a sticked state.");
      97       12866 :   params.addParam<Real>("stick_unlock_factor",
      98       12866 :                         1.5,
      99             :                         "Factor by which frictional capacity must be "
     100             :                         "exceeded to permit stick-locked node to slip "
     101             :                         "again.");
     102       12866 :   params.addParam<Real>("al_penetration_tolerance",
     103             :                         "The tolerance of the penetration for augmented Lagrangian method.");
     104       12866 :   params.addParam<Real>("al_incremental_slip_tolerance",
     105             :                         "The tolerance of the incremental slip for augmented Lagrangian method.");
     106             : 
     107       12866 :   params.addParam<Real>("al_frictional_force_tolerance",
     108             :                         "The tolerance of the frictional force for augmented Lagrangian method.");
     109       12866 :   params.addParam<bool>(
     110       12866 :       "print_contact_nodes", false, "Whether to print the number of nodes in contact.");
     111             : 
     112        6433 :   params.addClassDescription(
     113             :       "Apply non-penetration constraints on the mechanical deformation "
     114             :       "using a node on face, primary/secondary algorithm, and multiple options "
     115             :       "for the physical behavior on the interface and the mathematical "
     116             :       "formulation for constraint enforcement");
     117             : 
     118        6433 :   return params;
     119           0 : }
     120             : 
     121             : Threads::spin_mutex MechanicalContactConstraint::_contact_set_mutex;
     122             : 
     123        4562 : MechanicalContactConstraint::MechanicalContactConstraint(const InputParameters & parameters)
     124             :   : NodeFaceConstraint(parameters),
     125        4562 :     _displaced_problem(parameters.get<FEProblemBase *>("_fe_problem_base")->getDisplacedProblem()),
     126        9124 :     _component(getParam<unsigned int>("component")),
     127        9124 :     _model(getParam<MooseEnum>("model").getEnum<ContactModel>()),
     128        9124 :     _formulation(getParam<MooseEnum>("formulation").getEnum<ContactFormulation>()),
     129        9124 :     _normalize_penalty(getParam<bool>("normalize_penalty")),
     130        9124 :     _penalty(getParam<Real>("penalty")),
     131        9124 :     _penalty_multiplier(getParam<Real>("penalty_multiplier")),
     132        9124 :     _friction_coefficient(getParam<Real>("friction_coefficient")),
     133        9124 :     _tension_release(getParam<Real>("tension_release")),
     134        9124 :     _capture_tolerance(getParam<Real>("capture_tolerance")),
     135        9124 :     _stick_lock_iterations(getParam<unsigned int>("stick_lock_iterations")),
     136        9124 :     _stick_unlock_factor(getParam<Real>("stick_unlock_factor")),
     137        4562 :     _update_stateful_data(true),
     138        4562 :     _residual_copy(_sys.residualGhosted()),
     139        4562 :     _mesh_dimension(_mesh.dimension()),
     140        4562 :     _vars(3, libMesh::invalid_uint),
     141        4562 :     _var_objects(3, nullptr),
     142        4562 :     _has_secondary_gap_offset(isCoupled("secondary_gap_offset")),
     143        4562 :     _secondary_gap_offset_var(_has_secondary_gap_offset ? getVar("secondary_gap_offset", 0)
     144             :                                                         : nullptr),
     145        4562 :     _has_mapped_primary_gap_offset(isCoupled("mapped_primary_gap_offset")),
     146        4562 :     _mapped_primary_gap_offset_var(
     147        4562 :         _has_mapped_primary_gap_offset ? getVar("mapped_primary_gap_offset", 0) : nullptr),
     148        4562 :     _nodal_area_var(getVar("nodal_area", 0)),
     149        4562 :     _aux_system(_nodal_area_var->sys()),
     150        4562 :     _aux_solution(_aux_system.currentSolution()),
     151        9124 :     _primary_secondary_jacobian(getParam<bool>("primary_secondary_jacobian")),
     152        9124 :     _connected_secondary_nodes_jacobian(getParam<bool>("connected_secondary_nodes_jacobian")),
     153        9124 :     _non_displacement_vars_jacobian(getParam<bool>("non_displacement_variables_jacobian")),
     154        4562 :     _contact_linesearch(dynamic_cast<ContactLineSearchBase *>(_subproblem.getLineSearch())),
     155        9124 :     _print_contact_nodes(getParam<bool>("print_contact_nodes")),
     156        4562 :     _augmented_lagrange_problem(
     157        4562 :         dynamic_cast<AugmentedLagrangianContactProblemInterface *>(&_fe_problem)),
     158        4562 :     _lagrangian_iteration_number(_augmented_lagrange_problem
     159        4562 :                                      ? _augmented_lagrange_problem->getLagrangianIterationNumber()
     160        9124 :                                      : _no_iterations)
     161             : {
     162        4562 :   _overwrite_secondary_residual = false;
     163             : 
     164        9124 :   if (isParamValid("displacements"))
     165             :   {
     166             :     // modern parameter scheme for displacements
     167       30008 :     for (unsigned int i = 0; i < coupledComponents("displacements"); ++i)
     168             :     {
     169       10442 :       _vars[i] = coupled("displacements", i);
     170       10442 :       _var_objects[i] = getVar("displacements", i);
     171             :     }
     172             :   }
     173             : 
     174        9124 :   if (parameters.isParamValid("tangential_tolerance"))
     175        9189 :     _penetration_locator.setTangentialTolerance(getParam<Real>("tangential_tolerance"));
     176             : 
     177        9124 :   if (parameters.isParamValid("normal_smoothing_distance"))
     178        1350 :     _penetration_locator.setNormalSmoothingDistance(getParam<Real>("normal_smoothing_distance"));
     179             : 
     180        9124 :   if (parameters.isParamValid("normal_smoothing_method"))
     181           0 :     _penetration_locator.setNormalSmoothingMethod(
     182             :         parameters.get<std::string>("normal_smoothing_method"));
     183             : 
     184        4562 :   if (_formulation == ContactFormulation::TANGENTIAL_PENALTY && _model != ContactModel::COULOMB)
     185           0 :     mooseError("The 'tangential_penalty' formulation can only be used with the 'coulomb' model");
     186             : 
     187        4562 :   if (_model == ContactModel::GLUED)
     188         567 :     _penetration_locator.setUpdate(false);
     189             : 
     190        4562 :   if (_friction_coefficient < 0)
     191           0 :     mooseError("The friction coefficient must be nonnegative");
     192             : 
     193             :   // set _penalty_tangential to the value of _penalty for now
     194        4562 :   _penalty_tangential = _penalty;
     195             : 
     196        4562 :   if (_formulation == ContactFormulation::AUGMENTED_LAGRANGE)
     197             :   {
     198         495 :     if (_model == ContactModel::GLUED)
     199           0 :       mooseError("The Augmented Lagrangian contact formulation does not support GLUED case.");
     200             : 
     201         495 :     if (!_augmented_lagrange_problem)
     202           0 :       mooseError("The Augmented Lagrangian contact formulation must use "
     203             :                  "AugmentedLagrangianContactProblem.");
     204             : 
     205         990 :     if (!parameters.isParamValid("al_penetration_tolerance"))
     206           0 :       mooseError("For Augmented Lagrangian contact, al_penetration_tolerance must be provided.");
     207             :     else
     208         495 :       _al_penetration_tolerance = parameters.get<Real>("al_penetration_tolerance");
     209             : 
     210         495 :     if (_model != ContactModel::FRICTIONLESS)
     211             :     {
     212         630 :       if (!parameters.isParamValid("al_incremental_slip_tolerance") ||
     213         630 :           !parameters.isParamValid("al_frictional_force_tolerance"))
     214             :       {
     215           0 :         mooseError("For the Augmented Lagrangian frictional contact formualton, "
     216             :                    "al_incremental_slip_tolerance and "
     217             :                    "al_frictional_force_tolerance must be provided.");
     218             :       }
     219             :       else
     220             :       {
     221         210 :         _al_incremental_slip_tolerance = parameters.get<Real>("al_incremental_slip_tolerance");
     222         210 :         _al_frictional_force_tolerance = parameters.get<Real>("al_frictional_force_tolerance");
     223             :       }
     224             :     }
     225             :   }
     226        4562 : }
     227             : 
     228             : void
     229       18040 : MechanicalContactConstraint::timestepSetup()
     230             : {
     231       18040 :   if (_component == 0)
     232             :   {
     233        8661 :     updateContactStatefulData(/* beginning_of_step = */ true);
     234        8661 :     if (_formulation == ContactFormulation::AUGMENTED_LAGRANGE)
     235         153 :       updateAugmentedLagrangianMultiplier(/* beginning_of_step = */ true);
     236             : 
     237        8661 :     _update_stateful_data = false;
     238             : 
     239        8661 :     if (_contact_linesearch)
     240          14 :       _contact_linesearch->reset();
     241             :   }
     242       18040 : }
     243             : 
     244             : void
     245       52667 : MechanicalContactConstraint::jacobianSetup()
     246             : {
     247       52667 :   if (_component == 0)
     248             :   {
     249       25538 :     if (_update_stateful_data)
     250       17483 :       updateContactStatefulData(/* beginning_of_step = */ false);
     251       25538 :     _update_stateful_data = true;
     252             :   }
     253       52667 : }
     254             : 
     255             : void
     256         309 : MechanicalContactConstraint::updateAugmentedLagrangianMultiplier(bool beginning_of_step)
     257             : {
     258        2380 :   for (auto & [secondary_node_num, pinfo] : _penetration_locator._penetration_info)
     259             :   {
     260        2071 :     if (!pinfo)
     261           0 :       continue;
     262             : 
     263        2071 :     const Node & node = _mesh.nodeRef(secondary_node_num);
     264        2071 :     if (node.n_comp(_sys.number(), _vars[_component]) < 1)
     265           0 :       continue;
     266             : 
     267        2071 :     const Real distance = pinfo->_normal * (pinfo->_closest_point - node) - gapOffset(node);
     268             : 
     269        2071 :     if (beginning_of_step && _model == ContactModel::COULOMB)
     270             :     {
     271         350 :       pinfo->_lagrange_multiplier_slip.zero();
     272         350 :       if (pinfo->isCaptured())
     273           0 :         pinfo->_mech_status = PenetrationInfo::MS_STICKING;
     274             :     }
     275             : 
     276        2071 :     if (pinfo->isCaptured())
     277             :     {
     278        1124 :       if (_model == ContactModel::FRICTIONLESS)
     279         774 :         pinfo->_lagrange_multiplier -= getPenalty(node) * distance;
     280             : 
     281        1124 :       if (_model == ContactModel::COULOMB)
     282             :       {
     283         350 :         if (!beginning_of_step)
     284             :         {
     285         350 :           Real penalty = getPenalty(node);
     286             :           RealVectorValue pen_force_normal =
     287         350 :               penalty * (-distance) * pinfo->_normal + pinfo->_lagrange_multiplier * pinfo->_normal;
     288             : 
     289             :           // update normal lagrangian multiplier
     290         350 :           pinfo->_lagrange_multiplier += penalty * (-distance);
     291             : 
     292             :           // Frictional capacity
     293         635 :           const Real capacity(_friction_coefficient * (pen_force_normal * pinfo->_normal < 0
     294         350 :                                                            ? -pen_force_normal * pinfo->_normal
     295             :                                                            : 0));
     296             : 
     297             :           RealVectorValue tangential_inc_slip =
     298             :               pinfo->_incremental_slip -
     299             :               (pinfo->_incremental_slip * pinfo->_normal) * pinfo->_normal;
     300             : 
     301         350 :           Real penalty_slip = getTangentialPenalty(node);
     302             : 
     303             :           RealVectorValue inc_pen_force_tangential =
     304         350 :               pinfo->_lagrange_multiplier_slip + penalty_slip * tangential_inc_slip;
     305             : 
     306             :           RealVectorValue tau_old = pinfo->_contact_force_old -
     307             :                                     pinfo->_normal * (pinfo->_normal * pinfo->_contact_force_old);
     308             : 
     309             :           RealVectorValue contact_force_tangential = inc_pen_force_tangential + tau_old;
     310         350 :           const Real tan_mag(contact_force_tangential.norm());
     311             : 
     312         350 :           if (tan_mag > capacity * (_al_frictional_force_tolerance + 1.0))
     313             :           {
     314          45 :             pinfo->_lagrange_multiplier_slip =
     315             :                 -tau_old + capacity * contact_force_tangential / tan_mag;
     316          45 :             if (MooseUtils::absoluteFuzzyEqual(capacity, 0.0))
     317          45 :               pinfo->_mech_status = PenetrationInfo::MS_SLIPPING;
     318             :             else
     319           0 :               pinfo->_mech_status = PenetrationInfo::MS_SLIPPING_FRICTION;
     320             :           }
     321             :           else
     322             :           {
     323         305 :             pinfo->_mech_status = PenetrationInfo::MS_STICKING;
     324             :             pinfo->_lagrange_multiplier_slip += penalty_slip * tangential_inc_slip;
     325             :           }
     326             :         }
     327             :       }
     328             :     }
     329             :   }
     330         309 : }
     331             : 
     332             : bool
     333         510 : MechanicalContactConstraint::AugmentedLagrangianContactConverged()
     334             : {
     335             :   Real contactResidual = 0.0;
     336         510 :   unsigned int converged = 0;
     337             : 
     338        3016 :   for (auto & [secondary_node_num, pinfo] : _penetration_locator._penetration_info)
     339             :   {
     340        2662 :     if (!pinfo)
     341           0 :       continue;
     342             : 
     343        2662 :     const auto & node = _mesh.nodeRef(secondary_node_num);
     344             : 
     345             :     // Skip this pinfo if there are no DOFs on this node.
     346        2662 :     if (node.n_comp(_sys.number(), _vars[_component]) < 1)
     347           0 :       continue;
     348             : 
     349        2662 :     const Real distance = pinfo->_normal * (pinfo->_closest_point - node) - gapOffset(node);
     350             : 
     351        2662 :     if (pinfo->isCaptured())
     352             :     {
     353        2662 :       if (contactResidual < std::abs(distance))
     354             :         contactResidual = std::abs(distance);
     355             : 
     356             :       // penetration < tol
     357        2662 :       if (contactResidual > _al_penetration_tolerance)
     358             :       {
     359         156 :         converged = 1;
     360         156 :         break;
     361             :       }
     362             : 
     363        2506 :       if (_model == ContactModel::COULOMB)
     364             :       {
     365             :         RealVectorValue contact_force_normal((pinfo->_contact_force * pinfo->_normal) *
     366             :                                              pinfo->_normal);
     367             :         RealVectorValue contact_force_tangential(pinfo->_contact_force - contact_force_normal);
     368             : 
     369             :         RealVectorValue tangential_inc_slip =
     370             :             pinfo->_incremental_slip - (pinfo->_incremental_slip * pinfo->_normal) * pinfo->_normal;
     371             : 
     372         910 :         const Real tan_mag(contact_force_tangential.norm());
     373         910 :         const Real tangential_inc_slip_mag = tangential_inc_slip.norm();
     374             : 
     375             :         RealVectorValue distance_vec =
     376         910 :             (pinfo->_normal * (node - pinfo->_closest_point) + gapOffset(node)) * pinfo->_normal;
     377             : 
     378         910 :         Real penalty = getPenalty(node);
     379             :         RealVectorValue pen_force_normal =
     380         910 :             penalty * distance_vec + pinfo->_lagrange_multiplier * pinfo->_normal;
     381             : 
     382             :         // Frictional capacity
     383        1625 :         Real capacity(_friction_coefficient * (pen_force_normal * pinfo->_normal < 0
     384         910 :                                                    ? -pen_force_normal * pinfo->_normal
     385             :                                                    : 0.0));
     386             : 
     387             :         // incremental slip <= tol for all pinfo_pair such that tan_mag < capacity
     388         910 :         if (MooseUtils::absoluteFuzzyLessThan(tan_mag, capacity) &&
     389         715 :             pinfo->_mech_status == PenetrationInfo::MS_STICKING)
     390             :         {
     391         715 :           if (MooseUtils::absoluteFuzzyGreaterThan(tangential_inc_slip_mag,
     392             :                                                    _al_incremental_slip_tolerance))
     393             :           {
     394           0 :             converged = 2;
     395           0 :             break;
     396             :           }
     397             :         }
     398             : 
     399             :         // for all pinfo_pair, tag_mag should be less than (1 + tol) * (capacity + tol)
     400         910 :         if (tan_mag >
     401         910 :             (1 + _al_frictional_force_tolerance) * (capacity + _al_frictional_force_tolerance))
     402             :         {
     403           0 :           converged = 3;
     404           0 :           break;
     405             :         }
     406             :       }
     407             :     }
     408             :   }
     409             : 
     410         510 :   _communicator.max(converged);
     411             : 
     412         510 :   if (converged == 1)
     413         156 :     _console << "The Augmented Lagrangian contact tangential sliding enforcement is NOT satisfied "
     414         156 :              << std::endl;
     415         354 :   else if (converged == 2)
     416           0 :     _console << "The Augmented Lagrangian contact tangential sliding enforcement is NOT satisfied "
     417           0 :              << std::endl;
     418         354 :   else if (converged == 3)
     419           0 :     _console << "The Augmented Lagrangian contact frictional force enforcement is NOT satisfied "
     420           0 :              << std::endl;
     421             :   else
     422             :     return true;
     423             : 
     424             :   return false;
     425             : }
     426             : 
     427             : void
     428       26144 : MechanicalContactConstraint::updateContactStatefulData(bool beginning_of_step)
     429             : {
     430      222794 :   for (auto & [secondary_node_num, pinfo] : _penetration_locator._penetration_info)
     431             :   {
     432      196650 :     if (!pinfo)
     433        7355 :       continue;
     434             : 
     435      189295 :     const Node & node = _mesh.nodeRef(secondary_node_num);
     436      189295 :     if (node.n_comp(_sys.number(), _vars[_component]) < 1)
     437           0 :       continue;
     438             : 
     439      189295 :     if (beginning_of_step)
     440             :     {
     441       59880 :       if (_app.getExecutioner()->lastSolveConverged())
     442             :       {
     443       59880 :         pinfo->_contact_force_old = pinfo->_contact_force;
     444       59880 :         pinfo->_accumulated_slip_old = pinfo->_accumulated_slip;
     445       59880 :         pinfo->_frictional_energy_old = pinfo->_frictional_energy;
     446       59880 :         pinfo->_mech_status_old = pinfo->_mech_status;
     447             :       }
     448           0 :       else if (pinfo->_mech_status_old == PenetrationInfo::MS_NO_CONTACT &&
     449           0 :                pinfo->_mech_status != PenetrationInfo::MS_NO_CONTACT)
     450             :       {
     451             :         // The penetration info object could be based on a bad state so delete it
     452           0 :         delete pinfo;
     453           0 :         pinfo = NULL;
     454           0 :         continue;
     455             :       }
     456             : 
     457       59880 :       pinfo->_locked_this_step = 0;
     458       59880 :       pinfo->_stick_locked_this_step = 0;
     459       59880 :       pinfo->_starting_elem = pinfo->_elem;
     460       59880 :       pinfo->_starting_side_num = pinfo->_side_num;
     461       59880 :       pinfo->_starting_closest_point_ref = pinfo->_closest_point_ref;
     462             :     }
     463      189295 :     pinfo->_incremental_slip_prev_iter = pinfo->_incremental_slip;
     464             :   }
     465       26144 : }
     466             : 
     467             : bool
     468     2774272 : MechanicalContactConstraint::shouldApply()
     469             : {
     470             :   bool in_contact = false;
     471             : 
     472             :   std::map<dof_id_type, PenetrationInfo *>::iterator found =
     473     2774272 :       _penetration_locator._penetration_info.find(_current_node->id());
     474     2774272 :   if (found != _penetration_locator._penetration_info.end())
     475             :   {
     476     2774272 :     PenetrationInfo * pinfo = found->second;
     477     2774272 :     if (pinfo != NULL)
     478             :     {
     479     2774272 :       bool is_nonlinear = _subproblem.computingNonlinearResid();
     480             : 
     481             :       // This computes the contact force once per constraint, rather than once per quad point
     482             :       // and for both primary and secondary cases.
     483     2774272 :       if (_component == 0)
     484     1189014 :         computeContactForce(*_current_node, pinfo, is_nonlinear);
     485             : 
     486     2774272 :       if (pinfo->isCaptured())
     487             :       {
     488             :         in_contact = true;
     489     1805776 :         if (is_nonlinear)
     490             :         {
     491             :           Threads::spin_mutex::scoped_lock lock(_contact_set_mutex);
     492      209148 :           _current_contact_state.insert(_current_node->id());
     493             :         }
     494             :       }
     495             :     }
     496             :   }
     497             : 
     498     2774272 :   return in_contact;
     499             : }
     500             : 
     501             : void
     502     1189014 : MechanicalContactConstraint::computeContactForce(const Node & node,
     503             :                                                  PenetrationInfo * pinfo,
     504             :                                                  bool update_contact_set)
     505             : {
     506             :   // Build up residual vector
     507             :   RealVectorValue res_vec;
     508     3963286 :   for (unsigned int i = 0; i < _mesh_dimension; ++i)
     509             :   {
     510     2774272 :     dof_id_type dof_number = node.dof_number(0, _vars[i], 0);
     511     2774272 :     res_vec(i) = _residual_copy(dof_number) / _var_objects[i]->scalingFactor();
     512             :   }
     513             : 
     514             :   RealVectorValue distance_vec(node - pinfo->_closest_point);
     515     1189014 :   if (distance_vec.norm() != 0)
     516     1144710 :     distance_vec += gapOffset(node) * pinfo->_normal * distance_vec.unit() * distance_vec.unit();
     517             : 
     518             :   const Real gap_size = -1.0 * pinfo->_normal * distance_vec;
     519             : 
     520             :   // This is for preventing an increment of pinfo->_locked_this_step for nodes that are
     521             :   // captured and released in this function
     522             :   bool newly_captured = false;
     523             : 
     524             :   // Capture nodes that are newly in contact
     525     1189014 :   if (update_contact_set && !pinfo->isCaptured() &&
     526             :       MooseUtils::absoluteFuzzyGreaterEqual(gap_size, 0.0, _capture_tolerance))
     527             :   {
     528             :     newly_captured = true;
     529             :     pinfo->capture();
     530             : 
     531             :     // Increment the lock count every time the node comes back into contact from not being in
     532             :     // contact.
     533       11327 :     if (_formulation == ContactFormulation::KINEMATIC ||
     534             :         _formulation == ContactFormulation::TANGENTIAL_PENALTY)
     535        6236 :       ++pinfo->_locked_this_step;
     536             :   }
     537             : 
     538     1189014 :   if (!pinfo->isCaptured())
     539      431630 :     return;
     540             : 
     541      757384 :   const Real penalty = getPenalty(node);
     542      757384 :   const Real penalty_slip = getTangentialPenalty(node);
     543             : 
     544             :   RealVectorValue pen_force(penalty * distance_vec);
     545             : 
     546      757384 :   switch (_model)
     547             :   {
     548      526224 :     case ContactModel::FRICTIONLESS:
     549      526224 :       switch (_formulation)
     550             :       {
     551      293608 :         case ContactFormulation::KINEMATIC:
     552      293608 :           pinfo->_contact_force = -pinfo->_normal * (pinfo->_normal * res_vec);
     553      293608 :           break;
     554             : 
     555      212033 :         case ContactFormulation::PENALTY:
     556      212033 :           pinfo->_contact_force = pinfo->_normal * (pinfo->_normal * pen_force);
     557      212033 :           break;
     558             : 
     559       20583 :         case ContactFormulation::AUGMENTED_LAGRANGE:
     560       20583 :           pinfo->_contact_force =
     561             :               (pinfo->_normal *
     562             :                (pinfo->_normal * (pen_force + pinfo->_lagrange_multiplier * pinfo->_normal)));
     563       20583 :           break;
     564             : 
     565           0 :         default:
     566           0 :           mooseError("Invalid contact formulation");
     567             :           break;
     568             :       }
     569      526224 :       pinfo->_mech_status = PenetrationInfo::MS_SLIPPING;
     570      526224 :       break;
     571       88612 :     case ContactModel::COULOMB:
     572       88612 :       switch (_formulation)
     573             :       {
     574       21571 :         case ContactFormulation::KINEMATIC:
     575             :         {
     576             :           // Frictional capacity
     577       40667 :           const Real capacity(_friction_coefficient *
     578       21571 :                               (res_vec * pinfo->_normal > 0 ? res_vec * pinfo->_normal : 0));
     579             : 
     580             :           // Normal and tangential components of predictor force
     581       21571 :           pinfo->_contact_force = -res_vec;
     582             :           RealVectorValue contact_force_normal((pinfo->_contact_force * pinfo->_normal) *
     583             :                                                pinfo->_normal);
     584             :           RealVectorValue contact_force_tangential(pinfo->_contact_force - contact_force_normal);
     585             : 
     586             :           RealVectorValue tangential_inc_slip =
     587             :               pinfo->_incremental_slip -
     588             :               (pinfo->_incremental_slip * pinfo->_normal) * pinfo->_normal;
     589             : 
     590             :           // Magnitude of tangential predictor force
     591       21571 :           const Real tan_mag(contact_force_tangential.norm());
     592       21571 :           const Real tangential_inc_slip_mag = tangential_inc_slip.norm();
     593       21571 :           const Real slip_tol = capacity / penalty;
     594       21571 :           pinfo->_slip_tol = slip_tol;
     595             : 
     596       21571 :           if ((tangential_inc_slip_mag > slip_tol || tan_mag > capacity) &&
     597       20036 :               (pinfo->_stick_locked_this_step < _stick_lock_iterations ||
     598           0 :                tan_mag > capacity * _stick_unlock_factor))
     599             :           {
     600       20036 :             if (pinfo->_stick_locked_this_step >= _stick_lock_iterations)
     601           0 :               pinfo->_stick_locked_this_step = 0;
     602             : 
     603             :             // Check for scenario where node has slipped too far in a previous iteration
     604             :             // for special treatment (only done if the incremental slip is non-trivial)
     605             :             bool slipped_too_far = false;
     606             :             RealVectorValue slip_inc_direction;
     607       20036 :             if (tangential_inc_slip_mag > slip_tol)
     608             :             {
     609             :               slip_inc_direction = tangential_inc_slip / tangential_inc_slip_mag;
     610             :               Real slip_dot_tang_force = slip_inc_direction * contact_force_tangential;
     611       19370 :               if (slip_dot_tang_force < capacity)
     612             :                 slipped_too_far = true;
     613             :             }
     614             : 
     615             :             if (slipped_too_far) // slip back along slip increment
     616       11165 :               pinfo->_contact_force = contact_force_normal + capacity * slip_inc_direction;
     617             :             else
     618             :             {
     619        8871 :               if (tan_mag > 0) // slip along tangential force direction
     620        8848 :                 pinfo->_contact_force =
     621             :                     contact_force_normal + capacity * contact_force_tangential / tan_mag;
     622             :               else // treat as frictionless
     623          23 :                 pinfo->_contact_force = contact_force_normal;
     624             :             }
     625       20036 :             if (capacity == 0)
     626        2471 :               pinfo->_mech_status = PenetrationInfo::MS_SLIPPING;
     627             :             else
     628       17565 :               pinfo->_mech_status = PenetrationInfo::MS_SLIPPING_FRICTION;
     629             :           }
     630             :           else
     631             :           {
     632        1535 :             if (pinfo->_mech_status != PenetrationInfo::MS_STICKING &&
     633             :                 pinfo->_mech_status != PenetrationInfo::MS_NO_CONTACT)
     634         387 :               ++pinfo->_stick_locked_this_step;
     635        1535 :             pinfo->_mech_status = PenetrationInfo::MS_STICKING;
     636             :           }
     637             :           break;
     638             :         }
     639             : 
     640       13670 :         case ContactFormulation::PENALTY:
     641             :         {
     642       13670 :           distance_vec =
     643             :               pinfo->_incremental_slip +
     644       13670 :               (pinfo->_normal * (node - pinfo->_closest_point) + gapOffset(node)) * pinfo->_normal;
     645             :           pen_force = penalty * distance_vec;
     646             : 
     647             :           // Frictional capacity
     648       23311 :           const Real capacity(_friction_coefficient *
     649       13670 :                               (pen_force * pinfo->_normal < 0 ? -pen_force * pinfo->_normal : 0));
     650             : 
     651             :           // Elastic predictor
     652       13670 :           pinfo->_contact_force =
     653             :               pen_force + (pinfo->_contact_force_old -
     654             :                            pinfo->_normal * (pinfo->_normal * pinfo->_contact_force_old));
     655             :           RealVectorValue contact_force_normal((pinfo->_contact_force * pinfo->_normal) *
     656             :                                                pinfo->_normal);
     657             :           RealVectorValue contact_force_tangential(pinfo->_contact_force - contact_force_normal);
     658             : 
     659             :           // Tangential magnitude of elastic predictor
     660       13670 :           const Real tan_mag(contact_force_tangential.norm());
     661             : 
     662       13670 :           if (tan_mag > capacity)
     663             :           {
     664        2384 :             pinfo->_contact_force =
     665             :                 contact_force_normal + capacity * contact_force_tangential / tan_mag;
     666        2384 :             if (MooseUtils::absoluteFuzzyEqual(capacity, 0))
     667        1784 :               pinfo->_mech_status = PenetrationInfo::MS_SLIPPING;
     668             :             else
     669         600 :               pinfo->_mech_status = PenetrationInfo::MS_SLIPPING_FRICTION;
     670             :           }
     671             :           else
     672       11286 :             pinfo->_mech_status = PenetrationInfo::MS_STICKING;
     673             :           break;
     674             :         }
     675             : 
     676       12540 :         case ContactFormulation::AUGMENTED_LAGRANGE:
     677             :         {
     678       12540 :           distance_vec =
     679       12540 :               (pinfo->_normal * (node - pinfo->_closest_point) + gapOffset(node)) * pinfo->_normal;
     680             : 
     681             :           RealVectorValue contact_force_normal =
     682             :               penalty * distance_vec + pinfo->_lagrange_multiplier * pinfo->_normal;
     683             : 
     684             :           RealVectorValue tangential_inc_slip =
     685             :               pinfo->_incremental_slip -
     686             :               (pinfo->_incremental_slip * pinfo->_normal) * pinfo->_normal;
     687             : 
     688             :           RealVectorValue contact_force_tangential =
     689             :               pinfo->_lagrange_multiplier_slip +
     690             :               (pinfo->_contact_force_old -
     691             :                pinfo->_normal * (pinfo->_normal * pinfo->_contact_force_old));
     692             : 
     693             :           RealVectorValue inc_pen_force_tangential = penalty_slip * tangential_inc_slip;
     694             : 
     695       12540 :           if (pinfo->_mech_status == PenetrationInfo::MS_STICKING)
     696        5295 :             pinfo->_contact_force =
     697             :                 contact_force_normal + contact_force_tangential + inc_pen_force_tangential;
     698             :           else
     699        7245 :             pinfo->_contact_force = contact_force_normal + contact_force_tangential;
     700             : 
     701             :           break;
     702             :         }
     703             : 
     704       40831 :         case ContactFormulation::TANGENTIAL_PENALTY:
     705             :         {
     706             :           // Frictional capacity (kinematic formulation)
     707       44339 :           const Real capacity = _friction_coefficient * std::max(res_vec * pinfo->_normal, 0.0);
     708             : 
     709             :           // Normal component of contact force (kinematic formulation)
     710             :           RealVectorValue contact_force_normal((-res_vec * pinfo->_normal) * pinfo->_normal);
     711             : 
     712             :           // Predictor tangential component of contact force (penalty formulation)
     713             :           RealVectorValue inc_pen_force_tangential = penalty * pinfo->_incremental_slip;
     714             :           RealVectorValue contact_force_tangential =
     715             :               inc_pen_force_tangential +
     716             :               (pinfo->_contact_force_old -
     717             :                pinfo->_normal * (pinfo->_normal * pinfo->_contact_force_old));
     718             : 
     719             :           // Magnitude of tangential predictor
     720       40831 :           const Real tan_mag(contact_force_tangential.norm());
     721             : 
     722       40831 :           if (tan_mag > capacity)
     723             :           {
     724       32514 :             pinfo->_contact_force =
     725             :                 contact_force_normal + capacity * contact_force_tangential / tan_mag;
     726       32514 :             if (MooseUtils::absoluteFuzzyEqual(capacity, 0))
     727        4668 :               pinfo->_mech_status = PenetrationInfo::MS_SLIPPING;
     728             :             else
     729       27846 :               pinfo->_mech_status = PenetrationInfo::MS_SLIPPING_FRICTION;
     730             :           }
     731             :           else
     732             :           {
     733        8317 :             pinfo->_contact_force = contact_force_normal + contact_force_tangential;
     734        8317 :             pinfo->_mech_status = PenetrationInfo::MS_STICKING;
     735             :           }
     736             :           break;
     737             :         }
     738             : 
     739           0 :         default:
     740           0 :           mooseError("Invalid contact formulation");
     741             :           break;
     742             :       }
     743             :       break;
     744             : 
     745      142548 :     case ContactModel::GLUED:
     746      142548 :       switch (_formulation)
     747             :       {
     748             :         case ContactFormulation::KINEMATIC:
     749      100540 :           pinfo->_contact_force = -res_vec;
     750      100540 :           break;
     751             : 
     752       42008 :         case ContactFormulation::PENALTY:
     753       42008 :           pinfo->_contact_force = pen_force;
     754       42008 :           break;
     755             : 
     756           0 :         case ContactFormulation::AUGMENTED_LAGRANGE:
     757           0 :           pinfo->_contact_force =
     758           0 :               pen_force + pinfo->_lagrange_multiplier * distance_vec / distance_vec.norm();
     759           0 :           break;
     760             : 
     761           0 :         default:
     762           0 :           mooseError("Invalid contact formulation");
     763             :           break;
     764             :       }
     765      142548 :       pinfo->_mech_status = PenetrationInfo::MS_STICKING;
     766      142548 :       break;
     767             : 
     768           0 :     default:
     769           0 :       mooseError("Invalid or unavailable contact model");
     770             :       break;
     771             :   }
     772             : 
     773             :   // Release
     774       90842 :   if (update_contact_set && _model != ContactModel::GLUED && pinfo->isCaptured() &&
     775      824617 :       !newly_captured && _tension_release >= 0.0 &&
     776       64681 :       (_contact_linesearch ? true : pinfo->_locked_this_step < 2))
     777             :   {
     778       64625 :     const Real contact_pressure = -(pinfo->_normal * pinfo->_contact_force) / nodalArea(node);
     779       64625 :     if (-contact_pressure >= _tension_release)
     780             :     {
     781             :       pinfo->release();
     782             :       pinfo->_contact_force.zero();
     783             :     }
     784             :   }
     785             : }
     786             : 
     787             : Real
     788       29023 : MechanicalContactConstraint::computeQpSecondaryValue()
     789             : {
     790       29023 :   return _u_secondary[_qp];
     791             : }
     792             : 
     793             : Real
     794    16771335 : MechanicalContactConstraint::computeQpResidual(Moose::ConstraintType type)
     795             : {
     796    16771335 :   PenetrationInfo * pinfo = _penetration_locator._penetration_info[_current_node->id()];
     797    16771335 :   Real resid = pinfo->_contact_force(_component);
     798    16771335 :   switch (type)
     799             :   {
     800     1621090 :     case Moose::Secondary:
     801     1621090 :       if (_formulation == ContactFormulation::KINEMATIC)
     802             :       {
     803      937072 :         RealVectorValue distance_vec(*_current_node - pinfo->_closest_point);
     804      937072 :         if (distance_vec.norm() != 0)
     805      891622 :           distance_vec += gapOffset(*_current_node) * pinfo->_normal * distance_vec.unit() *
     806     1783244 :                           distance_vec.unit();
     807             : 
     808      937072 :         const Real penalty = getPenalty(*_current_node);
     809             :         RealVectorValue pen_force(penalty * distance_vec);
     810             : 
     811      937072 :         if (_model == ContactModel::FRICTIONLESS)
     812      653331 :           resid += pinfo->_normal(_component) * pinfo->_normal * pen_force;
     813      283741 :         else if (_model == ContactModel::COULOMB)
     814             :         {
     815             :           distance_vec = distance_vec - pinfo->_incremental_slip;
     816       35916 :           pen_force = penalty * distance_vec;
     817       35916 :           if (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
     818             :               pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION)
     819       32946 :             resid += pinfo->_normal(_component) * pinfo->_normal * pen_force;
     820             :           else
     821        2970 :             resid += pen_force(_component);
     822             :         }
     823      247825 :         else if (_model == ContactModel::GLUED)
     824      247825 :           resid += pen_force(_component);
     825             :       }
     826      684018 :       else if (_formulation == ContactFormulation::TANGENTIAL_PENALTY &&
     827       69832 :                _model == ContactModel::COULOMB)
     828             :       {
     829       69832 :         RealVectorValue distance_vec = (pinfo->_normal * (*_current_node - pinfo->_closest_point) +
     830       69832 :                                         gapOffset(*_current_node)) *
     831             :                                        pinfo->_normal;
     832             : 
     833       69832 :         const Real penalty = getPenalty(*_current_node);
     834             :         RealVectorValue pen_force(penalty * distance_vec);
     835       69832 :         resid += pinfo->_normal(_component) * pinfo->_normal * pen_force;
     836             :       }
     837     1621090 :       return _test_secondary[_i][_qp] * resid;
     838             : 
     839    15150245 :     case Moose::Primary:
     840    15150245 :       return _test_primary[_i][_qp] * -resid;
     841             :   }
     842             : 
     843             :   return 0.0;
     844             : }
     845             : 
     846             : Real
     847    58164767 : MechanicalContactConstraint::computeQpJacobian(Moose::ConstraintJacobianType type)
     848             : {
     849    58164767 :   PenetrationInfo * pinfo = _penetration_locator._penetration_info[_current_node->id()];
     850             : 
     851    58164767 :   const Real penalty = getPenalty(*_current_node);
     852    58164767 :   const Real penalty_slip = getTangentialPenalty(*_current_node);
     853             : 
     854    58164767 :   switch (type)
     855             :   {
     856           0 :     default:
     857           0 :       mooseError("Unhandled ConstraintJacobianType");
     858             : 
     859     2059607 :     case Moose::SecondarySecondary:
     860     2059607 :       switch (_model)
     861             :       {
     862     1630243 :         case ContactModel::FRICTIONLESS:
     863     1630243 :           switch (_formulation)
     864             :           {
     865             :             case ContactFormulation::KINEMATIC:
     866             :             {
     867             :               RealVectorValue jac_vec;
     868     4336464 :               for (unsigned int i = 0; i < _mesh_dimension; ++i)
     869             :               {
     870     3213371 :                 dof_id_type dof_number = _current_node->dof_number(0, _vars[i], 0);
     871     3213371 :                 jac_vec(i) = (*_jacobian)(dof_number, _connected_dof_indices[_j]) /
     872     3213371 :                              _var_objects[i]->scalingFactor();
     873             :               }
     874     1123093 :               return -pinfo->_normal(_component) * (pinfo->_normal * jac_vec) +
     875     1123093 :                      (_phi_secondary[_j][_qp] * penalty * _test_secondary[_i][_qp]) *
     876     1123093 :                          pinfo->_normal(_component) * pinfo->_normal(_component);
     877             :             }
     878             : 
     879      507150 :             case ContactFormulation::PENALTY:
     880             :             case ContactFormulation::AUGMENTED_LAGRANGE:
     881      507150 :               return _phi_secondary[_j][_qp] * penalty * _test_secondary[_i][_qp] *
     882      507150 :                      pinfo->_normal(_component) * pinfo->_normal(_component);
     883             : 
     884           0 :             default:
     885           0 :               mooseError("Invalid contact formulation");
     886             :           }
     887             : 
     888      214170 :         case ContactModel::COULOMB:
     889      214170 :           switch (_formulation)
     890             :           {
     891       34692 :             case ContactFormulation::KINEMATIC:
     892             :             {
     893       34692 :               if (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
     894             :                   pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION)
     895             :               {
     896             :                 RealVectorValue jac_vec;
     897      102444 :                 for (unsigned int i = 0; i < _mesh_dimension; ++i)
     898             :                 {
     899       68296 :                   dof_id_type dof_number = _current_node->dof_number(0, _vars[i], 0);
     900       68296 :                   jac_vec(i) = (*_jacobian)(dof_number, _connected_dof_indices[_j]) /
     901       68296 :                                _var_objects[i]->scalingFactor();
     902             :                 }
     903       34148 :                 return -pinfo->_normal(_component) * (pinfo->_normal * jac_vec) +
     904       34148 :                        (_phi_secondary[_j][_qp] * penalty * _test_secondary[_i][_qp]) *
     905       34148 :                            pinfo->_normal(_component) * pinfo->_normal(_component);
     906             :               }
     907             :               else
     908             :               {
     909             :                 const Real curr_jac =
     910         544 :                     (*_jacobian)(_current_node->dof_number(0, _vars[_component], 0),
     911         544 :                                  _connected_dof_indices[_j]) /
     912         544 :                     _var.scalingFactor();
     913         544 :                 return (-curr_jac + _phi_secondary[_j][_qp] * penalty * _test_secondary[_i][_qp]);
     914             :               }
     915             :             }
     916             : 
     917       50553 :             case ContactFormulation::PENALTY:
     918             :             {
     919       50553 :               if (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
     920             :                   pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION)
     921       10342 :                 return _phi_secondary[_j][_qp] * penalty * _test_secondary[_i][_qp] *
     922       10342 :                        pinfo->_normal(_component) * pinfo->_normal(_component);
     923             :               else
     924       40211 :                 return _phi_secondary[_j][_qp] * penalty * _test_secondary[_i][_qp];
     925             :             }
     926       75489 :             case ContactFormulation::AUGMENTED_LAGRANGE:
     927             :             {
     928       75489 :               Real normal_comp = _phi_secondary[_j][_qp] * penalty * _test_secondary[_i][_qp] *
     929       75489 :                                  pinfo->_normal(_component) * pinfo->_normal(_component);
     930             : 
     931             :               Real tang_comp = 0.0;
     932       75489 :               if (pinfo->_mech_status == PenetrationInfo::MS_STICKING)
     933       28230 :                 tang_comp = _phi_secondary[_j][_qp] * penalty_slip * _test_secondary[_i][_qp] *
     934       28230 :                             (1.0 - pinfo->_normal(_component) * pinfo->_normal(_component));
     935       75489 :               return normal_comp + tang_comp;
     936             :             }
     937             : 
     938             :             case ContactFormulation::TANGENTIAL_PENALTY:
     939             :             {
     940             :               RealVectorValue jac_vec;
     941      160308 :               for (unsigned int i = 0; i < _mesh_dimension; ++i)
     942             :               {
     943      106872 :                 dof_id_type dof_number = _current_node->dof_number(0, _vars[i], 0);
     944      106872 :                 jac_vec(i) = (*_jacobian)(dof_number, _connected_dof_indices[_j]) /
     945      106872 :                              _var_objects[i]->scalingFactor();
     946             :               }
     947       53436 :               Real normal_comp = -pinfo->_normal(_component) * (pinfo->_normal * jac_vec) +
     948       53436 :                                  (_phi_secondary[_j][_qp] * penalty * _test_secondary[_i][_qp]) *
     949       53436 :                                      pinfo->_normal(_component) * pinfo->_normal(_component);
     950             : 
     951             :               Real tang_comp = 0.0;
     952       53436 :               if (pinfo->_mech_status == PenetrationInfo::MS_STICKING)
     953         512 :                 tang_comp = _phi_secondary[_j][_qp] * penalty * _test_secondary[_i][_qp] *
     954         512 :                             (1.0 - pinfo->_normal(_component) * pinfo->_normal(_component));
     955             : 
     956       53436 :               return normal_comp + tang_comp;
     957             :             }
     958             : 
     959           0 :             default:
     960           0 :               mooseError("Invalid contact formulation");
     961             :           }
     962             : 
     963      215194 :         case ContactModel::GLUED:
     964      215194 :           switch (_formulation)
     965             :           {
     966      141305 :             case ContactFormulation::KINEMATIC:
     967             :             {
     968      141305 :               const Real curr_jac = (*_jacobian)(_current_node->dof_number(0, _vars[_component], 0),
     969      141305 :                                                  _connected_dof_indices[_j]) /
     970      141305 :                                     _var.scalingFactor();
     971      141305 :               return (-curr_jac + _phi_secondary[_j][_qp] * penalty * _test_secondary[_i][_qp]);
     972             :             }
     973             : 
     974       73889 :             case ContactFormulation::PENALTY:
     975             :             case ContactFormulation::AUGMENTED_LAGRANGE:
     976       73889 :               return _phi_secondary[_j][_qp] * penalty * _test_secondary[_i][_qp];
     977             : 
     978           0 :             default:
     979           0 :               mooseError("Invalid contact formulation");
     980             :           }
     981           0 :         default:
     982           0 :           mooseError("Invalid or unavailable contact model");
     983             :       }
     984             : 
     985     1465948 :     case Moose::SecondaryPrimary:
     986     1465948 :       switch (_model)
     987             :       {
     988     1138156 :         case ContactModel::FRICTIONLESS:
     989     1138156 :           switch (_formulation)
     990             :           {
     991      770828 :             case ContactFormulation::KINEMATIC:
     992             :             {
     993      770828 :               const Node * curr_primary_node = _current_primary->node_ptr(_j);
     994             : 
     995             :               RealVectorValue jac_vec;
     996     2962632 :               for (unsigned int i = 0; i < _mesh_dimension; ++i)
     997             :               {
     998     2191804 :                 dof_id_type dof_number = _current_node->dof_number(0, _vars[i], 0);
     999     4383608 :                 jac_vec(i) = (*_jacobian)(dof_number,
    1000     2191804 :                                           curr_primary_node->dof_number(0, _vars[_component], 0)) /
    1001     2191804 :                              _var_objects[i]->scalingFactor();
    1002             :               }
    1003      770828 :               return -pinfo->_normal(_component) * (pinfo->_normal * jac_vec) -
    1004      770828 :                      (_phi_primary[_j][_qp] * penalty * _test_secondary[_i][_qp]) *
    1005      770828 :                          pinfo->_normal(_component) * pinfo->_normal(_component);
    1006             :             }
    1007             : 
    1008      367328 :             case ContactFormulation::PENALTY:
    1009             :             case ContactFormulation::AUGMENTED_LAGRANGE:
    1010      367328 :               return -_phi_primary[_j][_qp] * penalty * _test_secondary[_i][_qp] *
    1011      367328 :                      pinfo->_normal(_component) * pinfo->_normal(_component);
    1012             : 
    1013           0 :             default:
    1014           0 :               mooseError("Invalid contact formulation");
    1015             :           }
    1016             : 
    1017      171240 :         case ContactModel::COULOMB:
    1018      171240 :           switch (_formulation)
    1019             :           {
    1020       26312 :             case ContactFormulation::KINEMATIC:
    1021             :             {
    1022       26312 :               if (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
    1023             :                   pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION)
    1024             :               {
    1025       25928 :                 const Node * curr_primary_node = _current_primary->node_ptr(_j);
    1026             : 
    1027             :                 RealVectorValue jac_vec;
    1028       77784 :                 for (unsigned int i = 0; i < _mesh_dimension; ++i)
    1029             :                 {
    1030       51856 :                   dof_id_type dof_number = _current_node->dof_number(0, _vars[i], 0);
    1031       51856 :                   jac_vec(i) =
    1032       51856 :                       (*_jacobian)(dof_number,
    1033       51856 :                                    curr_primary_node->dof_number(0, _vars[_component], 0)) /
    1034       51856 :                       _var_objects[i]->scalingFactor();
    1035             :                 }
    1036       25928 :                 return -pinfo->_normal(_component) * (pinfo->_normal * jac_vec) -
    1037       25928 :                        (_phi_primary[_j][_qp] * penalty * _test_secondary[_i][_qp]) *
    1038       25928 :                            pinfo->_normal(_component) * pinfo->_normal(_component);
    1039             :               }
    1040             :               else
    1041             :               {
    1042         384 :                 const Node * curr_primary_node = _current_primary->node_ptr(_j);
    1043             :                 const Real curr_jac =
    1044         384 :                     (*_jacobian)(_current_node->dof_number(0, _vars[_component], 0),
    1045         384 :                                  curr_primary_node->dof_number(0, _vars[_component], 0)) /
    1046         384 :                     _var.scalingFactor();
    1047         384 :                 return (-curr_jac - _phi_primary[_j][_qp] * penalty * _test_secondary[_i][_qp]);
    1048             :               }
    1049             :             }
    1050             : 
    1051       40780 :             case ContactFormulation::PENALTY:
    1052             :             {
    1053       40780 :               if (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
    1054             :                   pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION)
    1055        7748 :                 return -_phi_primary[_j][_qp] * penalty * _test_secondary[_i][_qp] *
    1056        7748 :                        pinfo->_normal(_component) * pinfo->_normal(_component);
    1057             :               else
    1058       33032 :                 return -_phi_primary[_j][_qp] * penalty * _test_secondary[_i][_qp];
    1059             :             }
    1060       62140 :             case ContactFormulation::AUGMENTED_LAGRANGE:
    1061             :             {
    1062       62140 :               Real normal_comp = -_phi_primary[_j][_qp] * penalty * _test_secondary[_i][_qp] *
    1063       62140 :                                  pinfo->_normal(_component) * pinfo->_normal(_component);
    1064             : 
    1065             :               Real tang_comp = 0.0;
    1066       62140 :               if (pinfo->_mech_status == PenetrationInfo::MS_STICKING)
    1067       24560 :                 tang_comp = -_phi_primary[_j][_qp] * penalty_slip * _test_secondary[_i][_qp] *
    1068       24560 :                             (1.0 - pinfo->_normal(_component) * pinfo->_normal(_component));
    1069       62140 :               return normal_comp + tang_comp;
    1070             :             }
    1071             : 
    1072       42008 :             case ContactFormulation::TANGENTIAL_PENALTY:
    1073             :             {
    1074       42008 :               const Node * curr_primary_node = _current_primary->node_ptr(_j);
    1075             : 
    1076             :               RealVectorValue jac_vec;
    1077      126024 :               for (unsigned int i = 0; i < _mesh_dimension; ++i)
    1078             :               {
    1079       84016 :                 dof_id_type dof_number = _current_node->dof_number(0, _vars[i], 0);
    1080      168032 :                 jac_vec(i) = (*_jacobian)(dof_number,
    1081       84016 :                                           curr_primary_node->dof_number(0, _vars[_component], 0)) /
    1082       84016 :                              _var_objects[i]->scalingFactor();
    1083             :               }
    1084       42008 :               Real normal_comp = -pinfo->_normal(_component) * (pinfo->_normal * jac_vec) -
    1085       42008 :                                  (_phi_primary[_j][_qp] * penalty * _test_secondary[_i][_qp]) *
    1086       42008 :                                      pinfo->_normal(_component) * pinfo->_normal(_component);
    1087             : 
    1088             :               Real tang_comp = 0.0;
    1089       42008 :               if (pinfo->_mech_status == PenetrationInfo::MS_STICKING)
    1090         384 :                 tang_comp = -_phi_primary[_j][_qp] * penalty * _test_secondary[_i][_qp] *
    1091         384 :                             (1.0 - pinfo->_normal(_component) * pinfo->_normal(_component));
    1092             : 
    1093       42008 :               return normal_comp + tang_comp;
    1094             :             }
    1095             : 
    1096           0 :             default:
    1097           0 :               mooseError("Invalid contact formulation");
    1098             :           }
    1099      156552 :         case ContactModel::GLUED:
    1100      156552 :           switch (_formulation)
    1101             :           {
    1102       98028 :             case ContactFormulation::KINEMATIC:
    1103             :             {
    1104       98028 :               const Node * curr_primary_node = _current_primary->node_ptr(_j);
    1105             :               const Real curr_jac =
    1106       98028 :                   (*_jacobian)(_current_node->dof_number(0, _vars[_component], 0),
    1107       98028 :                                curr_primary_node->dof_number(0, _vars[_component], 0)) /
    1108       98028 :                   _var.scalingFactor();
    1109       98028 :               return (-curr_jac - _phi_primary[_j][_qp] * penalty * _test_secondary[_i][_qp]);
    1110             :             }
    1111             : 
    1112       58524 :             case ContactFormulation::PENALTY:
    1113             :             case ContactFormulation::AUGMENTED_LAGRANGE:
    1114       58524 :               return -_phi_primary[_j][_qp] * penalty * _test_secondary[_i][_qp];
    1115             : 
    1116           0 :             default:
    1117           0 :               mooseError("Invalid contact formulation");
    1118             :           }
    1119             : 
    1120           0 :         default:
    1121           0 :           mooseError("Invalid or unavailable contact model");
    1122             :       }
    1123             : 
    1124    32098236 :     case Moose::PrimarySecondary:
    1125    32098236 :       switch (_model)
    1126             :       {
    1127    27493772 :         case ContactModel::FRICTIONLESS:
    1128    27493772 :           switch (_formulation)
    1129             :           {
    1130             :             case ContactFormulation::KINEMATIC:
    1131             :             {
    1132             :               RealVectorValue jac_vec;
    1133    84513264 :               for (unsigned int i = 0; i < _mesh_dimension; ++i)
    1134             :               {
    1135    63180724 :                 dof_id_type dof_number = _current_node->dof_number(0, _vars[i], 0);
    1136    63180724 :                 jac_vec(i) = (*_jacobian)(dof_number, _connected_dof_indices[_j]) /
    1137    63180724 :                              _var_objects[i]->scalingFactor();
    1138             :               }
    1139    21332540 :               return pinfo->_normal(_component) * (pinfo->_normal * jac_vec) *
    1140    21332540 :                      _test_primary[_i][_qp];
    1141             :             }
    1142             : 
    1143     6161232 :             case ContactFormulation::PENALTY:
    1144             :             case ContactFormulation::AUGMENTED_LAGRANGE:
    1145     6161232 :               return -_test_primary[_i][_qp] * penalty * _phi_secondary[_j][_qp] *
    1146     6161232 :                      pinfo->_normal(_component) * pinfo->_normal(_component);
    1147             : 
    1148           0 :             default:
    1149           0 :               mooseError("Invalid contact formulation");
    1150             :           }
    1151     2379144 :         case ContactModel::COULOMB:
    1152     2379144 :           switch (_formulation)
    1153             :           {
    1154      138768 :             case ContactFormulation::KINEMATIC:
    1155             :             {
    1156      138768 :               if (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
    1157             :                   pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION)
    1158             :               {
    1159             :                 RealVectorValue jac_vec;
    1160      409776 :                 for (unsigned int i = 0; i < _mesh_dimension; ++i)
    1161             :                 {
    1162      273184 :                   dof_id_type dof_number = _current_node->dof_number(0, _vars[i], 0);
    1163      273184 :                   jac_vec(i) = (*_jacobian)(dof_number, _connected_dof_indices[_j]) /
    1164      273184 :                                _var_objects[i]->scalingFactor();
    1165             :                 }
    1166      136592 :                 return pinfo->_normal(_component) * (pinfo->_normal * jac_vec) *
    1167      136592 :                        _test_primary[_i][_qp];
    1168             :               }
    1169             :               else
    1170             :               {
    1171             :                 const Real secondary_jac =
    1172        2176 :                     (*_jacobian)(_current_node->dof_number(0, _vars[_component], 0),
    1173        2176 :                                  _connected_dof_indices[_j]) /
    1174        2176 :                     _var.scalingFactor();
    1175        2176 :                 return secondary_jac * _test_primary[_i][_qp];
    1176             :               }
    1177             :             }
    1178             : 
    1179      747012 :             case ContactFormulation::PENALTY:
    1180             :             {
    1181      747012 :               if (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
    1182             :                   pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION)
    1183      190008 :                 return -_test_primary[_i][_qp] * penalty * _phi_secondary[_j][_qp] *
    1184      190008 :                        pinfo->_normal(_component) * pinfo->_normal(_component);
    1185             :               else
    1186      557004 :                 return -_test_primary[_i][_qp] * penalty * _phi_secondary[_j][_qp];
    1187             :             }
    1188     1279620 :             case ContactFormulation::AUGMENTED_LAGRANGE:
    1189             :             {
    1190     1279620 :               Real normal_comp = -_phi_secondary[_j][_qp] * penalty * _test_primary[_i][_qp] *
    1191     1279620 :                                  pinfo->_normal(_component) * pinfo->_normal(_component);
    1192             : 
    1193             :               Real tang_comp = 0.0;
    1194     1279620 :               if (pinfo->_mech_status == PenetrationInfo::MS_STICKING)
    1195      435120 :                 tang_comp = -_phi_secondary[_j][_qp] * penalty_slip * _test_primary[_i][_qp] *
    1196      435120 :                             (1.0 - pinfo->_normal(_component) * pinfo->_normal(_component));
    1197     1279620 :               return normal_comp + tang_comp;
    1198             :             }
    1199             : 
    1200             :             case ContactFormulation::TANGENTIAL_PENALTY:
    1201             :             {
    1202             :               RealVectorValue jac_vec;
    1203      641232 :               for (unsigned int i = 0; i < _mesh_dimension; ++i)
    1204             :               {
    1205      427488 :                 dof_id_type dof_number = _current_node->dof_number(0, _vars[i], 0);
    1206      427488 :                 jac_vec(i) = (*_jacobian)(dof_number, _connected_dof_indices[_j]) /
    1207      427488 :                              _var_objects[i]->scalingFactor();
    1208             :               }
    1209             :               Real normal_comp =
    1210      213744 :                   pinfo->_normal(_component) * (pinfo->_normal * jac_vec) * _test_primary[_i][_qp];
    1211             : 
    1212             :               Real tang_comp = 0.0;
    1213      213744 :               if (pinfo->_mech_status == PenetrationInfo::MS_STICKING)
    1214        2048 :                 tang_comp = -_test_primary[_i][_qp] * penalty * _phi_secondary[_j][_qp] *
    1215        2048 :                             (1.0 - pinfo->_normal(_component) * pinfo->_normal(_component));
    1216             : 
    1217      213744 :               return normal_comp + tang_comp;
    1218             :             }
    1219             : 
    1220           0 :             default:
    1221           0 :               mooseError("Invalid contact formulation");
    1222             :           }
    1223             : 
    1224     2225320 :         case ContactModel::GLUED:
    1225     2225320 :           switch (_formulation)
    1226             :           {
    1227     1342940 :             case ContactFormulation::KINEMATIC:
    1228             :             {
    1229             :               const Real secondary_jac =
    1230     1342940 :                   (*_jacobian)(_current_node->dof_number(0, _vars[_component], 0),
    1231     1342940 :                                _connected_dof_indices[_j]) /
    1232     1342940 :                   _var.scalingFactor();
    1233     1342940 :               return secondary_jac * _test_primary[_i][_qp];
    1234             :             }
    1235             : 
    1236      882380 :             case ContactFormulation::PENALTY:
    1237             :             case ContactFormulation::AUGMENTED_LAGRANGE:
    1238      882380 :               return -_test_primary[_i][_qp] * penalty * _phi_secondary[_j][_qp];
    1239             : 
    1240           0 :             default:
    1241           0 :               mooseError("Invalid contact formulation");
    1242             :           }
    1243             : 
    1244           0 :         default:
    1245           0 :           mooseError("Invalid or unavailable contact model");
    1246             :       }
    1247             : 
    1248    22540976 :     case Moose::PrimaryPrimary:
    1249    22540976 :       switch (_model)
    1250             :       {
    1251    18970032 :         case ContactModel::FRICTIONLESS:
    1252    18970032 :           switch (_formulation)
    1253             :           {
    1254             :             case ContactFormulation::KINEMATIC:
    1255             :               return 0.0;
    1256             : 
    1257     4541056 :             case ContactFormulation::PENALTY:
    1258             :             case ContactFormulation::AUGMENTED_LAGRANGE:
    1259     4541056 :               return _test_primary[_i][_qp] * penalty * _phi_primary[_j][_qp] *
    1260     4541056 :                      pinfo->_normal(_component) * pinfo->_normal(_component);
    1261             : 
    1262           0 :             default:
    1263           0 :               mooseError("Invalid contact formulation");
    1264             :           }
    1265             : 
    1266     3570944 :         case ContactModel::COULOMB:
    1267             :         case ContactModel::GLUED:
    1268     3570944 :           switch (_formulation)
    1269             :           {
    1270             :             case ContactFormulation::KINEMATIC:
    1271             :               return 0.0;
    1272             : 
    1273     1306336 :             case ContactFormulation::PENALTY:
    1274             :             {
    1275     1306336 :               if (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
    1276             :                   pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION)
    1277      141712 :                 return _test_primary[_i][_qp] * penalty * _phi_primary[_j][_qp] *
    1278      141712 :                        pinfo->_normal(_component) * pinfo->_normal(_component);
    1279             :               else
    1280     1164624 :                 return _test_primary[_i][_qp] * penalty * _phi_primary[_j][_qp];
    1281             :             }
    1282             : 
    1283      168032 :             case ContactFormulation::TANGENTIAL_PENALTY:
    1284             :             {
    1285             :               Real tang_comp = 0.0;
    1286      168032 :               if (pinfo->_mech_status == PenetrationInfo::MS_STICKING)
    1287        1536 :                 tang_comp = _test_primary[_i][_qp] * penalty * _phi_primary[_j][_qp] *
    1288        1536 :                             (1.0 - pinfo->_normal(_component) * pinfo->_normal(_component));
    1289             :               return tang_comp; // normal component is zero
    1290             :             }
    1291             : 
    1292     1041200 :             case ContactFormulation::AUGMENTED_LAGRANGE:
    1293             :             {
    1294     1041200 :               Real normal_comp = _phi_primary[_j][_qp] * penalty * _test_primary[_i][_qp] *
    1295     1041200 :                                  pinfo->_normal(_component) * pinfo->_normal(_component);
    1296             : 
    1297             :               Real tang_comp = 0.0;
    1298     1041200 :               if (pinfo->_mech_status == PenetrationInfo::MS_STICKING)
    1299      376000 :                 tang_comp = _phi_primary[_j][_qp] * penalty_slip * _test_primary[_i][_qp] *
    1300      376000 :                             (1.0 - pinfo->_normal(_component) * pinfo->_normal(_component));
    1301     1041200 :               return normal_comp + tang_comp;
    1302             :             }
    1303             : 
    1304           0 :             default:
    1305           0 :               mooseError("Invalid contact formulation");
    1306             :           }
    1307             : 
    1308           0 :         default:
    1309           0 :           mooseError("Invalid or unavailable contact model");
    1310             :       }
    1311             :   }
    1312             : 
    1313             :   return 0.0;
    1314             : }
    1315             : 
    1316             : Real
    1317    11169190 : MechanicalContactConstraint::computeQpOffDiagJacobian(Moose::ConstraintJacobianType type,
    1318             :                                                       unsigned int jvar)
    1319             : {
    1320    11169190 :   PenetrationInfo * pinfo = _penetration_locator._penetration_info[_current_node->id()];
    1321             : 
    1322    11169190 :   const Real penalty = getPenalty(*_current_node);
    1323    11169190 :   const Real penalty_slip = getTangentialPenalty(*_current_node);
    1324             : 
    1325             :   unsigned int coupled_component;
    1326             :   Real normal_component_in_coupled_var_dir = 1.0;
    1327    11169190 :   if (getCoupledVarComponent(jvar, coupled_component))
    1328    11169190 :     normal_component_in_coupled_var_dir = pinfo->_normal(coupled_component);
    1329             : 
    1330    11169190 :   switch (type)
    1331             :   {
    1332           0 :     default:
    1333           0 :       mooseError("Unhandled ConstraintJacobianType");
    1334             : 
    1335      524806 :     case Moose::SecondarySecondary:
    1336      524806 :       switch (_model)
    1337             :       {
    1338      440000 :         case ContactModel::FRICTIONLESS:
    1339      440000 :           switch (_formulation)
    1340             :           {
    1341             :             case ContactFormulation::KINEMATIC:
    1342             :             {
    1343             :               RealVectorValue jac_vec;
    1344      966672 :               for (unsigned int i = 0; i < _mesh_dimension; ++i)
    1345             :               {
    1346      718784 :                 dof_id_type dof_number = _current_node->dof_number(0, _vars[i], 0);
    1347      718784 :                 jac_vec(i) = (*_jacobian)(dof_number, _connected_dof_indices[_j]) /
    1348      718784 :                              _var_objects[i]->scalingFactor();
    1349             :               }
    1350      247888 :               return -pinfo->_normal(_component) * (pinfo->_normal * jac_vec) +
    1351      247888 :                      (_phi_secondary[_j][_qp] * penalty * _test_secondary[_i][_qp]) *
    1352      247888 :                          pinfo->_normal(_component) * normal_component_in_coupled_var_dir;
    1353             :             }
    1354             : 
    1355      192112 :             case ContactFormulation::PENALTY:
    1356             :             case ContactFormulation::AUGMENTED_LAGRANGE:
    1357      192112 :               return _phi_secondary[_j][_qp] * penalty * _test_secondary[_i][_qp] *
    1358      192112 :                      pinfo->_normal(_component) * normal_component_in_coupled_var_dir;
    1359             : 
    1360           0 :             default:
    1361           0 :               mooseError("Invalid contact formulation");
    1362             :           }
    1363             : 
    1364       84806 :         case ContactModel::COULOMB:
    1365             :         {
    1366       84806 :           if ((_formulation == ContactFormulation::KINEMATIC ||
    1367       76808 :                _formulation == ContactFormulation::TANGENTIAL_PENALTY) &&
    1368       76808 :               (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
    1369             :                pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION))
    1370             :           {
    1371             :             RealVectorValue jac_vec;
    1372      228120 :             for (unsigned int i = 0; i < _mesh_dimension; ++i)
    1373             :             {
    1374      152080 :               dof_id_type dof_number = _current_node->dof_number(0, _vars[i], 0);
    1375      152080 :               jac_vec(i) = (*_jacobian)(dof_number, _connected_dof_indices[_j]) /
    1376      152080 :                            _var_objects[i]->scalingFactor();
    1377             :             }
    1378             : 
    1379       76040 :             return -pinfo->_normal(_component) * (pinfo->_normal * jac_vec) +
    1380       76040 :                    (_phi_secondary[_j][_qp] * penalty * _test_secondary[_i][_qp]) *
    1381       76040 :                        pinfo->_normal(_component) * normal_component_in_coupled_var_dir;
    1382             :           }
    1383        8766 :           else if ((_formulation == ContactFormulation::PENALTY) &&
    1384        7998 :                    (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
    1385             :                     pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION))
    1386         672 :             return _phi_secondary[_j][_qp] * penalty * _test_secondary[_i][_qp] *
    1387         672 :                    pinfo->_normal(_component) * normal_component_in_coupled_var_dir;
    1388        8094 :           else if (_formulation == ContactFormulation::AUGMENTED_LAGRANGE)
    1389             :           {
    1390           0 :             Real normal_comp = _phi_secondary[_j][_qp] * penalty * _test_secondary[_i][_qp] *
    1391           0 :                                pinfo->_normal(_component) * normal_component_in_coupled_var_dir;
    1392             : 
    1393             :             Real tang_comp = 0.0;
    1394           0 :             if (pinfo->_mech_status == PenetrationInfo::MS_STICKING)
    1395           0 :               tang_comp = _phi_secondary[_j][_qp] * penalty_slip * _test_secondary[_i][_qp] *
    1396           0 :                           (-pinfo->_normal(_component) * normal_component_in_coupled_var_dir);
    1397           0 :             return normal_comp + tang_comp;
    1398             :           }
    1399             :           else
    1400             :           {
    1401        8094 :             const Real curr_jac = (*_jacobian)(_current_node->dof_number(0, _vars[_component], 0),
    1402        8094 :                                                _connected_dof_indices[_j]);
    1403        8094 :             return -curr_jac;
    1404             :           }
    1405             :         }
    1406             : 
    1407           0 :         case ContactModel::GLUED:
    1408             :         {
    1409           0 :           const Real curr_jac = (*_jacobian)(_current_node->dof_number(0, _vars[_component], 0),
    1410           0 :                                              _connected_dof_indices[_j]);
    1411           0 :           return -curr_jac;
    1412             :         }
    1413           0 :         default:
    1414           0 :           mooseError("Invalid or unavailable contact model");
    1415             :       }
    1416             : 
    1417      388264 :     case Moose::SecondaryPrimary:
    1418      388264 :       switch (_model)
    1419             :       {
    1420      322464 :         case ContactModel::FRICTIONLESS:
    1421      322464 :           switch (_formulation)
    1422             :           {
    1423      186944 :             case ContactFormulation::KINEMATIC:
    1424             :             {
    1425      186944 :               const Node * curr_primary_node = _current_primary->node_ptr(_j);
    1426             : 
    1427             :               RealVectorValue jac_vec;
    1428      727680 :               for (unsigned int i = 0; i < _mesh_dimension; ++i)
    1429             :               {
    1430      540736 :                 dof_id_type dof_number = _current_node->dof_number(0, _vars[i], 0);
    1431     1081472 :                 jac_vec(i) = (*_jacobian)(dof_number,
    1432      540736 :                                           curr_primary_node->dof_number(0, _vars[_component], 0)) /
    1433      540736 :                              _var_objects[i]->scalingFactor();
    1434             :               }
    1435      186944 :               return -pinfo->_normal(_component) * (pinfo->_normal * jac_vec) -
    1436      186944 :                      (_phi_primary[_j][_qp] * penalty * _test_secondary[_i][_qp]) *
    1437      186944 :                          pinfo->_normal(_component) * normal_component_in_coupled_var_dir;
    1438             :             }
    1439             : 
    1440      135520 :             case ContactFormulation::PENALTY:
    1441             :             case ContactFormulation::AUGMENTED_LAGRANGE:
    1442      135520 :               return -_phi_primary[_j][_qp] * penalty * _test_secondary[_i][_qp] *
    1443      135520 :                      pinfo->_normal(_component) * normal_component_in_coupled_var_dir;
    1444             : 
    1445           0 :             default:
    1446           0 :               mooseError("Invalid contact formulation");
    1447             :           }
    1448             : 
    1449       65800 :         case ContactModel::COULOMB:
    1450       65800 :           if ((_formulation == ContactFormulation::KINEMATIC ||
    1451       60560 :                _formulation == ContactFormulation::TANGENTIAL_PENALTY) &&
    1452       60560 :               (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
    1453             :                pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION))
    1454             :           {
    1455       59984 :             const Node * curr_primary_node = _current_primary->node_ptr(_j);
    1456             : 
    1457             :             RealVectorValue jac_vec;
    1458      179952 :             for (unsigned int i = 0; i < _mesh_dimension; ++i)
    1459             :             {
    1460      119968 :               dof_id_type dof_number = _current_node->dof_number(0, _vars[i], 0);
    1461      119968 :               jac_vec(i) =
    1462      119968 :                   (*_jacobian)(dof_number, curr_primary_node->dof_number(0, _vars[_component], 0)) /
    1463      119968 :                   _var_objects[i]->scalingFactor();
    1464             :             }
    1465             : 
    1466       59984 :             return -pinfo->_normal(_component) * (pinfo->_normal * jac_vec) -
    1467       59984 :                    (_phi_primary[_j][_qp] * penalty * _test_secondary[_i][_qp]) *
    1468       59984 :                        pinfo->_normal(_component) * normal_component_in_coupled_var_dir;
    1469             :           }
    1470        5816 :           else if ((_formulation == ContactFormulation::PENALTY) &&
    1471        5240 :                    (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
    1472             :                     pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION))
    1473         448 :             return -_phi_primary[_j][_qp] * penalty * _test_secondary[_i][_qp] *
    1474         448 :                    pinfo->_normal(_component) * normal_component_in_coupled_var_dir;
    1475        5368 :           else if (_formulation == ContactFormulation::AUGMENTED_LAGRANGE)
    1476             :           {
    1477           0 :             Real normal_comp = -_phi_primary[_j][_qp] * penalty * _test_secondary[_i][_qp] *
    1478           0 :                                pinfo->_normal(_component) * normal_component_in_coupled_var_dir;
    1479             : 
    1480             :             Real tang_comp = 0.0;
    1481           0 :             if (pinfo->_mech_status == PenetrationInfo::MS_STICKING)
    1482           0 :               tang_comp = -_phi_primary[_j][_qp] * penalty_slip * _test_secondary[_i][_qp] *
    1483           0 :                           (-pinfo->_normal(_component) * normal_component_in_coupled_var_dir);
    1484           0 :             return normal_comp + tang_comp;
    1485             :           }
    1486             :           else
    1487             :             return 0.0;
    1488             : 
    1489             :         case ContactModel::GLUED:
    1490             :           return 0;
    1491             : 
    1492           0 :         default:
    1493           0 :           mooseError("Invalid or unavailable contact model");
    1494             :       }
    1495             : 
    1496     5907032 :     case Moose::PrimarySecondary:
    1497     5907032 :       switch (_model)
    1498             :       {
    1499     5567808 :         case ContactModel::FRICTIONLESS:
    1500     5567808 :           switch (_formulation)
    1501             :           {
    1502             :             case ContactFormulation::KINEMATIC:
    1503             :             {
    1504             :               RealVectorValue jac_vec;
    1505    17582976 :               for (unsigned int i = 0; i < _mesh_dimension; ++i)
    1506             :               {
    1507    13152256 :                 dof_id_type dof_number = _current_node->dof_number(0, _vars[i], 0);
    1508    13152256 :                 jac_vec(i) = (*_jacobian)(dof_number, _connected_dof_indices[_j]) /
    1509    13152256 :                              _var_objects[i]->scalingFactor();
    1510             :               }
    1511     4430720 :               return pinfo->_normal(_component) * (pinfo->_normal * jac_vec) *
    1512     4430720 :                      _test_primary[_i][_qp];
    1513             :             }
    1514             : 
    1515     1137088 :             case ContactFormulation::PENALTY:
    1516             :             case ContactFormulation::AUGMENTED_LAGRANGE:
    1517     1137088 :               return -_test_primary[_i][_qp] * penalty * _phi_secondary[_j][_qp] *
    1518     1137088 :                      pinfo->_normal(_component) * normal_component_in_coupled_var_dir;
    1519             : 
    1520           0 :             default:
    1521           0 :               mooseError("Invalid contact formulation");
    1522             :           }
    1523      339224 :         case ContactModel::COULOMB:
    1524      339224 :           switch (_formulation)
    1525             :           {
    1526      115856 :             case ContactFormulation::KINEMATIC:
    1527             :             {
    1528      115856 :               if (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
    1529             :                   pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION)
    1530             :               {
    1531             :                 RealVectorValue jac_vec;
    1532      343344 :                 for (unsigned int i = 0; i < _mesh_dimension; ++i)
    1533             :                 {
    1534      228896 :                   dof_id_type dof_number = _current_node->dof_number(0, _vars[i], 0);
    1535      228896 :                   jac_vec(i) = (*_jacobian)(dof_number, _connected_dof_indices[_j]) /
    1536      228896 :                                _var_objects[i]->scalingFactor();
    1537             :                 }
    1538      114448 :                 return pinfo->_normal(_component) * (pinfo->_normal * jac_vec) *
    1539      114448 :                        _test_primary[_i][_qp];
    1540             :               }
    1541             :               else
    1542             :               {
    1543             :                 const Real secondary_jac =
    1544        1408 :                     (*_jacobian)(_current_node->dof_number(0, _vars[_component], 0),
    1545        1408 :                                  _connected_dof_indices[_j]) /
    1546        1408 :                     _var.scalingFactor();
    1547        1408 :                 return secondary_jac * _test_primary[_i][_qp];
    1548             :               }
    1549             :             }
    1550             : 
    1551       31992 :             case ContactFormulation::PENALTY:
    1552             :             {
    1553       31992 :               if (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
    1554             :                   pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION)
    1555        2688 :                 return -_test_primary[_i][_qp] * penalty * _phi_secondary[_j][_qp] *
    1556        2688 :                        pinfo->_normal(_component) * normal_component_in_coupled_var_dir;
    1557             :               else
    1558             :                 return 0.0;
    1559             :             }
    1560           0 :             case ContactFormulation::AUGMENTED_LAGRANGE:
    1561             :             {
    1562           0 :               Real normal_comp = -_phi_secondary[_j][_qp] * penalty * _test_primary[_i][_qp] *
    1563           0 :                                  pinfo->_normal(_component) * normal_component_in_coupled_var_dir;
    1564             : 
    1565             :               Real tang_comp = 0.0;
    1566           0 :               if (pinfo->_mech_status == PenetrationInfo::MS_STICKING)
    1567           0 :                 tang_comp = -_phi_secondary[_j][_qp] * penalty_slip * _test_primary[_i][_qp] *
    1568           0 :                             (-pinfo->_normal(_component) * normal_component_in_coupled_var_dir);
    1569           0 :               return normal_comp + tang_comp;
    1570             :             }
    1571      191376 :             case ContactFormulation::TANGENTIAL_PENALTY:
    1572             :             {
    1573      191376 :               if (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
    1574             :                   pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION)
    1575             :               {
    1576             :                 RealVectorValue jac_vec;
    1577      569136 :                 for (unsigned int i = 0; i < _mesh_dimension; ++i)
    1578             :                 {
    1579      379424 :                   dof_id_type dof_number = _current_node->dof_number(0, _vars[i], 0);
    1580      379424 :                   jac_vec(i) = (*_jacobian)(dof_number, _connected_dof_indices[_j]) /
    1581      379424 :                                _var_objects[i]->scalingFactor();
    1582             :                 }
    1583      189712 :                 return pinfo->_normal(_component) * (pinfo->_normal * jac_vec) *
    1584      189712 :                        _test_primary[_i][_qp];
    1585             :               }
    1586             :               else
    1587             :                 return 0.0;
    1588             :             }
    1589             : 
    1590           0 :             default:
    1591           0 :               mooseError("Invalid contact formulation");
    1592             :           }
    1593             : 
    1594           0 :         case ContactModel::GLUED:
    1595           0 :           switch (_formulation)
    1596             :           {
    1597           0 :             case ContactFormulation::KINEMATIC:
    1598             :             {
    1599             :               const Real secondary_jac =
    1600           0 :                   (*_jacobian)(_current_node->dof_number(0, _vars[_component], 0),
    1601           0 :                                _connected_dof_indices[_j]) /
    1602           0 :                   _var.scalingFactor();
    1603           0 :               return secondary_jac * _test_primary[_i][_qp];
    1604             :             }
    1605             : 
    1606             :             case ContactFormulation::PENALTY:
    1607             :             case ContactFormulation::AUGMENTED_LAGRANGE:
    1608             :               return 0.0;
    1609             : 
    1610           0 :             default:
    1611           0 :               mooseError("Invalid contact formulation");
    1612             :           }
    1613             : 
    1614           0 :         default:
    1615           0 :           mooseError("Invalid or unavailable contact model");
    1616             :       }
    1617             : 
    1618     4349088 :     case Moose::PrimaryPrimary:
    1619     4349088 :       switch (_model)
    1620             :       {
    1621     4085888 :         case ContactModel::FRICTIONLESS:
    1622     4085888 :           switch (_formulation)
    1623             :           {
    1624             :             case ContactFormulation::KINEMATIC:
    1625             :               return 0.0;
    1626             : 
    1627      763264 :             case ContactFormulation::PENALTY:
    1628             :             case ContactFormulation::AUGMENTED_LAGRANGE:
    1629      763264 :               return _test_primary[_i][_qp] * penalty * _phi_primary[_j][_qp] *
    1630      763264 :                      pinfo->_normal(_component) * normal_component_in_coupled_var_dir;
    1631             : 
    1632           0 :             default:
    1633           0 :               mooseError("Invalid contact formulation");
    1634             :           }
    1635             : 
    1636      263200 :         case ContactModel::COULOMB:
    1637             :         {
    1638      263200 :           if (_formulation == ContactFormulation::AUGMENTED_LAGRANGE)
    1639             :           {
    1640           0 :             Real normal_comp = _phi_primary[_j][_qp] * penalty * _test_primary[_i][_qp] *
    1641           0 :                                pinfo->_normal(_component) * normal_component_in_coupled_var_dir;
    1642             : 
    1643           0 :             if (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
    1644             :                 pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION)
    1645             :               return normal_comp;
    1646             :             else
    1647           0 :               return 0.0;
    1648             :           }
    1649      263200 :           else if (_formulation == ContactFormulation::PENALTY &&
    1650       20960 :                    (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
    1651             :                     pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION))
    1652        1792 :             return _test_primary[_i][_qp] * penalty * _phi_primary[_j][_qp] *
    1653        1792 :                    pinfo->_normal(_component) * normal_component_in_coupled_var_dir;
    1654             :           else
    1655             :             return 0.0;
    1656             :         }
    1657             : 
    1658           0 :         case ContactModel::GLUED:
    1659           0 :           if (_formulation == ContactFormulation::PENALTY &&
    1660           0 :               (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
    1661             :                pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION))
    1662           0 :             return _test_primary[_i][_qp] * penalty * _phi_primary[_j][_qp] *
    1663           0 :                    pinfo->_normal(_component) * normal_component_in_coupled_var_dir;
    1664           0 :           else if (_formulation == ContactFormulation::AUGMENTED_LAGRANGE)
    1665             :           {
    1666           0 :             Real normal_comp = _phi_primary[_j][_qp] * penalty * _test_primary[_i][_qp] *
    1667           0 :                                pinfo->_normal(_component) * normal_component_in_coupled_var_dir;
    1668             : 
    1669             :             Real tang_comp = 0.0;
    1670           0 :             if (pinfo->_mech_status == PenetrationInfo::MS_STICKING)
    1671           0 :               tang_comp = _phi_primary[_j][_qp] * penalty_slip * _test_primary[_i][_qp] *
    1672           0 :                           (-pinfo->_normal(_component) * normal_component_in_coupled_var_dir);
    1673           0 :             return normal_comp + tang_comp;
    1674             :           }
    1675             :           else
    1676             :             return 0.0;
    1677             : 
    1678           0 :         default:
    1679           0 :           mooseError("Invalid or unavailable contact model");
    1680             :       }
    1681             :   }
    1682             : 
    1683             :   return 0.0;
    1684             : }
    1685             : 
    1686             : Real
    1687     2138017 : MechanicalContactConstraint::gapOffset(const Node & node)
    1688             : {
    1689             :   Real val = 0;
    1690             : 
    1691     2138017 :   if (_has_secondary_gap_offset)
    1692       83808 :     val += _secondary_gap_offset_var->getNodalValue(node);
    1693             : 
    1694     2138017 :   if (_has_mapped_primary_gap_offset)
    1695       83808 :     val += _mapped_primary_gap_offset_var->getNodalValue(node);
    1696             : 
    1697     2138017 :   return val;
    1698             : }
    1699             : 
    1700             : Real
    1701    28352946 : MechanicalContactConstraint::nodalArea(const Node & node)
    1702             : {
    1703    28352946 :   dof_id_type dof = node.dof_number(_aux_system.number(), _nodal_area_var->number(), 0);
    1704             : 
    1705    28352946 :   Real area = (*_aux_solution)(dof);
    1706    28352946 :   if (area == 0.0)
    1707             :   {
    1708           0 :     if (_t_step > 1)
    1709           0 :       mooseError("Zero nodal area found");
    1710             :     else
    1711             :       area = 1.0; // Avoid divide by zero during initialization
    1712             :   }
    1713             : 
    1714    28352946 :   return area;
    1715             : }
    1716             : 
    1717             : Real
    1718    71100279 : MechanicalContactConstraint::getPenalty(const Node & node)
    1719             : {
    1720    71100279 :   Real penalty = _penalty;
    1721    71100279 :   if (_normalize_penalty)
    1722    14176840 :     penalty *= nodalArea(node);
    1723    71100279 :   return penalty * MathUtils::pow(_penalty_multiplier, _lagrangian_iteration_number);
    1724             : }
    1725             : 
    1726             : Real
    1727    70091691 : MechanicalContactConstraint::getTangentialPenalty(const Node & node)
    1728             : {
    1729    70091691 :   Real penalty = _penalty_tangential;
    1730    70091691 :   if (_normalize_penalty)
    1731    14111481 :     penalty *= nodalArea(node);
    1732             : 
    1733    70091691 :   return penalty * MathUtils::pow(_penalty_multiplier, _lagrangian_iteration_number);
    1734             : }
    1735             : 
    1736             : void
    1737      155663 : MechanicalContactConstraint::computeJacobian()
    1738             : {
    1739      155663 :   getConnectedDofIndices(_var.number());
    1740             : 
    1741      155663 :   prepareMatrixTagNeighbor(
    1742      155663 :       _assembly, _primary_var.number(), _var.number(), Moose::NeighborNeighbor, _Knn);
    1743             : 
    1744      155663 :   _Kee.resize(_test_secondary.size(), _connected_dof_indices.size());
    1745             : 
    1746      311326 :   for (_i = 0; _i < _test_secondary.size(); _i++)
    1747             :     // Loop over the connected dof indices so we can get all the jacobian contributions
    1748     2215270 :     for (_j = 0; _j < _connected_dof_indices.size(); _j++)
    1749     2059607 :       _Kee(_i, _j) += computeQpJacobian(Moose::SecondarySecondary);
    1750             : 
    1751      155663 :   if (_primary_secondary_jacobian)
    1752             :   {
    1753      153239 :     prepareMatrixTagNeighbor(_assembly, _var.number(), _var.number(), Moose::ElementNeighbor, _Ken);
    1754      153239 :     if (_Ken.m() && _Ken.n())
    1755             :     {
    1756      306478 :       for (_i = 0; _i < _test_secondary.size(); _i++)
    1757     1619187 :         for (_j = 0; _j < _phi_primary.size(); _j++)
    1758     1465948 :           _Ken(_i, _j) += computeQpJacobian(Moose::SecondaryPrimary);
    1759      153239 :       accumulateTaggedLocalMatrix(
    1760      153239 :           _assembly, _var.number(), _var.number(), Moose::ElementNeighbor, _Ken);
    1761             :     }
    1762             : 
    1763      153239 :     _Kne.resize(_test_primary.size(), _connected_dof_indices.size());
    1764     1619187 :     for (_i = 0; _i < _test_primary.size(); _i++)
    1765             :       // Loop over the connected dof indices so we can get all the jacobian contributions
    1766    33564184 :       for (_j = 0; _j < _connected_dof_indices.size(); _j++)
    1767    32098236 :         _Kne(_i, _j) += computeQpJacobian(Moose::PrimarySecondary);
    1768             :   }
    1769             : 
    1770      155663 :   if (_Knn.m() && _Knn.n())
    1771             :   {
    1772     1641003 :     for (_i = 0; _i < _test_primary.size(); _i++)
    1773    24026316 :       for (_j = 0; _j < _phi_primary.size(); _j++)
    1774    22540976 :         _Knn(_i, _j) += computeQpJacobian(Moose::PrimaryPrimary);
    1775      155663 :     accumulateTaggedLocalMatrix(
    1776      155663 :         _assembly, _primary_var.number(), _var.number(), Moose::NeighborNeighbor, _Knn);
    1777             :   }
    1778      155663 : }
    1779             : 
    1780             : void
    1781       56634 : MechanicalContactConstraint::computeOffDiagJacobian(const unsigned int jvar_num)
    1782             : {
    1783       56634 :   getConnectedDofIndices(jvar_num);
    1784             : 
    1785       56634 :   _Kee.resize(_test_secondary.size(), _connected_dof_indices.size());
    1786             : 
    1787       56634 :   prepareMatrixTagNeighbor(
    1788       56634 :       _assembly, _primary_var.number(), jvar_num, Moose::NeighborNeighbor, _Knn);
    1789             : 
    1790      113268 :   for (_i = 0; _i < _test_secondary.size(); _i++)
    1791             :     // Loop over the connected dof indices so we can get all the jacobian contributions
    1792      581440 :     for (_j = 0; _j < _connected_dof_indices.size(); _j++)
    1793      524806 :       _Kee(_i, _j) += computeQpOffDiagJacobian(Moose::SecondarySecondary, jvar_num);
    1794             : 
    1795       56634 :   if (_primary_secondary_jacobian)
    1796             :   {
    1797       56634 :     prepareMatrixTagNeighbor(_assembly, _var.number(), jvar_num, Moose::ElementNeighbor, _Ken);
    1798      113268 :     for (_i = 0; _i < _test_secondary.size(); _i++)
    1799      444898 :       for (_j = 0; _j < _phi_primary.size(); _j++)
    1800      388264 :         _Ken(_i, _j) += computeQpOffDiagJacobian(Moose::SecondaryPrimary, jvar_num);
    1801       56634 :     accumulateTaggedLocalMatrix(_assembly, _var.number(), jvar_num, Moose::ElementNeighbor, _Ken);
    1802             : 
    1803       56634 :     _Kne.resize(_test_primary.size(), _connected_dof_indices.size());
    1804       56634 :     if (_Kne.m() && _Kne.n())
    1805      444898 :       for (_i = 0; _i < _test_primary.size(); _i++)
    1806             :         // Loop over the connected dof indices so we can get all the jacobian contributions
    1807     6295296 :         for (_j = 0; _j < _connected_dof_indices.size(); _j++)
    1808     5907032 :           _Kne(_i, _j) += computeQpOffDiagJacobian(Moose::PrimarySecondary, jvar_num);
    1809             :   }
    1810             : 
    1811      444898 :   for (_i = 0; _i < _test_primary.size(); _i++)
    1812     4737352 :     for (_j = 0; _j < _phi_primary.size(); _j++)
    1813     4349088 :       _Knn(_i, _j) += computeQpOffDiagJacobian(Moose::PrimaryPrimary, jvar_num);
    1814       56634 :   accumulateTaggedLocalMatrix(
    1815       56634 :       _assembly, _primary_var.number(), jvar_num, Moose::NeighborNeighbor, _Knn);
    1816       56634 : }
    1817             : 
    1818             : void
    1819      212297 : MechanicalContactConstraint::getConnectedDofIndices(unsigned int var_num)
    1820             : {
    1821             :   unsigned int component;
    1822      212297 :   if (getCoupledVarComponent(var_num, component) || _non_displacement_vars_jacobian)
    1823             :   {
    1824      212297 :     if (_primary_secondary_jacobian && _connected_secondary_nodes_jacobian)
    1825      209873 :       NodeFaceConstraint::getConnectedDofIndices(var_num);
    1826             :     else
    1827             :     {
    1828        2424 :       _connected_dof_indices.clear();
    1829        2424 :       MooseVariableFEBase & var = _sys.getVariable(0, var_num);
    1830        2424 :       _connected_dof_indices.push_back(var.nodalDofIndex());
    1831             :     }
    1832             :   }
    1833             : 
    1834      212297 :   _phi_secondary.resize(_connected_dof_indices.size());
    1835             : 
    1836      212297 :   dof_id_type current_node_var_dof_index = _sys.getVariable(0, var_num).nodalDofIndex();
    1837      212297 :   _qp = 0;
    1838             : 
    1839             :   // Fill up _phi_secondary so that it is 1 when j corresponds to the dof associated with this node
    1840             :   // and 0 for every other dof
    1841             :   // This corresponds to evaluating all of the connected shape functions at _this_ node
    1842     2796710 :   for (unsigned int j = 0; j < _connected_dof_indices.size(); j++)
    1843             :   {
    1844     2584413 :     _phi_secondary[j].resize(1);
    1845             : 
    1846     2584413 :     if (_connected_dof_indices[j] == current_node_var_dof_index)
    1847      212297 :       _phi_secondary[j][_qp] = 1.0;
    1848             :     else
    1849     2372116 :       _phi_secondary[j][_qp] = 0.0;
    1850             :   }
    1851      212297 : }
    1852             : 
    1853             : bool
    1854    11381487 : MechanicalContactConstraint::getCoupledVarComponent(unsigned int var_num, unsigned int & component)
    1855             : {
    1856    11381487 :   component = std::numeric_limits<unsigned int>::max();
    1857             :   bool coupled_var_is_disp_var = false;
    1858    21723906 :   for (const auto i : make_range(Moose::dim))
    1859             :   {
    1860    21723906 :     if (var_num == _vars[i])
    1861             :     {
    1862             :       coupled_var_is_disp_var = true;
    1863    11381487 :       component = i;
    1864    11381487 :       break;
    1865             :     }
    1866             :   }
    1867             : 
    1868    11381487 :   return coupled_var_is_disp_var;
    1869             : }
    1870             : 
    1871             : void
    1872       70671 : MechanicalContactConstraint::residualEnd()
    1873             : {
    1874       70671 :   if (_component == 0 && (_print_contact_nodes || _contact_linesearch))
    1875             :   {
    1876          70 :     _communicator.set_union(_current_contact_state);
    1877          70 :     if (_print_contact_nodes)
    1878             :     {
    1879           0 :       if (_current_contact_state == _old_contact_state)
    1880           0 :         _console << "Unchanged contact state. " << _current_contact_state.size()
    1881           0 :                  << " nodes in contact.\n";
    1882             :       else
    1883           0 :         _console << "Changed contact state!!! " << _current_contact_state.size()
    1884           0 :                  << " nodes in contact.\n";
    1885             :     }
    1886          70 :     if (_contact_linesearch)
    1887          70 :       _contact_linesearch->insertSet(_current_contact_state);
    1888             :     _old_contact_state.swap(_current_contact_state);
    1889             :     _current_contact_state.clear();
    1890             :   }
    1891       70671 : }

Generated by: LCOV version 1.14