12 #include "FEProblem.h"
13 #include "DisplacedProblem.h"
14 #include "AuxiliarySystem.h"
15 #include "PenetrationLocator.h"
16 #include "NearestNodeLocator.h"
17 #include "SystemBase.h"
19 #include "MooseMesh.h"
21 #include "Executioner.h"
22 #include "AddVariableAction.h"
26 #include "libmesh/string_to_enum.h"
27 #include "libmesh/sparse_matrix.h"
35 InputParameters params = validParams<NodeFaceConstraint>();
38 params.addRequiredParam<BoundaryName>(
"boundary",
"The master boundary");
39 params.addRequiredParam<BoundaryName>(
"slave",
"The slave boundary");
40 params.addRequiredParam<
unsigned int>(
"component",
41 "An integer corresponding to the direction "
42 "the variable this kernel acts in. (0 for x, "
45 params.addCoupledVar(
"disp_x",
"The x displacement");
46 params.addCoupledVar(
"disp_y",
"The y displacement");
47 params.addCoupledVar(
"disp_z",
"The z displacement");
51 "The displacements appropriate for the simulation geometry and coordinate system");
53 params.addRequiredCoupledVar(
"nodal_area",
"The nodal area");
55 params.set<
bool>(
"use_displaced_mesh") =
true;
56 params.addParam<Real>(
59 "The penalty to apply. This can vary depending on the stiffness of your materials");
60 params.addParam<Real>(
"friction_coefficient", 0,
"The friction coefficient");
61 params.addParam<Real>(
"tangential_tolerance",
62 "Tangential distance to extend edges of contact surfaces");
63 params.addParam<Real>(
64 "capture_tolerance", 0,
"Normal distance from surface within which nodes are captured");
66 params.addParam<Real>(
"tension_release",
68 "Tension release threshold. A node in contact "
69 "will not be released if its tensile load is below "
70 "this value. No tension release if negative.");
72 params.addParam<
bool>(
75 "Whether to normalize the penalty parameter with the nodal area for penalty contact.");
76 params.addParam<
bool>(
"master_slave_jacobian",
78 "Whether to include jacobian entries coupling master and slave nodes.");
79 params.addParam<
bool>(
80 "connected_slave_nodes_jacobian",
82 "Whether to include jacobian entries coupling nodes connected to slave nodes.");
83 params.addParam<
bool>(
"non_displacement_variables_jacobian",
85 "Whether to include jacobian entries coupling with variables that are not "
86 "displacement variables.");
87 params.addParam<
unsigned int>(
"stick_lock_iterations",
88 std::numeric_limits<unsigned int>::max(),
89 "Number of times permitted to switch between sticking and slipping "
90 "in a solution before locking node in a sticked state.");
91 params.addParam<Real>(
"stick_unlock_factor",
93 "Factor by which frictional capacity must be "
94 "exceeded to permit stick-locked node to slip "
96 params.addParam<Real>(
"al_penetration_tolerance",
97 "The tolerance of the penetration for augmented Lagrangian method.");
98 params.addParam<Real>(
"al_incremental_slip_tolerance",
99 "The tolerance of the incremental slip for augmented Lagrangian method.");
101 params.addParam<Real>(
"al_frictional_force_tolerance",
102 "The tolerance of the frictional force for augmented Lagrangian method.");
103 params.addParam<
bool>(
104 "print_contact_nodes",
false,
"Whether to print the number of nodes in contact.");
111 : NodeFaceConstraint(parameters),
112 _displaced_problem(parameters.get<FEProblemBase *>(
"_fe_problem_base")->getDisplacedProblem()),
113 _component(getParam<unsigned int>(
"component")),
114 _model(getParam<MooseEnum>(
"model").getEnum<
ContactModel>()),
116 _normalize_penalty(getParam<bool>(
"normalize_penalty")),
117 _penalty(getParam<Real>(
"penalty")),
118 _friction_coefficient(getParam<Real>(
"friction_coefficient")),
119 _tension_release(getParam<Real>(
"tension_release")),
120 _capture_tolerance(getParam<Real>(
"capture_tolerance")),
121 _stick_lock_iterations(getParam<unsigned int>(
"stick_lock_iterations")),
122 _stick_unlock_factor(getParam<Real>(
"stick_unlock_factor")),
123 _update_stateful_data(true),
124 _residual_copy(_sys.residualGhosted()),
125 _mesh_dimension(_mesh.dimension()),
126 _vars(3,
libMesh::invalid_uint),
127 _var_objects(3, nullptr),
128 _nodal_area_var(getVar(
"nodal_area", 0)),
129 _aux_system(_nodal_area_var->sys()),
130 _aux_solution(_aux_system.currentSolution()),
131 _master_slave_jacobian(getParam<bool>(
"master_slave_jacobian")),
132 _connected_slave_nodes_jacobian(getParam<bool>(
"connected_slave_nodes_jacobian")),
133 _non_displacement_vars_jacobian(getParam<bool>(
"non_displacement_variables_jacobian")),
135 _print_contact_nodes(getParam<bool>(
"print_contact_nodes"))
137 _overwrite_slave_residual =
false;
139 if (isParamValid(
"displacements"))
142 for (
unsigned int i = 0; i < coupledComponents(
"displacements"); ++i)
144 _vars[i] = coupled(
"displacements", i);
151 if (isParamValid(
"disp_x"))
153 _vars[0] = coupled(
"disp_x");
156 if (isParamValid(
"disp_y"))
158 _vars[1] = coupled(
"disp_y");
161 if (isParamValid(
"disp_z"))
163 _vars[2] = coupled(
"disp_z");
167 mooseDeprecated(
"use the `displacements` parameter rather than the `disp_*` parameters (those "
168 "will go away with the deprecation of the Solid Mechanics module).");
171 if (parameters.isParamValid(
"tangential_tolerance"))
172 _penetration_locator.setTangentialTolerance(getParam<Real>(
"tangential_tolerance"));
174 if (parameters.isParamValid(
"normal_smoothing_distance"))
175 _penetration_locator.setNormalSmoothingDistance(getParam<Real>(
"normal_smoothing_distance"));
177 if (parameters.isParamValid(
"normal_smoothing_method"))
178 _penetration_locator.setNormalSmoothingMethod(
179 parameters.get<std::string>(
"normal_smoothing_method"));
182 mooseError(
"The 'tangential_penalty' formulation can only be used with the 'coulomb' model");
185 _penetration_locator.setUpdate(
false);
188 mooseError(
"The friction coefficient must be nonnegative");
196 mooseError(
"The Augmented Lagrangian contact formulation does not support GLUED case.");
198 FEProblemBase * fe_problem = getParam<FEProblemBase *>(
"_fe_problem_base");
199 if (dynamic_cast<AugmentedLagrangianContactProblem *>(fe_problem) == NULL)
200 mooseError(
"The Augmented Lagrangian contact formulation must use "
201 "AugmentedLagrangianContactProblem.");
203 if (!parameters.isParamValid(
"al_penetration_tolerance"))
204 mooseError(
"For Augmented Lagrangian contact, al_penetration_tolerance must be provided.");
210 if (!parameters.isParamValid(
"al_incremental_slip_tolerance") ||
211 !parameters.isParamValid(
"al_frictional_force_tolerance"))
213 mooseError(
"For the Augmented Lagrangian frictional contact formualton, "
214 "al_incremental_slip_tolerance and "
215 "al_frictional_force_tolerance must be provided.");
256 for (
auto & pinfo_pair : _penetration_locator._penetration_info)
258 const dof_id_type slave_node_num = pinfo_pair.first;
259 PenetrationInfo * pinfo = pinfo_pair.second;
261 if (!pinfo || pinfo->_node->n_comp(_sys.number(),
_vars[
_component]) < 1)
264 const Real distance = pinfo->_normal * (pinfo->_closest_point - _mesh.nodeRef(slave_node_num));
268 pinfo->_lagrange_multiplier_slip.zero();
269 if (pinfo->isCaptured())
270 pinfo->_mech_status = PenetrationInfo::MS_STICKING;
273 if (pinfo->isCaptured())
276 pinfo->_lagrange_multiplier -=
getPenalty(*pinfo) * distance;
280 if (!beginning_of_step)
283 RealVectorValue pen_force_normal =
284 penalty * (-distance) * pinfo->_normal + pinfo->_lagrange_multiplier * pinfo->_normal;
287 pinfo->_lagrange_multiplier += penalty * (-distance);
291 ? -pen_force_normal * pinfo->_normal
294 RealVectorValue tangential_inc_slip =
295 pinfo->_incremental_slip -
296 (pinfo->_incremental_slip * pinfo->_normal) * pinfo->_normal;
300 RealVectorValue inc_pen_force_tangential =
301 pinfo->_lagrange_multiplier_slip + penalty_slip * tangential_inc_slip;
303 RealVectorValue tau_old = pinfo->_contact_force_old -
304 pinfo->_normal * (pinfo->_normal * pinfo->_contact_force_old);
306 RealVectorValue contact_force_tangential = inc_pen_force_tangential + tau_old;
307 const Real tan_mag(contact_force_tangential.norm());
311 pinfo->_lagrange_multiplier_slip =
312 -tau_old + capacity * contact_force_tangential / tan_mag;
313 if (MooseUtils::absoluteFuzzyEqual(capacity, 0.0))
314 pinfo->_mech_status = PenetrationInfo::MS_SLIPPING;
316 pinfo->_mech_status = PenetrationInfo::MS_SLIPPING_FRICTION;
320 pinfo->_mech_status = PenetrationInfo::MS_STICKING;
321 pinfo->_lagrange_multiplier_slip += penalty_slip * tangential_inc_slip;
332 Real contactResidual = 0.0;
333 unsigned int converged = 0;
335 for (
auto & pinfo_pair : _penetration_locator._penetration_info)
337 const dof_id_type slave_node_num = pinfo_pair.first;
338 PenetrationInfo * pinfo = pinfo_pair.second;
341 if (!pinfo || pinfo->_node->n_comp(_sys.number(),
_vars[
_component]) < 1)
344 const Real distance = pinfo->_normal * (pinfo->_closest_point - _mesh.nodeRef(slave_node_num));
346 if (pinfo->isCaptured())
348 if (contactResidual < std::abs(distance))
349 contactResidual = std::abs(distance);
360 RealVectorValue contact_force_normal((pinfo->_contact_force * pinfo->_normal) *
362 RealVectorValue contact_force_tangential(pinfo->_contact_force - contact_force_normal);
364 RealVectorValue tangential_inc_slip =
365 pinfo->_incremental_slip - (pinfo->_incremental_slip * pinfo->_normal) * pinfo->_normal;
367 const Real tan_mag(contact_force_tangential.norm());
368 const Real tangential_inc_slip_mag = tangential_inc_slip.norm();
370 RealVectorValue distance_vec =
371 (pinfo->_normal * (_mesh.nodeRef(slave_node_num) - pinfo->_closest_point)) *
375 RealVectorValue pen_force_normal =
376 penalty * distance_vec + pinfo->_lagrange_multiplier * pinfo->_normal;
380 ? -pen_force_normal * pinfo->_normal
384 if (MooseUtils::absoluteFuzzyLessThan(tan_mag, capacity) &&
385 pinfo->_mech_status == PenetrationInfo::MS_STICKING)
387 if (MooseUtils::absoluteFuzzyGreaterThan(tangential_inc_slip_mag,
406 _communicator.max(converged);
410 <<
"The Augmented Lagrangian contact tangential sliding enforcement is NOT satisfied \n";
411 else if (converged == 2)
413 <<
"The Augmented Lagrangian contact tangential sliding enforcement is NOT satisfied \n";
414 else if (converged == 3)
415 _console <<
"The Augmented Lagrangian contact frictional force enforcement is NOT satisfied \n";
425 for (
auto & pinfo_pair : _penetration_locator._penetration_info)
427 PenetrationInfo * pinfo = pinfo_pair.second;
430 if (!pinfo || pinfo->_node->n_comp(_sys.number(),
_vars[
_component]) < 1)
433 if (beginning_of_step)
435 if (_app.getExecutioner()->lastSolveConverged())
437 pinfo->_contact_force_old = pinfo->_contact_force;
438 pinfo->_accumulated_slip_old = pinfo->_accumulated_slip;
439 pinfo->_frictional_energy_old = pinfo->_frictional_energy;
440 pinfo->_mech_status_old = pinfo->_mech_status;
442 else if (pinfo->_mech_status_old == PenetrationInfo::MS_NO_CONTACT &&
443 pinfo->_mech_status != PenetrationInfo::MS_NO_CONTACT)
446 delete pinfo_pair.second;
447 pinfo_pair.second = NULL;
451 pinfo->_locked_this_step = 0;
452 pinfo->_stick_locked_this_step = 0;
453 pinfo->_starting_elem = pinfo->_elem;
454 pinfo->_starting_side_num = pinfo->_side_num;
455 pinfo->_starting_closest_point_ref = pinfo->_closest_point_ref;
457 pinfo->_incremental_slip_prev_iter = pinfo->_incremental_slip;
464 bool in_contact =
false;
466 std::map<dof_id_type, PenetrationInfo *>::iterator found =
467 _penetration_locator._penetration_info.find(_current_node->id());
468 if (found != _penetration_locator._penetration_info.end())
470 PenetrationInfo * pinfo = found->second;
473 bool is_nonlinear = _subproblem.computingNonlinearResid();
480 if (pinfo->isCaptured())
498 const Node * node = pinfo->_node;
501 RealVectorValue res_vec;
504 dof_id_type dof_number = node->dof_number(0,
_vars[i], 0);
508 RealVectorValue distance_vec(_mesh.nodeRef(node->id()) - pinfo->_closest_point);
510 const Real gap_size = -1.0 * pinfo->_normal * distance_vec;
514 bool newly_captured =
false;
517 if (update_contact_set && !pinfo->isCaptured() &&
520 newly_captured =
true;
527 ++pinfo->_locked_this_step;
530 if (!pinfo->isCaptured())
536 RealVectorValue pen_force(penalty * distance_vec);
544 pinfo->_contact_force = -pinfo->_normal * (pinfo->_normal * res_vec);
548 pinfo->_contact_force = pinfo->_normal * (pinfo->_normal * pen_force);
552 pinfo->_contact_force =
554 (pinfo->_normal * (pen_force + pinfo->_lagrange_multiplier * pinfo->_normal)));
558 mooseError(
"Invalid contact formulation");
561 pinfo->_mech_status = PenetrationInfo::MS_SLIPPING;
570 (res_vec * pinfo->_normal > 0 ? res_vec * pinfo->_normal : 0));
573 pinfo->_contact_force = -res_vec;
574 RealVectorValue contact_force_normal((pinfo->_contact_force * pinfo->_normal) *
576 RealVectorValue contact_force_tangential(pinfo->_contact_force - contact_force_normal);
578 RealVectorValue tangential_inc_slip =
579 pinfo->_incremental_slip -
580 (pinfo->_incremental_slip * pinfo->_normal) * pinfo->_normal;
583 const Real tan_mag(contact_force_tangential.norm());
584 const Real tangential_inc_slip_mag = tangential_inc_slip.norm();
585 const Real slip_tol = capacity / penalty;
586 pinfo->_slip_tol = slip_tol;
588 if ((tangential_inc_slip_mag > slip_tol || tan_mag > capacity) &&
593 pinfo->_stick_locked_this_step = 0;
597 bool slipped_too_far =
false;
598 RealVectorValue slip_inc_direction;
599 if (tangential_inc_slip_mag > slip_tol)
601 slip_inc_direction = tangential_inc_slip / tangential_inc_slip_mag;
602 Real slip_dot_tang_force = slip_inc_direction * contact_force_tangential;
603 if (slip_dot_tang_force < capacity)
604 slipped_too_far =
true;
608 pinfo->_contact_force = contact_force_normal + capacity * slip_inc_direction;
612 pinfo->_contact_force =
613 contact_force_normal + capacity * contact_force_tangential / tan_mag;
615 pinfo->_contact_force = contact_force_normal;
618 pinfo->_mech_status = PenetrationInfo::MS_SLIPPING;
620 pinfo->_mech_status = PenetrationInfo::MS_SLIPPING_FRICTION;
624 if (pinfo->_mech_status != PenetrationInfo::MS_STICKING &&
625 pinfo->_mech_status != PenetrationInfo::MS_NO_CONTACT)
626 ++pinfo->_stick_locked_this_step;
627 pinfo->_mech_status = PenetrationInfo::MS_STICKING;
634 distance_vec = pinfo->_incremental_slip +
635 (pinfo->_normal * (_mesh.nodeRef(node->id()) - pinfo->_closest_point)) *
637 pen_force = penalty * distance_vec;
643 (res_vec * pinfo->_normal > 0 ? res_vec * pinfo->_normal : 0));
646 pinfo->_contact_force =
647 pen_force + (pinfo->_contact_force_old -
648 pinfo->_normal * (pinfo->_normal * pinfo->_contact_force_old));
649 RealVectorValue contact_force_normal((pinfo->_contact_force * pinfo->_normal) *
651 RealVectorValue contact_force_tangential(pinfo->_contact_force - contact_force_normal);
654 const Real tan_mag(contact_force_tangential.norm());
656 if (tan_mag > capacity)
658 pinfo->_contact_force =
659 contact_force_normal + capacity * contact_force_tangential / tan_mag;
660 if (MooseUtils::absoluteFuzzyEqual(capacity, 0))
661 pinfo->_mech_status = PenetrationInfo::MS_SLIPPING;
663 pinfo->_mech_status = PenetrationInfo::MS_SLIPPING_FRICTION;
666 pinfo->_mech_status = PenetrationInfo::MS_STICKING;
672 distance_vec = (pinfo->_normal * (_mesh.nodeRef(node->id()) - pinfo->_closest_point)) *
675 RealVectorValue contact_force_normal =
676 penalty * distance_vec + pinfo->_lagrange_multiplier * pinfo->_normal;
678 RealVectorValue tangential_inc_slip =
679 pinfo->_incremental_slip -
680 (pinfo->_incremental_slip * pinfo->_normal) * pinfo->_normal;
682 RealVectorValue contact_force_tangential =
683 pinfo->_lagrange_multiplier_slip +
684 (pinfo->_contact_force_old -
685 pinfo->_normal * (pinfo->_normal * pinfo->_contact_force_old));
687 RealVectorValue inc_pen_force_tangential = penalty_slip * tangential_inc_slip;
689 if (pinfo->_mech_status == PenetrationInfo::MS_STICKING)
690 pinfo->_contact_force =
691 contact_force_normal + contact_force_tangential + inc_pen_force_tangential;
693 pinfo->_contact_force = contact_force_normal + contact_force_tangential;
704 RealVectorValue contact_force_normal((-res_vec * pinfo->_normal) * pinfo->_normal);
707 RealVectorValue inc_pen_force_tangential = penalty * pinfo->_incremental_slip;
708 RealVectorValue contact_force_tangential =
709 inc_pen_force_tangential +
710 (pinfo->_contact_force_old -
711 pinfo->_normal * (pinfo->_normal * pinfo->_contact_force_old));
714 const Real tan_mag(contact_force_tangential.norm());
716 if (tan_mag > capacity)
718 pinfo->_contact_force =
719 contact_force_normal + capacity * contact_force_tangential / tan_mag;
720 if (MooseUtils::absoluteFuzzyEqual(capacity, 0))
721 pinfo->_mech_status = PenetrationInfo::MS_SLIPPING;
723 pinfo->_mech_status = PenetrationInfo::MS_SLIPPING_FRICTION;
727 pinfo->_contact_force = contact_force_normal + contact_force_tangential;
728 pinfo->_mech_status = PenetrationInfo::MS_STICKING;
734 mooseError(
"Invalid contact formulation");
743 pinfo->_contact_force = -res_vec;
747 pinfo->_contact_force = pen_force;
751 pinfo->_contact_force =
752 pen_force + pinfo->_lagrange_multiplier * distance_vec / distance_vec.norm();
756 mooseError(
"Invalid contact formulation");
759 pinfo->_mech_status = PenetrationInfo::MS_STICKING;
763 mooseError(
"Invalid or unavailable contact model");
772 const Real contact_pressure = -(pinfo->_normal * pinfo->_contact_force) /
nodalArea(*pinfo);
776 pinfo->_contact_force.zero();
784 return _u_slave[_qp];
790 PenetrationInfo * pinfo = _penetration_locator._penetration_info[_current_node->id()];
791 Real resid = pinfo->_contact_force(
_component);
797 RealVectorValue distance_vec(*_current_node - pinfo->_closest_point);
799 RealVectorValue pen_force(penalty * distance_vec);
802 resid += pinfo->_normal(
_component) * pinfo->_normal * pen_force;
806 distance_vec = distance_vec - pinfo->_incremental_slip;
807 pen_force = penalty * distance_vec;
808 if (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
809 pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION)
810 resid += pinfo->_normal(
_component) * pinfo->_normal * pen_force;
820 RealVectorValue distance_vec(*_current_node - pinfo->_closest_point);
822 RealVectorValue pen_force(penalty * distance_vec);
823 resid += pinfo->_normal(
_component) * pinfo->_normal * pen_force;
825 return _test_slave[_i][_qp] * resid;
828 return _test_master[_i][_qp] * -resid;
837 PenetrationInfo * pinfo = _penetration_locator._penetration_info[_current_node->id()];
845 mooseError(
"Unhandled ConstraintJacobianType");
847 case Moose::SlaveSlave:
855 RealVectorValue jac_vec;
858 dof_id_type dof_number = _current_node->dof_number(0,
_vars[i], 0);
859 jac_vec(i) = (*_jacobian)(dof_number, _connected_dof_indices[_j]);
861 return -pinfo->_normal(
_component) * (pinfo->_normal * jac_vec) +
862 (_phi_slave[_j][_qp] * penalty * _test_slave[_i][_qp]) *
868 return _phi_slave[_j][_qp] * penalty * _test_slave[_i][_qp] *
872 mooseError(
"Invalid contact formulation");
880 if (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
881 pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION)
883 RealVectorValue jac_vec;
886 dof_id_type dof_number = _current_node->dof_number(0,
_vars[i], 0);
887 jac_vec(i) = (*_jacobian)(dof_number, _connected_dof_indices[_j]);
889 return -pinfo->_normal(
_component) * (pinfo->_normal * jac_vec) +
890 (_phi_slave[_j][_qp] * penalty * _test_slave[_i][_qp]) *
895 const Real curr_jac = (*_jacobian)(
896 _current_node->dof_number(0,
_vars[
_component], 0), _connected_dof_indices[_j]);
897 return -curr_jac + _phi_slave[_j][_qp] * penalty * _test_slave[_i][_qp];
903 if (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
904 pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION)
905 return _phi_slave[_j][_qp] * penalty * _test_slave[_i][_qp] *
908 return _phi_slave[_j][_qp] * penalty * _test_slave[_i][_qp];
912 Real normal_comp = _phi_slave[_j][_qp] * penalty * _test_slave[_i][_qp] *
915 Real tang_comp = 0.0;
916 if (pinfo->_mech_status == PenetrationInfo::MS_STICKING)
917 tang_comp = _phi_slave[_j][_qp] * penalty_slip * _test_slave[_i][_qp] *
919 return normal_comp + tang_comp;
924 RealVectorValue jac_vec;
927 dof_id_type dof_number = _current_node->dof_number(0,
_vars[i], 0);
928 jac_vec(i) = (*_jacobian)(dof_number, _connected_dof_indices[_j]);
930 Real normal_comp = -pinfo->_normal(
_component) * (pinfo->_normal * jac_vec) +
931 (_phi_slave[_j][_qp] * penalty * _test_slave[_i][_qp]) *
934 Real tang_comp = 0.0;
935 if (pinfo->_mech_status == PenetrationInfo::MS_STICKING)
936 tang_comp = _phi_slave[_j][_qp] * penalty * _test_slave[_i][_qp] *
939 return normal_comp + tang_comp;
943 mooseError(
"Invalid contact formulation");
951 const Real curr_jac = (*_jacobian)(_current_node->dof_number(0,
_vars[
_component], 0),
952 _connected_dof_indices[_j]);
953 return -curr_jac + _phi_slave[_j][_qp] * penalty * _test_slave[_i][_qp];
958 return _phi_slave[_j][_qp] * penalty * _test_slave[_i][_qp];
961 mooseError(
"Invalid contact formulation");
964 mooseError(
"Invalid or unavailable contact model");
967 case Moose::SlaveMaster:
975 const Node * curr_master_node = _current_master->node_ptr(_j);
977 RealVectorValue jac_vec;
980 dof_id_type dof_number = _current_node->dof_number(0,
_vars[i], 0);
982 (*_jacobian)(dof_number, curr_master_node->dof_number(0,
_vars[
_component], 0));
984 return -pinfo->_normal(
_component) * (pinfo->_normal * jac_vec) -
985 (_phi_master[_j][_qp] * penalty * _test_slave[_i][_qp]) *
991 return -_phi_master[_j][_qp] * penalty * _test_slave[_i][_qp] *
995 mooseError(
"Invalid contact formulation");
1003 if (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
1004 pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION)
1006 const Node * curr_master_node = _current_master->node_ptr(_j);
1008 RealVectorValue jac_vec;
1011 dof_id_type dof_number = _current_node->dof_number(0,
_vars[i], 0);
1012 jac_vec(i) = (*_jacobian)(dof_number,
1015 return -pinfo->_normal(
_component) * (pinfo->_normal * jac_vec) -
1016 (_phi_master[_j][_qp] * penalty * _test_slave[_i][_qp]) *
1021 const Node * curr_master_node = _current_master->node_ptr(_j);
1022 const Real curr_jac =
1025 return -curr_jac - _phi_master[_j][_qp] * penalty * _test_slave[_i][_qp];
1031 if (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
1032 pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION)
1033 return -_phi_master[_j][_qp] * penalty * _test_slave[_i][_qp] *
1036 return -_phi_master[_j][_qp] * penalty * _test_slave[_i][_qp];
1040 Real normal_comp = -_phi_master[_j][_qp] * penalty * _test_slave[_i][_qp] *
1043 Real tang_comp = 0.0;
1044 if (pinfo->_mech_status == PenetrationInfo::MS_STICKING)
1045 tang_comp = -_phi_master[_j][_qp] * penalty_slip * _test_slave[_i][_qp] *
1047 return normal_comp + tang_comp;
1052 const Node * curr_master_node = _current_master->node_ptr(_j);
1054 RealVectorValue jac_vec;
1057 dof_id_type dof_number = _current_node->dof_number(0,
_vars[i], 0);
1059 (*_jacobian)(dof_number, curr_master_node->dof_number(0,
_vars[
_component], 0));
1061 Real normal_comp = -pinfo->_normal(
_component) * (pinfo->_normal * jac_vec) -
1062 (_phi_master[_j][_qp] * penalty * _test_slave[_i][_qp]) *
1065 Real tang_comp = 0.0;
1066 if (pinfo->_mech_status == PenetrationInfo::MS_STICKING)
1067 tang_comp = -_phi_master[_j][_qp] * penalty * _test_slave[_i][_qp] *
1070 return normal_comp + tang_comp;
1074 mooseError(
"Invalid contact formulation");
1081 const Node * curr_master_node = _current_master->node_ptr(_j);
1082 const Real curr_jac =
1085 return -curr_jac - _phi_master[_j][_qp] * penalty * _test_slave[_i][_qp];
1090 return -_phi_master[_j][_qp] * penalty * _test_slave[_i][_qp];
1093 mooseError(
"Invalid contact formulation");
1097 mooseError(
"Invalid or unavailable contact model");
1100 case Moose::MasterSlave:
1108 RealVectorValue jac_vec;
1111 dof_id_type dof_number = _current_node->dof_number(0,
_vars[i], 0);
1112 jac_vec(i) = (*_jacobian)(dof_number, _connected_dof_indices[_j]);
1114 return pinfo->_normal(
_component) * (pinfo->_normal * jac_vec) *
1115 _test_master[_i][_qp];
1120 return -_test_master[_i][_qp] * penalty * _phi_slave[_j][_qp] *
1124 mooseError(
"Invalid contact formulation");
1131 if (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
1132 pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION)
1134 RealVectorValue jac_vec;
1137 dof_id_type dof_number = _current_node->dof_number(0,
_vars[i], 0);
1138 jac_vec(i) = (*_jacobian)(dof_number, _connected_dof_indices[_j]);
1140 return pinfo->_normal(
_component) * (pinfo->_normal * jac_vec) *
1141 _test_master[_i][_qp];
1145 const Real slave_jac = (*_jacobian)(
1146 _current_node->dof_number(0,
_vars[
_component], 0), _connected_dof_indices[_j]);
1147 return slave_jac * _test_master[_i][_qp];
1153 if (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
1154 pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION)
1155 return -_test_master[_i][_qp] * penalty * _phi_slave[_j][_qp] *
1158 return -_test_master[_i][_qp] * penalty * _phi_slave[_j][_qp];
1162 Real normal_comp = -_phi_slave[_j][_qp] * penalty * _test_master[_i][_qp] *
1165 Real tang_comp = 0.0;
1166 if (pinfo->_mech_status == PenetrationInfo::MS_STICKING)
1167 tang_comp = -_phi_slave[_j][_qp] * penalty_slip * _test_master[_i][_qp] *
1169 return normal_comp + tang_comp;
1174 RealVectorValue jac_vec;
1177 dof_id_type dof_number = _current_node->dof_number(0,
_vars[i], 0);
1178 jac_vec(i) = (*_jacobian)(dof_number, _connected_dof_indices[_j]);
1181 pinfo->_normal(
_component) * (pinfo->_normal * jac_vec) * _test_master[_i][_qp];
1183 Real tang_comp = 0.0;
1184 if (pinfo->_mech_status == PenetrationInfo::MS_STICKING)
1185 tang_comp = -_test_master[_i][_qp] * penalty * _phi_slave[_j][_qp] *
1188 return normal_comp + tang_comp;
1192 mooseError(
"Invalid contact formulation");
1200 const Real slave_jac = (*_jacobian)(
1201 _current_node->dof_number(0,
_vars[
_component], 0), _connected_dof_indices[_j]);
1202 return slave_jac * _test_master[_i][_qp];
1207 return -_test_master[_i][_qp] * penalty * _phi_slave[_j][_qp];
1210 mooseError(
"Invalid contact formulation");
1214 mooseError(
"Invalid or unavailable contact model");
1217 case Moose::MasterMaster:
1228 return _test_master[_i][_qp] * penalty * _phi_master[_j][_qp] *
1232 mooseError(
"Invalid contact formulation");
1244 if (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
1245 pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION)
1246 return _test_master[_i][_qp] * penalty * _phi_master[_j][_qp] *
1249 return _test_master[_i][_qp] * penalty * _phi_master[_j][_qp];
1254 Real tang_comp = 0.0;
1255 if (pinfo->_mech_status == PenetrationInfo::MS_STICKING)
1256 tang_comp = _test_master[_i][_qp] * penalty * _phi_master[_j][_qp] *
1263 Real normal_comp = _phi_master[_j][_qp] * penalty * _test_master[_i][_qp] *
1266 Real tang_comp = 0.0;
1267 if (pinfo->_mech_status == PenetrationInfo::MS_STICKING)
1268 tang_comp = _phi_master[_j][_qp] * penalty_slip * _test_master[_i][_qp] *
1270 return normal_comp + tang_comp;
1274 mooseError(
"Invalid contact formulation");
1278 mooseError(
"Invalid or unavailable contact model");
1289 PenetrationInfo * pinfo = _penetration_locator._penetration_info[_current_node->id()];
1294 unsigned int coupled_component;
1295 Real normal_component_in_coupled_var_dir = 1.0;
1297 normal_component_in_coupled_var_dir = pinfo->_normal(coupled_component);
1302 mooseError(
"Unhandled ConstraintJacobianType");
1304 case Moose::SlaveSlave:
1312 RealVectorValue jac_vec;
1315 dof_id_type dof_number = _current_node->dof_number(0,
_vars[i], 0);
1316 jac_vec(i) = (*_jacobian)(dof_number, _connected_dof_indices[_j]);
1318 return -pinfo->_normal(
_component) * (pinfo->_normal * jac_vec) +
1319 (_phi_slave[_j][_qp] * penalty * _test_slave[_i][_qp]) *
1320 pinfo->_normal(
_component) * normal_component_in_coupled_var_dir;
1325 return _phi_slave[_j][_qp] * penalty * _test_slave[_i][_qp] *
1326 pinfo->_normal(
_component) * normal_component_in_coupled_var_dir;
1329 mooseError(
"Invalid contact formulation");
1336 (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
1337 pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION))
1339 RealVectorValue jac_vec;
1342 dof_id_type dof_number = _current_node->dof_number(0,
_vars[i], 0);
1343 jac_vec(i) = (*_jacobian)(dof_number, _connected_dof_indices[_j]);
1345 return -pinfo->_normal(
_component) * (pinfo->_normal * jac_vec) +
1346 (_phi_slave[_j][_qp] * penalty * _test_slave[_i][_qp]) *
1347 pinfo->_normal(
_component) * normal_component_in_coupled_var_dir;
1350 (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
1351 pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION))
1352 return _phi_slave[_j][_qp] * penalty * _test_slave[_i][_qp] *
1353 pinfo->_normal(
_component) * normal_component_in_coupled_var_dir;
1357 Real normal_comp = _phi_slave[_j][_qp] * penalty * _test_slave[_i][_qp] *
1358 pinfo->_normal(
_component) * normal_component_in_coupled_var_dir;
1360 Real tang_comp = 0.0;
1361 if (pinfo->_mech_status == PenetrationInfo::MS_STICKING)
1362 tang_comp = _phi_slave[_j][_qp] * penalty_slip * _test_slave[_i][_qp] *
1363 (-pinfo->_normal(
_component) * normal_component_in_coupled_var_dir);
1364 return normal_comp + tang_comp;
1368 const Real curr_jac = (*_jacobian)(_current_node->dof_number(0,
_vars[
_component], 0),
1369 _connected_dof_indices[_j]);
1376 const Real curr_jac = (*_jacobian)(_current_node->dof_number(0,
_vars[
_component], 0),
1377 _connected_dof_indices[_j]);
1381 mooseError(
"Invalid or unavailable contact model");
1384 case Moose::SlaveMaster:
1392 const Node * curr_master_node = _current_master->node_ptr(_j);
1394 RealVectorValue jac_vec;
1397 dof_id_type dof_number = _current_node->dof_number(0,
_vars[i], 0);
1399 (*_jacobian)(dof_number, curr_master_node->dof_number(0,
_vars[
_component], 0));
1401 return -pinfo->_normal(
_component) * (pinfo->_normal * jac_vec) -
1402 (_phi_master[_j][_qp] * penalty * _test_slave[_i][_qp]) *
1403 pinfo->_normal(
_component) * normal_component_in_coupled_var_dir;
1408 return -_phi_master[_j][_qp] * penalty * _test_slave[_i][_qp] *
1409 pinfo->_normal(
_component) * normal_component_in_coupled_var_dir;
1412 mooseError(
"Invalid contact formulation");
1418 (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
1419 pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION))
1421 const Node * curr_master_node = _current_master->node_ptr(_j);
1423 RealVectorValue jac_vec;
1426 dof_id_type dof_number = _current_node->dof_number(0,
_vars[i], 0);
1428 (*_jacobian)(dof_number, curr_master_node->dof_number(0,
_vars[
_component], 0));
1430 return -pinfo->_normal(
_component) * (pinfo->_normal * jac_vec) -
1431 (_phi_master[_j][_qp] * penalty * _test_slave[_i][_qp]) *
1432 pinfo->_normal(
_component) * normal_component_in_coupled_var_dir;
1435 (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
1436 pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION))
1437 return -_phi_master[_j][_qp] * penalty * _test_slave[_i][_qp] *
1438 pinfo->_normal(
_component) * normal_component_in_coupled_var_dir;
1442 Real normal_comp = -_phi_master[_j][_qp] * penalty * _test_slave[_i][_qp] *
1443 pinfo->_normal(
_component) * normal_component_in_coupled_var_dir;
1445 Real tang_comp = 0.0;
1446 if (pinfo->_mech_status == PenetrationInfo::MS_STICKING)
1447 tang_comp = -_phi_master[_j][_qp] * penalty_slip * _test_slave[_i][_qp] *
1448 (-pinfo->_normal(
_component) * normal_component_in_coupled_var_dir);
1449 return normal_comp + tang_comp;
1458 mooseError(
"Invalid or unavailable contact model");
1461 case Moose::MasterSlave:
1469 RealVectorValue jac_vec;
1472 dof_id_type dof_number = _current_node->dof_number(0,
_vars[i], 0);
1473 jac_vec(i) = (*_jacobian)(dof_number, _connected_dof_indices[_j]);
1475 return pinfo->_normal(
_component) * (pinfo->_normal * jac_vec) *
1476 _test_master[_i][_qp];
1481 return -_test_master[_i][_qp] * penalty * _phi_slave[_j][_qp] *
1482 pinfo->_normal(
_component) * normal_component_in_coupled_var_dir;
1485 mooseError(
"Invalid contact formulation");
1492 if (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
1493 pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION)
1495 RealVectorValue jac_vec;
1498 dof_id_type dof_number = _current_node->dof_number(0,
_vars[i], 0);
1499 jac_vec(i) = (*_jacobian)(dof_number, _connected_dof_indices[_j]);
1501 return pinfo->_normal(
_component) * (pinfo->_normal * jac_vec) *
1502 _test_master[_i][_qp];
1506 const Real slave_jac = (*_jacobian)(
1507 _current_node->dof_number(0,
_vars[
_component], 0), _connected_dof_indices[_j]);
1508 return slave_jac * _test_master[_i][_qp];
1514 if (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
1515 pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION)
1516 return -_test_master[_i][_qp] * penalty * _phi_slave[_j][_qp] *
1517 pinfo->_normal(
_component) * normal_component_in_coupled_var_dir;
1523 Real normal_comp = -_phi_slave[_j][_qp] * penalty * _test_master[_i][_qp] *
1524 pinfo->_normal(
_component) * normal_component_in_coupled_var_dir;
1526 Real tang_comp = 0.0;
1527 if (pinfo->_mech_status == PenetrationInfo::MS_STICKING)
1528 tang_comp = -_phi_slave[_j][_qp] * penalty_slip * _test_master[_i][_qp] *
1529 (-pinfo->_normal(
_component) * normal_component_in_coupled_var_dir);
1530 return normal_comp + tang_comp;
1534 if (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
1535 pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION)
1537 RealVectorValue jac_vec;
1540 dof_id_type dof_number = _current_node->dof_number(0,
_vars[i], 0);
1541 jac_vec(i) = (*_jacobian)(dof_number, _connected_dof_indices[_j]);
1543 return pinfo->_normal(
_component) * (pinfo->_normal * jac_vec) *
1544 _test_master[_i][_qp];
1551 mooseError(
"Invalid contact formulation");
1559 const Real slave_jac = (*_jacobian)(
1560 _current_node->dof_number(0,
_vars[
_component], 0), _connected_dof_indices[_j]);
1561 return slave_jac * _test_master[_i][_qp];
1569 mooseError(
"Invalid contact formulation");
1573 mooseError(
"Invalid or unavailable contact model");
1576 case Moose::MasterMaster:
1587 return _test_master[_i][_qp] * penalty * _phi_master[_j][_qp] *
1588 pinfo->_normal(
_component) * normal_component_in_coupled_var_dir;
1591 mooseError(
"Invalid contact formulation");
1599 Real normal_comp = _phi_master[_j][_qp] * penalty * _test_master[_i][_qp] *
1600 pinfo->_normal(
_component) * normal_component_in_coupled_var_dir;
1602 if (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
1603 pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION)
1609 (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
1610 pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION))
1611 return _test_master[_i][_qp] * penalty * _phi_master[_j][_qp] *
1612 pinfo->_normal(
_component) * normal_component_in_coupled_var_dir;
1619 (pinfo->_mech_status == PenetrationInfo::MS_SLIPPING ||
1620 pinfo->_mech_status == PenetrationInfo::MS_SLIPPING_FRICTION))
1621 return _test_master[_i][_qp] * penalty * _phi_master[_j][_qp] *
1622 pinfo->_normal(
_component) * normal_component_in_coupled_var_dir;
1625 Real normal_comp = _phi_master[_j][_qp] * penalty * _test_master[_i][_qp] *
1626 pinfo->_normal(
_component) * normal_component_in_coupled_var_dir;
1628 Real tang_comp = 0.0;
1629 if (pinfo->_mech_status == PenetrationInfo::MS_STICKING)
1630 tang_comp = _phi_master[_j][_qp] * penalty_slip * _test_master[_i][_qp] *
1631 (-pinfo->_normal(
_component) * normal_component_in_coupled_var_dir);
1632 return normal_comp + tang_comp;
1638 mooseError(
"Invalid or unavailable contact model");
1648 const Node * node = pinfo._node;
1652 Real area = (*_aux_solution)(dof);
1656 mooseError(
"Zero nodal area found");
1688 DenseMatrix<Number> & Knn =
1689 _assembly.jacobianBlockNeighbor(Moose::NeighborNeighbor, _master_var.number(), _var.number());
1691 _Kee.resize(_test_slave.size(), _connected_dof_indices.size());
1693 for (_i = 0; _i < _test_slave.size(); _i++)
1695 for (_j = 0; _j < _connected_dof_indices.size(); _j++)
1700 DenseMatrix<Number> & Ken =
1701 _assembly.jacobianBlockNeighbor(Moose::ElementNeighbor, _var.number(), _var.number());
1702 if (Ken.m() && Ken.n())
1703 for (_i = 0; _i < _test_slave.size(); _i++)
1704 for (_j = 0; _j < _phi_master.size(); _j++)
1707 _Kne.resize(_test_master.size(), _connected_dof_indices.size());
1708 for (_i = 0; _i < _test_master.size(); _i++)
1710 for (_j = 0; _j < _connected_dof_indices.size(); _j++)
1714 if (Knn.m() && Knn.n())
1715 for (_i = 0; _i < _test_master.size(); _i++)
1716 for (_j = 0; _j < _phi_master.size(); _j++)
1725 _Kee.resize(_test_slave.size(), _connected_dof_indices.size());
1727 DenseMatrix<Number> & Knn =
1728 _assembly.jacobianBlockNeighbor(Moose::NeighborNeighbor, _master_var.number(), jvar);
1730 for (_i = 0; _i < _test_slave.size(); _i++)
1732 for (_j = 0; _j < _connected_dof_indices.size(); _j++)
1737 DenseMatrix<Number> & Ken =
1738 _assembly.jacobianBlockNeighbor(Moose::ElementNeighbor, _var.number(), jvar);
1739 for (_i = 0; _i < _test_slave.size(); _i++)
1740 for (_j = 0; _j < _phi_master.size(); _j++)
1743 _Kne.resize(_test_master.size(), _connected_dof_indices.size());
1744 if (_Kne.m() && _Kne.n())
1745 for (_i = 0; _i < _test_master.size(); _i++)
1747 for (_j = 0; _j < _connected_dof_indices.size(); _j++)
1751 for (_i = 0; _i < _test_master.size(); _i++)
1752 for (_j = 0; _j < _phi_master.size(); _j++)
1763 NodeFaceConstraint::getConnectedDofIndices(var_num);
1766 _connected_dof_indices.clear();
1767 MooseVariableFEBase & var = _sys.getVariable(0, var_num);
1768 _connected_dof_indices.push_back(var.nodalDofIndex());
1772 _phi_slave.resize(_connected_dof_indices.size());
1774 dof_id_type current_node_var_dof_index = _sys.getVariable(0, var_num).nodalDofIndex();
1780 for (
unsigned int j = 0; j < _connected_dof_indices.size(); j++)
1782 _phi_slave[j].resize(1);
1784 if (_connected_dof_indices[j] == current_node_var_dof_index)
1785 _phi_slave[j][_qp] = 1.0;
1787 _phi_slave[j][_qp] = 0.0;
1794 component = std::numeric_limits<unsigned int>::max();
1795 bool coupled_var_is_disp_var =
false;
1796 for (
unsigned int i = 0; i < LIBMESH_DIM; ++i)
1798 if (var_num ==
_vars[i])
1800 coupled_var_is_disp_var =
true;
1805 return coupled_var_is_disp_var;
1818 <<
" nodes in contact.\n";
1821 <<
" nodes in contact.\n";