LCOV - code coverage report
Current view: top level - src/constraints - MechanicalContactConstraint.C (source / functions) Hit Total Coverage
Test: idaholab/moose contact: #31405 (292dce) with base fef103 Lines: 789 932 84.7 %
Date: 2025-09-04 07:52:48 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        7072 : MechanicalContactConstraint::validParams()
      36             : {
      37        7072 :   InputParameters params = NodeFaceConstraint::validParams();
      38        7072 :   params += ContactAction::commonParameters();
      39             : 
      40       14144 :   params.addRequiredParam<BoundaryName>("boundary", "The primary boundary");
      41       14144 :   params.addParam<BoundaryName>("secondary", "The secondary boundary");
      42       14144 :   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       14144 :   params.addCoupledVar(
      48             :       "displacements",
      49             :       "The displacements appropriate for the simulation geometry and coordinate system");
      50             : 
      51       14144 :   params.addCoupledVar("secondary_gap_offset", "offset to the gap distance from secondary side");
      52       14144 :   params.addCoupledVar("mapped_primary_gap_offset",
      53             :                        "offset to the gap distance mapped from primary side");
      54       14144 :   params.addRequiredCoupledVar("nodal_area", "The nodal area");
      55             : 
      56        7072 :   params.set<bool>("use_displaced_mesh") = true;
      57       14144 :   params.addParam<Real>(
      58             :       "penalty",
      59       14144 :       1e8,
      60             :       "The penalty to apply.  This can vary depending on the stiffness of your materials");
      61       14144 :   params.addParam<Real>("penalty_multiplier",
      62       14144 :                         1.0,
      63             :                         "The growth factor for the penalty applied at the end of each augmented "
      64             :                         "Lagrange update iteration");
      65       14144 :   params.addParam<Real>("friction_coefficient", 0, "The friction coefficient");
      66       14144 :   params.addParam<Real>("tangential_tolerance",
      67             :                         "Tangential distance to extend edges of contact surfaces");
      68       14144 :   params.addParam<Real>(
      69       14144 :       "capture_tolerance", 0, "Normal distance from surface within which nodes are captured");
      70             : 
      71       14144 :   params.addParam<Real>("tension_release",
      72       14144 :                         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       14144 :   params.addParam<bool>(
      78             :       "normalize_penalty",
      79       14144 :       false,
      80             :       "Whether to normalize the penalty parameter with the nodal area for penalty contact.");
      81       14144 :   params.addParam<bool>(
      82             :       "primary_secondary_jacobian",
      83       14144 :       true,
      84             :       "Whether to include jacobian entries coupling primary and secondary nodes.");
      85       14144 :   params.addParam<bool>(
      86             :       "connected_secondary_nodes_jacobian",
      87       14144 :       true,
      88             :       "Whether to include jacobian entries coupling nodes connected to secondary nodes.");
      89       14144 :   params.addParam<bool>("non_displacement_variables_jacobian",
      90       14144 :                         true,
      91             :                         "Whether to include jacobian entries coupling with variables that are not "
      92             :                         "displacement variables.");
      93       14144 :   params.addParam<unsigned int>("stick_lock_iterations",
      94       14144 :                                 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       14144 :   params.addParam<Real>("stick_unlock_factor",
      98       14144 :                         1.5,
      99             :                         "Factor by which frictional capacity must be "
     100             :                         "exceeded to permit stick-locked node to slip "
     101             :                         "again.");
     102       14144 :   params.addParam<Real>("al_penetration_tolerance",
     103             :                         "The tolerance of the penetration for augmented Lagrangian method.");
     104       14144 :   params.addParam<Real>("al_incremental_slip_tolerance",
     105             :                         "The tolerance of the incremental slip for augmented Lagrangian method.");
     106             : 
     107       14144 :   params.addParam<Real>("al_frictional_force_tolerance",
     108             :                         "The tolerance of the frictional force for augmented Lagrangian method.");
     109       14144 :   params.addParam<bool>(
     110       14144 :       "print_contact_nodes", false, "Whether to print the number of nodes in contact.");
     111             : 
     112        7072 :   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        7072 :   return params;
     119           0 : }
     120             : 
     121             : Threads::spin_mutex MechanicalContactConstraint::_contact_set_mutex;
     122             : 
     123        5011 : MechanicalContactConstraint::MechanicalContactConstraint(const InputParameters & parameters)
     124             :   : NodeFaceConstraint(parameters),
     125        5011 :     _displaced_problem(parameters.get<FEProblemBase *>("_fe_problem_base")->getDisplacedProblem()),
     126       10022 :     _component(getParam<unsigned int>("component")),
     127       10022 :     _model(getParam<MooseEnum>("model").getEnum<ContactModel>()),
     128       10022 :     _formulation(getParam<MooseEnum>("formulation").getEnum<ContactFormulation>()),
     129       10022 :     _normalize_penalty(getParam<bool>("normalize_penalty")),
     130       10022 :     _penalty(getParam<Real>("penalty")),
     131       10022 :     _penalty_multiplier(getParam<Real>("penalty_multiplier")),
     132       10022 :     _friction_coefficient(getParam<Real>("friction_coefficient")),
     133       10022 :     _tension_release(getParam<Real>("tension_release")),
     134       10022 :     _capture_tolerance(getParam<Real>("capture_tolerance")),
     135       10022 :     _stick_lock_iterations(getParam<unsigned int>("stick_lock_iterations")),
     136       10022 :     _stick_unlock_factor(getParam<Real>("stick_unlock_factor")),
     137        5011 :     _update_stateful_data(true),
     138        5011 :     _residual_copy(_sys.residualGhosted()),
     139        5011 :     _mesh_dimension(_mesh.dimension()),
     140        5011 :     _vars(3, libMesh::invalid_uint),
     141        5011 :     _var_objects(3, nullptr),
     142        5011 :     _has_secondary_gap_offset(isCoupled("secondary_gap_offset")),
     143        5011 :     _secondary_gap_offset_var(_has_secondary_gap_offset ? getVar("secondary_gap_offset", 0)
     144             :                                                         : nullptr),
     145        5011 :     _has_mapped_primary_gap_offset(isCoupled("mapped_primary_gap_offset")),
     146        5011 :     _mapped_primary_gap_offset_var(
     147        5011 :         _has_mapped_primary_gap_offset ? getVar("mapped_primary_gap_offset", 0) : nullptr),
     148        5011 :     _nodal_area_var(getVar("nodal_area", 0)),
     149        5011 :     _aux_system(_nodal_area_var->sys()),
     150        5011 :     _aux_solution(_aux_system.currentSolution()),
     151       10022 :     _primary_secondary_jacobian(getParam<bool>("primary_secondary_jacobian")),
     152       10022 :     _connected_secondary_nodes_jacobian(getParam<bool>("connected_secondary_nodes_jacobian")),
     153       10022 :     _non_displacement_vars_jacobian(getParam<bool>("non_displacement_variables_jacobian")),
     154        5011 :     _contact_linesearch(dynamic_cast<ContactLineSearchBase *>(_subproblem.getLineSearch())),
     155       10022 :     _print_contact_nodes(getParam<bool>("print_contact_nodes")),
     156        5011 :     _augmented_lagrange_problem(
     157        5011 :         dynamic_cast<AugmentedLagrangianContactProblemInterface *>(&_fe_problem)),
     158        5011 :     _lagrangian_iteration_number(_augmented_lagrange_problem
     159        5011 :                                      ? _augmented_lagrange_problem->getLagrangianIterationNumber()
     160       10022 :                                      : _no_iterations)
     161             : {
     162        5011 :   _overwrite_secondary_residual = false;
     163             : 
     164       10022 :   if (isParamValid("displacements"))
     165             :   {
     166             :     // modern parameter scheme for displacements
     167       32964 :     for (unsigned int i = 0; i < coupledComponents("displacements"); ++i)
     168             :     {
     169       11471 :       _vars[i] = coupled("displacements", i);
     170       11471 :       _var_objects[i] = getVar("displacements", i);
     171             :     }
     172             :   }
     173             : 
     174       10022 :   if (parameters.isParamValid("tangential_tolerance"))
     175       10206 :     _penetration_locator.setTangentialTolerance(getParam<Real>("tangential_tolerance"));
     176             : 
     177       10022 :   if (parameters.isParamValid("normal_smoothing_distance"))
     178        1425 :     _penetration_locator.setNormalSmoothingDistance(getParam<Real>("normal_smoothing_distance"));
     179             : 
     180       10022 :   if (parameters.isParamValid("normal_smoothing_method"))
     181           0 :     _penetration_locator.setNormalSmoothingMethod(
     182             :         parameters.get<std::string>("normal_smoothing_method"));
     183             : 
     184        5011 :   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        5011 :   if (_model == ContactModel::GLUED)
     188         644 :     _penetration_locator.setUpdate(false);
     189             : 
     190        5011 :   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        5011 :   _penalty_tangential = _penalty;
     195             : 
     196        5011 :   if (_formulation == ContactFormulation::AUGMENTED_LAGRANGE)
     197             :   {
     198         564 :     if (_model == ContactModel::GLUED)
     199           0 :       mooseError("The Augmented Lagrangian contact formulation does not support GLUED case.");
     200             : 
     201         564 :     if (!_augmented_lagrange_problem)
     202           0 :       mooseError("The Augmented Lagrangian contact formulation must use "
     203             :                  "AugmentedLagrangianContactProblem.");
     204             : 
     205        1128 :     if (!parameters.isParamValid("al_penetration_tolerance"))
     206           0 :       mooseError("For Augmented Lagrangian contact, al_penetration_tolerance must be provided.");
     207             :     else
     208         564 :       _al_penetration_tolerance = parameters.get<Real>("al_penetration_tolerance");
     209             : 
     210         564 :     if (_model != ContactModel::FRICTIONLESS)
     211             :     {
     212         720 :       if (!parameters.isParamValid("al_incremental_slip_tolerance") ||
     213         720 :           !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         240 :         _al_incremental_slip_tolerance = parameters.get<Real>("al_incremental_slip_tolerance");
     222         240 :         _al_frictional_force_tolerance = parameters.get<Real>("al_frictional_force_tolerance");
     223             :       }
     224             :     }
     225             :   }
     226        5011 : }
     227             : 
     228             : void
     229       20450 : MechanicalContactConstraint::timestepSetup()
     230             : {
     231       20450 :   if (_component == 0)
     232             :   {
     233        9801 :     updateContactStatefulData(/* beginning_of_step = */ true);
     234        9801 :     if (_formulation == ContactFormulation::AUGMENTED_LAGRANGE)
     235         213 :       updateAugmentedLagrangianMultiplier(/* beginning_of_step = */ true);
     236             : 
     237        9801 :     _update_stateful_data = false;
     238             : 
     239        9801 :     if (_contact_linesearch)
     240          17 :       _contact_linesearch->reset();
     241             :   }
     242       20450 : }
     243             : 
     244             : void
     245       59402 : MechanicalContactConstraint::jacobianSetup()
     246             : {
     247       59402 :   if (_component == 0)
     248             :   {
     249       28735 :     if (_update_stateful_data)
     250       19620 :       updateContactStatefulData(/* beginning_of_step = */ false);
     251       28735 :     _update_stateful_data = true;
     252             :   }
     253       59402 : }
     254             : 
     255             : void
     256         429 : MechanicalContactConstraint::updateAugmentedLagrangianMultiplier(bool beginning_of_step)
     257             : {
     258        3242 :   for (auto & [secondary_node_num, pinfo] : _penetration_locator._penetration_info)
     259             :   {
     260        2813 :     if (!pinfo)
     261         175 :       continue;
     262             : 
     263        2638 :     const Node & node = _mesh.nodeRef(secondary_node_num);
     264        2638 :     if (node.n_comp(_sys.number(), _vars[_component]) < 1)
     265           0 :       continue;
     266             : 
     267        2638 :     const Real distance = pinfo->_normal * (pinfo->_closest_point - node) - gapOffset(node);
     268             : 
     269        2638 :     if (beginning_of_step && _model == ContactModel::COULOMB)
     270             :     {
     271         420 :       pinfo->_lagrange_multiplier_slip.zero();
     272         420 :       if (pinfo->isCaptured())
     273           0 :         pinfo->_mech_status = PenetrationInfo::MS_STICKING;
     274             :     }
     275             : 
     276        2638 :     if (pinfo->isCaptured())
     277             :     {
     278        1516 :       if (_model == ContactModel::FRICTIONLESS)
     279        1026 :         pinfo->_lagrange_multiplier -= getPenalty(node) * distance;
     280             : 
     281        1516 :       if (_model == ContactModel::COULOMB)
     282             :       {
     283         490 :         if (!beginning_of_step)
     284             :         {
     285         490 :           Real penalty = getPenalty(node);
     286             :           RealVectorValue pen_force_normal =
     287         490 :               penalty * (-distance) * pinfo->_normal + pinfo->_lagrange_multiplier * pinfo->_normal;
     288             : 
     289             :           // update normal lagrangian multiplier
     290         490 :           pinfo->_lagrange_multiplier += penalty * (-distance);
     291             : 
     292             :           // Frictional capacity
     293         889 :           const Real capacity(_friction_coefficient * (pen_force_normal * pinfo->_normal < 0
     294         490 :                                                            ? -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         490 :           Real penalty_slip = getTangentialPenalty(node);
     302             : 
     303             :           RealVectorValue inc_pen_force_tangential =
     304         490 :               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         490 :           const Real tan_mag(contact_force_tangential.norm());
     311             : 
     312         490 :           if (tan_mag > capacity * (_al_frictional_force_tolerance + 1.0))
     313             :           {
     314          63 :             pinfo->_lagrange_multiplier_slip =
     315             :                 -tau_old + capacity * contact_force_tangential / tan_mag;
     316          63 :             if (MooseUtils::absoluteFuzzyEqual(capacity, 0.0))
     317          63 :               pinfo->_mech_status = PenetrationInfo::MS_SLIPPING;
     318             :             else
     319           0 :               pinfo->_mech_status = PenetrationInfo::MS_SLIPPING_FRICTION;
     320             :           }
     321             :           else
     322             :           {
     323         427 :             pinfo->_mech_status = PenetrationInfo::MS_STICKING;
     324             :             pinfo->_lagrange_multiplier_slip += penalty_slip * tangential_inc_slip;
     325             :           }
     326             :         }
     327             :       }
     328             :     }
     329             :   }
     330         429 : }
     331             : 
     332             : bool
     333         708 : MechanicalContactConstraint::AugmentedLagrangianContactConverged()
     334             : {
     335             :   Real contactResidual = 0.0;
     336         708 :   unsigned int converged = 0;
     337             : 
     338        4130 :   for (auto & [secondary_node_num, pinfo] : _penetration_locator._penetration_info)
     339             :   {
     340        3638 :     if (!pinfo)
     341           0 :       continue;
     342             : 
     343        3638 :     const auto & node = _mesh.nodeRef(secondary_node_num);
     344             : 
     345             :     // Skip this pinfo if there are no DOFs on this node.
     346        3638 :     if (node.n_comp(_sys.number(), _vars[_component]) < 1)
     347           0 :       continue;
     348             : 
     349        3638 :     const Real distance = pinfo->_normal * (pinfo->_closest_point - node) - gapOffset(node);
     350             : 
     351        3638 :     if (pinfo->isCaptured())
     352             :     {
     353        3638 :       if (contactResidual < std::abs(distance))
     354             :         contactResidual = std::abs(distance);
     355             : 
     356             :       // penetration < tol
     357        3638 :       if (contactResidual > _al_penetration_tolerance)
     358             :       {
     359         216 :         converged = 1;
     360         216 :         break;
     361             :       }
     362             : 
     363        3422 :       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        1274 :         const Real tan_mag(contact_force_tangential.norm());
     373        1274 :         const Real tangential_inc_slip_mag = tangential_inc_slip.norm();
     374             : 
     375             :         RealVectorValue distance_vec =
     376        1274 :             (pinfo->_normal * (node - pinfo->_closest_point) + gapOffset(node)) * pinfo->_normal;
     377             : 
     378        1274 :         Real penalty = getPenalty(node);
     379             :         RealVectorValue pen_force_normal =
     380        1274 :             penalty * distance_vec + pinfo->_lagrange_multiplier * pinfo->_normal;
     381             : 
     382             :         // Frictional capacity
     383        2275 :         Real capacity(_friction_coefficient * (pen_force_normal * pinfo->_normal < 0
     384        1274 :                                                    ? -pen_force_normal * pinfo->_normal
     385             :                                                    : 0.0));
     386             : 
     387             :         // incremental slip <= tol for all pinfo_pair such that tan_mag < capacity
     388        1274 :         if (MooseUtils::absoluteFuzzyLessThan(tan_mag, capacity) &&
     389        1001 :             pinfo->_mech_status == PenetrationInfo::MS_STICKING)
     390             :         {
     391        1001 :           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        1274 :         if (tan_mag >
     401        1274 :             (1 + _al_frictional_force_tolerance) * (capacity + _al_frictional_force_tolerance))
     402             :         {
     403           0 :           converged = 3;
     404           0 :           break;
     405             :         }
     406             :       }
     407             :     }
     408             :   }
     409             : 
     410         708 :   _communicator.max(converged);
     411             : 
     412         708 :   if (converged == 1)
     413         216 :     _console << "The Augmented Lagrangian contact tangential sliding enforcement is NOT satisfied "
     414         216 :              << std::endl;
     415         492 :   else if (converged == 2)
     416           0 :     _console << "The Augmented Lagrangian contact tangential sliding enforcement is NOT satisfied "
     417           0 :              << std::endl;
     418         492 :   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       29421 : MechanicalContactConstraint::updateContactStatefulData(bool beginning_of_step)
     429             : {
     430      253784 :   for (auto & [secondary_node_num, pinfo] : _penetration_locator._penetration_info)
     431             :   {
     432      224363 :     if (!pinfo)
     433        8355 :       continue;
     434             : 
     435      216008 :     const Node & node = _mesh.nodeRef(secondary_node_num);
     436      216008 :     if (node.n_comp(_sys.number(), _vars[_component]) < 1)
     437           0 :       continue;
     438             : 
     439      216008 :     if (beginning_of_step)
     440             :     {
     441       68439 :       if (_app.getExecutioner()->lastSolveConverged())
     442             :       {
     443       66577 :         pinfo->_contact_force_old = pinfo->_contact_force;
     444       66577 :         pinfo->_accumulated_slip_old = pinfo->_accumulated_slip;
     445       66577 :         pinfo->_frictional_energy_old = pinfo->_frictional_energy;
     446       66577 :         pinfo->_mech_status_old = pinfo->_mech_status;
     447             :       }
     448        1862 :       else if (pinfo->_mech_status_old == PenetrationInfo::MS_NO_CONTACT &&
     449        1675 :                pinfo->_mech_status != PenetrationInfo::MS_NO_CONTACT)
     450             :       {
     451             :         // The penetration info object could be based on a bad state so delete it
     452        1217 :         delete pinfo;
     453        1217 :         pinfo = NULL;
     454        1217 :         continue;
     455             :       }
     456             : 
     457       67222 :       pinfo->_locked_this_step = 0;
     458       67222 :       pinfo->_stick_locked_this_step = 0;
     459       67222 :       pinfo->_starting_elem = pinfo->_elem;
     460       67222 :       pinfo->_starting_side_num = pinfo->_side_num;
     461       67222 :       pinfo->_starting_closest_point_ref = pinfo->_closest_point_ref;
     462             :     }
     463      214791 :     pinfo->_incremental_slip_prev_iter = pinfo->_incremental_slip;
     464             :   }
     465       29421 : }
     466             : 
     467             : bool
     468     3291286 : MechanicalContactConstraint::shouldApply()
     469             : {
     470             :   bool in_contact = false;
     471             : 
     472             :   std::map<dof_id_type, PenetrationInfo *>::iterator found =
     473     3291286 :       _penetration_locator._penetration_info.find(_current_node->id());
     474     3291286 :   if (found != _penetration_locator._penetration_info.end())
     475             :   {
     476     3291286 :     PenetrationInfo * pinfo = found->second;
     477     3291286 :     if (pinfo != NULL)
     478             :     {
     479     3291286 :       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     3291286 :       if (_component == 0)
     484     1403672 :         computeContactForce(*_current_node, pinfo, is_nonlinear);
     485             : 
     486     3291286 :       if (pinfo->isCaptured())
     487             :       {
     488             :         in_contact = true;
     489     2165165 :         if (is_nonlinear)
     490             :         {
     491             :           Threads::spin_mutex::scoped_lock lock(_contact_set_mutex);
     492      253107 :           _current_contact_state.insert(_current_node->id());
     493             :         }
     494             :       }
     495             :     }
     496             :   }
     497             : 
     498     3291286 :   return in_contact;
     499             : }
     500             : 
     501             : void
     502     1403672 : MechanicalContactConstraint::computeContactForce(const Node & node,
     503             :                                                  PenetrationInfo * pinfo,
     504             :                                                  bool update_contact_set)
     505             : {
     506             :   // Build up residual vector
     507             :   RealVectorValue res_vec;
     508     4694958 :   for (unsigned int i = 0; i < _mesh_dimension; ++i)
     509             :   {
     510     3291286 :     dof_id_type dof_number = node.dof_number(0, _vars[i], 0);
     511     3291286 :     res_vec(i) = _residual_copy(dof_number) / _var_objects[i]->scalingFactor();
     512             :   }
     513             : 
     514             :   RealVectorValue distance_vec(node - pinfo->_closest_point);
     515     1403672 :   if (distance_vec.norm() != 0)
     516     1347896 :     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     1403672 :   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       14208 :     if (_formulation == ContactFormulation::KINEMATIC ||
     534             :         _formulation == ContactFormulation::TANGENTIAL_PENALTY)
     535        7720 :       ++pinfo->_locked_this_step;
     536             :   }
     537             : 
     538     1403672 :   if (!pinfo->isCaptured())
     539      501625 :     return;
     540             : 
     541      902047 :   const Real penalty = getPenalty(node);
     542      902047 :   const Real penalty_slip = getTangentialPenalty(node);
     543             : 
     544             :   RealVectorValue pen_force(penalty * distance_vec);
     545             : 
     546      902047 :   switch (_model)
     547             :   {
     548      627985 :     case ContactModel::FRICTIONLESS:
     549      627985 :       switch (_formulation)
     550             :       {
     551      350657 :         case ContactFormulation::KINEMATIC:
     552      350657 :           pinfo->_contact_force = -pinfo->_normal * (pinfo->_normal * res_vec);
     553      350657 :           break;
     554             : 
     555      249635 :         case ContactFormulation::PENALTY:
     556      249635 :           pinfo->_contact_force = pinfo->_normal * (pinfo->_normal * pen_force);
     557      249635 :           break;
     558             : 
     559       27693 :         case ContactFormulation::AUGMENTED_LAGRANGE:
     560       27693 :           pinfo->_contact_force =
     561             :               (pinfo->_normal *
     562             :                (pinfo->_normal * (pen_force + pinfo->_lagrange_multiplier * pinfo->_normal)));
     563       27693 :           break;
     564             : 
     565           0 :         default:
     566           0 :           mooseError("Invalid contact formulation");
     567             :           break;
     568             :       }
     569      627985 :       pinfo->_mech_status = PenetrationInfo::MS_SLIPPING;
     570      627985 :       break;
     571      106989 :     case ContactModel::COULOMB:
     572      106989 :       switch (_formulation)
     573             :       {
     574       24152 :         case ContactFormulation::KINEMATIC:
     575             :         {
     576             :           // Frictional capacity
     577       45512 :           const Real capacity(_friction_coefficient *
     578       24152 :                               (res_vec * pinfo->_normal > 0 ? res_vec * pinfo->_normal : 0));
     579             : 
     580             :           // Normal and tangential components of predictor force
     581       24152 :           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       24152 :           const Real tan_mag(contact_force_tangential.norm());
     592       24152 :           const Real tangential_inc_slip_mag = tangential_inc_slip.norm();
     593       24152 :           const Real slip_tol = capacity / penalty;
     594       24152 :           pinfo->_slip_tol = slip_tol;
     595             : 
     596       24152 :           if ((tangential_inc_slip_mag > slip_tol || tan_mag > capacity) &&
     597       22412 :               (pinfo->_stick_locked_this_step < _stick_lock_iterations ||
     598           0 :                tan_mag > capacity * _stick_unlock_factor))
     599             :           {
     600       22412 :             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       22412 :             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       21650 :               if (slip_dot_tang_force < capacity)
     612             :                 slipped_too_far = true;
     613             :             }
     614             : 
     615             :             if (slipped_too_far) // slip back along slip increment
     616       12520 :               pinfo->_contact_force = contact_force_normal + capacity * slip_inc_direction;
     617             :             else
     618             :             {
     619        9892 :               if (tan_mag > 0) // slip along tangential force direction
     620        9869 :                 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       22412 :             if (capacity == 0)
     626        2809 :               pinfo->_mech_status = PenetrationInfo::MS_SLIPPING;
     627             :             else
     628       19603 :               pinfo->_mech_status = PenetrationInfo::MS_SLIPPING_FRICTION;
     629             :           }
     630             :           else
     631             :           {
     632        1740 :             if (pinfo->_mech_status != PenetrationInfo::MS_STICKING &&
     633             :                 pinfo->_mech_status != PenetrationInfo::MS_NO_CONTACT)
     634         449 :               ++pinfo->_stick_locked_this_step;
     635        1740 :             pinfo->_mech_status = PenetrationInfo::MS_STICKING;
     636             :           }
     637             :           break;
     638             :         }
     639             : 
     640       17783 :         case ContactFormulation::PENALTY:
     641             :         {
     642       17783 :           distance_vec =
     643             :               pinfo->_incremental_slip +
     644       17783 :               (pinfo->_normal * (node - pinfo->_closest_point) + gapOffset(node)) * pinfo->_normal;
     645             :           pen_force = penalty * distance_vec;
     646             : 
     647             :           // Frictional capacity
     648       30076 :           const Real capacity(_friction_coefficient *
     649       17783 :                               (pen_force * pinfo->_normal < 0 ? -pen_force * pinfo->_normal : 0));
     650             : 
     651             :           // Elastic predictor
     652       17783 :           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       17783 :           const Real tan_mag(contact_force_tangential.norm());
     661             : 
     662       17783 :           if (tan_mag > capacity)
     663             :           {
     664        3181 :             pinfo->_contact_force =
     665             :                 contact_force_normal + capacity * contact_force_tangential / tan_mag;
     666        3181 :             if (MooseUtils::absoluteFuzzyEqual(capacity, 0))
     667        2461 :               pinfo->_mech_status = PenetrationInfo::MS_SLIPPING;
     668             :             else
     669         720 :               pinfo->_mech_status = PenetrationInfo::MS_SLIPPING_FRICTION;
     670             :           }
     671             :           else
     672       14602 :             pinfo->_mech_status = PenetrationInfo::MS_STICKING;
     673             :           break;
     674             :         }
     675             : 
     676       17598 :         case ContactFormulation::AUGMENTED_LAGRANGE:
     677             :         {
     678       17598 :           distance_vec =
     679       17598 :               (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       17598 :           if (pinfo->_mech_status == PenetrationInfo::MS_STICKING)
     696        7441 :             pinfo->_contact_force =
     697             :                 contact_force_normal + contact_force_tangential + inc_pen_force_tangential;
     698             :           else
     699       10157 :             pinfo->_contact_force = contact_force_normal + contact_force_tangential;
     700             : 
     701             :           break;
     702             :         }
     703             : 
     704       47456 :         case ContactFormulation::TANGENTIAL_PENALTY:
     705             :         {
     706             :           // Frictional capacity (kinematic formulation)
     707       51614 :           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       47456 :           const Real tan_mag(contact_force_tangential.norm());
     721             : 
     722       47456 :           if (tan_mag > capacity)
     723             :           {
     724       38201 :             pinfo->_contact_force =
     725             :                 contact_force_normal + capacity * contact_force_tangential / tan_mag;
     726       38201 :             if (MooseUtils::absoluteFuzzyEqual(capacity, 0))
     727        5521 :               pinfo->_mech_status = PenetrationInfo::MS_SLIPPING;
     728             :             else
     729       32680 :               pinfo->_mech_status = PenetrationInfo::MS_SLIPPING_FRICTION;
     730             :           }
     731             :           else
     732             :           {
     733        9255 :             pinfo->_contact_force = contact_force_normal + contact_force_tangential;
     734        9255 :             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      167073 :     case ContactModel::GLUED:
     746      167073 :       switch (_formulation)
     747             :       {
     748             :         case ContactFormulation::KINEMATIC:
     749      116033 :           pinfo->_contact_force = -res_vec;
     750      116033 :           break;
     751             : 
     752       51040 :         case ContactFormulation::PENALTY:
     753       51040 :           pinfo->_contact_force = pen_force;
     754       51040 :           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      167073 :       pinfo->_mech_status = PenetrationInfo::MS_STICKING;
     766      167073 :       break;
     767             : 
     768           0 :     default:
     769           0 :       mooseError("Invalid or unavailable contact model");
     770             :       break;
     771             :   }
     772             : 
     773             :   // Release
     774      109105 :   if (update_contact_set && _model != ContactModel::GLUED && pinfo->isCaptured() &&
     775      982272 :       !newly_captured && _tension_release >= 0.0 &&
     776       77183 :       (_contact_linesearch ? true : pinfo->_locked_this_step < 2))
     777             :   {
     778       77120 :     const Real contact_pressure = -(pinfo->_normal * pinfo->_contact_force) / nodalArea(node);
     779       77120 :     if (-contact_pressure >= _tension_release)
     780             :     {
     781             :       pinfo->release();
     782             :       pinfo->_contact_force.zero();
     783             :     }
     784             :   }
     785             : }
     786             : 
     787             : Real
     788       33113 : MechanicalContactConstraint::computeQpSecondaryValue()
     789             : {
     790       33113 :   return _u_secondary[_qp];
     791             : }
     792             : 
     793             : Real
     794    20620598 : MechanicalContactConstraint::computeQpResidual(Moose::ConstraintType type)
     795             : {
     796    20620598 :   PenetrationInfo * pinfo = _penetration_locator._penetration_info[_current_node->id()];
     797    20620598 :   Real resid = pinfo->_contact_force(_component);
     798    20620598 :   switch (type)
     799             :   {
     800     1943405 :     case Moose::Secondary:
     801     1943405 :       if (_formulation == ContactFormulation::KINEMATIC)
     802             :       {
     803     1112652 :         RealVectorValue distance_vec(*_current_node - pinfo->_closest_point);
     804     1112652 :         if (distance_vec.norm() != 0)
     805     1054878 :           distance_vec += gapOffset(*_current_node) * pinfo->_normal * distance_vec.unit() *
     806     2109756 :                           distance_vec.unit();
     807             : 
     808     1112652 :         const Real penalty = getPenalty(*_current_node);
     809             :         RealVectorValue pen_force(penalty * distance_vec);
     810             : 
     811     1112652 :         if (_model == ContactModel::FRICTIONLESS)
     812      786753 :           resid += pinfo->_normal(_component) * pinfo->_normal * pen_force;
     813      325899 :         else if (_model == ContactModel::COULOMB)
     814             :         {
     815             :           distance_vec = distance_vec - pinfo->_incremental_slip;
     816       40214 :           pen_force = penalty * distance_vec;
     817       40214 :           if (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
     818             :               pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION)
     819       36846 :             resid += pinfo->_normal(_component) * pinfo->_normal * pen_force;
     820             :           else
     821        3368 :             resid += pen_force(_component);
     822             :         }
     823      285685 :         else if (_model == ContactModel::GLUED)
     824      285685 :           resid += pen_force(_component);
     825             :       }
     826      830753 :       else if (_formulation == ContactFormulation::TANGENTIAL_PENALTY &&
     827       80958 :                _model == ContactModel::COULOMB)
     828             :       {
     829       80958 :         RealVectorValue distance_vec = (pinfo->_normal * (*_current_node - pinfo->_closest_point) +
     830       80958 :                                         gapOffset(*_current_node)) *
     831             :                                        pinfo->_normal;
     832             : 
     833       80958 :         const Real penalty = getPenalty(*_current_node);
     834             :         RealVectorValue pen_force(penalty * distance_vec);
     835       80958 :         resid += pinfo->_normal(_component) * pinfo->_normal * pen_force;
     836             :       }
     837     1943405 :       return _test_secondary[_i][_qp] * resid;
     838             : 
     839    18677193 :     case Moose::Primary:
     840    18677193 :       return _test_primary[_i][_qp] * -resid;
     841             :   }
     842             : 
     843             :   return 0.0;
     844             : }
     845             : 
     846             : Real
     847    73522813 : MechanicalContactConstraint::computeQpJacobian(Moose::ConstraintJacobianType type)
     848             : {
     849    73522813 :   PenetrationInfo * pinfo = _penetration_locator._penetration_info[_current_node->id()];
     850             : 
     851    73522813 :   const Real penalty = getPenalty(*_current_node);
     852    73522813 :   const Real penalty_slip = getTangentialPenalty(*_current_node);
     853             : 
     854    73522813 :   switch (type)
     855             :   {
     856           0 :     default:
     857           0 :       mooseError("Unhandled ConstraintJacobianType");
     858             : 
     859     2564905 :     case Moose::SecondarySecondary:
     860     2564905 :       switch (_model)
     861             :       {
     862     2017787 :         case ContactModel::FRICTIONLESS:
     863     2017787 :           switch (_formulation)
     864             :           {
     865             :             case ContactFormulation::KINEMATIC:
     866             :             {
     867             :               RealVectorValue jac_vec;
     868     5357460 :               for (unsigned int i = 0; i < _mesh_dimension; ++i)
     869             :               {
     870     3972467 :                 dof_id_type dof_number = _current_node->dof_number(0, _vars[i], 0);
     871     3972467 :                 jac_vec(i) = (*_jacobian)(dof_number, _connected_dof_indices[_j]) /
     872     3972467 :                              _var_objects[i]->scalingFactor();
     873             :               }
     874     1384993 :               return -pinfo->_normal(_component) * (pinfo->_normal * jac_vec) +
     875     1384993 :                      (_phi_secondary[_j][_qp] * penalty * _test_secondary[_i][_qp]) *
     876     1384993 :                          pinfo->_normal(_component) * pinfo->_normal(_component);
     877             :             }
     878             : 
     879      632794 :             case ContactFormulation::PENALTY:
     880             :             case ContactFormulation::AUGMENTED_LAGRANGE:
     881      632794 :               return _phi_secondary[_j][_qp] * penalty * _test_secondary[_i][_qp] *
     882      632794 :                      pinfo->_normal(_component) * pinfo->_normal(_component);
     883             : 
     884           0 :             default:
     885           0 :               mooseError("Invalid contact formulation");
     886             :           }
     887             : 
     888      277238 :         case ContactModel::COULOMB:
     889      277238 :           switch (_formulation)
     890             :           {
     891       38712 :             case ContactFormulation::KINEMATIC:
     892             :             {
     893       38712 :               if (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
     894             :                   pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION)
     895             :               {
     896             :                 RealVectorValue jac_vec;
     897      114300 :                 for (unsigned int i = 0; i < _mesh_dimension; ++i)
     898             :                 {
     899       76200 :                   dof_id_type dof_number = _current_node->dof_number(0, _vars[i], 0);
     900       76200 :                   jac_vec(i) = (*_jacobian)(dof_number, _connected_dof_indices[_j]) /
     901       76200 :                                _var_objects[i]->scalingFactor();
     902             :                 }
     903       38100 :                 return -pinfo->_normal(_component) * (pinfo->_normal * jac_vec) +
     904       38100 :                        (_phi_secondary[_j][_qp] * penalty * _test_secondary[_i][_qp]) *
     905       38100 :                            pinfo->_normal(_component) * pinfo->_normal(_component);
     906             :               }
     907             :               else
     908             :               {
     909             :                 const Real curr_jac =
     910         612 :                     (*_jacobian)(_current_node->dof_number(0, _vars[_component], 0),
     911         612 :                                  _connected_dof_indices[_j]) /
     912         612 :                     _var.scalingFactor();
     913         612 :                 return (-curr_jac + _phi_secondary[_j][_qp] * penalty * _test_secondary[_i][_qp]);
     914             :               }
     915             :             }
     916             : 
     917       68769 :             case ContactFormulation::PENALTY:
     918             :             {
     919       68769 :               if (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
     920             :                   pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION)
     921       14282 :                 return _phi_secondary[_j][_qp] * penalty * _test_secondary[_i][_qp] *
     922       14282 :                        pinfo->_normal(_component) * pinfo->_normal(_component);
     923             :               else
     924       54487 :                 return _phi_secondary[_j][_qp] * penalty * _test_secondary[_i][_qp];
     925             :             }
     926      106341 :             case ContactFormulation::AUGMENTED_LAGRANGE:
     927             :             {
     928      106341 :               Real normal_comp = _phi_secondary[_j][_qp] * penalty * _test_secondary[_i][_qp] *
     929      106341 :                                  pinfo->_normal(_component) * pinfo->_normal(_component);
     930             : 
     931             :               Real tang_comp = 0.0;
     932      106341 :               if (pinfo->_mech_status == PenetrationInfo::MS_STICKING)
     933       39930 :                 tang_comp = _phi_secondary[_j][_qp] * penalty_slip * _test_secondary[_i][_qp] *
     934       39930 :                             (1.0 - pinfo->_normal(_component) * pinfo->_normal(_component));
     935      106341 :               return normal_comp + tang_comp;
     936             :             }
     937             : 
     938             :             case ContactFormulation::TANGENTIAL_PENALTY:
     939             :             {
     940             :               RealVectorValue jac_vec;
     941      190248 :               for (unsigned int i = 0; i < _mesh_dimension; ++i)
     942             :               {
     943      126832 :                 dof_id_type dof_number = _current_node->dof_number(0, _vars[i], 0);
     944      126832 :                 jac_vec(i) = (*_jacobian)(dof_number, _connected_dof_indices[_j]) /
     945      126832 :                              _var_objects[i]->scalingFactor();
     946             :               }
     947       63416 :               Real normal_comp = -pinfo->_normal(_component) * (pinfo->_normal * jac_vec) +
     948       63416 :                                  (_phi_secondary[_j][_qp] * penalty * _test_secondary[_i][_qp]) *
     949       63416 :                                      pinfo->_normal(_component) * pinfo->_normal(_component);
     950             : 
     951             :               Real tang_comp = 0.0;
     952       63416 :               if (pinfo->_mech_status == PenetrationInfo::MS_STICKING)
     953         576 :                 tang_comp = _phi_secondary[_j][_qp] * penalty * _test_secondary[_i][_qp] *
     954         576 :                             (1.0 - pinfo->_normal(_component) * pinfo->_normal(_component));
     955             : 
     956       63416 :               return normal_comp + tang_comp;
     957             :             }
     958             : 
     959           0 :             default:
     960           0 :               mooseError("Invalid contact formulation");
     961             :           }
     962             : 
     963      269880 :         case ContactModel::GLUED:
     964      269880 :           switch (_formulation)
     965             :           {
     966      170883 :             case ContactFormulation::KINEMATIC:
     967             :             {
     968      170883 :               const Real curr_jac = (*_jacobian)(_current_node->dof_number(0, _vars[_component], 0),
     969      170883 :                                                  _connected_dof_indices[_j]) /
     970      170883 :                                     _var.scalingFactor();
     971      170883 :               return (-curr_jac + _phi_secondary[_j][_qp] * penalty * _test_secondary[_i][_qp]);
     972             :             }
     973             : 
     974       98997 :             case ContactFormulation::PENALTY:
     975             :             case ContactFormulation::AUGMENTED_LAGRANGE:
     976       98997 :               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     1829048 :     case Moose::SecondaryPrimary:
     986     1829048 :       switch (_model)
     987             :       {
     988     1408288 :         case ContactModel::FRICTIONLESS:
     989     1408288 :           switch (_formulation)
     990             :           {
     991      949544 :             case ContactFormulation::KINEMATIC:
     992             :             {
     993      949544 :               const Node * curr_primary_node = _current_primary->node_ptr(_j);
     994             : 
     995             :               RealVectorValue jac_vec;
     996     3656544 :               for (unsigned int i = 0; i < _mesh_dimension; ++i)
     997             :               {
     998     2707000 :                 dof_id_type dof_number = _current_node->dof_number(0, _vars[i], 0);
     999     5414000 :                 jac_vec(i) = (*_jacobian)(dof_number,
    1000     2707000 :                                           curr_primary_node->dof_number(0, _vars[_component], 0)) /
    1001     2707000 :                              _var_objects[i]->scalingFactor();
    1002             :               }
    1003      949544 :               return -pinfo->_normal(_component) * (pinfo->_normal * jac_vec) -
    1004      949544 :                      (_phi_primary[_j][_qp] * penalty * _test_secondary[_i][_qp]) *
    1005      949544 :                          pinfo->_normal(_component) * pinfo->_normal(_component);
    1006             :             }
    1007             : 
    1008      458744 :             case ContactFormulation::PENALTY:
    1009             :             case ContactFormulation::AUGMENTED_LAGRANGE:
    1010      458744 :               return -_phi_primary[_j][_qp] * penalty * _test_secondary[_i][_qp] *
    1011      458744 :                      pinfo->_normal(_component) * pinfo->_normal(_component);
    1012             : 
    1013           0 :             default:
    1014           0 :               mooseError("Invalid contact formulation");
    1015             :           }
    1016             : 
    1017      222424 :         case ContactModel::COULOMB:
    1018      222424 :           switch (_formulation)
    1019             :           {
    1020       29376 :             case ContactFormulation::KINEMATIC:
    1021             :             {
    1022       29376 :               if (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
    1023             :                   pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION)
    1024             :               {
    1025       28944 :                 const Node * curr_primary_node = _current_primary->node_ptr(_j);
    1026             : 
    1027             :                 RealVectorValue jac_vec;
    1028       86832 :                 for (unsigned int i = 0; i < _mesh_dimension; ++i)
    1029             :                 {
    1030       57888 :                   dof_id_type dof_number = _current_node->dof_number(0, _vars[i], 0);
    1031       57888 :                   jac_vec(i) =
    1032       57888 :                       (*_jacobian)(dof_number,
    1033       57888 :                                    curr_primary_node->dof_number(0, _vars[_component], 0)) /
    1034       57888 :                       _var_objects[i]->scalingFactor();
    1035             :                 }
    1036       28944 :                 return -pinfo->_normal(_component) * (pinfo->_normal * jac_vec) -
    1037       28944 :                        (_phi_primary[_j][_qp] * penalty * _test_secondary[_i][_qp]) *
    1038       28944 :                            pinfo->_normal(_component) * pinfo->_normal(_component);
    1039             :               }
    1040             :               else
    1041             :               {
    1042         432 :                 const Node * curr_primary_node = _current_primary->node_ptr(_j);
    1043             :                 const Real curr_jac =
    1044         432 :                     (*_jacobian)(_current_node->dof_number(0, _vars[_component], 0),
    1045         432 :                                  curr_primary_node->dof_number(0, _vars[_component], 0)) /
    1046         432 :                     _var.scalingFactor();
    1047         432 :                 return (-curr_jac - _phi_primary[_j][_qp] * penalty * _test_secondary[_i][_qp]);
    1048             :               }
    1049             :             }
    1050             : 
    1051       55756 :             case ContactFormulation::PENALTY:
    1052             :             {
    1053       55756 :               if (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
    1054             :                   pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION)
    1055       10700 :                 return -_phi_primary[_j][_qp] * penalty * _test_secondary[_i][_qp] *
    1056       10700 :                        pinfo->_normal(_component) * pinfo->_normal(_component);
    1057             :               else
    1058       45056 :                 return -_phi_primary[_j][_qp] * penalty * _test_secondary[_i][_qp];
    1059             :             }
    1060       87500 :             case ContactFormulation::AUGMENTED_LAGRANGE:
    1061             :             {
    1062       87500 :               Real normal_comp = -_phi_primary[_j][_qp] * penalty * _test_secondary[_i][_qp] *
    1063       87500 :                                  pinfo->_normal(_component) * pinfo->_normal(_component);
    1064             : 
    1065             :               Real tang_comp = 0.0;
    1066       87500 :               if (pinfo->_mech_status == PenetrationInfo::MS_STICKING)
    1067       34720 :                 tang_comp = -_phi_primary[_j][_qp] * penalty_slip * _test_secondary[_i][_qp] *
    1068       34720 :                             (1.0 - pinfo->_normal(_component) * pinfo->_normal(_component));
    1069       87500 :               return normal_comp + tang_comp;
    1070             :             }
    1071             : 
    1072       49792 :             case ContactFormulation::TANGENTIAL_PENALTY:
    1073             :             {
    1074       49792 :               const Node * curr_primary_node = _current_primary->node_ptr(_j);
    1075             : 
    1076             :               RealVectorValue jac_vec;
    1077      149376 :               for (unsigned int i = 0; i < _mesh_dimension; ++i)
    1078             :               {
    1079       99584 :                 dof_id_type dof_number = _current_node->dof_number(0, _vars[i], 0);
    1080      199168 :                 jac_vec(i) = (*_jacobian)(dof_number,
    1081       99584 :                                           curr_primary_node->dof_number(0, _vars[_component], 0)) /
    1082       99584 :                              _var_objects[i]->scalingFactor();
    1083             :               }
    1084       49792 :               Real normal_comp = -pinfo->_normal(_component) * (pinfo->_normal * jac_vec) -
    1085       49792 :                                  (_phi_primary[_j][_qp] * penalty * _test_secondary[_i][_qp]) *
    1086       49792 :                                      pinfo->_normal(_component) * pinfo->_normal(_component);
    1087             : 
    1088             :               Real tang_comp = 0.0;
    1089       49792 :               if (pinfo->_mech_status == PenetrationInfo::MS_STICKING)
    1090         432 :                 tang_comp = -_phi_primary[_j][_qp] * penalty * _test_secondary[_i][_qp] *
    1091         432 :                             (1.0 - pinfo->_normal(_component) * pinfo->_normal(_component));
    1092             : 
    1093       49792 :               return normal_comp + tang_comp;
    1094             :             }
    1095             : 
    1096           0 :             default:
    1097           0 :               mooseError("Invalid contact formulation");
    1098             :           }
    1099      198336 :         case ContactModel::GLUED:
    1100      198336 :           switch (_formulation)
    1101             :           {
    1102      119580 :             case ContactFormulation::KINEMATIC:
    1103             :             {
    1104      119580 :               const Node * curr_primary_node = _current_primary->node_ptr(_j);
    1105             :               const Real curr_jac =
    1106      119580 :                   (*_jacobian)(_current_node->dof_number(0, _vars[_component], 0),
    1107      119580 :                                curr_primary_node->dof_number(0, _vars[_component], 0)) /
    1108      119580 :                   _var.scalingFactor();
    1109      119580 :               return (-curr_jac - _phi_primary[_j][_qp] * penalty * _test_secondary[_i][_qp]);
    1110             :             }
    1111             : 
    1112       78756 :             case ContactFormulation::PENALTY:
    1113             :             case ContactFormulation::AUGMENTED_LAGRANGE:
    1114       78756 :               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    40565148 :     case Moose::PrimarySecondary:
    1125    40565148 :       switch (_model)
    1126             :       {
    1127    34401220 :         case ContactModel::FRICTIONLESS:
    1128    34401220 :           switch (_formulation)
    1129             :           {
    1130             :             case ContactFormulation::KINEMATIC:
    1131             :             {
    1132             :               RealVectorValue jac_vec;
    1133   105044016 :               for (unsigned int i = 0; i < _mesh_dimension; ++i)
    1134             :               {
    1135    78541748 :                 dof_id_type dof_number = _current_node->dof_number(0, _vars[i], 0);
    1136    78541748 :                 jac_vec(i) = (*_jacobian)(dof_number, _connected_dof_indices[_j]) /
    1137    78541748 :                              _var_objects[i]->scalingFactor();
    1138             :               }
    1139    26502268 :               return pinfo->_normal(_component) * (pinfo->_normal * jac_vec) *
    1140    26502268 :                      _test_primary[_i][_qp];
    1141             :             }
    1142             : 
    1143     7898952 :             case ContactFormulation::PENALTY:
    1144             :             case ContactFormulation::AUGMENTED_LAGRANGE:
    1145     7898952 :               return -_test_primary[_i][_qp] * penalty * _phi_secondary[_j][_qp] *
    1146     7898952 :                      pinfo->_normal(_component) * pinfo->_normal(_component);
    1147             : 
    1148           0 :             default:
    1149           0 :               mooseError("Invalid contact formulation");
    1150             :           }
    1151     3250904 :         case ContactModel::COULOMB:
    1152     3250904 :           switch (_formulation)
    1153             :           {
    1154      154848 :             case ContactFormulation::KINEMATIC:
    1155             :             {
    1156      154848 :               if (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
    1157             :                   pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION)
    1158             :               {
    1159             :                 RealVectorValue jac_vec;
    1160      457200 :                 for (unsigned int i = 0; i < _mesh_dimension; ++i)
    1161             :                 {
    1162      304800 :                   dof_id_type dof_number = _current_node->dof_number(0, _vars[i], 0);
    1163      304800 :                   jac_vec(i) = (*_jacobian)(dof_number, _connected_dof_indices[_j]) /
    1164      304800 :                                _var_objects[i]->scalingFactor();
    1165             :                 }
    1166      152400 :                 return pinfo->_normal(_component) * (pinfo->_normal * jac_vec) *
    1167      152400 :                        _test_primary[_i][_qp];
    1168             :               }
    1169             :               else
    1170             :               {
    1171             :                 const Real secondary_jac =
    1172        2448 :                     (*_jacobian)(_current_node->dof_number(0, _vars[_component], 0),
    1173        2448 :                                  _connected_dof_indices[_j]) /
    1174        2448 :                     _var.scalingFactor();
    1175        2448 :                 return secondary_jac * _test_primary[_i][_qp];
    1176             :               }
    1177             :             }
    1178             : 
    1179     1037796 :             case ContactFormulation::PENALTY:
    1180             :             {
    1181     1037796 :               if (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
    1182             :                   pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION)
    1183      265224 :                 return -_test_primary[_i][_qp] * penalty * _phi_secondary[_j][_qp] *
    1184      265224 :                        pinfo->_normal(_component) * pinfo->_normal(_component);
    1185             :               else
    1186      772572 :                 return -_test_primary[_i][_qp] * penalty * _phi_secondary[_j][_qp];
    1187             :             }
    1188     1804596 :             case ContactFormulation::AUGMENTED_LAGRANGE:
    1189             :             {
    1190     1804596 :               Real normal_comp = -_phi_secondary[_j][_qp] * penalty * _test_primary[_i][_qp] *
    1191     1804596 :                                  pinfo->_normal(_component) * pinfo->_normal(_component);
    1192             : 
    1193             :               Real tang_comp = 0.0;
    1194     1804596 :               if (pinfo->_mech_status == PenetrationInfo::MS_STICKING)
    1195      617328 :                 tang_comp = -_phi_secondary[_j][_qp] * penalty_slip * _test_primary[_i][_qp] *
    1196      617328 :                             (1.0 - pinfo->_normal(_component) * pinfo->_normal(_component));
    1197     1804596 :               return normal_comp + tang_comp;
    1198             :             }
    1199             : 
    1200             :             case ContactFormulation::TANGENTIAL_PENALTY:
    1201             :             {
    1202             :               RealVectorValue jac_vec;
    1203      760992 :               for (unsigned int i = 0; i < _mesh_dimension; ++i)
    1204             :               {
    1205      507328 :                 dof_id_type dof_number = _current_node->dof_number(0, _vars[i], 0);
    1206      507328 :                 jac_vec(i) = (*_jacobian)(dof_number, _connected_dof_indices[_j]) /
    1207      507328 :                              _var_objects[i]->scalingFactor();
    1208             :               }
    1209             :               Real normal_comp =
    1210      253664 :                   pinfo->_normal(_component) * (pinfo->_normal * jac_vec) * _test_primary[_i][_qp];
    1211             : 
    1212             :               Real tang_comp = 0.0;
    1213      253664 :               if (pinfo->_mech_status == PenetrationInfo::MS_STICKING)
    1214        2304 :                 tang_comp = -_test_primary[_i][_qp] * penalty * _phi_secondary[_j][_qp] *
    1215        2304 :                             (1.0 - pinfo->_normal(_component) * pinfo->_normal(_component));
    1216             : 
    1217      253664 :               return normal_comp + tang_comp;
    1218             :             }
    1219             : 
    1220           0 :             default:
    1221           0 :               mooseError("Invalid contact formulation");
    1222             :           }
    1223             : 
    1224     2913024 :         case ContactModel::GLUED:
    1225     2913024 :           switch (_formulation)
    1226             :           {
    1227     1684980 :             case ContactFormulation::KINEMATIC:
    1228             :             {
    1229             :               const Real secondary_jac =
    1230     1684980 :                   (*_jacobian)(_current_node->dof_number(0, _vars[_component], 0),
    1231     1684980 :                                _connected_dof_indices[_j]) /
    1232     1684980 :                   _var.scalingFactor();
    1233     1684980 :               return secondary_jac * _test_primary[_i][_qp];
    1234             :             }
    1235             : 
    1236     1228044 :             case ContactFormulation::PENALTY:
    1237             :             case ContactFormulation::AUGMENTED_LAGRANGE:
    1238     1228044 :               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    28563712 :     case Moose::PrimaryPrimary:
    1249    28563712 :       switch (_model)
    1250             :       {
    1251    23756768 :         case ContactModel::FRICTIONLESS:
    1252    23756768 :           switch (_formulation)
    1253             :           {
    1254             :             case ContactFormulation::KINEMATIC:
    1255             :               return 0.0;
    1256             : 
    1257     5838752 :             case ContactFormulation::PENALTY:
    1258             :             case ContactFormulation::AUGMENTED_LAGRANGE:
    1259     5838752 :               return _test_primary[_i][_qp] * penalty * _phi_primary[_j][_qp] *
    1260     5838752 :                      pinfo->_normal(_component) * pinfo->_normal(_component);
    1261             : 
    1262           0 :             default:
    1263           0 :               mooseError("Invalid contact formulation");
    1264             :           }
    1265             : 
    1266     4806944 :         case ContactModel::COULOMB:
    1267             :         case ContactModel::GLUED:
    1268     4806944 :           switch (_formulation)
    1269             :           {
    1270             :             case ContactFormulation::KINEMATIC:
    1271             :               return 0.0;
    1272             : 
    1273     1818880 :             case ContactFormulation::PENALTY:
    1274             :             {
    1275     1818880 :               if (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
    1276             :                   pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION)
    1277      197808 :                 return _test_primary[_i][_qp] * penalty * _phi_primary[_j][_qp] *
    1278      197808 :                        pinfo->_normal(_component) * pinfo->_normal(_component);
    1279             :               else
    1280     1621072 :                 return _test_primary[_i][_qp] * penalty * _phi_primary[_j][_qp];
    1281             :             }
    1282             : 
    1283      199168 :             case ContactFormulation::TANGENTIAL_PENALTY:
    1284             :             {
    1285             :               Real tang_comp = 0.0;
    1286      199168 :               if (pinfo->_mech_status == PenetrationInfo::MS_STICKING)
    1287        1728 :                 tang_comp = _test_primary[_i][_qp] * penalty * _phi_primary[_j][_qp] *
    1288        1728 :                             (1.0 - pinfo->_normal(_component) * pinfo->_normal(_component));
    1289             :               return tang_comp; // normal component is zero
    1290             :             }
    1291             : 
    1292     1467760 :             case ContactFormulation::AUGMENTED_LAGRANGE:
    1293             :             {
    1294     1467760 :               Real normal_comp = _phi_primary[_j][_qp] * penalty * _test_primary[_i][_qp] *
    1295     1467760 :                                  pinfo->_normal(_component) * pinfo->_normal(_component);
    1296             : 
    1297             :               Real tang_comp = 0.0;
    1298     1467760 :               if (pinfo->_mech_status == PenetrationInfo::MS_STICKING)
    1299      533120 :                 tang_comp = _phi_primary[_j][_qp] * penalty_slip * _test_primary[_i][_qp] *
    1300      533120 :                             (1.0 - pinfo->_normal(_component) * pinfo->_normal(_component));
    1301     1467760 :               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    13095784 : MechanicalContactConstraint::computeQpOffDiagJacobian(Moose::ConstraintJacobianType type,
    1318             :                                                       unsigned int jvar)
    1319             : {
    1320    13095784 :   PenetrationInfo * pinfo = _penetration_locator._penetration_info[_current_node->id()];
    1321             : 
    1322    13095784 :   const Real penalty = getPenalty(*_current_node);
    1323    13095784 :   const Real penalty_slip = getTangentialPenalty(*_current_node);
    1324             : 
    1325             :   unsigned int coupled_component;
    1326             :   Real normal_component_in_coupled_var_dir = 1.0;
    1327    13095784 :   if (getCoupledVarComponent(jvar, coupled_component))
    1328    13095784 :     normal_component_in_coupled_var_dir = pinfo->_normal(coupled_component);
    1329             : 
    1330    13095784 :   switch (type)
    1331             :   {
    1332           0 :     default:
    1333           0 :       mooseError("Unhandled ConstraintJacobianType");
    1334             : 
    1335      615816 :     case Moose::SecondarySecondary:
    1336      615816 :       switch (_model)
    1337             :       {
    1338      517408 :         case ContactModel::FRICTIONLESS:
    1339      517408 :           switch (_formulation)
    1340             :           {
    1341             :             case ContactFormulation::KINEMATIC:
    1342             :             {
    1343             :               RealVectorValue jac_vec;
    1344     1128600 :               for (unsigned int i = 0; i < _mesh_dimension; ++i)
    1345             :               {
    1346      839304 :                 dof_id_type dof_number = _current_node->dof_number(0, _vars[i], 0);
    1347      839304 :                 jac_vec(i) = (*_jacobian)(dof_number, _connected_dof_indices[_j]) /
    1348      839304 :                              _var_objects[i]->scalingFactor();
    1349             :               }
    1350      289296 :               return -pinfo->_normal(_component) * (pinfo->_normal * jac_vec) +
    1351      289296 :                      (_phi_secondary[_j][_qp] * penalty * _test_secondary[_i][_qp]) *
    1352      289296 :                          pinfo->_normal(_component) * normal_component_in_coupled_var_dir;
    1353             :             }
    1354             : 
    1355      228112 :             case ContactFormulation::PENALTY:
    1356             :             case ContactFormulation::AUGMENTED_LAGRANGE:
    1357      228112 :               return _phi_secondary[_j][_qp] * penalty * _test_secondary[_i][_qp] *
    1358      228112 :                      pinfo->_normal(_component) * normal_component_in_coupled_var_dir;
    1359             : 
    1360           0 :             default:
    1361           0 :               mooseError("Invalid contact formulation");
    1362             :           }
    1363             : 
    1364       98408 :         case ContactModel::COULOMB:
    1365             :         {
    1366       98408 :           if ((_formulation == ContactFormulation::KINEMATIC ||
    1367       89152 :                _formulation == ContactFormulation::TANGENTIAL_PENALTY) &&
    1368       89152 :               (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
    1369             :                pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION))
    1370             :           {
    1371             :             RealVectorValue jac_vec;
    1372      264864 :             for (unsigned int i = 0; i < _mesh_dimension; ++i)
    1373             :             {
    1374      176576 :               dof_id_type dof_number = _current_node->dof_number(0, _vars[i], 0);
    1375      176576 :               jac_vec(i) = (*_jacobian)(dof_number, _connected_dof_indices[_j]) /
    1376      176576 :                            _var_objects[i]->scalingFactor();
    1377             :             }
    1378             : 
    1379       88288 :             return -pinfo->_normal(_component) * (pinfo->_normal * jac_vec) +
    1380       88288 :                    (_phi_secondary[_j][_qp] * penalty * _test_secondary[_i][_qp]) *
    1381       88288 :                        pinfo->_normal(_component) * normal_component_in_coupled_var_dir;
    1382             :           }
    1383       10120 :           else if ((_formulation == ContactFormulation::PENALTY) &&
    1384        9256 :                    (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
    1385             :                     pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION))
    1386         792 :             return _phi_secondary[_j][_qp] * penalty * _test_secondary[_i][_qp] *
    1387         792 :                    pinfo->_normal(_component) * normal_component_in_coupled_var_dir;
    1388        9328 :           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        9328 :             const Real curr_jac = (*_jacobian)(_current_node->dof_number(0, _vars[_component], 0),
    1402        9328 :                                                _connected_dof_indices[_j]);
    1403        9328 :             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      454144 :     case Moose::SecondaryPrimary:
    1418      454144 :       switch (_model)
    1419             :       {
    1420      377840 :         case ContactModel::FRICTIONLESS:
    1421      377840 :           switch (_formulation)
    1422             :           {
    1423      218176 :             case ContactFormulation::KINEMATIC:
    1424             :             {
    1425      218176 :               const Node * curr_primary_node = _current_primary->node_ptr(_j);
    1426             : 
    1427             :               RealVectorValue jac_vec;
    1428      849648 :               for (unsigned int i = 0; i < _mesh_dimension; ++i)
    1429             :               {
    1430      631472 :                 dof_id_type dof_number = _current_node->dof_number(0, _vars[i], 0);
    1431     1262944 :                 jac_vec(i) = (*_jacobian)(dof_number,
    1432      631472 :                                           curr_primary_node->dof_number(0, _vars[_component], 0)) /
    1433      631472 :                              _var_objects[i]->scalingFactor();
    1434             :               }
    1435      218176 :               return -pinfo->_normal(_component) * (pinfo->_normal * jac_vec) -
    1436      218176 :                      (_phi_primary[_j][_qp] * penalty * _test_secondary[_i][_qp]) *
    1437      218176 :                          pinfo->_normal(_component) * normal_component_in_coupled_var_dir;
    1438             :             }
    1439             : 
    1440      159664 :             case ContactFormulation::PENALTY:
    1441             :             case ContactFormulation::AUGMENTED_LAGRANGE:
    1442      159664 :               return -_phi_primary[_j][_qp] * penalty * _test_secondary[_i][_qp] *
    1443      159664 :                      pinfo->_normal(_component) * normal_component_in_coupled_var_dir;
    1444             : 
    1445           0 :             default:
    1446           0 :               mooseError("Invalid contact formulation");
    1447             :           }
    1448             : 
    1449       76304 :         case ContactModel::COULOMB:
    1450       76304 :           if ((_formulation == ContactFormulation::KINEMATIC ||
    1451       70240 :                _formulation == ContactFormulation::TANGENTIAL_PENALTY) &&
    1452       70240 :               (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
    1453             :                pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION))
    1454             :           {
    1455       69592 :             const Node * curr_primary_node = _current_primary->node_ptr(_j);
    1456             : 
    1457             :             RealVectorValue jac_vec;
    1458      208776 :             for (unsigned int i = 0; i < _mesh_dimension; ++i)
    1459             :             {
    1460      139184 :               dof_id_type dof_number = _current_node->dof_number(0, _vars[i], 0);
    1461      139184 :               jac_vec(i) =
    1462      139184 :                   (*_jacobian)(dof_number, curr_primary_node->dof_number(0, _vars[_component], 0)) /
    1463      139184 :                   _var_objects[i]->scalingFactor();
    1464             :             }
    1465             : 
    1466       69592 :             return -pinfo->_normal(_component) * (pinfo->_normal * jac_vec) -
    1467       69592 :                    (_phi_primary[_j][_qp] * penalty * _test_secondary[_i][_qp]) *
    1468       69592 :                        pinfo->_normal(_component) * normal_component_in_coupled_var_dir;
    1469             :           }
    1470        6712 :           else if ((_formulation == ContactFormulation::PENALTY) &&
    1471        6064 :                    (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
    1472             :                     pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION))
    1473         528 :             return -_phi_primary[_j][_qp] * penalty * _test_secondary[_i][_qp] *
    1474         528 :                    pinfo->_normal(_component) * normal_component_in_coupled_var_dir;
    1475        6184 :           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     6931360 :     case Moose::PrimarySecondary:
    1497     6931360 :       switch (_model)
    1498             :       {
    1499     6537728 :         case ContactModel::FRICTIONLESS:
    1500     6537728 :           switch (_formulation)
    1501             :           {
    1502             :             case ContactFormulation::KINEMATIC:
    1503             :             {
    1504             :               RealVectorValue jac_vec;
    1505    20496000 :               for (unsigned int i = 0; i < _mesh_dimension; ++i)
    1506             :               {
    1507    15331520 :                 dof_id_type dof_number = _current_node->dof_number(0, _vars[i], 0);
    1508    15331520 :                 jac_vec(i) = (*_jacobian)(dof_number, _connected_dof_indices[_j]) /
    1509    15331520 :                              _var_objects[i]->scalingFactor();
    1510             :               }
    1511     5164480 :               return pinfo->_normal(_component) * (pinfo->_normal * jac_vec) *
    1512     5164480 :                      _test_primary[_i][_qp];
    1513             :             }
    1514             : 
    1515     1373248 :             case ContactFormulation::PENALTY:
    1516             :             case ContactFormulation::AUGMENTED_LAGRANGE:
    1517     1373248 :               return -_test_primary[_i][_qp] * penalty * _phi_secondary[_j][_qp] *
    1518     1373248 :                      pinfo->_normal(_component) * normal_component_in_coupled_var_dir;
    1519             : 
    1520           0 :             default:
    1521           0 :               mooseError("Invalid contact formulation");
    1522             :           }
    1523      393632 :         case ContactModel::COULOMB:
    1524      393632 :           switch (_formulation)
    1525             :           {
    1526      128336 :             case ContactFormulation::KINEMATIC:
    1527             :             {
    1528      128336 :               if (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
    1529             :                   pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION)
    1530             :               {
    1531             :                 RealVectorValue jac_vec;
    1532      380256 :                 for (unsigned int i = 0; i < _mesh_dimension; ++i)
    1533             :                 {
    1534      253504 :                   dof_id_type dof_number = _current_node->dof_number(0, _vars[i], 0);
    1535      253504 :                   jac_vec(i) = (*_jacobian)(dof_number, _connected_dof_indices[_j]) /
    1536      253504 :                                _var_objects[i]->scalingFactor();
    1537             :                 }
    1538      126752 :                 return pinfo->_normal(_component) * (pinfo->_normal * jac_vec) *
    1539      126752 :                        _test_primary[_i][_qp];
    1540             :               }
    1541             :               else
    1542             :               {
    1543             :                 const Real secondary_jac =
    1544        1584 :                     (*_jacobian)(_current_node->dof_number(0, _vars[_component], 0),
    1545        1584 :                                  _connected_dof_indices[_j]) /
    1546        1584 :                     _var.scalingFactor();
    1547        1584 :                 return secondary_jac * _test_primary[_i][_qp];
    1548             :               }
    1549             :             }
    1550             : 
    1551       37024 :             case ContactFormulation::PENALTY:
    1552             :             {
    1553       37024 :               if (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
    1554             :                   pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION)
    1555        3168 :                 return -_test_primary[_i][_qp] * penalty * _phi_secondary[_j][_qp] *
    1556        3168 :                        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      228272 :             case ContactFormulation::TANGENTIAL_PENALTY:
    1572             :             {
    1573      228272 :               if (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
    1574             :                   pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION)
    1575             :               {
    1576             :                 RealVectorValue jac_vec;
    1577      679200 :                 for (unsigned int i = 0; i < _mesh_dimension; ++i)
    1578             :                 {
    1579      452800 :                   dof_id_type dof_number = _current_node->dof_number(0, _vars[i], 0);
    1580      452800 :                   jac_vec(i) = (*_jacobian)(dof_number, _connected_dof_indices[_j]) /
    1581      452800 :                                _var_objects[i]->scalingFactor();
    1582             :                 }
    1583      226400 :                 return pinfo->_normal(_component) * (pinfo->_normal * jac_vec) *
    1584      226400 :                        _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     5094464 :     case Moose::PrimaryPrimary:
    1619     5094464 :       switch (_model)
    1620             :       {
    1621     4789248 :         case ContactModel::FRICTIONLESS:
    1622     4789248 :           switch (_formulation)
    1623             :           {
    1624             :             case ContactFormulation::KINEMATIC:
    1625             :               return 0.0;
    1626             : 
    1627      915136 :             case ContactFormulation::PENALTY:
    1628             :             case ContactFormulation::AUGMENTED_LAGRANGE:
    1629      915136 :               return _test_primary[_i][_qp] * penalty * _phi_primary[_j][_qp] *
    1630      915136 :                      pinfo->_normal(_component) * normal_component_in_coupled_var_dir;
    1631             : 
    1632           0 :             default:
    1633           0 :               mooseError("Invalid contact formulation");
    1634             :           }
    1635             : 
    1636      305216 :         case ContactModel::COULOMB:
    1637             :         {
    1638      305216 :           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      305216 :           else if (_formulation == ContactFormulation::PENALTY &&
    1650       24256 :                    (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
    1651             :                     pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION))
    1652        2112 :             return _test_primary[_i][_qp] * penalty * _phi_primary[_j][_qp] *
    1653        2112 :                    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     2526663 : MechanicalContactConstraint::gapOffset(const Node & node)
    1688             : {
    1689             :   Real val = 0;
    1690             : 
    1691     2526663 :   if (_has_secondary_gap_offset)
    1692       95202 :     val += _secondary_gap_offset_var->getNodalValue(node);
    1693             : 
    1694     2526663 :   if (_has_mapped_primary_gap_offset)
    1695       95202 :     val += _mapped_primary_gap_offset_var->getNodalValue(node);
    1696             : 
    1697     2526663 :   return val;
    1698             : }
    1699             : 
    1700             : Real
    1701    38608901 : MechanicalContactConstraint::nodalArea(const Node & node)
    1702             : {
    1703    38608901 :   dof_id_type dof = node.dof_number(_aux_system.number(), _nodal_area_var->number(), 0);
    1704             : 
    1705    38608901 :   Real area = (*_aux_solution)(dof);
    1706    38608901 :   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    38608901 :   return area;
    1715             : }
    1716             : 
    1717             : Real
    1718    88717044 : MechanicalContactConstraint::getPenalty(const Node & node)
    1719             : {
    1720    88717044 :   Real penalty = _penalty;
    1721    88717044 :   if (_normalize_penalty)
    1722    19308376 :     penalty *= nodalArea(node);
    1723    88717044 :   return penalty * MathUtils::pow(_penalty_multiplier, _lagrangian_iteration_number);
    1724             : }
    1725             : 
    1726             : Real
    1727    87521134 : MechanicalContactConstraint::getTangentialPenalty(const Node & node)
    1728             : {
    1729    87521134 :   Real penalty = _penalty_tangential;
    1730    87521134 :   if (_normalize_penalty)
    1731    19223405 :     penalty *= nodalArea(node);
    1732             : 
    1733    87521134 :   return penalty * MathUtils::pow(_penalty_multiplier, _lagrangian_iteration_number);
    1734             : }
    1735             : 
    1736             : void
    1737      188647 : MechanicalContactConstraint::computeJacobian()
    1738             : {
    1739      188647 :   getConnectedDofIndices(_var.number());
    1740             : 
    1741      188647 :   prepareMatrixTagNeighbor(
    1742      188647 :       _assembly, _primary_var.number(), _var.number(), Moose::NeighborNeighbor, _Knn);
    1743             : 
    1744      188647 :   _Kee.resize(_test_secondary.size(), _connected_dof_indices.size());
    1745             : 
    1746      377294 :   for (_i = 0; _i < _test_secondary.size(); _i++)
    1747             :     // Loop over the connected dof indices so we can get all the jacobian contributions
    1748     2753552 :     for (_j = 0; _j < _connected_dof_indices.size(); _j++)
    1749     2564905 :       _Kee(_i, _j) += computeQpJacobian(Moose::SecondarySecondary);
    1750             : 
    1751      188647 :   if (_primary_secondary_jacobian)
    1752             :   {
    1753      185617 :     prepareMatrixTagNeighbor(_assembly, _var.number(), _var.number(), Moose::ElementNeighbor, _Ken);
    1754      185617 :     if (_Ken.m() && _Ken.n())
    1755             :     {
    1756      371234 :       for (_i = 0; _i < _test_secondary.size(); _i++)
    1757     2014665 :         for (_j = 0; _j < _phi_primary.size(); _j++)
    1758     1829048 :           _Ken(_i, _j) += computeQpJacobian(Moose::SecondaryPrimary);
    1759      185617 :       accumulateTaggedLocalMatrix(
    1760      185617 :           _assembly, _var.number(), _var.number(), Moose::ElementNeighbor, _Ken);
    1761             :     }
    1762             : 
    1763      185617 :     _Kne.resize(_test_primary.size(), _connected_dof_indices.size());
    1764     2014665 :     for (_i = 0; _i < _test_primary.size(); _i++)
    1765             :       // Loop over the connected dof indices so we can get all the jacobian contributions
    1766    42394196 :       for (_j = 0; _j < _connected_dof_indices.size(); _j++)
    1767    40565148 :         _Kne(_i, _j) += computeQpJacobian(Moose::PrimarySecondary);
    1768             :   }
    1769             : 
    1770      188647 :   if (_Knn.m() && _Knn.n())
    1771             :   {
    1772     2041935 :     for (_i = 0; _i < _test_primary.size(); _i++)
    1773    30417000 :       for (_j = 0; _j < _phi_primary.size(); _j++)
    1774    28563712 :         _Knn(_i, _j) += computeQpJacobian(Moose::PrimaryPrimary);
    1775      188647 :     accumulateTaggedLocalMatrix(
    1776      188647 :         _assembly, _primary_var.number(), _var.number(), Moose::NeighborNeighbor, _Knn);
    1777             :   }
    1778      188647 : }
    1779             : 
    1780             : void
    1781       65750 : MechanicalContactConstraint::computeOffDiagJacobian(const unsigned int jvar_num)
    1782             : {
    1783       65750 :   getConnectedDofIndices(jvar_num);
    1784             : 
    1785       65750 :   _Kee.resize(_test_secondary.size(), _connected_dof_indices.size());
    1786             : 
    1787       65750 :   prepareMatrixTagNeighbor(
    1788       65750 :       _assembly, _primary_var.number(), jvar_num, Moose::NeighborNeighbor, _Knn);
    1789             : 
    1790      131500 :   for (_i = 0; _i < _test_secondary.size(); _i++)
    1791             :     // Loop over the connected dof indices so we can get all the jacobian contributions
    1792      681566 :     for (_j = 0; _j < _connected_dof_indices.size(); _j++)
    1793      615816 :       _Kee(_i, _j) += computeQpOffDiagJacobian(Moose::SecondarySecondary, jvar_num);
    1794             : 
    1795       65750 :   if (_primary_secondary_jacobian)
    1796             :   {
    1797       65750 :     prepareMatrixTagNeighbor(_assembly, _var.number(), jvar_num, Moose::ElementNeighbor, _Ken);
    1798      131500 :     for (_i = 0; _i < _test_secondary.size(); _i++)
    1799      519894 :       for (_j = 0; _j < _phi_primary.size(); _j++)
    1800      454144 :         _Ken(_i, _j) += computeQpOffDiagJacobian(Moose::SecondaryPrimary, jvar_num);
    1801       65750 :     accumulateTaggedLocalMatrix(_assembly, _var.number(), jvar_num, Moose::ElementNeighbor, _Ken);
    1802             : 
    1803       65750 :     _Kne.resize(_test_primary.size(), _connected_dof_indices.size());
    1804       65750 :     if (_Kne.m() && _Kne.n())
    1805      519894 :       for (_i = 0; _i < _test_primary.size(); _i++)
    1806             :         // Loop over the connected dof indices so we can get all the jacobian contributions
    1807     7385504 :         for (_j = 0; _j < _connected_dof_indices.size(); _j++)
    1808     6931360 :           _Kne(_i, _j) += computeQpOffDiagJacobian(Moose::PrimarySecondary, jvar_num);
    1809             :   }
    1810             : 
    1811      519894 :   for (_i = 0; _i < _test_primary.size(); _i++)
    1812     5548608 :     for (_j = 0; _j < _phi_primary.size(); _j++)
    1813     5094464 :       _Knn(_i, _j) += computeQpOffDiagJacobian(Moose::PrimaryPrimary, jvar_num);
    1814       65750 :   accumulateTaggedLocalMatrix(
    1815       65750 :       _assembly, _primary_var.number(), jvar_num, Moose::NeighborNeighbor, _Knn);
    1816       65750 : }
    1817             : 
    1818             : void
    1819      254397 : MechanicalContactConstraint::getConnectedDofIndices(unsigned int var_num)
    1820             : {
    1821             :   unsigned int component;
    1822      254397 :   if (getCoupledVarComponent(var_num, component) || _non_displacement_vars_jacobian)
    1823             :   {
    1824      254397 :     if (_primary_secondary_jacobian && _connected_secondary_nodes_jacobian)
    1825      251367 :       NodeFaceConstraint::getConnectedDofIndices(var_num);
    1826             :     else
    1827             :     {
    1828        3030 :       _connected_dof_indices.clear();
    1829        3030 :       MooseVariableFEBase & var = _sys.getVariable(0, var_num);
    1830        3030 :       _connected_dof_indices.push_back(var.nodalDofIndex());
    1831             :     }
    1832             :   }
    1833             : 
    1834      254397 :   _phi_secondary.resize(_connected_dof_indices.size());
    1835             : 
    1836      254397 :   dof_id_type current_node_var_dof_index = _sys.getVariable(0, var_num).nodalDofIndex();
    1837      254397 :   _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     3435118 :   for (unsigned int j = 0; j < _connected_dof_indices.size(); j++)
    1843             :   {
    1844     3180721 :     _phi_secondary[j].resize(1);
    1845             : 
    1846     3180721 :     if (_connected_dof_indices[j] == current_node_var_dof_index)
    1847      254397 :       _phi_secondary[j][_qp] = 1.0;
    1848             :     else
    1849     2926324 :       _phi_secondary[j][_qp] = 0.0;
    1850             :   }
    1851      254397 : }
    1852             : 
    1853             : bool
    1854    13350181 : MechanicalContactConstraint::getCoupledVarComponent(unsigned int var_num, unsigned int & component)
    1855             : {
    1856    13350181 :   component = std::numeric_limits<unsigned int>::max();
    1857             :   bool coupled_var_is_disp_var = false;
    1858    25509339 :   for (const auto i : make_range(Moose::dim))
    1859             :   {
    1860    25509339 :     if (var_num == _vars[i])
    1861             :     {
    1862             :       coupled_var_is_disp_var = true;
    1863    13350181 :       component = i;
    1864    13350181 :       break;
    1865             :     }
    1866             :   }
    1867             : 
    1868    13350181 :   return coupled_var_is_disp_var;
    1869             : }
    1870             : 
    1871             : void
    1872       79814 : MechanicalContactConstraint::residualEnd()
    1873             : {
    1874       79814 :   if (_component == 0 && (_print_contact_nodes || _contact_linesearch))
    1875             :   {
    1876          86 :     _communicator.set_union(_current_contact_state);
    1877          86 :     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          86 :     if (_contact_linesearch)
    1887          86 :       _contact_linesearch->insertSet(_current_contact_state);
    1888             :     _old_contact_state.swap(_current_contact_state);
    1889             :     _current_contact_state.clear();
    1890             :   }
    1891       79814 : }

Generated by: LCOV version 1.14