www.mooseframework.org
Classes | Public Member Functions | Public Attributes | Protected Types | Protected Member Functions | Protected Attributes | List of all members
PenetrationThread Class Reference

#include <PenetrationThread.h>

Classes

struct  RidgeData
 
struct  RidgeSetData
 

Public Member Functions

 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, std::vector< std::vector< FEBase *>> &fes, FEType &fe_type, NearestNodeLocator &nearest_node, const std::map< dof_id_type, std::vector< dof_id_type >> &node_to_elem_map, const std::vector< std::tuple< dof_id_type, unsigned short int, boundary_id_type >> &bc_tuples)
 
 PenetrationThread (PenetrationThread &x, Threads::split split)
 
void operator() (const NodeIdRange &range)
 
void join (const PenetrationThread &other)
 

Public Attributes

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 patch has to be updated. More...
 

Protected Types

enum  CompeteInteractionResult { FIRST_WINS, SECOND_WINS, NEITHER_WINS }
 
enum  CommonEdgeResult { NO_COMMON, COMMON_EDGE, COMMON_NODE, EDGE_AND_COMMON_NODE }
 

Protected Member Functions

CompeteInteractionResult competeInteractions (PenetrationInfo *pi1, PenetrationInfo *pi2)
 When interactions are identified between a node and two faces, compete between the faces to determine whether first (pi1) or second (pi2) interaction is stronger. More...
 
CompeteInteractionResult competeInteractionsBothOnFace (PenetrationInfo *pi1, PenetrationInfo *pi2)
 Determine whether first (pi1) or second (pi2) interaction is stronger when it is known that the node projects to both of the two competing faces. More...
 
CommonEdgeResult interactionsOffCommonEdge (PenetrationInfo *pi1, PenetrationInfo *pi2)
 
bool findRidgeContactPoint (Point &contact_point, Real &tangential_distance, const Node *&closest_node, unsigned int &index, Point &contact_point_ref, std::vector< PenetrationInfo *> &p_info, const unsigned int index1, const unsigned int index2)
 
void getSideCornerNodes (const Elem *side, std::vector< const Node *> &corner_nodes)
 
bool restrictPointToSpecifiedEdgeOfFace (Point &p, const Node *&closest_node, const Elem *side, const std::vector< const Node *> &edge_nodes)
 
bool restrictPointToFace (Point &p, const Node *&closest_node, const Elem *side)
 
bool isFaceReasonableCandidate (const Elem *primary_elem, const Elem *side, FEBase *fe, const Point *secondary_point, const Real tangential_tolerance)
 
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)
 
void getSmoothingEdgeNodesAndWeights (const Point &p, const Elem *side, std::vector< std::vector< const Node *>> &edge_nodes, std::vector< Real > &edge_face_weights)
 
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 getInfoForElem (std::vector< PenetrationInfo *> &thisElemInfo, std::vector< PenetrationInfo *> &p_info, const Elem *elem)
 
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)
 
void getSidesOnPrimaryBoundary (std::vector< unsigned int > &sides, const Elem *const elem)
 
void computeSlip (FEBase &fe, PenetrationInfo &info)
 
void switchInfo (PenetrationInfo *&info, PenetrationInfo *&infoNew)
 

Protected Attributes

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
 
MooseVariable_nodal_normal_x
 
MooseVariable_nodal_normal_y
 
MooseVariable_nodal_normal_z
 
std::vector< std::vector< FEBase * > > & _fes
 
FEType & _fe_type
 
NearestNodeLocator_nearest_node
 
const std::map< dof_id_type, std::vector< dof_id_type > > & _node_to_elem_map
 
const std::vector< std::tuple< dof_id_type, unsigned short int, boundary_id_type > > & _bc_tuples
 
THREAD_ID _tid
 
ElemSideBuilder _elem_side_builder
 Helper for building element sides without extraneous allocation. More...
 

Detailed Description

Definition at line 24 of file PenetrationThread.h.

Member Enumeration Documentation

◆ CommonEdgeResult

Enumerator
NO_COMMON 
COMMON_EDGE 
COMMON_NODE 
EDGE_AND_COMMON_NODE 

Definition at line 98 of file PenetrationThread.h.

◆ CompeteInteractionResult

Enumerator
FIRST_WINS 
SECOND_WINS 
NEITHER_WINS 

Definition at line 91 of file PenetrationThread.h.

Constructor & Destructor Documentation

◆ PenetrationThread() [1/2]

PenetrationThread::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,
std::vector< std::vector< FEBase *>> &  fes,
FEType &  fe_type,
NearestNodeLocator nearest_node,
const std::map< dof_id_type, std::vector< dof_id_type >> &  node_to_elem_map,
const std::vector< std::tuple< dof_id_type, unsigned short int, boundary_id_type >> &  bc_tuples 
)

Definition at line 27 of file PenetrationThread.C.

44  : _subproblem(subproblem),
45  _mesh(mesh),
46  _primary_boundary(primary_boundary),
47  _secondary_boundary(secondary_boundary),
48  _penetration_info(penetration_info),
49  _check_whether_reasonable(check_whether_reasonable),
50  _update_location(update_location),
51  _tangential_tolerance(tangential_tolerance),
52  _do_normal_smoothing(do_normal_smoothing),
53  _normal_smoothing_distance(normal_smoothing_distance),
54  _normal_smoothing_method(normal_smoothing_method),
55  _nodal_normal_x(NULL),
56  _nodal_normal_y(NULL),
57  _nodal_normal_z(NULL),
58  _fes(fes),
59  _fe_type(fe_type),
60  _nearest_node(nearest_node),
61  _node_to_elem_map(node_to_elem_map),
62  _bc_tuples(bc_tuples)
63 {
64 }
MooseVariable * _nodal_normal_z
NearestNodeLocator & _nearest_node
const std::vector< std::tuple< dof_id_type, unsigned short int, boundary_id_type > > & _bc_tuples
BoundaryID _primary_boundary
SubProblem & _subproblem
const MooseMesh & _mesh
std::vector< std::vector< FEBase * > > & _fes
BoundaryID _secondary_boundary
std::map< dof_id_type, PenetrationInfo * > & _penetration_info
MooseVariable * _nodal_normal_y
const std::map< dof_id_type, std::vector< dof_id_type > > & _node_to_elem_map
MooseVariable * _nodal_normal_x
PenetrationLocator::NORMAL_SMOOTHING_METHOD _normal_smoothing_method

◆ PenetrationThread() [2/2]

PenetrationThread::PenetrationThread ( PenetrationThread x,
Threads::split  split 
)

Definition at line 67 of file PenetrationThread.C.

69  _mesh(x._mesh),
79  _fes(x._fes),
80  _fe_type(x._fe_type),
84 {
85 }
NearestNodeLocator & _nearest_node
const std::vector< std::tuple< dof_id_type, unsigned short int, boundary_id_type > > & _bc_tuples
BoundaryID _primary_boundary
SubProblem & _subproblem
const MooseMesh & _mesh
std::vector< std::vector< FEBase * > > & _fes
BoundaryID _secondary_boundary
std::map< dof_id_type, PenetrationInfo * > & _penetration_info
const std::map< dof_id_type, std::vector< dof_id_type > > & _node_to_elem_map
PenetrationLocator::NORMAL_SMOOTHING_METHOD _normal_smoothing_method

Member Function Documentation

◆ competeInteractions()

PenetrationThread::CompeteInteractionResult PenetrationThread::competeInteractions ( PenetrationInfo pi1,
PenetrationInfo pi2 
)
protected

When interactions are identified between a node and two faces, compete between the faces to determine whether first (pi1) or second (pi2) interaction is stronger.

Parameters
pi1Pointer to the PenetrationInfo object for the first face
pi2Pointer to the PenetrationInfo object for the second face
Returns
Appropriate ComputeInterationResult enum entry identifying which face is a better match

Definition at line 504 of file PenetrationThread.C.

Referenced by operator()().

505 {
506 
508 
510  pi2->_tangential_distance > _tangential_tolerance) // out of tol on both faces
511  result = NEITHER_WINS;
512 
513  else if (pi1->_tangential_distance == 0.0 &&
514  pi2->_tangential_distance > 0.0) // on face 1, off face 2
515  result = FIRST_WINS;
516 
517  else if (pi2->_tangential_distance == 0.0 &&
518  pi1->_tangential_distance > 0.0) // on face 2, off face 1
519  result = SECOND_WINS;
520 
521  else if (pi1->_tangential_distance <= _tangential_tolerance &&
522  pi2->_tangential_distance > _tangential_tolerance) // in face 1 tol, out of face 2 tol
523  result = FIRST_WINS;
524 
525  else if (pi2->_tangential_distance <= _tangential_tolerance &&
526  pi1->_tangential_distance > _tangential_tolerance) // in face 2 tol, out of face 1 tol
527  result = SECOND_WINS;
528 
529  else if (pi1->_tangential_distance == 0.0 && pi2->_tangential_distance == 0.0) // on both faces
530  result = competeInteractionsBothOnFace(pi1, pi2);
531 
532  else if (pi1->_tangential_distance <= _tangential_tolerance &&
533  pi2->_tangential_distance <= _tangential_tolerance) // off but within tol of both faces
534  {
536  if (cer == COMMON_EDGE || cer == COMMON_NODE) // ridge case.
537  {
538  // We already checked for ridges, and it got rejected, so neither face must be valid
539  result = NEITHER_WINS;
540  // mooseError("Erroneously encountered ridge case");
541  }
542  else if (cer == EDGE_AND_COMMON_NODE) // off side of face, off corner of another face. Favor
543  // the off-side face
544  {
545  if (pi1->_off_edge_nodes.size() == pi2->_off_edge_nodes.size())
546  mooseError("Invalid off_edge_nodes counts");
547 
548  else if (pi1->_off_edge_nodes.size() == 2)
549  result = FIRST_WINS;
550 
551  else if (pi2->_off_edge_nodes.size() == 2)
552  result = SECOND_WINS;
553 
554  else
555  mooseError("Invalid off_edge_nodes counts");
556  }
557  else // The node projects to both faces within tangential tolerance.
558  result = competeInteractionsBothOnFace(pi1, pi2);
559  }
560 
561  return result;
562 }
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:299
std::vector< const Node * > _off_edge_nodes
CompeteInteractionResult competeInteractionsBothOnFace(PenetrationInfo *pi1, PenetrationInfo *pi2)
Determine whether first (pi1) or second (pi2) interaction is stronger when it is known that the node ...
CommonEdgeResult interactionsOffCommonEdge(PenetrationInfo *pi1, PenetrationInfo *pi2)

◆ competeInteractionsBothOnFace()

PenetrationThread::CompeteInteractionResult PenetrationThread::competeInteractionsBothOnFace ( PenetrationInfo pi1,
PenetrationInfo pi2 
)
protected

Determine whether first (pi1) or second (pi2) interaction is stronger when it is known that the node projects to both of the two competing faces.

Parameters
pi1Pointer to the PenetrationInfo object for the first face
pi2Pointer to the PenetrationInfo object for the second face
Returns
Appropriate ComputeInterationResult enum entry identifying which face is a better match

Definition at line 565 of file PenetrationThread.C.

Referenced by competeInteractions().

566 {
568 
569  if (pi1->_distance >= 0.0 && pi2->_distance < 0.0)
570  result = FIRST_WINS; // favor face with positive distance (penetrated) -- first in this case
571 
572  else if (pi2->_distance >= 0.0 && pi1->_distance < 0.0)
573  result = SECOND_WINS; // favor face with positive distance (penetrated) -- second in this case
574 
575  // TODO: This logic below could cause an abrupt jump from one face to the other with small mesh
576  // movement. If there is some way to smooth the transition, we should do it.
578  result = FIRST_WINS; // otherwise, favor the closer face -- first in this case
579 
581  result = SECOND_WINS; // otherwise, favor the closer face -- second in this case
582 
583  else // Equal within tolerance. Favor the one with a smaller element id (for repeatibility)
584  {
585  if (pi1->_elem->id() < pi2->_elem->id())
586  result = FIRST_WINS;
587 
588  else
589  result = SECOND_WINS;
590  }
591 
592  return result;
593 }
ADRealEigenVector< T, D, asd > abs(const ADRealEigenVector< T, D, asd > &)
const Elem * _elem
bool relativeFuzzyLessThan(const T &var1, const T2 &var2, const T3 &tol=libMesh::TOLERANCE *libMesh::TOLERANCE)
Function to check whether a variable is less than another variable within a relative tolerance...
Definition: MooseUtils.h:587

◆ computeSlip()

void PenetrationThread::computeSlip ( FEBase fe,
PenetrationInfo info 
)
protected

Definition at line 1213 of file PenetrationThread.C.

Referenced by operator()().

1214 {
1215  // Slip is current projected position of secondary node minus
1216  // original projected position of secondary node
1217  std::vector<Point> points(1);
1218  points[0] = info._starting_closest_point_ref;
1219  const auto & side = _elem_side_builder(*info._starting_elem, info._starting_side_num);
1220  fe.reinit(&side, &points);
1221  const std::vector<Point> & starting_point = fe.get_xyz();
1222  info._incremental_slip = info._closest_point - starting_point[0];
1223  if (info.isCaptured())
1224  {
1225  info._frictional_energy =
1226  info._frictional_energy_old + info._contact_force * info._incremental_slip;
1227  info._accumulated_slip = info._accumulated_slip_old + info._incremental_slip.norm();
1228  }
1229 }
MPI_Info info
ElemSideBuilder _elem_side_builder
Helper for building element sides without extraneous allocation.

◆ createInfoForElem()

void PenetrationThread::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 
)
protected

Definition at line 1631 of file PenetrationThread.C.

Referenced by getInfoForFacesWithCommonNodes(), and operator()().

1637 {
1638  std::vector<unsigned int> sides;
1639  // TODO: After libMesh update, add this line to MooseMesh.h, call sidesWithBoundaryID, delete
1640  // getSidesOnPrimaryBoundary, and delete vectors used by it
1641  // void sidesWithBoundaryID(std::vector<unsigned int>& sides, const Elem * const elem, const
1642  // BoundaryID boundary_id) const
1643  // {
1644  // _mesh.get_boundary_info().sides_with_boundary_id(sides, elem, boundary_id);
1645  // }
1646  getSidesOnPrimaryBoundary(sides, elem);
1647  // _mesh.sidesWithBoundaryID(sides, elem, _primary_boundary);
1648 
1649  for (unsigned int i = 0; i < sides.size(); ++i)
1650  {
1651  // Don't create info for this side if one already exists
1652  bool already_have_info_this_side = false;
1653  for (const auto & pi : thisElemInfo)
1654  if (pi->_side_num == sides[i])
1655  {
1656  already_have_info_this_side = true;
1657  break;
1658  }
1659 
1660  if (already_have_info_this_side)
1661  break;
1662 
1663  const Elem * side = (elem->build_side_ptr(sides[i], false)).release();
1664 
1665  // Only continue with creating info for this side if the side contains
1666  // all of the nodes in nodes_that_must_be_on_side
1667  std::vector<const Node *> nodevec;
1668  for (unsigned int ni = 0; ni < side->n_nodes(); ++ni)
1669  nodevec.push_back(side->node_ptr(ni));
1670 
1671  std::sort(nodevec.begin(), nodevec.end());
1672  std::vector<const Node *> common_nodes;
1673  std::set_intersection(nodes_that_must_be_on_side.begin(),
1674  nodes_that_must_be_on_side.end(),
1675  nodevec.begin(),
1676  nodevec.end(),
1677  std::inserter(common_nodes, common_nodes.end()));
1678  if (common_nodes.size() != nodes_that_must_be_on_side.size())
1679  {
1680  delete side;
1681  break;
1682  }
1683 
1684  FEBase * fe_elem = _fes[_tid][elem->dim()];
1685  FEBase * fe_side = _fes[_tid][side->dim()];
1686 
1687  // Optionally check to see whether face is reasonable candidate based on an
1688  // estimate of how closely it is likely to project to the face
1689  if (check_whether_reasonable)
1690  if (!isFaceReasonableCandidate(elem, side, fe_side, secondary_node, _tangential_tolerance))
1691  {
1692  delete side;
1693  break;
1694  }
1695 
1696  Point contact_phys;
1697  Point contact_ref;
1698  Point contact_on_face_ref;
1699  Real distance = 0.;
1700  Real tangential_distance = 0.;
1701  RealGradient normal;
1702  bool contact_point_on_side;
1703  std::vector<const Node *> off_edge_nodes;
1704  std::vector<std::vector<Real>> side_phi;
1705  std::vector<std::vector<RealGradient>> side_grad_phi;
1706  std::vector<RealGradient> dxyzdxi;
1707  std::vector<RealGradient> dxyzdeta;
1708  std::vector<RealGradient> d2xyzdxideta;
1709 
1710  PenetrationInfo * pen_info = new PenetrationInfo(elem,
1711  side,
1712  sides[i],
1713  normal,
1714  distance,
1715  tangential_distance,
1716  contact_phys,
1717  contact_ref,
1718  contact_on_face_ref,
1719  off_edge_nodes,
1720  side_phi,
1721  side_grad_phi,
1722  dxyzdxi,
1723  dxyzdeta,
1724  d2xyzdxideta);
1725 
1726  Moose::findContactPoint(*pen_info,
1727  fe_elem,
1728  fe_side,
1729  _fe_type,
1730  *secondary_node,
1731  true,
1733  contact_point_on_side);
1734 
1735  thisElemInfo.push_back(pen_info);
1736 
1737  p_info.push_back(pen_info);
1738  }
1739 }
void getSidesOnPrimaryBoundary(std::vector< unsigned int > &sides, const Elem *const elem)
Data structure used to hold penetration information.
Real distance(const Point &p)
std::vector< std::vector< FEBase * > > & _fes
void findContactPoint(PenetrationInfo &p_info, FEBase *fe_elem, FEBase *fe_side, FEType &fe_side_type, const Point &secondary_point, bool start_with_centroid, const Real tangential_tolerance, bool &contact_point_on_side)
Finds the closest point (called the contact point) on the primary_elem on side "side" to the secondar...
bool isFaceReasonableCandidate(const Elem *primary_elem, const Elem *side, FEBase *fe, const Point *secondary_point, const Real tangential_tolerance)
FEGenericBase< Real > FEBase
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
const Real pi

◆ findRidgeContactPoint()

bool PenetrationThread::findRidgeContactPoint ( Point &  contact_point,
Real tangential_distance,
const Node *&  closest_node,
unsigned int index,
Point &  contact_point_ref,
std::vector< PenetrationInfo *> &  p_info,
const unsigned int  index1,
const unsigned int  index2 
)
protected

Definition at line 650 of file PenetrationThread.C.

Referenced by operator()().

658 {
659  tangential_distance = 0.0;
660  closest_node = NULL;
661  PenetrationInfo * pi1 = p_info[index1];
662  PenetrationInfo * pi2 = p_info[index2];
663  const unsigned sidedim(pi1->_side->dim());
664  mooseAssert(sidedim == pi2->_side->dim(), "Incompatible dimensionalities");
665 
666  // Nodes on faces for the two interactions
667  std::vector<const Node *> side1_nodes;
668  getSideCornerNodes(pi1->_side, side1_nodes);
669  std::vector<const Node *> side2_nodes;
670  getSideCornerNodes(pi2->_side, side2_nodes);
671 
672  std::sort(side1_nodes.begin(), side1_nodes.end());
673  std::sort(side2_nodes.begin(), side2_nodes.end());
674 
675  // Find nodes shared by the two faces
676  std::vector<const Node *> common_nodes;
677  std::set_intersection(side1_nodes.begin(),
678  side1_nodes.end(),
679  side2_nodes.begin(),
680  side2_nodes.end(),
681  std::inserter(common_nodes, common_nodes.end()));
682 
683  if (common_nodes.size() != sidedim)
684  return false;
685 
686  bool found_point1, found_point2;
687  Point closest_coor_ref1(pi1->_closest_point_ref);
688  const Node * closest_node1;
689  found_point1 = restrictPointToSpecifiedEdgeOfFace(
690  closest_coor_ref1, closest_node1, pi1->_side, common_nodes);
691 
692  Point closest_coor_ref2(pi2->_closest_point_ref);
693  const Node * closest_node2;
694  found_point2 = restrictPointToSpecifiedEdgeOfFace(
695  closest_coor_ref2, closest_node2, pi2->_side, common_nodes);
696 
697  if (!found_point1 || !found_point2)
698  return false;
699 
700  // if (sidedim == 2)
701  // {
702  // TODO:
703  // We have the parametric coordinates of the closest intersection point for both faces.
704  // We need to find a point somewhere in the middle of them so there's not an abrupt jump.
705  // Find that point by taking dot products of vector from contact point to secondary node point
706  // with face normal vectors to see which face we're closer to.
707  // }
708 
709  FEBase * fe = NULL;
710  std::vector<Point> points(1);
711 
712  // We have to pick one of the two faces to own the contact point. It doesn't really matter
713  // which one we pick. For repeatibility, pick the face with the lowest index.
714  if (index1 < index2)
715  {
716  fe = _fes[_tid][pi1->_side->dim()];
717  contact_point_ref = closest_coor_ref1;
718  points[0] = closest_coor_ref1;
719  fe->reinit(pi1->_side, &points);
720  index = index1;
721  }
722  else
723  {
724  fe = _fes[_tid][pi2->_side->dim()];
725  contact_point_ref = closest_coor_ref2;
726  points[0] = closest_coor_ref2;
727  fe->reinit(pi2->_side, &points);
728  index = index2;
729  }
730 
731  contact_point = fe->get_xyz()[0];
732 
733  if (sidedim == 2)
734  {
735  if (closest_node1) // point is off the ridge between the two elements
736  {
737  mooseAssert((closest_node1 == closest_node2 || closest_node2 == NULL),
738  "If off edge of ridge, closest node must be the same on both elements");
739  closest_node = closest_node1;
740 
741  RealGradient off_face = *closest_node1 - contact_point;
742  tangential_distance = off_face.norm();
743  }
744  }
745 
746  return true;
747 }
auto norm() const -> decltype(std::norm(Real()))
Data structure used to hold penetration information.
void getSideCornerNodes(const Elem *side, std::vector< const Node *> &corner_nodes)
std::vector< std::vector< FEBase * > > & _fes
bool restrictPointToSpecifiedEdgeOfFace(Point &p, const Node *&closest_node, const Elem *side, const std::vector< const Node *> &edge_nodes)
const Elem * _side
FEGenericBase< Real > FEBase

◆ getInfoForElem()

void PenetrationThread::getInfoForElem ( std::vector< PenetrationInfo *> &  thisElemInfo,
std::vector< PenetrationInfo *> &  p_info,
const Elem *  elem 
)
protected

Definition at line 1616 of file PenetrationThread.C.

Referenced by getInfoForFacesWithCommonNodes().

1619 {
1620  for (const auto & pi : p_info)
1621  {
1622  if (!pi)
1623  continue;
1624 
1625  if (pi->_elem == elem)
1626  thisElemInfo.push_back(pi);
1627  }
1628 }
const Real pi

◆ getInfoForFacesWithCommonNodes()

void PenetrationThread::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 
)
protected

Definition at line 1526 of file PenetrationThread.C.

Referenced by getSmoothingFacesAndWeights().

1532 {
1533  // elems connected to a node on this edge, find one that has the same corners as this, and is not
1534  // the current elem
1535  auto node_to_elem_pair = _node_to_elem_map.find(edge_nodes[0]->id()); // just need one of the
1536  // nodes
1537  mooseAssert(node_to_elem_pair != _node_to_elem_map.end(), "Missing entry in node to elem map");
1538  const std::vector<dof_id_type> & elems_connected_to_node = node_to_elem_pair->second;
1539 
1540  std::vector<const Elem *> elems_connected_to_edge;
1541 
1542  for (unsigned int ecni = 0; ecni < elems_connected_to_node.size(); ecni++)
1543  {
1544  if (elems_to_exclude.find(elems_connected_to_node[ecni]) != elems_to_exclude.end())
1545  continue;
1546  const Elem * elem = _mesh.elemPtr(elems_connected_to_node[ecni]);
1547 
1548  std::vector<const Node *> nodevec;
1549  for (unsigned int ni = 0; ni < elem->n_nodes(); ++ni)
1550  if (elem->is_vertex(ni))
1551  nodevec.push_back(elem->node_ptr(ni));
1552 
1553  std::vector<const Node *> common_nodes;
1554  std::sort(nodevec.begin(), nodevec.end());
1555  std::set_intersection(edge_nodes.begin(),
1556  edge_nodes.end(),
1557  nodevec.begin(),
1558  nodevec.end(),
1559  std::inserter(common_nodes, common_nodes.end()));
1560 
1561  if (common_nodes.size() == edge_nodes.size())
1562  elems_connected_to_edge.push_back(elem);
1563  }
1564 
1565  if (elems_connected_to_edge.size() > 0)
1566  {
1567 
1568  // There are potentially multiple elements that share a common edge
1569  // 2D:
1570  // There can only be one element on the same surface
1571  // 3D:
1572  // If there are two edge nodes, there can only be one element on the same surface
1573  // If there is only one edge node (a corner), there could be multiple elements on the same
1574  // surface
1575  bool allowMultipleNeighbors = false;
1576 
1577  if (elems_connected_to_edge[0]->dim() == 3)
1578  {
1579  if (edge_nodes.size() == 1)
1580  {
1581  allowMultipleNeighbors = true;
1582  }
1583  }
1584 
1585  for (unsigned int i = 0; i < elems_connected_to_edge.size(); ++i)
1586  {
1587  std::vector<PenetrationInfo *> thisElemInfo;
1588  getInfoForElem(thisElemInfo, p_info, elems_connected_to_edge[i]);
1589  if (thisElemInfo.size() > 0 && !allowMultipleNeighbors)
1590  {
1591  if (thisElemInfo.size() > 1)
1592  mooseError(
1593  "Found multiple neighbors to current edge/face on surface when only one is allowed");
1594  face_info_comm_edge.push_back(thisElemInfo[0]);
1595  break;
1596  }
1597 
1599  thisElemInfo, p_info, secondary_node, elems_connected_to_edge[i], edge_nodes);
1600  if (thisElemInfo.size() > 0 && !allowMultipleNeighbors)
1601  {
1602  if (thisElemInfo.size() > 1)
1603  mooseError(
1604  "Found multiple neighbors to current edge/face on surface when only one is allowed");
1605  face_info_comm_edge.push_back(thisElemInfo[0]);
1606  break;
1607  }
1608 
1609  for (unsigned int j = 0; j < thisElemInfo.size(); ++j)
1610  face_info_comm_edge.push_back(thisElemInfo[j]);
1611  }
1612  }
1613 }
virtual Elem * elemPtr(const dof_id_type i)
Definition: MooseMesh.C:2864
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:299
static constexpr std::size_t dim
This is the dimension of all vector and tensor datastructures used in MOOSE.
Definition: Moose.h:148
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)
const MooseMesh & _mesh
void getInfoForElem(std::vector< PenetrationInfo *> &thisElemInfo, std::vector< PenetrationInfo *> &p_info, const Elem *elem)
const std::map< dof_id_type, std::vector< dof_id_type > > & _node_to_elem_map

◆ getSideCornerNodes()

void PenetrationThread::getSideCornerNodes ( const Elem *  side,
std::vector< const Node *> &  corner_nodes 
)
protected

Definition at line 750 of file PenetrationThread.C.

Referenced by findRidgeContactPoint().

751 {
752  const ElemType t(side->type());
753  corner_nodes.clear();
754 
755  corner_nodes.push_back(side->node_ptr(0));
756  corner_nodes.push_back(side->node_ptr(1));
757  switch (t)
758  {
759  case EDGE2:
760  case EDGE3:
761  case EDGE4:
762  {
763  break;
764  }
765 
766  case TRI3:
767  case TRI6:
768  case TRI7:
769  {
770  corner_nodes.push_back(side->node_ptr(2));
771  break;
772  }
773 
774  case QUAD4:
775  case QUAD8:
776  case QUAD9:
777  {
778  corner_nodes.push_back(side->node_ptr(2));
779  corner_nodes.push_back(side->node_ptr(3));
780  break;
781  }
782 
783  default:
784  {
785  mooseError("Unsupported face type: ", t);
786  break;
787  }
788  }
789 }
ElemType
QUAD8
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:299
EDGE4
TRI3
QUAD4
TRI6
EDGE2
TRI7
QUAD9
EDGE3

◆ getSidesOnPrimaryBoundary()

void PenetrationThread::getSidesOnPrimaryBoundary ( std::vector< unsigned int > &  sides,
const Elem *const  elem 
)
protected

Definition at line 1744 of file PenetrationThread.C.

Referenced by createInfoForElem().

1746 {
1747  // For each tuple, the fields are (0=elem_id, 1=side_id, 2=bc_id)
1748  sides.clear();
1749  struct Comp
1750  {
1751  bool operator()(const libMesh::BoundaryInfo::BCTuple & tup, dof_id_type id) const
1752  {
1753  return std::get<0>(tup) < id;
1754  }
1755  bool operator()(dof_id_type id, const libMesh::BoundaryInfo::BCTuple & tup) const
1756  {
1757  return id < std::get<0>(tup);
1758  }
1759  };
1760 
1761  auto range = std::equal_range(_bc_tuples.begin(), _bc_tuples.end(), elem->id(), Comp{});
1762 
1763  for (auto & t = range.first; t != range.second; ++t)
1764  if (std::get<2>(*t) == static_cast<boundary_id_type>(_primary_boundary))
1765  sides.push_back(std::get<1>(*t));
1766 }
std::tuple< dof_id_type, unsigned short int, boundary_id_type > BCTuple
const std::vector< std::tuple< dof_id_type, unsigned short int, boundary_id_type > > & _bc_tuples
BoundaryID _primary_boundary
int8_t boundary_id_type
void operator()(const NodeIdRange &range)
uint8_t dof_id_type

◆ getSmoothingEdgeNodesAndWeights()

void PenetrationThread::getSmoothingEdgeNodesAndWeights ( const Point &  p,
const Elem *  side,
std::vector< std::vector< const Node *>> &  edge_nodes,
std::vector< Real > &  edge_face_weights 
)
protected

Definition at line 1385 of file PenetrationThread.C.

Referenced by getSmoothingFacesAndWeights().

1390 {
1391  const ElemType t(side->type());
1392  const Real & xi = p(0);
1393  const Real & eta = p(1);
1394 
1395  Real smooth_limit = 1.0 - _normal_smoothing_distance;
1396 
1397  switch (t)
1398  {
1399  case EDGE2:
1400  case EDGE3:
1401  case EDGE4:
1402  {
1403  if (xi < -smooth_limit)
1404  {
1405  std::vector<const Node *> en;
1406  en.push_back(side->node_ptr(0));
1407  edge_nodes.push_back(en);
1408  Real fw = 0.5 - (1.0 + xi) / (2.0 * _normal_smoothing_distance);
1409  if (fw > 0.5)
1410  fw = 0.5;
1411  edge_face_weights.push_back(fw);
1412  }
1413  else if (xi > smooth_limit)
1414  {
1415  std::vector<const Node *> en;
1416  en.push_back(side->node_ptr(1));
1417  edge_nodes.push_back(en);
1418  Real fw = 0.5 - (1.0 - xi) / (2.0 * _normal_smoothing_distance);
1419  if (fw > 0.5)
1420  fw = 0.5;
1421  edge_face_weights.push_back(fw);
1422  }
1423  break;
1424  }
1425 
1426  case TRI3:
1427  case TRI6:
1428  case TRI7:
1429  {
1430  if (eta < -smooth_limit)
1431  {
1432  std::vector<const Node *> en;
1433  en.push_back(side->node_ptr(0));
1434  en.push_back(side->node_ptr(1));
1435  edge_nodes.push_back(en);
1436  Real fw = 0.5 - (1.0 + eta) / (2.0 * _normal_smoothing_distance);
1437  if (fw > 0.5)
1438  fw = 0.5;
1439  edge_face_weights.push_back(fw);
1440  }
1441  if ((xi + eta) > smooth_limit)
1442  {
1443  std::vector<const Node *> en;
1444  en.push_back(side->node_ptr(1));
1445  en.push_back(side->node_ptr(2));
1446  edge_nodes.push_back(en);
1447  Real fw = 0.5 - (1.0 - xi - eta) / (2.0 * _normal_smoothing_distance);
1448  if (fw > 0.5)
1449  fw = 0.5;
1450  edge_face_weights.push_back(fw);
1451  }
1452  if (xi < -smooth_limit)
1453  {
1454  std::vector<const Node *> en;
1455  en.push_back(side->node_ptr(2));
1456  en.push_back(side->node_ptr(0));
1457  edge_nodes.push_back(en);
1458  Real fw = 0.5 - (1.0 + xi) / (2.0 * _normal_smoothing_distance);
1459  if (fw > 0.5)
1460  fw = 0.5;
1461  edge_face_weights.push_back(fw);
1462  }
1463  break;
1464  }
1465 
1466  case QUAD4:
1467  case QUAD8:
1468  case QUAD9:
1469  {
1470  if (eta < -smooth_limit)
1471  {
1472  std::vector<const Node *> en;
1473  en.push_back(side->node_ptr(0));
1474  en.push_back(side->node_ptr(1));
1475  edge_nodes.push_back(en);
1476  Real fw = 0.5 - (1.0 + eta) / (2.0 * _normal_smoothing_distance);
1477  if (fw > 0.5)
1478  fw = 0.5;
1479  edge_face_weights.push_back(fw);
1480  }
1481  if (xi > smooth_limit)
1482  {
1483  std::vector<const Node *> en;
1484  en.push_back(side->node_ptr(1));
1485  en.push_back(side->node_ptr(2));
1486  edge_nodes.push_back(en);
1487  Real fw = 0.5 - (1.0 - xi) / (2.0 * _normal_smoothing_distance);
1488  if (fw > 0.5)
1489  fw = 0.5;
1490  edge_face_weights.push_back(fw);
1491  }
1492  if (eta > smooth_limit)
1493  {
1494  std::vector<const Node *> en;
1495  en.push_back(side->node_ptr(2));
1496  en.push_back(side->node_ptr(3));
1497  edge_nodes.push_back(en);
1498  Real fw = 0.5 - (1.0 - eta) / (2.0 * _normal_smoothing_distance);
1499  if (fw > 0.5)
1500  fw = 0.5;
1501  edge_face_weights.push_back(fw);
1502  }
1503  if (xi < -smooth_limit)
1504  {
1505  std::vector<const Node *> en;
1506  en.push_back(side->node_ptr(3));
1507  en.push_back(side->node_ptr(0));
1508  edge_nodes.push_back(en);
1509  Real fw = 0.5 - (1.0 + xi) / (2.0 * _normal_smoothing_distance);
1510  if (fw > 0.5)
1511  fw = 0.5;
1512  edge_face_weights.push_back(fw);
1513  }
1514  break;
1515  }
1516 
1517  default:
1518  {
1519  mooseError("Unsupported face type: ", t);
1520  break;
1521  }
1522  }
1523 }
ElemType
QUAD8
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:299
EDGE4
TRI3
QUAD4
TRI6
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
EDGE2
TRI7
QUAD9
EDGE3

◆ getSmoothingFacesAndWeights()

void PenetrationThread::getSmoothingFacesAndWeights ( PenetrationInfo info,
std::vector< PenetrationInfo *> &  edge_face_info,
std::vector< Real > &  edge_face_weights,
std::vector< PenetrationInfo *> &  p_info,
const Node &  secondary_node 
)
protected

Definition at line 1290 of file PenetrationThread.C.

Referenced by smoothNormal().

1295 {
1296  const Elem * side = info->_side;
1297  const Point & p = info->_closest_point_ref;
1298  std::set<dof_id_type> elems_to_exclude;
1299  elems_to_exclude.insert(info->_elem->id());
1300 
1301  std::vector<std::vector<const Node *>> edge_nodes;
1302 
1303  // Get the pairs of nodes along every edge that we are close enough to smooth with
1304  getSmoothingEdgeNodesAndWeights(p, side, edge_nodes, edge_face_weights);
1305  std::vector<Elem *> edge_neighbor_elems;
1306  edge_face_info.resize(edge_nodes.size(), NULL);
1307 
1308  std::vector<unsigned int> edges_without_neighbors;
1309 
1310  for (unsigned int i = 0; i < edge_nodes.size(); ++i)
1311  {
1312  // Sort all sets of edge nodes (needed for comparing edges)
1313  std::sort(edge_nodes[i].begin(), edge_nodes[i].end());
1314 
1315  std::vector<PenetrationInfo *> face_info_comm_edge;
1317  &secondary_node, elems_to_exclude, edge_nodes[i], face_info_comm_edge, p_info);
1318 
1319  if (face_info_comm_edge.size() == 0)
1320  edges_without_neighbors.push_back(i);
1321  else if (face_info_comm_edge.size() > 1)
1322  mooseError("Only one neighbor allowed per edge");
1323  else
1324  edge_face_info[i] = face_info_comm_edge[0];
1325  }
1326 
1327  // Remove edges without neighbors from the vector, starting from end
1328  std::vector<unsigned int>::reverse_iterator rit;
1329  for (rit = edges_without_neighbors.rbegin(); rit != edges_without_neighbors.rend(); ++rit)
1330  {
1331  unsigned int index = *rit;
1332  edge_nodes.erase(edge_nodes.begin() + index);
1333  edge_face_weights.erase(edge_face_weights.begin() + index);
1334  edge_face_info.erase(edge_face_info.begin() + index);
1335  }
1336 
1337  // Handle corner case
1338  if (edge_nodes.size() > 1)
1339  {
1340  if (edge_nodes.size() != 2)
1341  mooseError("Invalid number of smoothing edges");
1342 
1343  // find common node
1344  std::vector<const Node *> common_nodes;
1345  std::set_intersection(edge_nodes[0].begin(),
1346  edge_nodes[0].end(),
1347  edge_nodes[1].begin(),
1348  edge_nodes[1].end(),
1349  std::inserter(common_nodes, common_nodes.end()));
1350 
1351  if (common_nodes.size() != 1)
1352  mooseError("Invalid number of common nodes");
1353 
1354  for (const auto & pinfo : edge_face_info)
1355  elems_to_exclude.insert(pinfo->_elem->id());
1356 
1357  std::vector<PenetrationInfo *> face_info_comm_edge;
1359  &secondary_node, elems_to_exclude, common_nodes, face_info_comm_edge, p_info);
1360 
1361  unsigned int num_corner_neighbors = face_info_comm_edge.size();
1362 
1363  if (num_corner_neighbors > 0)
1364  {
1365  Real fw0 = edge_face_weights[0];
1366  Real fw1 = edge_face_weights[1];
1367 
1368  // Corner weight is product of edge weights. Spread out over multiple neighbors.
1369  Real fw_corner = (fw0 * fw1) / static_cast<Real>(num_corner_neighbors);
1370 
1371  // Adjust original edge weights
1372  edge_face_weights[0] *= (1.0 - fw1);
1373  edge_face_weights[1] *= (1.0 - fw0);
1374 
1375  for (unsigned int i = 0; i < num_corner_neighbors; ++i)
1376  {
1377  edge_face_weights.push_back(fw_corner);
1378  edge_face_info.push_back(face_info_comm_edge[i]);
1379  }
1380  }
1381  }
1382 }
void getSmoothingEdgeNodesAndWeights(const Point &p, const Elem *side, std::vector< std::vector< const Node *>> &edge_nodes, std::vector< Real > &edge_face_weights)
MPI_Info info
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:299
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)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real

◆ interactionsOffCommonEdge()

PenetrationThread::CommonEdgeResult PenetrationThread::interactionsOffCommonEdge ( PenetrationInfo pi1,
PenetrationInfo pi2 
)
protected

Definition at line 596 of file PenetrationThread.C.

Referenced by competeInteractions().

597 {
598  CommonEdgeResult common_edge(NO_COMMON);
599  const std::vector<const Node *> & off_edge_nodes1 = pi1->_off_edge_nodes;
600  const std::vector<const Node *> & off_edge_nodes2 = pi2->_off_edge_nodes;
601  const unsigned dim1 = pi1->_side->dim();
602 
603  if (dim1 == 1)
604  {
605  mooseAssert(pi2->_side->dim() == 1, "Incompatible dimensions.");
606  mooseAssert(off_edge_nodes1.size() < 2 && off_edge_nodes2.size() < 2,
607  "off_edge_nodes size should be <2 for 2D contact");
608  if (off_edge_nodes1.size() == 1 && off_edge_nodes2.size() == 1 &&
609  off_edge_nodes1[0] == off_edge_nodes2[0])
610  common_edge = COMMON_EDGE;
611  }
612  else
613  {
614  mooseAssert(dim1 == 2 && pi2->_side->dim() == 2, "Incompatible dimensions.");
615  mooseAssert(off_edge_nodes1.size() < 3 && off_edge_nodes2.size() < 3,
616  "off_edge_nodes size should be <3 for 3D contact");
617  if (off_edge_nodes1.size() == 1)
618  {
619  if (off_edge_nodes2.size() == 1)
620  {
621  if (off_edge_nodes1[0] == off_edge_nodes2[0])
622  common_edge = COMMON_NODE;
623  }
624  else if (off_edge_nodes2.size() == 2)
625  {
626  if (off_edge_nodes1[0] == off_edge_nodes2[0] || off_edge_nodes1[0] == off_edge_nodes2[1])
627  common_edge = EDGE_AND_COMMON_NODE;
628  }
629  }
630  else if (off_edge_nodes1.size() == 2)
631  {
632  if (off_edge_nodes2.size() == 1)
633  {
634  if (off_edge_nodes1[0] == off_edge_nodes2[0] || off_edge_nodes1[1] == off_edge_nodes2[0])
635  common_edge = EDGE_AND_COMMON_NODE;
636  }
637  else if (off_edge_nodes2.size() == 2)
638  {
639  if ((off_edge_nodes1[0] == off_edge_nodes2[0] &&
640  off_edge_nodes1[1] == off_edge_nodes2[1]) ||
641  (off_edge_nodes1[1] == off_edge_nodes2[0] && off_edge_nodes1[0] == off_edge_nodes2[1]))
642  common_edge = COMMON_EDGE;
643  }
644  }
645  }
646  return common_edge;
647 }
const Elem * _side
std::vector< const Node * > _off_edge_nodes

◆ isFaceReasonableCandidate()

bool PenetrationThread::isFaceReasonableCandidate ( const Elem *  primary_elem,
const Elem *  side,
FEBase fe,
const Point *  secondary_point,
const Real  tangential_tolerance 
)
protected

Definition at line 1147 of file PenetrationThread.C.

Referenced by createInfoForElem().

1152 {
1153  unsigned int dim = primary_elem->dim();
1154 
1155  const std::vector<Point> & phys_point = fe->get_xyz();
1156 
1157  const std::vector<RealGradient> & dxyz_dxi = fe->get_dxyzdxi();
1158  const std::vector<RealGradient> & dxyz_deta = fe->get_dxyzdeta();
1159 
1160  Point ref_point;
1161 
1162  std::vector<Point> points(1); // Default constructor gives us a point at 0,0,0
1163 
1164  fe->reinit(side, &points);
1165 
1166  RealGradient d = *secondary_point - phys_point[0];
1167 
1168  const Real twosqrt2 = 2.8284; // way more precision than we actually need here
1169  Real max_face_length = side->hmax() + twosqrt2 * tangential_tolerance;
1170 
1171  RealVectorValue normal;
1172  if (dim - 1 == 2)
1173  {
1174  normal = dxyz_dxi[0].cross(dxyz_deta[0]);
1175  }
1176  else if (dim - 1 == 1)
1177  {
1178  const Node * const * elem_nodes = primary_elem->get_nodes();
1179  const Point in_plane_vector1 = *elem_nodes[1] - *elem_nodes[0];
1180  const Point in_plane_vector2 = *elem_nodes[2] - *elem_nodes[0];
1181 
1182  Point out_of_plane_normal = in_plane_vector1.cross(in_plane_vector2);
1183  out_of_plane_normal /= out_of_plane_normal.norm();
1184 
1185  normal = dxyz_dxi[0].cross(out_of_plane_normal);
1186  }
1187  else
1188  {
1189  return true;
1190  }
1191  normal /= normal.norm();
1192 
1193  const Real dot(d * normal);
1194 
1195  const RealGradient normcomp = dot * normal;
1196  const RealGradient tangcomp = d - normcomp;
1197 
1198  const Real tangdist = tangcomp.norm();
1199 
1200  // Increase the size of the zone that we consider if the vector from the face
1201  // to the node has a larger normal component
1202  const Real faceExpansionFactor = 2.0 * (1.0 + normcomp.norm() / d.norm());
1203 
1204  bool isReasonableCandidate = true;
1205  if (tangdist > faceExpansionFactor * max_face_length)
1206  {
1207  isReasonableCandidate = false;
1208  }
1209  return isReasonableCandidate;
1210 }
auto norm() const -> decltype(std::norm(Real()))
static constexpr std::size_t dim
This is the dimension of all vector and tensor datastructures used in MOOSE.
Definition: Moose.h:148
TypeVector< typename CompareTypes< Real, T2 >::supertype > cross(const TypeVector< T2 > &v) const
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real

◆ join()

void PenetrationThread::join ( const PenetrationThread other)

Definition at line 462 of file PenetrationThread.C.

463 {
465  other._recheck_secondary_nodes.begin(),
466  other._recheck_secondary_nodes.end());
467 }
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...

◆ operator()()

void PenetrationThread::operator() ( const NodeIdRange range)

Definition at line 88 of file PenetrationThread.C.

Referenced by getSidesOnPrimaryBoundary().

89 {
90  ParallelUniqueId puid;
91  _tid = puid.id;
92 
93  // Must get the variables every time this is run because _tid can change
96  {
100  }
101 
102  for (const auto & node_id : range)
103  {
104  const Node & node = _mesh.nodeRef(node_id);
105 
106  // We're going to get a reference to the pointer for the pinfo for this node
107  // This will allow us to manipulate this pointer without having to go through
108  // the _penetration_info map... meaning this is the only mutex we'll have to do!
109  pinfo_mutex.lock();
110  PenetrationInfo *& info = _penetration_info[node.id()];
111  pinfo_mutex.unlock();
112 
113  std::vector<PenetrationInfo *> p_info;
114  bool info_set(false);
115 
116  // See if we already have info about this node
117  if (info)
118  {
119  FEBase * fe_elem = _fes[_tid][info->_elem->dim()];
120  FEBase * fe_side = _fes[_tid][info->_side->dim()];
121 
122  if (!_update_location && (info->_distance >= 0 || info->isCaptured()))
123  {
124  const Point contact_ref = info->_closest_point_ref;
125  bool contact_point_on_side(false);
126 
127  // Secondary position must be the previous contact point
128  // Use the previous reference coordinates
129  std::vector<Point> points(1);
130  points[0] = contact_ref;
131  const std::vector<Point> & secondary_pos = fe_side->get_xyz();
132 
134  fe_elem,
135  fe_side,
136  _fe_type,
137  secondary_pos[0],
138  false,
140  contact_point_on_side);
141 
142  // Restore the original reference coordinates
143  info->_closest_point_ref = contact_ref;
144  // Just calculated as the distance of the contact point off the surface (0). Set to 0 to
145  // avoid round-off.
146  info->_distance = 0.0;
147  info_set = true;
148  }
149  else
150  {
151  Real old_tangential_distance(info->_tangential_distance);
152  bool contact_point_on_side(false);
153 
155  fe_elem,
156  fe_side,
157  _fe_type,
158  node,
159  false,
161  contact_point_on_side);
162 
163  if (contact_point_on_side)
164  {
165  if (info->_tangential_distance <= 0.0) // on the face
166  {
167  info_set = true;
168  }
169  else if (info->_tangential_distance > 0.0 && old_tangential_distance > 0.0)
170  { // off the face but within tolerance, was that way on the last step too
171  if (info->_side->dim() == 2 && info->_off_edge_nodes.size() < 2)
172  { // Closest point on face is on a node rather than an edge. Another
173  // face might be a better candidate.
174  }
175  else
176  {
177  info_set = true;
178  }
179  }
180  }
181  }
182  }
183 
184  if (!info_set)
185  {
186  const Node * closest_node = _nearest_node.nearestNode(node.id());
187  auto node_to_elem_pair = _node_to_elem_map.find(closest_node->id());
188  mooseAssert(node_to_elem_pair != _node_to_elem_map.end(),
189  "Missing entry in node to elem map");
190  const std::vector<dof_id_type> & closest_elems = node_to_elem_pair->second;
191 
192  for (const auto & elem_id : closest_elems)
193  {
194  const Elem * elem = _mesh.elemPtr(elem_id);
195 
196  std::vector<PenetrationInfo *> thisElemInfo;
197  std::vector<const Node *> nodesThatMustBeOnSide;
198  nodesThatMustBeOnSide.push_back(closest_node);
200  thisElemInfo, p_info, &node, elem, nodesThatMustBeOnSide, _check_whether_reasonable);
201  }
202 
203  if (p_info.size() == 1)
204  {
205  if (p_info[0]->_tangential_distance <= _tangential_tolerance)
206  {
207  switchInfo(info, p_info[0]);
208  info_set = true;
209  }
210  }
211  else if (p_info.size() > 1)
212  {
213 
214  // Loop through all pairs of faces, and check for contact on ridge betweeen each face pair
215  std::vector<RidgeData> ridgeDataVec;
216  for (unsigned int i = 0; i + 1 < p_info.size(); ++i)
217  for (unsigned int j = i + 1; j < p_info.size(); ++j)
218  {
219  Point closest_coor;
220  Real tangential_distance(0.0);
221  const Node * closest_node_on_ridge = NULL;
222  unsigned int index = 0;
223  Point closest_coor_ref;
224  bool found_ridge_contact_point = findRidgeContactPoint(closest_coor,
225  tangential_distance,
226  closest_node_on_ridge,
227  index,
228  closest_coor_ref,
229  p_info,
230  i,
231  j);
232  if (found_ridge_contact_point)
233  {
234  RidgeData rpd;
235  rpd._closest_coor = closest_coor;
236  rpd._tangential_distance = tangential_distance;
237  rpd._closest_node = closest_node_on_ridge;
238  rpd._index = index;
239  rpd._closest_coor_ref = closest_coor_ref;
240  ridgeDataVec.push_back(rpd);
241  }
242  }
243 
244  if (ridgeDataVec.size() > 0) // Either find the ridge pair that is the best or find a peak
245  {
246  // Group together ridges for which we are off the edge of a common node.
247  // Those are peaks.
248  std::vector<RidgeSetData> ridgeSetDataVec;
249  for (unsigned int i = 0; i < ridgeDataVec.size(); ++i)
250  {
251  bool foundSetWithMatchingNode = false;
252  for (unsigned int j = 0; j < ridgeSetDataVec.size(); ++j)
253  {
254  if (ridgeDataVec[i]._closest_node != NULL &&
255  ridgeDataVec[i]._closest_node == ridgeSetDataVec[j]._closest_node)
256  {
257  foundSetWithMatchingNode = true;
258  ridgeSetDataVec[j]._ridge_data_vec.push_back(ridgeDataVec[i]);
259  break;
260  }
261  }
262  if (!foundSetWithMatchingNode)
263  {
264  RidgeSetData rsd;
265  rsd._distance = std::numeric_limits<Real>::max();
266  rsd._ridge_data_vec.push_back(ridgeDataVec[i]);
267  rsd._closest_node = ridgeDataVec[i]._closest_node;
268  ridgeSetDataVec.push_back(rsd);
269  }
270  }
271  // Compute distance to each set of ridges
272  for (unsigned int i = 0; i < ridgeSetDataVec.size(); ++i)
273  {
274  if (ridgeSetDataVec[i]._closest_node !=
275  NULL) // Either a peak or off the edge of single ridge
276  {
277  if (ridgeSetDataVec[i]._ridge_data_vec.size() == 1) // off edge of single ridge
278  {
279  if (ridgeSetDataVec[i]._ridge_data_vec[0]._tangential_distance <=
280  _tangential_tolerance) // off within tolerance
281  {
282  ridgeSetDataVec[i]._closest_coor =
283  ridgeSetDataVec[i]._ridge_data_vec[0]._closest_coor;
284  Point contact_point_vec = node - ridgeSetDataVec[i]._closest_coor;
285  ridgeSetDataVec[i]._distance = contact_point_vec.norm();
286  }
287  }
288  else // several ridges join at common node to make peak. The common node is the
289  // contact point
290  {
291  ridgeSetDataVec[i]._closest_coor = *ridgeSetDataVec[i]._closest_node;
292  Point contact_point_vec = node - ridgeSetDataVec[i]._closest_coor;
293  ridgeSetDataVec[i]._distance = contact_point_vec.norm();
294  }
295  }
296  else // on a single ridge
297  {
298  ridgeSetDataVec[i]._closest_coor =
299  ridgeSetDataVec[i]._ridge_data_vec[0]._closest_coor;
300  Point contact_point_vec = node - ridgeSetDataVec[i]._closest_coor;
301  ridgeSetDataVec[i]._distance = contact_point_vec.norm();
302  }
303  }
304  // Find the set of ridges closest to us.
305  unsigned int closest_ridge_set_index(0);
306  Real closest_distance(ridgeSetDataVec[0]._distance);
307  Point closest_point(ridgeSetDataVec[0]._closest_coor);
308  for (unsigned int i = 1; i < ridgeSetDataVec.size(); ++i)
309  {
310  if (ridgeSetDataVec[i]._distance < closest_distance)
311  {
312  closest_ridge_set_index = i;
313  closest_distance = ridgeSetDataVec[i]._distance;
314  closest_point = ridgeSetDataVec[i]._closest_coor;
315  }
316  }
317 
318  if (closest_distance <
319  std::numeric_limits<Real>::max()) // contact point is on the closest ridge set
320  {
321  // find the face in the ridge set with the smallest index, assign that one to the
322  // interaction
323  unsigned int face_index(std::numeric_limits<unsigned int>::max());
324  for (unsigned int i = 0;
325  i < ridgeSetDataVec[closest_ridge_set_index]._ridge_data_vec.size();
326  ++i)
327  {
328  if (ridgeSetDataVec[closest_ridge_set_index]._ridge_data_vec[i]._index < face_index)
329  face_index = ridgeSetDataVec[closest_ridge_set_index]._ridge_data_vec[i]._index;
330  }
331 
332  mooseAssert(face_index < std::numeric_limits<unsigned int>::max(),
333  "face_index invalid");
334 
335  p_info[face_index]->_closest_point = closest_point;
336  p_info[face_index]->_distance =
337  (p_info[face_index]->_distance >= 0.0 ? 1.0 : -1.0) * closest_distance;
338  // Calculate the normal as the vector from the ridge to the point only if we're not
339  // doing normal
340  // smoothing. Normal smoothing will average out the normals on its own.
342  {
343  Point normal(closest_point - node);
344  const Real len(normal.norm());
345  if (len > 0)
346  {
347  normal /= len;
348  }
349  const Real dot(normal * p_info[face_index]->_normal);
350  if (dot < 0)
351  {
352  normal *= -1;
353  }
354  p_info[face_index]->_normal = normal;
355  }
356  p_info[face_index]->_tangential_distance = 0.0;
357 
358  Point closest_point_ref;
359  if (ridgeSetDataVec[closest_ridge_set_index]._ridge_data_vec.size() ==
360  1) // contact with a single ridge rather than a peak
361  {
362  p_info[face_index]->_tangential_distance =
363  ridgeSetDataVec[closest_ridge_set_index]._ridge_data_vec[0]._tangential_distance;
364  p_info[face_index]->_closest_point_ref =
365  ridgeSetDataVec[closest_ridge_set_index]._ridge_data_vec[0]._closest_coor_ref;
366  }
367  else
368  { // peak
369  const Node * closest_node_on_face;
370  bool restricted = restrictPointToFace(p_info[face_index]->_closest_point_ref,
371  closest_node_on_face,
372  p_info[face_index]->_side);
373  if (restricted)
374  {
375  if (closest_node_on_face != ridgeSetDataVec[closest_ridge_set_index]._closest_node)
376  {
377  mooseError("Closest node when restricting point to face != closest node from "
378  "RidgeSetData");
379  }
380  }
381  }
382 
383  FEBase * fe = _fes[_tid][p_info[face_index]->_side->dim()];
384  std::vector<Point> points(1);
385  points[0] = p_info[face_index]->_closest_point_ref;
386  fe->reinit(p_info[face_index]->_side, &points);
387  p_info[face_index]->_side_phi = fe->get_phi();
388  p_info[face_index]->_side_grad_phi = fe->get_dphi();
389  p_info[face_index]->_dxyzdxi = fe->get_dxyzdxi();
390  p_info[face_index]->_dxyzdeta = fe->get_dxyzdeta();
391  p_info[face_index]->_d2xyzdxideta = fe->get_d2xyzdxideta();
392 
393  switchInfo(info, p_info[face_index]);
394  info_set = true;
395  }
396  else
397  { // todo:remove invalid ridge cases so they don't mess up individual face competition????
398  }
399  }
400 
401  if (!info_set) // contact wasn't on a ridge -- compete individual interactions
402  {
403  unsigned int best(0), i(1);
404  do
405  {
406  CompeteInteractionResult CIResult = competeInteractions(p_info[best], p_info[i]);
407  if (CIResult == FIRST_WINS)
408  {
409  i++;
410  }
411  else if (CIResult == SECOND_WINS)
412  {
413  best = i;
414  i++;
415  }
416  else if (CIResult == NEITHER_WINS)
417  {
418  best = i + 1;
419  i += 2;
420  }
421  } while (i < p_info.size() && best < p_info.size());
422  if (best < p_info.size())
423  {
424  switchInfo(info, p_info[best]);
425  info_set = true;
426  }
427  }
428  }
429  }
430 
431  if (!info_set)
432  {
433  // If penetration is not detected within the saved patch, it is possible
434  // that the secondary node has moved outside the saved patch. So, the patch
435  // for the secondary nodes saved in _recheck_secondary_nodes has to be updated
436  // and the penetration detection has to be re-run on the updated patch.
437 
438  _recheck_secondary_nodes.push_back(node_id);
439 
440  delete info;
441  info = NULL;
442  }
443  else
444  {
445  smoothNormal(info, p_info, node);
446  FEBase * fe = _fes[_tid][info->_side->dim()];
447  computeSlip(*fe, *info);
448  }
449 
450  for (unsigned int j = 0; j < p_info.size(); ++j)
451  {
452  if (p_info[j])
453  {
454  delete p_info[j];
455  p_info[j] = NULL;
456  }
457  }
458  }
459 }
MooseVariable * _nodal_normal_z
virtual Elem * elemPtr(const dof_id_type i)
Definition: MooseMesh.C:2864
MPI_Info info
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:299
Data structure used to hold penetration information.
NearestNodeLocator & _nearest_node
bool findRidgeContactPoint(Point &contact_point, Real &tangential_distance, const Node *&closest_node, unsigned int &index, Point &contact_point_ref, std::vector< PenetrationInfo *> &p_info, const unsigned int index1, const unsigned int index2)
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)
bool restrictPointToFace(Point &p, const Node *&closest_node, const Elem *side)
Threads::spin_mutex pinfo_mutex
virtual const Node & nodeRef(const dof_id_type i) const
Definition: MooseMesh.C:637
void smoothNormal(PenetrationInfo *info, std::vector< PenetrationInfo *> &p_info, const Node &node)
auto max(const L &left, const R &right)
SubProblem & _subproblem
const MooseMesh & _mesh
std::vector< std::vector< FEBase * > > & _fes
void findContactPoint(PenetrationInfo &p_info, FEBase *fe_elem, FEBase *fe_side, FEType &fe_side_type, const Point &secondary_point, bool start_with_centroid, const Real tangential_tolerance, bool &contact_point_on_side)
Finds the closest point (called the contact point) on the primary_elem on side "side" to the secondar...
CompeteInteractionResult competeInteractions(PenetrationInfo *pi1, PenetrationInfo *pi2)
When interactions are identified between a node and two faces, compete between the faces to determine...
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...
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.
FEGenericBase< Real > FEBase
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
std::map< dof_id_type, PenetrationInfo * > & _penetration_info
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...
MooseVariable * _nodal_normal_y
void computeSlip(FEBase &fe, PenetrationInfo &info)
const std::map< dof_id_type, std::vector< dof_id_type > > & _node_to_elem_map
void switchInfo(PenetrationInfo *&info, PenetrationInfo *&infoNew)
MooseVariable * _nodal_normal_x
PenetrationLocator::NORMAL_SMOOTHING_METHOD _normal_smoothing_method

◆ restrictPointToFace()

bool PenetrationThread::restrictPointToFace ( Point &  p,
const Node *&  closest_node,
const Elem *  side 
)
protected

Definition at line 966 of file PenetrationThread.C.

Referenced by operator()().

967 {
968  const ElemType t(side->type());
969  Real & xi = p(0);
970  Real & eta = p(1);
971  closest_node = NULL;
972 
973  bool off_of_this_face(false);
974 
975  switch (t)
976  {
977  case EDGE2:
978  case EDGE3:
979  case EDGE4:
980  {
981  if (xi < -1.0)
982  {
983  xi = -1.0;
984  off_of_this_face = true;
985  closest_node = side->node_ptr(0);
986  }
987  else if (xi > 1.0)
988  {
989  xi = 1.0;
990  off_of_this_face = true;
991  closest_node = side->node_ptr(1);
992  }
993  break;
994  }
995 
996  case TRI3:
997  case TRI6:
998  case TRI7:
999  {
1000  if (eta < 0.0)
1001  {
1002  eta = 0.0;
1003  off_of_this_face = true;
1004  if (xi < 0.5)
1005  {
1006  closest_node = side->node_ptr(0);
1007  if (xi < 0.0)
1008  xi = 0.0;
1009  }
1010  else
1011  {
1012  closest_node = side->node_ptr(1);
1013  if (xi > 1.0)
1014  xi = 1.0;
1015  }
1016  }
1017  else if ((xi + eta) > 1.0)
1018  {
1019  Real delta = (xi + eta - 1.0) / 2.0;
1020  xi -= delta;
1021  eta -= delta;
1022  off_of_this_face = true;
1023  if (xi > 0.5)
1024  {
1025  closest_node = side->node_ptr(1);
1026  if (xi > 1.0)
1027  {
1028  xi = 1.0;
1029  eta = 0.0;
1030  }
1031  }
1032  else
1033  {
1034  closest_node = side->node_ptr(2);
1035  if (xi < 0.0)
1036  {
1037  xi = 0.0;
1038  eta = 1.0;
1039  }
1040  }
1041  }
1042  else if (xi < 0.0)
1043  {
1044  xi = 0.0;
1045  off_of_this_face = true;
1046  if (eta > 0.5)
1047  {
1048  closest_node = side->node_ptr(2);
1049  if (eta > 1.0)
1050  eta = 1.0;
1051  }
1052  else
1053  {
1054  closest_node = side->node_ptr(0);
1055  if (eta < 0.0)
1056  eta = 0.0;
1057  }
1058  }
1059  break;
1060  }
1061 
1062  case QUAD4:
1063  case QUAD8:
1064  case QUAD9:
1065  {
1066  if (eta < -1.0)
1067  {
1068  eta = -1.0;
1069  off_of_this_face = true;
1070  if (xi < 0.0)
1071  {
1072  closest_node = side->node_ptr(0);
1073  if (xi < -1.0)
1074  xi = -1.0;
1075  }
1076  else
1077  {
1078  closest_node = side->node_ptr(1);
1079  if (xi > 1.0)
1080  xi = 1.0;
1081  }
1082  }
1083  else if (xi > 1.0)
1084  {
1085  xi = 1.0;
1086  off_of_this_face = true;
1087  if (eta < 0.0)
1088  {
1089  closest_node = side->node_ptr(1);
1090  if (eta < -1.0)
1091  eta = -1.0;
1092  }
1093  else
1094  {
1095  closest_node = side->node_ptr(2);
1096  if (eta > 1.0)
1097  eta = 1.0;
1098  }
1099  }
1100  else if (eta > 1.0)
1101  {
1102  eta = 1.0;
1103  off_of_this_face = true;
1104  if (xi < 0.0)
1105  {
1106  closest_node = side->node_ptr(3);
1107  if (xi < -1.0)
1108  xi = -1.0;
1109  }
1110  else
1111  {
1112  closest_node = side->node_ptr(2);
1113  if (xi > 1.0)
1114  xi = 1.0;
1115  }
1116  }
1117  else if (xi < -1.0)
1118  {
1119  xi = -1.0;
1120  off_of_this_face = true;
1121  if (eta < 0.0)
1122  {
1123  closest_node = side->node_ptr(0);
1124  if (eta < -1.0)
1125  eta = -1.0;
1126  }
1127  else
1128  {
1129  closest_node = side->node_ptr(3);
1130  if (eta > 1.0)
1131  eta = 1.0;
1132  }
1133  }
1134  break;
1135  }
1136 
1137  default:
1138  {
1139  mooseError("Unsupported face type: ", t);
1140  break;
1141  }
1142  }
1143  return off_of_this_face;
1144 }
ElemType
QUAD8
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:299
EDGE4
TRI3
QUAD4
TRI6
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
EDGE2
TRI7
QUAD9
EDGE3

◆ restrictPointToSpecifiedEdgeOfFace()

bool PenetrationThread::restrictPointToSpecifiedEdgeOfFace ( Point &  p,
const Node *&  closest_node,
const Elem *  side,
const std::vector< const Node *> &  edge_nodes 
)
protected

Definition at line 792 of file PenetrationThread.C.

Referenced by findRidgeContactPoint().

796 {
797  const ElemType t = side->type();
798  Real & xi = p(0);
799  Real & eta = p(1);
800  closest_node = NULL;
801 
802  std::vector<unsigned int> local_node_indices;
803  for (const auto & edge_node : edge_nodes)
804  {
805  unsigned int local_index = side->get_node_index(edge_node);
806  if (local_index == libMesh::invalid_uint)
807  mooseError("Side does not contain node");
808  local_node_indices.push_back(local_index);
809  }
810  mooseAssert(local_node_indices.size() == side->dim(),
811  "Number of edge nodes must match side dimensionality");
812  std::sort(local_node_indices.begin(), local_node_indices.end());
813 
814  bool off_of_this_edge = false;
815 
816  switch (t)
817  {
818  case EDGE2:
819  case EDGE3:
820  case EDGE4:
821  {
822  if (local_node_indices[0] == 0)
823  {
824  if (xi <= -1.0)
825  {
826  xi = -1.0;
827  off_of_this_edge = true;
828  closest_node = side->node_ptr(0);
829  }
830  }
831  else if (local_node_indices[0] == 1)
832  {
833  if (xi >= 1.0)
834  {
835  xi = 1.0;
836  off_of_this_edge = true;
837  closest_node = side->node_ptr(1);
838  }
839  }
840  else
841  {
842  mooseError("Invalid local node indices");
843  }
844  break;
845  }
846 
847  case TRI3:
848  case TRI6:
849  case TRI7:
850  {
851  if ((local_node_indices[0] == 0) && (local_node_indices[1] == 1))
852  {
853  if (eta <= 0.0)
854  {
855  eta = 0.0;
856  off_of_this_edge = true;
857  if (xi < 0.0)
858  closest_node = side->node_ptr(0);
859  else if (xi > 1.0)
860  closest_node = side->node_ptr(1);
861  }
862  }
863  else if ((local_node_indices[0] == 1) && (local_node_indices[1] == 2))
864  {
865  if ((xi + eta) > 1.0)
866  {
867  Real delta = (xi + eta - 1.0) / 2.0;
868  xi -= delta;
869  eta -= delta;
870  off_of_this_edge = true;
871  if (xi > 1.0)
872  closest_node = side->node_ptr(1);
873  else if (xi < 0.0)
874  closest_node = side->node_ptr(2);
875  }
876  }
877  else if ((local_node_indices[0] == 0) && (local_node_indices[1] == 2))
878  {
879  if (xi <= 0.0)
880  {
881  xi = 0.0;
882  off_of_this_edge = true;
883  if (eta > 1.0)
884  closest_node = side->node_ptr(2);
885  else if (eta < 0.0)
886  closest_node = side->node_ptr(0);
887  }
888  }
889  else
890  {
891  mooseError("Invalid local node indices");
892  }
893 
894  break;
895  }
896 
897  case QUAD4:
898  case QUAD8:
899  case QUAD9:
900  {
901  if ((local_node_indices[0] == 0) && (local_node_indices[1] == 1))
902  {
903  if (eta <= -1.0)
904  {
905  eta = -1.0;
906  off_of_this_edge = true;
907  if (xi < -1.0)
908  closest_node = side->node_ptr(0);
909  else if (xi > 1.0)
910  closest_node = side->node_ptr(1);
911  }
912  }
913  else if ((local_node_indices[0] == 1) && (local_node_indices[1] == 2))
914  {
915  if (xi >= 1.0)
916  {
917  xi = 1.0;
918  off_of_this_edge = true;
919  if (eta < -1.0)
920  closest_node = side->node_ptr(1);
921  else if (eta > 1.0)
922  closest_node = side->node_ptr(2);
923  }
924  }
925  else if ((local_node_indices[0] == 2) && (local_node_indices[1] == 3))
926  {
927  if (eta >= 1.0)
928  {
929  eta = 1.0;
930  off_of_this_edge = true;
931  if (xi < -1.0)
932  closest_node = side->node_ptr(3);
933  else if (xi > 1.0)
934  closest_node = side->node_ptr(2);
935  }
936  }
937  else if ((local_node_indices[0] == 0) && (local_node_indices[1] == 3))
938  {
939  if (xi <= -1.0)
940  {
941  xi = -1.0;
942  off_of_this_edge = true;
943  if (eta < -1.0)
944  closest_node = side->node_ptr(0);
945  else if (eta > 1.0)
946  closest_node = side->node_ptr(3);
947  }
948  }
949  else
950  {
951  mooseError("Invalid local node indices");
952  }
953  break;
954  }
955 
956  default:
957  {
958  mooseError("Unsupported face type: ", t);
959  break;
960  }
961  }
962  return off_of_this_edge;
963 }
ElemType
QUAD8
const unsigned int invalid_uint
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:299
EDGE4
TRI3
QUAD4
TRI6
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
EDGE2
TRI7
QUAD9
EDGE3

◆ smoothNormal()

void PenetrationThread::smoothNormal ( PenetrationInfo info,
std::vector< PenetrationInfo *> &  p_info,
const Node &  node 
)
protected

Definition at line 1232 of file PenetrationThread.C.

Referenced by operator()().

1235 {
1237  {
1239  {
1240  // If we are within the smoothing distance of any edges or corners, find the
1241  // corner nodes for those edges/corners, and weights from distance to edge/corner
1242  std::vector<Real> edge_face_weights;
1243  std::vector<PenetrationInfo *> edge_face_info;
1244 
1245  getSmoothingFacesAndWeights(info, edge_face_info, edge_face_weights, p_info, node);
1246 
1247  mooseAssert(edge_face_info.size() == edge_face_weights.size(),
1248  "edge_face_info.size() != edge_face_weights.size()");
1249 
1250  if (edge_face_info.size() > 0)
1251  {
1252  // Smooth the normal using the weighting functions for all participating faces.
1253  RealVectorValue new_normal;
1254  Real this_face_weight = 1.0;
1255 
1256  for (unsigned int efwi = 0; efwi < edge_face_weights.size(); ++efwi)
1257  {
1258  PenetrationInfo * npi = edge_face_info[efwi];
1259  if (npi)
1260  new_normal += npi->_normal * edge_face_weights[efwi];
1261 
1262  this_face_weight -= edge_face_weights[efwi];
1263  }
1264  mooseAssert(this_face_weight >= (0.25 - 1e-8),
1265  "Sum of weights of other faces shouldn't exceed 0.75");
1266  new_normal += info->_normal * this_face_weight;
1267 
1268  const Real len = new_normal.norm();
1269  if (len > 0)
1270  new_normal /= len;
1271 
1272  info->_normal = new_normal;
1273  }
1274  }
1276  {
1277  // params.addParam<VariableName>("var_name","description");
1278  // getParam<VariableName>("var_name")
1279  info->_normal(0) = _nodal_normal_x->getValue(info->_side, info->_side_phi);
1280  info->_normal(1) = _nodal_normal_y->getValue(info->_side, info->_side_phi);
1281  info->_normal(2) = _nodal_normal_z->getValue(info->_side, info->_side_phi);
1282  const Real len(info->_normal.norm());
1283  if (len > 0)
1284  info->_normal /= len;
1285  }
1286  }
1287 }
MooseVariable * _nodal_normal_z
auto norm() const -> decltype(std::norm(Real()))
RealVectorValue _normal
MPI_Info info
OutputType getValue(const Elem *elem, const std::vector< std::vector< OutputShape >> &phi) const
Compute the variable value at a point on an element.
Data structure used to hold penetration information.
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)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
MooseVariable * _nodal_normal_y
MooseVariable * _nodal_normal_x
PenetrationLocator::NORMAL_SMOOTHING_METHOD _normal_smoothing_method

◆ switchInfo()

void PenetrationThread::switchInfo ( PenetrationInfo *&  info,
PenetrationInfo *&  infoNew 
)
protected

Definition at line 470 of file PenetrationThread.C.

Referenced by operator()().

471 {
472  mooseAssert(infoNew != NULL, "infoNew object is null");
473  if (info)
474  {
475  infoNew->_starting_elem = info->_starting_elem;
476  infoNew->_starting_side_num = info->_starting_side_num;
477  infoNew->_starting_closest_point_ref = info->_starting_closest_point_ref;
478  infoNew->_incremental_slip = info->_incremental_slip;
479  infoNew->_accumulated_slip = info->_accumulated_slip;
480  infoNew->_accumulated_slip_old = info->_accumulated_slip_old;
481  infoNew->_frictional_energy = info->_frictional_energy;
482  infoNew->_frictional_energy_old = info->_frictional_energy_old;
483  infoNew->_contact_force = info->_contact_force;
484  infoNew->_contact_force_old = info->_contact_force_old;
485  infoNew->_lagrange_multiplier = info->_lagrange_multiplier;
486  infoNew->_lagrange_multiplier_slip = info->_lagrange_multiplier_slip;
487  infoNew->_locked_this_step = info->_locked_this_step;
488  infoNew->_stick_locked_this_step = info->_stick_locked_this_step;
489  infoNew->_mech_status = info->_mech_status;
490  infoNew->_mech_status_old = info->_mech_status_old;
491  }
492  else
493  {
494  infoNew->_starting_elem = infoNew->_elem;
495  infoNew->_starting_side_num = infoNew->_side_num;
497  }
498  delete info;
499  info = infoNew;
500  infoNew = NULL; // Set this to NULL so that we don't delete it (now owned by _penetration_info).
501 }
MPI_Info info
const Elem * _starting_elem
unsigned int _stick_locked_this_step
RealVectorValue _contact_force_old
unsigned int _locked_this_step
const Elem * _elem
unsigned int _starting_side_num
unsigned int _side_num
RealVectorValue _contact_force
MECH_STATUS_ENUM _mech_status
Point _starting_closest_point_ref
MECH_STATUS_ENUM _mech_status_old
RealVectorValue _lagrange_multiplier_slip

Member Data Documentation

◆ _bc_tuples

const std::vector<std::tuple<dof_id_type, unsigned short int, boundary_id_type> >& PenetrationThread::_bc_tuples
protected

Definition at line 84 of file PenetrationThread.h.

Referenced by getSidesOnPrimaryBoundary().

◆ _check_whether_reasonable

bool PenetrationThread::_check_whether_reasonable
protected

Definition at line 65 of file PenetrationThread.h.

Referenced by operator()().

◆ _do_normal_smoothing

bool PenetrationThread::_do_normal_smoothing
protected

Definition at line 68 of file PenetrationThread.h.

Referenced by operator()(), and smoothNormal().

◆ _elem_side_builder

ElemSideBuilder PenetrationThread::_elem_side_builder
protected

Helper for building element sides without extraneous allocation.

Definition at line 89 of file PenetrationThread.h.

Referenced by computeSlip().

◆ _fe_type

FEType& PenetrationThread::_fe_type
protected

Definition at line 77 of file PenetrationThread.h.

Referenced by createInfoForElem(), and operator()().

◆ _fes

std::vector<std::vector<FEBase *> >& PenetrationThread::_fes
protected

Definition at line 75 of file PenetrationThread.h.

Referenced by createInfoForElem(), findRidgeContactPoint(), and operator()().

◆ _mesh

const MooseMesh& PenetrationThread::_mesh
protected

Definition at line 58 of file PenetrationThread.h.

Referenced by getInfoForFacesWithCommonNodes(), and operator()().

◆ _nearest_node

NearestNodeLocator& PenetrationThread::_nearest_node
protected

Definition at line 79 of file PenetrationThread.h.

Referenced by operator()().

◆ _nodal_normal_x

MooseVariable* PenetrationThread::_nodal_normal_x
protected

Definition at line 71 of file PenetrationThread.h.

Referenced by operator()(), and smoothNormal().

◆ _nodal_normal_y

MooseVariable* PenetrationThread::_nodal_normal_y
protected

Definition at line 72 of file PenetrationThread.h.

Referenced by operator()(), and smoothNormal().

◆ _nodal_normal_z

MooseVariable* PenetrationThread::_nodal_normal_z
protected

Definition at line 73 of file PenetrationThread.h.

Referenced by operator()(), and smoothNormal().

◆ _node_to_elem_map

const std::map<dof_id_type, std::vector<dof_id_type> >& PenetrationThread::_node_to_elem_map
protected

Definition at line 81 of file PenetrationThread.h.

Referenced by getInfoForFacesWithCommonNodes(), and operator()().

◆ _normal_smoothing_distance

Real PenetrationThread::_normal_smoothing_distance
protected

Definition at line 69 of file PenetrationThread.h.

Referenced by getSmoothingEdgeNodesAndWeights().

◆ _normal_smoothing_method

PenetrationLocator::NORMAL_SMOOTHING_METHOD PenetrationThread::_normal_smoothing_method
protected

Definition at line 70 of file PenetrationThread.h.

Referenced by operator()(), and smoothNormal().

◆ _penetration_info

std::map<dof_id_type, PenetrationInfo *>& PenetrationThread::_penetration_info
protected

Definition at line 63 of file PenetrationThread.h.

Referenced by operator()().

◆ _primary_boundary

BoundaryID PenetrationThread::_primary_boundary
protected

Definition at line 59 of file PenetrationThread.h.

Referenced by getSidesOnPrimaryBoundary().

◆ _recheck_secondary_nodes

std::vector<dof_id_type> PenetrationThread::_recheck_secondary_nodes

List of secondary nodes for which penetration was not detected in the current patch and for which patch has to be updated.

Definition at line 53 of file PenetrationThread.h.

Referenced by join(), and operator()().

◆ _secondary_boundary

BoundaryID PenetrationThread::_secondary_boundary
protected

Definition at line 60 of file PenetrationThread.h.

◆ _subproblem

SubProblem& PenetrationThread::_subproblem
protected

Definition at line 56 of file PenetrationThread.h.

Referenced by operator()().

◆ _tangential_tolerance

Real PenetrationThread::_tangential_tolerance
protected

Definition at line 67 of file PenetrationThread.h.

Referenced by competeInteractions(), createInfoForElem(), and operator()().

◆ _tid

THREAD_ID PenetrationThread::_tid
protected

Definition at line 86 of file PenetrationThread.h.

Referenced by createInfoForElem(), findRidgeContactPoint(), and operator()().

◆ _update_location

bool PenetrationThread::_update_location
protected

Definition at line 66 of file PenetrationThread.h.

Referenced by operator()().


The documentation for this class was generated from the following files: