20#include "libmesh/threads.h"
29closest_point_to_edge(
const Point & src,
const Point & p0,
const Point & p1)
31 const Point line01 = p1 - p0;
32 const Real line0c_xi = ((src - p0) * line01) / line01.norm_sq();
40 return p0 + line0c_xi * line01;
44closest_point_to_side(
const Point & src,
const Elem & side)
51 mooseAssert(side.has_affine_map(),
52 "Penetration of elements with curved sides not implemented");
53 return closest_point_to_edge(src, side.point(0), side.point(1));
57 mooseAssert(side.has_affine_map(),
58 "Penetration of elements with curved sides not implemented");
59 const Point p0 = side.point(0), p1 = side.point(1), p2 = side.point(2);
60 const Point l01 = p1 - p0, l02 = p2 - p0;
61 const Point tri_normal = (l01.cross(l02)).unit();
62 const Point linecs = ((src - p0) * tri_normal) / tri_normal.norm_sq() * tri_normal;
63 const Point in_plane = src - linecs;
64 const Point planar_offset = in_plane - p0;
67 if (planar_offset.cross(l01) * tri_normal > 0)
68 return closest_point_to_edge(src, p0, p1);
71 if (planar_offset.cross(l02) * tri_normal < 0)
72 return closest_point_to_edge(src, p0, p2);
75 if ((in_plane - p1).cross(p2 - p1) * tri_normal > 0)
76 return closest_point_to_edge(src, p1, p2);
101 std::map<dof_id_type, PenetrationInfo *> & penetration_info,
102 bool check_whether_reasonable,
103 bool update_location,
104 Real tangential_tolerance,
105 bool do_normal_smoothing,
106 Real normal_smoothing_distance,
108 bool use_point_locator,
109 std::vector<std::vector<FEBase *>> & fes,
112 const std::unordered_map<dof_id_type, std::vector<dof_id_type>> & node_to_elem_map)
113 : _subproblem(subproblem),
115 _primary_boundary(primary_boundary),
116 _secondary_boundary(secondary_boundary),
117 _penetration_info(penetration_info),
118 _check_whether_reasonable(check_whether_reasonable),
119 _update_location(update_location),
120 _tangential_tolerance(tangential_tolerance),
121 _do_normal_smoothing(do_normal_smoothing),
122 _normal_smoothing_distance(normal_smoothing_distance),
123 _normal_smoothing_method(normal_smoothing_method),
124 _use_point_locator(use_point_locator),
125 _nodal_normal_x(NULL),
126 _nodal_normal_y(NULL),
127 _nodal_normal_z(NULL),
130 _nearest_node(nearest_node),
131 _node_to_elem_map(node_to_elem_map)
137 : _subproblem(x._subproblem),
139 _primary_boundary(x._primary_boundary),
140 _secondary_boundary(x._secondary_boundary),
141 _penetration_info(x._penetration_info),
142 _check_whether_reasonable(x._check_whether_reasonable),
143 _update_location(x._update_location),
144 _tangential_tolerance(x._tangential_tolerance),
145 _do_normal_smoothing(x._do_normal_smoothing),
146 _normal_smoothing_distance(x._normal_smoothing_distance),
147 _normal_smoothing_method(x._normal_smoothing_method),
148 _use_point_locator(x._use_point_locator),
150 _fe_type(x._fe_type),
151 _nearest_node(x._nearest_node),
152 _node_to_elem_map(x._node_to_elem_map)
171 const BoundaryInfo & boundary_info =
_mesh.
getMesh().get_boundary_info();
172 std::unique_ptr<PointLocatorBase> point_locator;
176 for (
const auto & node_id : range)
187 std::vector<PenetrationInfo *> p_info;
188 bool info_set(
false);
193 FEBase * fe_elem =
_fes[
_tid][info->_elem->dim()];
194 FEBase * fe_side =
_fes[
_tid][info->_side->dim()];
198 const Point contact_ref = info->_closest_point_ref;
199 bool contact_point_on_side(
false);
203 std::vector<Point> points(1);
204 points[0] = contact_ref;
205 const std::vector<Point> & secondary_pos = fe_side->get_xyz();
206 bool search_succeeded =
false;
215 contact_point_on_side,
219 info->_closest_point_ref = contact_ref;
222 info->_distance = 0.0;
227 Real old_tangential_distance(info->_tangential_distance);
228 bool contact_point_on_side(
false);
229 bool search_succeeded =
false;
238 contact_point_on_side,
241 if (contact_point_on_side)
243 if (info->_tangential_distance <= 0.0)
247 else if (info->_tangential_distance > 0.0 && old_tangential_distance > 0.0)
249 if (info->_side->dim() == 2 && info->_off_edge_nodes.size() < 2)
266 std::vector<dof_id_type> located_elem_ids;
267 const std::vector<dof_id_type> * closest_elems;
271 std::set<const Elem *> candidate_elements;
272 (*point_locator)(*closest_node, candidate_elements);
274 if (candidate_elements.empty())
275 mooseError(
"No proximate elements found at node ",
278 cast_ref<const Point &>(*closest_node),
281 ". This should never happen.");
283 for (
const Elem * elem : candidate_elements)
285 for (
auto s : elem->side_index_range())
288 located_elem_ids.push_back(elem->id());
293 if (located_elem_ids.empty())
294 mooseError(
"No proximate elements found at node ",
297 cast_ref<const Point &>(*closest_node),
300 " share that boundary. This may happen if the mesh uses the same boundary id "
301 "for a nodeset and an unrelated sideset.");
303 closest_elems = &located_elem_ids;
309 "Missing entry in node to elem map");
310 closest_elems = &(node_to_elem_pair->second);
313 for (
const auto & elem_id : *closest_elems)
317 std::vector<PenetrationInfo *> thisElemInfo;
319 std::vector<const Node *> nodesThatMustBeOnSide;
330 nodesThatMustBeOnSide.push_back(closest_node);
337 Real min_distance_sq = std::numeric_limits<Real>::max();
339 unsigned int best_i = invalid_uint;
342 for (
unsigned int i = 0; i < p_info.size(); ++i)
344 const Point closest_point = closest_point_to_side(node, *p_info[i]->_side);
345 const Real distance_sq = (closest_point - node).norm_sq();
346 if (distance_sq < min_distance_sq)
348 min_distance_sq = distance_sq;
349 best_point = closest_point;
354 p_info[best_i]->_closest_point = best_point;
355 p_info[best_i]->_distance =
356 (p_info[best_i]->_distance >= 0.0 ? 1.0 : -1.0) * std::sqrt(min_distance_sq);
358 mooseError(
"Normal smoothing not implemented with point locator code");
359 Point normal = (best_point - node).unit();
360 const Real dot = normal * p_info[best_i]->_normal;
363 p_info[best_i]->_normal = normal;
370 if (p_info.size() == 1)
378 else if (p_info.size() > 1)
381 std::vector<RidgeData> ridgeDataVec;
382 for (
unsigned int i = 0; i + 1 < p_info.size(); ++i)
383 for (
unsigned int j = i + 1; j < p_info.size(); ++j)
386 Real tangential_distance(0.0);
387 const Node * closest_node_on_ridge = NULL;
388 unsigned int index = 0;
389 Point closest_coor_ref;
392 closest_node_on_ridge,
398 if (found_ridge_contact_point)
406 ridgeDataVec.push_back(rpd);
410 if (ridgeDataVec.size() > 0)
414 std::vector<RidgeSetData> ridgeSetDataVec;
415 for (
unsigned int i = 0; i < ridgeDataVec.size(); ++i)
417 bool foundSetWithMatchingNode =
false;
418 for (
unsigned int j = 0; j < ridgeSetDataVec.size(); ++j)
420 if (ridgeDataVec[i]._closest_node != NULL &&
421 ridgeDataVec[i]._closest_node == ridgeSetDataVec[j]._closest_node)
423 foundSetWithMatchingNode =
true;
424 ridgeSetDataVec[j]._ridge_data_vec.push_back(ridgeDataVec[i]);
428 if (!foundSetWithMatchingNode)
431 rsd.
_distance = std::numeric_limits<Real>::max();
434 ridgeSetDataVec.push_back(rsd);
438 for (
unsigned int i = 0; i < ridgeSetDataVec.size(); ++i)
440 if (ridgeSetDataVec[i]._closest_node !=
443 if (ridgeSetDataVec[i]._ridge_data_vec.size() == 1)
445 if (ridgeSetDataVec[i]._ridge_data_vec[0]._tangential_distance <=
448 ridgeSetDataVec[i]._closest_coor =
449 ridgeSetDataVec[i]._ridge_data_vec[0]._closest_coor;
450 Point contact_point_vec = node - ridgeSetDataVec[i]._closest_coor;
451 ridgeSetDataVec[i]._distance = contact_point_vec.norm();
457 ridgeSetDataVec[i]._closest_coor = *ridgeSetDataVec[i]._closest_node;
458 Point contact_point_vec = node - ridgeSetDataVec[i]._closest_coor;
459 ridgeSetDataVec[i]._distance = contact_point_vec.norm();
464 ridgeSetDataVec[i]._closest_coor =
465 ridgeSetDataVec[i]._ridge_data_vec[0]._closest_coor;
466 Point contact_point_vec = node - ridgeSetDataVec[i]._closest_coor;
467 ridgeSetDataVec[i]._distance = contact_point_vec.norm();
471 unsigned int closest_ridge_set_index(0);
472 Real closest_distance(ridgeSetDataVec[0]._distance);
473 Point closest_point(ridgeSetDataVec[0]._closest_coor);
474 for (
unsigned int i = 1; i < ridgeSetDataVec.size(); ++i)
476 if (ridgeSetDataVec[i]._distance < closest_distance)
478 closest_ridge_set_index = i;
479 closest_distance = ridgeSetDataVec[i]._distance;
480 closest_point = ridgeSetDataVec[i]._closest_coor;
484 if (closest_distance <
485 std::numeric_limits<Real>::max())
494 unsigned int face_index(std::numeric_limits<unsigned int>::max());
495 for (
unsigned int i = 0;
496 i < ridgeSetDataVec[closest_ridge_set_index]._ridge_data_vec.size();
499 if (ridgeSetDataVec[closest_ridge_set_index]._ridge_data_vec[i]._index < face_index)
500 face_index = ridgeSetDataVec[closest_ridge_set_index]._ridge_data_vec[i]._index;
503 mooseAssert(face_index < std::numeric_limits<unsigned int>::max(),
504 "face_index invalid");
506 p_info[face_index]->_closest_point = closest_point;
507 p_info[face_index]->_distance =
508 (p_info[face_index]->_distance >= 0.0 ? 1.0 : -1.0) * closest_distance;
514 Point normal(closest_point - node);
515 const Real len(normal.norm());
520 const Real dot(normal * p_info[face_index]->_normal);
523 p_info[face_index]->_normal = normal;
525 p_info[face_index]->_tangential_distance = 0.0;
527 Point closest_point_ref;
528 if (ridgeSetDataVec[closest_ridge_set_index]._ridge_data_vec.size() ==
531 p_info[face_index]->_tangential_distance = ridgeSetDataVec[closest_ridge_set_index]
533 ._tangential_distance;
534 p_info[face_index]->_closest_point_ref =
535 ridgeSetDataVec[closest_ridge_set_index]._ridge_data_vec[0]._closest_coor_ref;
539 const Node * closest_node_on_face;
541 closest_node_on_face,
542 p_info[face_index]->_side);
545 if (closest_node_on_face !=
546 ridgeSetDataVec[closest_ridge_set_index]._closest_node)
548 mooseError(
"Closest node when restricting point to face != closest node from "
554 FEBase * fe =
_fes[
_tid][p_info[face_index]->_side->dim()];
555 std::vector<Point> points(1);
556 points[0] = p_info[face_index]->_closest_point_ref;
557 fe->reinit(p_info[face_index]->_side, &points);
558 p_info[face_index]->_side_phi = fe->get_phi();
559 p_info[face_index]->_side_grad_phi = fe->get_dphi();
560 p_info[face_index]->_dxyzdxi = fe->get_dxyzdxi();
561 p_info[face_index]->_dxyzdeta = fe->get_dxyzdeta();
562 p_info[face_index]->_d2xyzdxideta = fe->get_d2xyzdxideta();
575 unsigned int best(0), i(1);
593 }
while (i < p_info.size() && best < p_info.size());
594 if (best < p_info.size())
623 FEBase * fe =
_fes[
_tid][info->_side->dim()];
627 for (
unsigned int j = 0; j < p_info.size(); ++j)
649 mooseAssert(infoNew != NULL,
"infoNew object is null");
754 else if (MooseUtils::relativeFuzzyLessThan(std::abs(pi1->
_distance), std::abs(pi2->
_distance)))
757 else if (MooseUtils::relativeFuzzyLessThan(std::abs(pi2->
_distance), std::abs(pi1->
_distance)))
776 const std::vector<const Node *> & off_edge_nodes1 = pi1->
_off_edge_nodes;
777 const std::vector<const Node *> & off_edge_nodes2 = pi2->
_off_edge_nodes;
778 const unsigned dim1 = pi1->
_side->dim();
782 mooseAssert(pi2->
_side->dim() == 1,
"Incompatible dimensions.");
783 mooseAssert(off_edge_nodes1.size() < 2 && off_edge_nodes2.size() < 2,
784 "off_edge_nodes size should be <2 for 2D contact");
785 if (off_edge_nodes1.size() == 1 && off_edge_nodes2.size() == 1 &&
786 off_edge_nodes1[0] == off_edge_nodes2[0])
791 mooseAssert(dim1 == 2 && pi2->
_side->dim() == 2,
"Incompatible dimensions.");
792 mooseAssert(off_edge_nodes1.size() < 3 && off_edge_nodes2.size() < 3,
793 "off_edge_nodes size should be <3 for 3D contact");
794 if (off_edge_nodes1.size() == 1)
796 if (off_edge_nodes2.size() == 1)
798 if (off_edge_nodes1[0] == off_edge_nodes2[0])
801 else if (off_edge_nodes2.size() == 2)
803 if (off_edge_nodes1[0] == off_edge_nodes2[0] || off_edge_nodes1[0] == off_edge_nodes2[1])
807 else if (off_edge_nodes1.size() == 2)
809 if (off_edge_nodes2.size() == 1)
811 if (off_edge_nodes1[0] == off_edge_nodes2[0] || off_edge_nodes1[1] == off_edge_nodes2[0])
814 else if (off_edge_nodes2.size() == 2)
816 if ((off_edge_nodes1[0] == off_edge_nodes2[0] &&
817 off_edge_nodes1[1] == off_edge_nodes2[1]) ||
818 (off_edge_nodes1[1] == off_edge_nodes2[0] && off_edge_nodes1[0] == off_edge_nodes2[1]))
828 Real & tangential_distance,
829 const Node *& closest_node,
830 unsigned int & index,
831 Point & contact_point_ref,
832 std::vector<PenetrationInfo *> & p_info,
833 const unsigned int index1,
834 const unsigned int index2)
836 tangential_distance = 0.0;
840 const unsigned sidedim(pi1->
_side->dim());
841 mooseAssert(sidedim == pi2->
_side->dim(),
"Incompatible dimensionalities");
844 std::vector<const Node *> side1_nodes;
846 std::vector<const Node *> side2_nodes;
849 std::sort(side1_nodes.begin(), side1_nodes.end());
850 std::sort(side2_nodes.begin(), side2_nodes.end());
853 std::vector<const Node *> common_nodes;
854 std::set_intersection(side1_nodes.begin(),
858 std::inserter(common_nodes, common_nodes.end()));
860 if (common_nodes.size() != sidedim)
863 bool found_point1, found_point2;
865 const Node * closest_node1;
867 closest_coor_ref1, closest_node1, pi1->
_side, common_nodes);
870 const Node * closest_node2;
872 closest_coor_ref2, closest_node2, pi2->
_side, common_nodes);
874 if (!found_point1 || !found_point2)
887 std::vector<Point> points(1);
895 if (MooseUtils::absoluteFuzzyGreaterThan(std::abs(pi1->
_distance), std::abs(pi2->
_distance)) ||
896 (MooseUtils::absoluteFuzzyEqual(std::abs(pi1->
_distance), std::abs(pi2->
_distance)) &&
900 contact_point_ref = closest_coor_ref1;
901 points[0] = closest_coor_ref1;
902 fe->reinit(pi1->
_side, &points);
908 contact_point_ref = closest_coor_ref2;
909 points[0] = closest_coor_ref2;
910 fe->reinit(pi2->
_side, &points);
914 contact_point = fe->get_xyz()[0];
920 mooseAssert((closest_node1 == closest_node2 || closest_node2 == NULL),
921 "If off edge of ridge, closest node must be the same on both elements");
922 closest_node = closest_node1;
924 RealGradient off_face = *closest_node1 - contact_point;
925 tangential_distance = off_face.
norm();
935 const ElemType t(side->type());
936 corner_nodes.clear();
938 corner_nodes.push_back(side->node_ptr(0));
939 corner_nodes.push_back(side->node_ptr(1));
953 corner_nodes.push_back(side->node_ptr(2));
961 corner_nodes.push_back(side->node_ptr(2));
962 corner_nodes.push_back(side->node_ptr(3));
976 const Node *& closest_node,
978 const std::vector<const Node *> & edge_nodes)
980 const ElemType t = side->type();
985 std::vector<unsigned int> local_node_indices;
986 for (
const auto & edge_node : edge_nodes)
988 unsigned int local_index = side->get_node_index(edge_node);
991 local_node_indices.push_back(local_index);
993 mooseAssert(local_node_indices.size() == side->dim(),
994 "Number of edge nodes must match side dimensionality");
995 std::sort(local_node_indices.begin(), local_node_indices.end());
997 bool off_of_this_edge =
false;
1005 if (local_node_indices[0] == 0)
1010 off_of_this_edge =
true;
1011 closest_node = side->node_ptr(0);
1014 else if (local_node_indices[0] == 1)
1019 off_of_this_edge =
true;
1020 closest_node = side->node_ptr(1);
1034 if ((local_node_indices[0] == 0) && (local_node_indices[1] == 1))
1039 off_of_this_edge =
true;
1041 closest_node = side->node_ptr(0);
1043 closest_node = side->node_ptr(1);
1046 else if ((local_node_indices[0] == 1) && (local_node_indices[1] == 2))
1048 if ((
xi +
eta) > 1.0)
1050 Real delta = (
xi +
eta - 1.0) / 2.0;
1053 off_of_this_edge =
true;
1055 closest_node = side->node_ptr(1);
1057 closest_node = side->node_ptr(2);
1060 else if ((local_node_indices[0] == 0) && (local_node_indices[1] == 2))
1065 off_of_this_edge =
true;
1067 closest_node = side->node_ptr(2);
1069 closest_node = side->node_ptr(0);
1084 if ((local_node_indices[0] == 0) && (local_node_indices[1] == 1))
1089 off_of_this_edge =
true;
1091 closest_node = side->node_ptr(0);
1093 closest_node = side->node_ptr(1);
1096 else if ((local_node_indices[0] == 1) && (local_node_indices[1] == 2))
1101 off_of_this_edge =
true;
1103 closest_node = side->node_ptr(1);
1105 closest_node = side->node_ptr(2);
1108 else if ((local_node_indices[0] == 2) && (local_node_indices[1] == 3))
1113 off_of_this_edge =
true;
1115 closest_node = side->node_ptr(3);
1117 closest_node = side->node_ptr(2);
1120 else if ((local_node_indices[0] == 0) && (local_node_indices[1] == 3))
1125 off_of_this_edge =
true;
1127 closest_node = side->node_ptr(0);
1129 closest_node = side->node_ptr(3);
1145 return off_of_this_edge;
1151 const ElemType t(side->type());
1154 closest_node = NULL;
1156 bool off_of_this_face(
false);
1167 off_of_this_face =
true;
1168 closest_node = side->node_ptr(0);
1173 off_of_this_face =
true;
1174 closest_node = side->node_ptr(1);
1186 off_of_this_face =
true;
1189 closest_node = side->node_ptr(0);
1195 closest_node = side->node_ptr(1);
1200 else if ((
xi +
eta) > 1.0)
1202 Real delta = (
xi +
eta - 1.0) / 2.0;
1205 off_of_this_face =
true;
1208 closest_node = side->node_ptr(1);
1217 closest_node = side->node_ptr(2);
1228 off_of_this_face =
true;
1231 closest_node = side->node_ptr(2);
1237 closest_node = side->node_ptr(0);
1252 off_of_this_face =
true;
1255 closest_node = side->node_ptr(0);
1261 closest_node = side->node_ptr(1);
1269 off_of_this_face =
true;
1272 closest_node = side->node_ptr(1);
1278 closest_node = side->node_ptr(2);
1286 off_of_this_face =
true;
1289 closest_node = side->node_ptr(3);
1295 closest_node = side->node_ptr(2);
1303 off_of_this_face =
true;
1306 closest_node = side->node_ptr(0);
1312 closest_node = side->node_ptr(3);
1326 return off_of_this_face;
1333 const Point * secondary_point,
1334 const Real tangential_tolerance)
1336 unsigned int dim = primary_elem->dim();
1338 const std::vector<Point> & phys_point = fe->get_xyz();
1340 const std::vector<RealGradient> & dxyz_dxi = fe->get_dxyzdxi();
1341 const std::vector<RealGradient> & dxyz_deta = fe->get_dxyzdeta();
1345 std::vector<Point> points(1);
1347 fe->reinit(side, &points);
1349 RealGradient d = *secondary_point - phys_point[0];
1351 const Real twosqrt2 = 2.8284;
1352 Real max_face_length = side->hmax() + twosqrt2 * tangential_tolerance;
1354 RealVectorValue normal;
1357 normal = dxyz_dxi[0].
cross(dxyz_deta[0]);
1359 else if (
dim - 1 == 1)
1361 const Node *
const * elem_nodes = primary_elem->get_nodes();
1362 const Point in_plane_vector1 = *elem_nodes[1] - *elem_nodes[0];
1363 const Point in_plane_vector2 = *elem_nodes[2] - *elem_nodes[0];
1365 Point out_of_plane_normal = in_plane_vector1.cross(in_plane_vector2);
1366 out_of_plane_normal /= out_of_plane_normal.norm();
1368 normal = dxyz_dxi[0].cross(out_of_plane_normal);
1374 normal /= normal.norm();
1376 const Real dot(d * normal);
1378 const RealGradient normcomp = dot * normal;
1379 const RealGradient tangcomp = d - normcomp;
1381 const Real tangdist = tangcomp.norm();
1385 const Real faceExpansionFactor = 2.0 * (1.0 + normcomp.norm() / d.norm());
1387 bool isReasonableCandidate =
true;
1388 if (tangdist > faceExpansionFactor * max_face_length)
1390 isReasonableCandidate =
false;
1392 return isReasonableCandidate;
1400 std::vector<Point> points(1);
1401 points[0] = info._starting_closest_point_ref;
1402 const auto & side =
_elem_side_builder(*info._starting_elem, info._starting_side_num);
1403 fe.reinit(&side, &points);
1404 const std::vector<Point> & starting_point = fe.get_xyz();
1405 info._incremental_slip = info._closest_point - starting_point[0];
1406 if (info.isCaptured())
1408 info._frictional_energy =
1409 info._frictional_energy_old + info._contact_force * info._incremental_slip;
1410 info._accumulated_slip = info._accumulated_slip_old + info._incremental_slip.norm();
1416 std::vector<PenetrationInfo *> & p_info,
1425 std::vector<Real> edge_face_weights;
1426 std::vector<PenetrationInfo *> edge_face_info;
1430 mooseAssert(edge_face_info.size() == edge_face_weights.size(),
1431 "edge_face_info.size() != edge_face_weights.size()");
1433 if (edge_face_info.size() > 0)
1436 RealVectorValue new_normal;
1437 Real this_face_weight = 1.0;
1439 for (
unsigned int efwi = 0; efwi < edge_face_weights.size(); ++efwi)
1443 new_normal += npi->
_normal * edge_face_weights[efwi];
1445 this_face_weight -= edge_face_weights[efwi];
1447 mooseAssert(this_face_weight >= (0.25 - 1e-8),
1448 "Sum of weights of other faces shouldn't exceed 0.75");
1449 new_normal += info->_normal * this_face_weight;
1451 const Real len = new_normal.norm();
1455 info->_normal = new_normal;
1465 const Real len(info->_normal.norm());
1467 info->_normal /= len;
1474 std::vector<PenetrationInfo *> & edge_face_info,
1475 std::vector<Real> & edge_face_weights,
1476 std::vector<PenetrationInfo *> & p_info,
1477 const Node & secondary_node)
1479 const Elem * side = info->_side;
1480 const Point & p = info->_closest_point_ref;
1481 std::set<dof_id_type> elems_to_exclude;
1482 elems_to_exclude.insert(info->_elem->id());
1484 std::vector<std::vector<const Node *>> edge_nodes;
1488 std::vector<Elem *> edge_neighbor_elems;
1489 edge_face_info.resize(edge_nodes.size(), NULL);
1491 std::vector<unsigned int> edges_without_neighbors;
1493 for (
unsigned int i = 0; i < edge_nodes.size(); ++i)
1496 std::sort(edge_nodes[i].begin(), edge_nodes[i].end());
1498 std::vector<PenetrationInfo *> face_info_comm_edge;
1500 &secondary_node, elems_to_exclude, edge_nodes[i], face_info_comm_edge, p_info);
1502 if (face_info_comm_edge.size() == 0)
1503 edges_without_neighbors.push_back(i);
1504 else if (face_info_comm_edge.size() > 1)
1505 mooseError(
"Only one neighbor allowed per edge");
1507 edge_face_info[i] = face_info_comm_edge[0];
1511 std::vector<unsigned int>::reverse_iterator rit;
1512 for (rit = edges_without_neighbors.rbegin(); rit != edges_without_neighbors.rend(); ++rit)
1514 unsigned int index = *rit;
1515 edge_nodes.erase(edge_nodes.begin() + index);
1516 edge_face_weights.erase(edge_face_weights.begin() + index);
1517 edge_face_info.erase(edge_face_info.begin() + index);
1521 if (edge_nodes.size() > 1)
1523 if (edge_nodes.size() != 2)
1524 mooseError(
"Invalid number of smoothing edges");
1527 std::vector<const Node *> common_nodes;
1528 std::set_intersection(edge_nodes[0].begin(),
1529 edge_nodes[0].end(),
1530 edge_nodes[1].begin(),
1531 edge_nodes[1].end(),
1532 std::inserter(common_nodes, common_nodes.end()));
1534 if (common_nodes.size() != 1)
1535 mooseError(
"Invalid number of common nodes");
1537 for (
const auto & pinfo : edge_face_info)
1538 elems_to_exclude.insert(pinfo->_elem->id());
1540 std::vector<PenetrationInfo *> face_info_comm_edge;
1542 &secondary_node, elems_to_exclude, common_nodes, face_info_comm_edge, p_info);
1544 unsigned int num_corner_neighbors = face_info_comm_edge.size();
1546 if (num_corner_neighbors > 0)
1548 Real fw0 = edge_face_weights[0];
1549 Real fw1 = edge_face_weights[1];
1552 Real fw_corner = (fw0 * fw1) /
static_cast<Real
>(num_corner_neighbors);
1555 edge_face_weights[0] *= (1.0 - fw1);
1556 edge_face_weights[1] *= (1.0 - fw0);
1558 for (
unsigned int i = 0; i < num_corner_neighbors; ++i)
1560 edge_face_weights.push_back(fw_corner);
1561 edge_face_info.push_back(face_info_comm_edge[i]);
1571 std::vector<std::vector<const Node *>> & edge_nodes,
1572 std::vector<Real> & edge_face_weights)
1574 const ElemType t(side->type());
1575 const Real &
xi = p(0);
1576 const Real &
eta = p(1);
1586 if (
xi < -smooth_limit)
1588 std::vector<const Node *> en;
1589 en.push_back(side->node_ptr(0));
1590 edge_nodes.push_back(en);
1594 edge_face_weights.push_back(fw);
1596 else if (
xi > smooth_limit)
1598 std::vector<const Node *> en;
1599 en.push_back(side->node_ptr(1));
1600 edge_nodes.push_back(en);
1604 edge_face_weights.push_back(fw);
1613 if (
eta < -smooth_limit)
1615 std::vector<const Node *> en;
1616 en.push_back(side->node_ptr(0));
1617 en.push_back(side->node_ptr(1));
1618 edge_nodes.push_back(en);
1622 edge_face_weights.push_back(fw);
1624 if ((
xi +
eta) > smooth_limit)
1626 std::vector<const Node *> en;
1627 en.push_back(side->node_ptr(1));
1628 en.push_back(side->node_ptr(2));
1629 edge_nodes.push_back(en);
1633 edge_face_weights.push_back(fw);
1635 if (
xi < -smooth_limit)
1637 std::vector<const Node *> en;
1638 en.push_back(side->node_ptr(2));
1639 en.push_back(side->node_ptr(0));
1640 edge_nodes.push_back(en);
1644 edge_face_weights.push_back(fw);
1653 if (
eta < -smooth_limit)
1655 std::vector<const Node *> en;
1656 en.push_back(side->node_ptr(0));
1657 en.push_back(side->node_ptr(1));
1658 edge_nodes.push_back(en);
1662 edge_face_weights.push_back(fw);
1664 if (
xi > smooth_limit)
1666 std::vector<const Node *> en;
1667 en.push_back(side->node_ptr(1));
1668 en.push_back(side->node_ptr(2));
1669 edge_nodes.push_back(en);
1673 edge_face_weights.push_back(fw);
1675 if (
eta > smooth_limit)
1677 std::vector<const Node *> en;
1678 en.push_back(side->node_ptr(2));
1679 en.push_back(side->node_ptr(3));
1680 edge_nodes.push_back(en);
1684 edge_face_weights.push_back(fw);
1686 if (
xi < -smooth_limit)
1688 std::vector<const Node *> en;
1689 en.push_back(side->node_ptr(3));
1690 en.push_back(side->node_ptr(0));
1691 edge_nodes.push_back(en);
1695 edge_face_weights.push_back(fw);
1710 const Node * secondary_node,
1711 const std::set<dof_id_type> & elems_to_exclude,
1712 const std::vector<const Node *> edge_nodes,
1713 std::vector<PenetrationInfo *> & face_info_comm_edge,
1714 std::vector<PenetrationInfo *> & p_info)
1720 mooseAssert(node_to_elem_pair !=
_node_to_elem_map.end(),
"Missing entry in node to elem map");
1721 const std::vector<dof_id_type> & elems_connected_to_node = node_to_elem_pair->second;
1723 std::vector<const Elem *> elems_connected_to_edge;
1725 for (
unsigned int ecni = 0; ecni < elems_connected_to_node.size(); ecni++)
1727 if (elems_to_exclude.find(elems_connected_to_node[ecni]) != elems_to_exclude.end())
1729 const Elem * elem =
_mesh.
elemPtr(elems_connected_to_node[ecni]);
1731 std::vector<const Node *> nodevec;
1732 for (
unsigned int ni = 0; ni < elem->n_nodes(); ++ni)
1733 if (elem->is_vertex(ni))
1734 nodevec.push_back(elem->node_ptr(ni));
1736 std::vector<const Node *> common_nodes;
1737 std::sort(nodevec.begin(), nodevec.end());
1738 std::set_intersection(edge_nodes.begin(),
1742 std::inserter(common_nodes, common_nodes.end()));
1744 if (common_nodes.size() == edge_nodes.size())
1745 elems_connected_to_edge.push_back(elem);
1748 if (elems_connected_to_edge.size() > 0)
1758 bool allowMultipleNeighbors =
false;
1760 if (elems_connected_to_edge[0]->
dim() == 3)
1762 if (edge_nodes.size() == 1)
1764 allowMultipleNeighbors =
true;
1768 for (
unsigned int i = 0; i < elems_connected_to_edge.size(); ++i)
1770 std::vector<PenetrationInfo *> thisElemInfo;
1771 getInfoForElem(thisElemInfo, p_info, elems_connected_to_edge[i]);
1772 if (thisElemInfo.size() > 0 && !allowMultipleNeighbors)
1774 if (thisElemInfo.size() > 1)
1776 "Found multiple neighbors to current edge/face on surface when only one is allowed");
1777 face_info_comm_edge.push_back(thisElemInfo[0]);
1782 thisElemInfo, p_info, secondary_node, elems_connected_to_edge[i], edge_nodes);
1783 if (thisElemInfo.size() > 0 && !allowMultipleNeighbors)
1785 if (thisElemInfo.size() > 1)
1787 "Found multiple neighbors to current edge/face on surface when only one is allowed");
1788 face_info_comm_edge.push_back(thisElemInfo[0]);
1792 for (
unsigned int j = 0; j < thisElemInfo.size(); ++j)
1793 face_info_comm_edge.push_back(thisElemInfo[j]);
1800 std::vector<PenetrationInfo *> & p_info,
1803 for (
const auto & pi : p_info)
1808 if (pi->_elem == elem)
1809 thisElemInfo.push_back(pi);
1815 std::vector<PenetrationInfo *> & p_info,
1816 const Node * secondary_node,
1818 const std::vector<const Node *> & nodes_that_must_be_on_side,
1819 const bool check_whether_reasonable)
1821 const BoundaryInfo & boundary_info =
_mesh.
getMesh().get_boundary_info();
1823 for (
auto s : elem->side_index_range())
1829 bool already_have_info_this_side =
false;
1830 for (
const auto & pi : thisElemInfo)
1831 if (pi->_side_num == s)
1833 already_have_info_this_side =
true;
1837 if (already_have_info_this_side)
1840 const Elem * side = elem->build_side_ptr(s).release();
1844 std::vector<const Node *> nodevec;
1845 for (
unsigned int ni = 0; ni < side->n_nodes(); ++ni)
1846 nodevec.push_back(side->node_ptr(ni));
1848 std::sort(nodevec.begin(), nodevec.end());
1849 std::vector<const Node *> common_nodes;
1850 std::set_intersection(nodes_that_must_be_on_side.begin(),
1851 nodes_that_must_be_on_side.end(),
1854 std::inserter(common_nodes, common_nodes.end()));
1855 if (common_nodes.size() != nodes_that_must_be_on_side.size())
1861 FEBase * fe_elem =
_fes[
_tid][elem->dim()];
1862 FEBase * fe_side =
_fes[
_tid][side->dim()];
1866 if (check_whether_reasonable)
1875 Point contact_on_face_ref;
1877 Real tangential_distance = 0.;
1878 RealGradient normal;
1879 bool contact_point_on_side;
1880 std::vector<const Node *> off_edge_nodes;
1881 std::vector<std::vector<Real>> side_phi;
1882 std::vector<std::vector<RealGradient>> side_grad_phi;
1883 std::vector<RealGradient> dxyzdxi;
1884 std::vector<RealGradient> dxyzdeta;
1885 std::vector<RealGradient> d2xyzdxideta;
1887 std::unique_ptr<PenetrationInfo> pen_info =
1888 std::make_unique<PenetrationInfo>(elem,
1893 tangential_distance,
1896 contact_on_face_ref,
1904 bool search_succeeded =
false;
1912 contact_point_on_side,
1916 if (search_succeeded)
1918 thisElemInfo.push_back(pen_info.get());
1919 p_info.push_back(pen_info.release());
boundary_id_type BoundaryID
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
Threads::spin_mutex pinfo_mutex
MooseMesh wraps a libMesh::Mesh object and enhances its capabilities by caching additional data and s...
virtual const Node & nodeRef(const dof_id_type i) const
virtual Elem * elemPtr(const dof_id_type i)
MeshBase & getMesh()
Accessor for the underlying libMesh Mesh object.
virtual std::unique_ptr< libMesh::PointLocatorBase > getPointLocator() const
Proxy function to get a (sub)PointLocator from either the underlying libMesh mesh (default),...
OutputType getValue(const Elem *elem, const std::vector< std::vector< OutputShape > > &phi) const
Compute the variable value at a point on an element.
Finds the nearest node to each node in boundary1 to each node in boundary2 and the other way around.
const Node * nearestNode(dof_id_type node_id)
Valid to call this after findNodes() has been called to get a pointer to the nearest node.
Data structure used to hold penetration information.
std::vector< const Node * > _off_edge_nodes
Real _accumulated_slip_old
MECH_STATUS_ENUM _mech_status
RealVectorValue _contact_force_old
Real _frictional_energy_old
unsigned int _locked_this_step
MECH_STATUS_ENUM _mech_status_old
RealVectorValue _contact_force
unsigned int _starting_side_num
const Elem * _starting_elem
Real _lagrange_multiplier
Real _tangential_distance
Point _starting_closest_point_ref
RealVectorValue _lagrange_multiplier_slip
unsigned int _stick_locked_this_step
void computeSlip(libMesh::FEBase &fe, PenetrationInfo &info)
void createInfoForElem(std::vector< PenetrationInfo * > &thisElemInfo, std::vector< PenetrationInfo * > &p_info, const Node *secondary_node, const Elem *elem, const std::vector< const Node * > &nodes_that_must_be_on_side, const bool check_whether_reasonable=false)
std::map< dof_id_type, PenetrationInfo * > & _penetration_info
MooseVariable * _nodal_normal_x
libMesh::ElemSideBuilder _elem_side_builder
Helper for building element sides without extraneous allocation.
bool _check_whether_reasonable
void operator()(const NodeIdRange &range)
bool isFaceReasonableCandidate(const Elem *primary_elem, const Elem *side, libMesh::FEBase *fe, const libMesh::Point *secondary_point, const Real tangential_tolerance)
void getInfoForElem(std::vector< PenetrationInfo * > &thisElemInfo, std::vector< PenetrationInfo * > &p_info, const Elem *elem)
bool restrictPointToSpecifiedEdgeOfFace(libMesh::Point &p, const Node *&closest_node, const Elem *side, const std::vector< const Node * > &edge_nodes)
MooseVariable * _nodal_normal_z
const std::unordered_map< dof_id_type, std::vector< dof_id_type > > & _node_to_elem_map
std::vector< dof_id_type > _recheck_secondary_nodes
List of secondary nodes for which penetration was not detected in the current patch and for which pat...
MooseVariable * _nodal_normal_y
void getSideCornerNodes(const Elem *side, std::vector< const Node * > &corner_nodes)
bool findRidgeContactPoint(libMesh::Point &contact_point, Real &tangential_distance, const Node *&closest_node, unsigned int &index, libMesh::Point &contact_point_ref, std::vector< PenetrationInfo * > &p_info, const unsigned int index1, const unsigned int index2)
Real _tangential_tolerance
std::vector< std::vector< libMesh::FEBase * > > & _fes
void switchInfo(PenetrationInfo *&info, PenetrationInfo *&infoNew)
void getSmoothingEdgeNodesAndWeights(const libMesh::Point &p, const Elem *side, std::vector< std::vector< const Node * > > &edge_nodes, std::vector< Real > &edge_face_weights)
bool _do_normal_smoothing
CommonEdgeResult interactionsOffCommonEdge(PenetrationInfo *pi1, PenetrationInfo *pi2)
bool restrictPointToFace(libMesh::Point &p, const Node *&closest_node, const Elem *side)
libMesh::FEType & _fe_type
Real _normal_smoothing_distance
void getInfoForFacesWithCommonNodes(const Node *secondary_node, const std::set< dof_id_type > &elems_to_exclude, const std::vector< const Node * > edge_nodes, std::vector< PenetrationInfo * > &face_info_comm_edge, std::vector< PenetrationInfo * > &p_info)
void join(const PenetrationThread &other)
NearestNodeLocator & _nearest_node
PenetrationLocator::NORMAL_SMOOTHING_METHOD _normal_smoothing_method
PenetrationThread(SubProblem &subproblem, const MooseMesh &mesh, BoundaryID primary_boundary, BoundaryID secondary_boundary, std::map< dof_id_type, PenetrationInfo * > &penetration_info, bool check_whether_reasonable, bool update_location, Real tangential_tolerance, bool do_normal_smoothing, Real normal_smoothing_distance, PenetrationLocator::NORMAL_SMOOTHING_METHOD normal_smoothing_method, bool use_point_locator, std::vector< std::vector< libMesh::FEBase * > > &fes, libMesh::FEType &fe_type, NearestNodeLocator &nearest_node, const std::unordered_map< dof_id_type, std::vector< dof_id_type > > &node_to_elem_map)
void smoothNormal(PenetrationInfo *info, std::vector< PenetrationInfo * > &p_info, const Node &node)
void getSmoothingFacesAndWeights(PenetrationInfo *info, std::vector< PenetrationInfo * > &edge_face_info, std::vector< Real > &edge_face_weights, std::vector< PenetrationInfo * > &p_info, const Node &secondary_node)
BoundaryID _primary_boundary
CompeteInteractionResult competeInteractionsBothOnFace(PenetrationInfo *pi1, PenetrationInfo *pi2)
Determine whether first (pi1) or second (pi2) interaction is stronger when it is known that the node ...
CompeteInteractionResult competeInteractions(PenetrationInfo *pi1, PenetrationInfo *pi2)
When interactions are identified between a node and two faces, compete between the faces to determine...
Generic class for solving transient nonlinear problems.
virtual MooseVariable & getStandardVariable(const THREAD_ID tid, const std::string &var_name)=0
Returns the variable reference for requested MooseVariable which may be in any system.
TypeVector< typename CompareTypes< T, T2 >::supertype > cross(const TypeVector< T2 > &v) const
void findContactPoint(PenetrationInfo &p_info, libMesh::FEBase *fe_elem, libMesh::FEBase *fe_side, libMesh::FEType &fe_side_type, const libMesh::Point &secondary_point, bool start_with_centroid, const Real tangential_tolerance, bool &contact_point_on_side, bool &search_succeeded)
const unsigned int invalid_uint
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
libMesh::Point _closest_coor
Real _tangential_distance
libMesh::Point _closest_coor_ref
const Node * _closest_node
std::vector< RidgeData > _ridge_data_vec
const Node * _closest_node
Real distance(const Point &p)