13 #include "SystemBase.h"
14 #include "PenetrationInfo.h"
15 #include "MooseMesh.h"
16 #include "Executioner.h"
19 #include "libmesh/sparse_matrix.h"
20 #include "libmesh/string_to_enum.h"
28 InputParameters params = validParams<DiracKernel>();
31 params.addRequiredParam<BoundaryName>(
"boundary",
"The master boundary");
32 params.addRequiredParam<BoundaryName>(
"slave",
"The slave boundary");
33 params.addRequiredParam<
unsigned int>(
"component",
34 "An integer corresponding to the direction "
35 "the variable this kernel acts in. (0 for x, "
38 params.addCoupledVar(
"disp_x",
"The x displacement");
39 params.addCoupledVar(
"disp_y",
"The y displacement");
40 params.addCoupledVar(
"disp_z",
"The z displacement");
44 "The displacements appropriate for the simulation geometry and coordinate system");
46 params.addRequiredCoupledVar(
"nodal_area",
"The nodal area");
48 params.set<
bool>(
"use_displaced_mesh") =
true;
49 params.addParam<Real>(
52 "The penalty to apply. This can vary depending on the stiffness of your materials");
53 params.addParam<Real>(
"friction_coefficient", 0,
"The friction coefficient");
54 params.addParam<Real>(
"tangential_tolerance",
55 "Tangential distance to extend edges of contact surfaces");
56 params.addParam<Real>(
57 "capture_tolerance", 0,
"Normal distance from surface within which nodes are captured");
59 params.addParam<Real>(
"tension_release",
61 "Tension release threshold. A node in contact "
62 "will not be released if its tensile load is below "
63 "this value. No tension release if negative.");
65 params.addParam<
bool>(
68 "Whether to normalize the penalty parameter with the nodal area for penalty contact.");
73 : DiracKernel(parameters),
74 _component(getParam<unsigned int>(
"component")),
75 _model(getParam<MooseEnum>(
"model").getEnum<
ContactModel>()),
77 _normalize_penalty(getParam<bool>(
"normalize_penalty")),
79 getPenetrationLocator(getParam<BoundaryName>(
"boundary"),
80 getParam<BoundaryName>(
"slave"),
81 Utility::string_to_enum<Order>(getParam<MooseEnum>(
"order")))),
82 _penalty(getParam<Real>(
"penalty")),
83 _friction_coefficient(getParam<Real>(
"friction_coefficient")),
84 _tension_release(getParam<Real>(
"tension_release")),
85 _capture_tolerance(getParam<Real>(
"capture_tolerance")),
86 _residual_copy(_sys.residualGhosted()),
87 _mesh_dimension(_mesh.dimension()),
88 _vars(3,
libMesh::invalid_uint),
89 _nodal_area_var(getVar(
"nodal_area", 0)),
90 _aux_system(_nodal_area_var->sys()),
91 _aux_solution(_aux_system.currentSolution())
93 if (isParamValid(
"displacements"))
96 for (
unsigned int i = 0; i < coupledComponents(
"displacements"); ++i)
97 _vars[i] = coupled(
"displacements", i);
102 if (isParamValid(
"disp_x"))
103 _vars[0] = coupled(
"disp_x");
104 if (isParamValid(
"disp_y"))
105 _vars[1] = coupled(
"disp_y");
106 if (isParamValid(
"disp_z"))
107 _vars[2] = coupled(
"disp_z");
109 mooseDeprecated(
"use the `displacements` parameter rather than the `disp_*` parameters (those "
110 "will go away with the deprecation of the Solid Mechanics module).");
113 if (parameters.isParamValid(
"tangential_tolerance"))
116 if (parameters.isParamValid(
"normal_smoothing_distance"))
119 if (parameters.isParamValid(
"normal_smoothing_method"))
121 parameters.get<MooseEnum>(
"normal_smoothing_method"));
128 mooseError(
"The friction coefficient must be nonnegative");
141 std::map<dof_id_type, PenetrationInfo *>::iterator
144 for (; it != end; ++it)
146 PenetrationInfo * pinfo = it->second;
149 if (!pinfo || pinfo->_node->n_comp(_sys.number(),
_vars[
_component]) < 1)
152 pinfo->_locked_this_step = 0;
153 pinfo->_starting_elem = it->second->_elem;
154 pinfo->_starting_side_num = it->second->_side_num;
155 pinfo->_starting_closest_point_ref = it->second->_closest_point_ref;
156 pinfo->_contact_force_old = pinfo->_contact_force;
157 pinfo->_accumulated_slip_old = pinfo->_accumulated_slip;
158 pinfo->_frictional_energy_old = pinfo->_frictional_energy;
167 std::map<dof_id_type, PenetrationInfo *>::iterator
171 for (; it != end; ++it)
173 PenetrationInfo * pinfo = it->second;
176 if (!pinfo || pinfo->_node->n_comp(_sys.number(),
_vars[
_component]) < 1)
180 _subproblem.getMooseApp().getExecutioner()->feProblem().computingNonlinearResid();
185 if (pinfo->isCaptured())
187 addPoint(pinfo->_elem, pinfo->_closest_point);
196 const Node * node = pinfo->_node;
198 RealVectorValue res_vec;
202 dof_id_type dof_number = node->dof_number(0,
_vars[i], 0);
206 RealVectorValue distance_vec(_mesh.nodeRef(node->id()) - pinfo->_closest_point);
207 const Real gap_size = -1. * pinfo->_normal * distance_vec;
211 bool newly_captured =
false;
214 if (update_contact_set && !pinfo->isCaptured() &&
217 newly_captured =
true;
223 ++pinfo->_locked_this_step;
226 if (!pinfo->isCaptured())
231 RealVectorValue pen_force(
_penalty * distance_vec);
240 pinfo->_contact_force = -pinfo->_normal * (pinfo->_normal * res_vec);
243 pinfo->_contact_force = pinfo->_normal * (pinfo->_normal * pen_force);
246 pinfo->_contact_force =
248 (pinfo->_normal * (pen_force + pinfo->_lagrange_multiplier * pinfo->_normal)));
251 mooseError(
"Invalid contact formulation");
254 pinfo->_mech_status = PenetrationInfo::MS_SLIPPING;
259 pinfo->_incremental_slip +
260 (pinfo->_normal * (_mesh.nodeRef(node->id()) - pinfo->_closest_point)) * pinfo->_normal;
261 pen_force =
_penalty * distance_vec;
269 (res_vec * pinfo->_normal > 0 ? res_vec * pinfo->_normal : 0));
272 pinfo->_contact_force =
274 (pinfo->_contact_force_old - pinfo->_normal * (pinfo->_normal * pinfo->_contact_force_old));
275 RealVectorValue contact_force_normal((pinfo->_contact_force * pinfo->_normal) * pinfo->_normal);
276 RealVectorValue contact_force_tangential(pinfo->_contact_force - contact_force_normal);
279 const Real tan_mag(contact_force_tangential.norm());
281 if (tan_mag > capacity)
283 pinfo->_contact_force = contact_force_normal + capacity * contact_force_tangential / tan_mag;
284 pinfo->_mech_status = PenetrationInfo::MS_SLIPPING;
288 pinfo->_mech_status = PenetrationInfo::MS_STICKING;
297 pinfo->_contact_force = -res_vec;
300 pinfo->_contact_force = pen_force;
303 pinfo->_contact_force =
304 pen_force + pinfo->_lagrange_multiplier * distance_vec / distance_vec.norm();
307 mooseError(
"Invalid contact formulation");
310 pinfo->_mech_status = PenetrationInfo::MS_STICKING;
314 mooseError(
"Invalid or unavailable contact model");
321 const Real contact_pressure = -(pinfo->_normal * pinfo->_contact_force) / area;
325 pinfo->_contact_force.zero();
330 pinfo->_lagrange_multiplier -=
getPenalty(*pinfo) * gap_size;
337 Real resid = -pinfo->_contact_force(
_component);
338 return _test[_i][_qp] * resid;
360 return _test[_i][_qp] * penalty * _phi[_j][_qp] * pinfo->_normal(
_component) *
364 mooseError(
"Invalid contact formulation");
377 return _test[_i][_qp] * penalty * _phi[_j][_qp];
380 mooseError(
"Invalid contact formulation");
385 mooseError(
"Invalid or unavailable contact model");
414 const Node * node = pinfo._node;
418 Real area = (*_aux_solution)(dof);
422 mooseError(
"Zero nodal area found");