https://mooseframework.inl.gov
Loading...
Searching...
No Matches
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, 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)
 
 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.
 

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.
 
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.
 
CommonEdgeResult interactionsOffCommonEdge (PenetrationInfo *pi1, PenetrationInfo *pi2)
 
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)
 
void getSideCornerNodes (const Elem *side, std::vector< const Node * > &corner_nodes)
 
bool restrictPointToSpecifiedEdgeOfFace (libMesh::Point &p, const Node *&closest_node, const Elem *side, const std::vector< const Node * > &edge_nodes)
 
bool restrictPointToFace (libMesh::Point &p, const Node *&closest_node, const Elem *side)
 
bool isFaceReasonableCandidate (const Elem *primary_elem, const Elem *side, libMesh::FEBase *fe, const libMesh::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 libMesh::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 (libMesh::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
 
bool _use_point_locator
 
MooseVariable_nodal_normal_x
 
MooseVariable_nodal_normal_y
 
MooseVariable_nodal_normal_z
 
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
 
THREAD_ID _tid
 
libMesh::ElemSideBuilder _elem_side_builder
 Helper for building element sides without extraneous allocation.
 

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 96 of file PenetrationThread.h.

◆ CompeteInteractionResult

Enumerator
FIRST_WINS 
SECOND_WINS 
NEITHER_WINS 

Definition at line 89 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,
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 
)

◆ PenetrationThread() [2/2]

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

Definition at line 138 of file PenetrationThread.C.

140 _mesh(x._mesh),
151 _fes(x._fes),
155{
156}
std::map< dof_id_type, PenetrationInfo * > & _penetration_info
const std::unordered_map< dof_id_type, std::vector< dof_id_type > > & _node_to_elem_map
std::vector< std::vector< libMesh::FEBase * > > & _fes
BoundaryID _secondary_boundary
const MooseMesh & _mesh
libMesh::FEType & _fe_type
NearestNodeLocator & _nearest_node
PenetrationLocator::NORMAL_SMOOTHING_METHOD _normal_smoothing_method
SubProblem & _subproblem
BoundaryID _primary_boundary

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 683 of file PenetrationThread.C.

684{
685
687
689 pi2->_tangential_distance > _tangential_tolerance) // out of tol on both faces
690 result = NEITHER_WINS;
691
692 else if (pi1->_tangential_distance == 0.0 &&
693 pi2->_tangential_distance > 0.0) // on face 1, off face 2
694 result = FIRST_WINS;
695
696 else if (pi2->_tangential_distance == 0.0 &&
697 pi1->_tangential_distance > 0.0) // on face 2, off face 1
698 result = SECOND_WINS;
699
701 pi2->_tangential_distance > _tangential_tolerance) // in face 1 tol, out of face 2 tol
702 result = FIRST_WINS;
703
705 pi1->_tangential_distance > _tangential_tolerance) // in face 2 tol, out of face 1 tol
706 result = SECOND_WINS;
707
708 else if (pi1->_tangential_distance == 0.0 && pi2->_tangential_distance == 0.0) // on both faces
709 result = competeInteractionsBothOnFace(pi1, pi2);
710
712 pi2->_tangential_distance <= _tangential_tolerance) // off but within tol of both faces
713 {
715 if (cer == COMMON_EDGE || cer == COMMON_NODE) // ridge case.
716 {
717 // We already checked for ridges, and it got rejected, so neither face must be valid
718 result = NEITHER_WINS;
719 // mooseError("Erroneously encountered ridge case");
720 }
721 else if (cer == EDGE_AND_COMMON_NODE) // off side of face, off corner of another face. Favor
722 // the off-side face
723 {
724 if (pi1->_off_edge_nodes.size() == pi2->_off_edge_nodes.size())
725 mooseError("Invalid off_edge_nodes counts");
726
727 else if (pi1->_off_edge_nodes.size() == 2)
728 result = FIRST_WINS;
729
730 else if (pi2->_off_edge_nodes.size() == 2)
731 result = SECOND_WINS;
732
733 else
734 mooseError("Invalid off_edge_nodes counts");
735 }
736 else // The node projects to both faces within tangential tolerance.
737 result = competeInteractionsBothOnFace(pi1, pi2);
738 }
739
740 return result;
741}
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
Definition MooseError.h:311
std::vector< const Node * > _off_edge_nodes
CommonEdgeResult interactionsOffCommonEdge(PenetrationInfo *pi1, PenetrationInfo *pi2)
CompeteInteractionResult competeInteractionsBothOnFace(PenetrationInfo *pi1, PenetrationInfo *pi2)
Determine whether first (pi1) or second (pi2) interaction is stronger when it is known that the node ...

Referenced by operator()().

◆ 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 744 of file PenetrationThread.C.

745{
747
748 if (pi1->_distance >= 0.0 && pi2->_distance < 0.0)
749 result = FIRST_WINS; // favor face with positive distance (penetrated) -- first in this case
750
751 else if (pi2->_distance >= 0.0 && pi1->_distance < 0.0)
752 result = SECOND_WINS; // favor face with positive distance (penetrated) -- second in this case
753
754 // TODO: This logic below could cause an abrupt jump from one face to the other with small mesh
755 // movement. If there is some way to smooth the transition, we should do it.
756 else if (MooseUtils::relativeFuzzyLessThan(std::abs(pi1->_distance), std::abs(pi2->_distance)))
757 result = FIRST_WINS; // otherwise, favor the closer face -- first in this case
758
759 else if (MooseUtils::relativeFuzzyLessThan(std::abs(pi2->_distance), std::abs(pi1->_distance)))
760 result = SECOND_WINS; // otherwise, favor the closer face -- second in this case
761
762 else // Equal within tolerance. Favor the one with a smaller element id (for repeatibility)
763 {
764 if (pi1->_elem->id() < pi2->_elem->id())
765 result = FIRST_WINS;
766
767 else
768 result = SECOND_WINS;
769 }
770
771 return result;
772}
const Elem * _elem
dof_id_type id() const

Referenced by competeInteractions().

◆ computeSlip()

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

Definition at line 1398 of file PenetrationThread.C.

1399{
1400 // Slip is current projected position of secondary node minus
1401 // original projected position of secondary node
1402 std::vector<Point> points(1);
1403 points[0] = info._starting_closest_point_ref;
1404 const auto & side = _elem_side_builder(*info._starting_elem, info._starting_side_num);
1405 fe.reinit(&side, &points);
1406 const std::vector<Point> & starting_point = fe.get_xyz();
1407 info._incremental_slip = info._closest_point - starting_point[0];
1408 if (info.isCaptured())
1409 {
1410 info._frictional_energy =
1411 info._frictional_energy_old + info._contact_force * info._incremental_slip;
1412 info._accumulated_slip = info._accumulated_slip_old + info._incremental_slip.norm();
1413 }
1414}
libMesh::ElemSideBuilder _elem_side_builder
Helper for building element sides without extraneous allocation.
virtual_for_inffe const std::vector< Point > & get_xyz() const
virtual void reinit(const Elem *elem, const std::vector< Point > *const pts=nullptr, const std::vector< Real > *const weights=nullptr)=0
MPI_Info info

Referenced by operator()().

◆ 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 1816 of file PenetrationThread.C.

1822{
1823 const BoundaryInfo & boundary_info = _mesh.getMesh().get_boundary_info();
1824
1825 for (auto s : elem->side_index_range())
1826 {
1827 if (!boundary_info.has_boundary_id(elem, s, _primary_boundary))
1828 continue;
1829
1830 // Don't create info for this side if one already exists
1831 bool already_have_info_this_side = false;
1832 for (const auto & pi : thisElemInfo)
1833 if (pi->_side_num == s)
1834 {
1835 already_have_info_this_side = true;
1836 break;
1837 }
1838
1839 if (already_have_info_this_side)
1840 break;
1841
1842 const Elem * side = elem->build_side_ptr(s).release();
1843
1844 // Only continue with creating info for this side if the side contains
1845 // all of the nodes in nodes_that_must_be_on_side
1846 std::vector<const Node *> nodevec;
1847 for (unsigned int ni = 0; ni < side->n_nodes(); ++ni)
1848 nodevec.push_back(side->node_ptr(ni));
1849
1850 std::sort(nodevec.begin(), nodevec.end());
1851 std::vector<const Node *> common_nodes;
1852 std::set_intersection(nodes_that_must_be_on_side.begin(),
1853 nodes_that_must_be_on_side.end(),
1854 nodevec.begin(),
1855 nodevec.end(),
1856 std::inserter(common_nodes, common_nodes.end()));
1857 if (common_nodes.size() != nodes_that_must_be_on_side.size())
1858 {
1859 delete side;
1860 break;
1861 }
1862
1863 FEBase * fe_elem = _fes[_tid][elem->dim()];
1864 FEBase * fe_side = _fes[_tid][side->dim()];
1865
1866 // Optionally check to see whether face is reasonable candidate based on an
1867 // estimate of how closely it is likely to project to the face
1868 if (check_whether_reasonable)
1869 if (!isFaceReasonableCandidate(elem, side, fe_side, secondary_node, _tangential_tolerance))
1870 {
1871 delete side;
1872 break;
1873 }
1874
1875 Point contact_phys;
1876 Point contact_ref;
1877 Point contact_on_face_ref;
1878 Real distance = 0.;
1879 Real tangential_distance = 0.;
1880 RealGradient normal;
1881 bool contact_point_on_side;
1882 std::vector<const Node *> off_edge_nodes;
1883 std::vector<std::vector<Real>> side_phi;
1884 std::vector<std::vector<RealGradient>> side_grad_phi;
1885 std::vector<RealGradient> dxyzdxi;
1886 std::vector<RealGradient> dxyzdeta;
1887 std::vector<RealGradient> d2xyzdxideta;
1888
1889 std::unique_ptr<PenetrationInfo> pen_info =
1890 std::make_unique<PenetrationInfo>(elem,
1891 side,
1892 s,
1893 normal,
1894 distance,
1895 tangential_distance,
1896 contact_phys,
1897 contact_ref,
1898 contact_on_face_ref,
1899 off_edge_nodes,
1900 side_phi,
1901 side_grad_phi,
1902 dxyzdxi,
1903 dxyzdeta,
1904 d2xyzdxideta);
1905
1906 bool search_succeeded = false;
1907 Moose::findContactPoint(*pen_info,
1908 fe_elem,
1909 fe_side,
1910 _fe_type,
1911 *secondary_node,
1912 true,
1914 contact_point_on_side,
1915 search_succeeded);
1916
1917 // Do not add contact info from failed searches
1918 if (search_succeeded)
1919 {
1920 thisElemInfo.push_back(pen_info.get());
1921 p_info.push_back(pen_info.release());
1922 }
1923 }
1924}
MeshBase & getMesh()
Accessor for the underlying libMesh Mesh object.
Definition MooseMesh.C:3549
bool isFaceReasonableCandidate(const Elem *primary_elem, const Elem *side, libMesh::FEBase *fe, const libMesh::Point *secondary_point, const Real tangential_tolerance)
bool has_boundary_id(const Node *const node, const boundary_id_type id) const
virtual unsigned int n_nodes() const=0
virtual unsigned short dim() const=0
const Node * node_ptr(const unsigned int i) const
virtual std::unique_ptr< Elem > build_side_ptr(const unsigned int i)=0
const BoundaryInfo & get_boundary_info() 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)
Finds the closest point (called the contact point) on the primary_elem on side "side" to the secondar...
if(subdm)
const Real pi
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
Real distance(const Point &p)

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

◆ findRidgeContactPoint()

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

Definition at line 829 of file PenetrationThread.C.

837{
838 tangential_distance = 0.0;
839 closest_node = NULL;
840 PenetrationInfo * pi1 = p_info[index1];
841 PenetrationInfo * pi2 = p_info[index2];
842 const unsigned sidedim(pi1->_side->dim());
843 mooseAssert(sidedim == pi2->_side->dim(), "Incompatible dimensionalities");
844
845 // Nodes on faces for the two interactions
846 std::vector<const Node *> side1_nodes;
847 getSideCornerNodes(pi1->_side, side1_nodes);
848 std::vector<const Node *> side2_nodes;
849 getSideCornerNodes(pi2->_side, side2_nodes);
850
851 std::sort(side1_nodes.begin(), side1_nodes.end());
852 std::sort(side2_nodes.begin(), side2_nodes.end());
853
854 // Find nodes shared by the two faces
855 std::vector<const Node *> common_nodes;
856 std::set_intersection(side1_nodes.begin(),
857 side1_nodes.end(),
858 side2_nodes.begin(),
859 side2_nodes.end(),
860 std::inserter(common_nodes, common_nodes.end()));
861
862 if (common_nodes.size() != sidedim)
863 return false;
864
865 bool found_point1, found_point2;
866 Point closest_coor_ref1(pi1->_closest_point_ref);
867 const Node * closest_node1;
869 closest_coor_ref1, closest_node1, pi1->_side, common_nodes);
870
871 Point closest_coor_ref2(pi2->_closest_point_ref);
872 const Node * closest_node2;
874 closest_coor_ref2, closest_node2, pi2->_side, common_nodes);
875
876 if (!found_point1 || !found_point2)
877 return false;
878
879 // if (sidedim == 2)
880 // {
881 // TODO:
882 // We have the parametric coordinates of the closest intersection point for both faces.
883 // We need to find a point somewhere in the middle of them so there's not an abrupt jump.
884 // Find that point by taking dot products of vector from contact point to secondary node point
885 // with face normal vectors to see which face we're closer to.
886 // }
887
888 FEBase * fe = NULL;
889 std::vector<Point> points(1);
890
891 // We have to pick one of the two faces to own the contact point. Either one would
892 // generally work, but to avoid some corner-case numerical roundoff issues when
893 // determining signs of the normal and displacement, pick the one that the point is
894 // closer to projecting onto, which is the one with the larger projected distance.
895 // If that distance is the same for both faces (within numerical precision), pick the
896 // face with the lowest index for repeatability.
897 if (MooseUtils::absoluteFuzzyGreaterThan(std::abs(pi1->_distance), std::abs(pi2->_distance)) ||
898 (MooseUtils::absoluteFuzzyEqual(std::abs(pi1->_distance), std::abs(pi2->_distance)) &&
899 index1 < index2))
900 {
901 fe = _fes[_tid][pi1->_side->dim()];
902 contact_point_ref = closest_coor_ref1;
903 points[0] = closest_coor_ref1;
904 fe->reinit(pi1->_side, &points);
905 index = index1;
906 }
907 else
908 {
909 fe = _fes[_tid][pi2->_side->dim()];
910 contact_point_ref = closest_coor_ref2;
911 points[0] = closest_coor_ref2;
912 fe->reinit(pi2->_side, &points);
913 index = index2;
914 }
915
916 contact_point = fe->get_xyz()[0];
917
918 if (sidedim == 2)
919 {
920 if (closest_node1) // point is off the ridge between the two elements
921 {
922 mooseAssert((closest_node1 == closest_node2 || closest_node2 == NULL),
923 "If off edge of ridge, closest node must be the same on both elements");
924 closest_node = closest_node1;
925
926 RealGradient off_face = *closest_node1 - contact_point;
927 tangential_distance = off_face.norm();
928 }
929 }
930
931 return true;
932}
Data structure used to hold penetration information.
const Elem * _side
bool restrictPointToSpecifiedEdgeOfFace(libMesh::Point &p, const Node *&closest_node, const Elem *side, const std::vector< const Node * > &edge_nodes)
void getSideCornerNodes(const Elem *side, std::vector< const Node * > &corner_nodes)

Referenced by operator()().

◆ getInfoForElem()

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

Definition at line 1801 of file PenetrationThread.C.

1804{
1805 for (const auto & pi : p_info)
1806 {
1807 if (!pi)
1808 continue;
1809
1810 if (pi->_elem == elem)
1811 thisElemInfo.push_back(pi);
1812 }
1813}

Referenced by getInfoForFacesWithCommonNodes().

◆ 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 1711 of file PenetrationThread.C.

1717{
1718 // elems connected to a node on this edge, find one that has the same corners as this, and is not
1719 // the current elem
1720 auto node_to_elem_pair = _node_to_elem_map.find(edge_nodes[0]->id()); // just need one of the
1721 // nodes
1722 mooseAssert(node_to_elem_pair != _node_to_elem_map.end(), "Missing entry in node to elem map");
1723 const std::vector<dof_id_type> & elems_connected_to_node = node_to_elem_pair->second;
1724
1725 std::vector<const Elem *> elems_connected_to_edge;
1726
1727 for (unsigned int ecni = 0; ecni < elems_connected_to_node.size(); ecni++)
1728 {
1729 if (elems_to_exclude.find(elems_connected_to_node[ecni]) != elems_to_exclude.end())
1730 continue;
1731 const Elem * elem = _mesh.elemPtr(elems_connected_to_node[ecni]);
1732
1733 std::vector<const Node *> nodevec;
1734 for (unsigned int ni = 0; ni < elem->n_nodes(); ++ni)
1735 if (elem->is_vertex(ni))
1736 nodevec.push_back(elem->node_ptr(ni));
1737
1738 std::vector<const Node *> common_nodes;
1739 std::sort(nodevec.begin(), nodevec.end());
1740 std::set_intersection(edge_nodes.begin(),
1741 edge_nodes.end(),
1742 nodevec.begin(),
1743 nodevec.end(),
1744 std::inserter(common_nodes, common_nodes.end()));
1745
1746 if (common_nodes.size() == edge_nodes.size())
1747 elems_connected_to_edge.push_back(elem);
1748 }
1749
1750 if (elems_connected_to_edge.size() > 0)
1751 {
1752
1753 // There are potentially multiple elements that share a common edge
1754 // 2D:
1755 // There can only be one element on the same surface
1756 // 3D:
1757 // If there are two edge nodes, there can only be one element on the same surface
1758 // If there is only one edge node (a corner), there could be multiple elements on the same
1759 // surface
1760 bool allowMultipleNeighbors = false;
1761
1762 if (elems_connected_to_edge[0]->dim() == 3)
1763 {
1764 if (edge_nodes.size() == 1)
1765 {
1766 allowMultipleNeighbors = true;
1767 }
1768 }
1769
1770 for (unsigned int i = 0; i < elems_connected_to_edge.size(); ++i)
1771 {
1772 std::vector<PenetrationInfo *> thisElemInfo;
1773 getInfoForElem(thisElemInfo, p_info, elems_connected_to_edge[i]);
1774 if (thisElemInfo.size() > 0 && !allowMultipleNeighbors)
1775 {
1776 if (thisElemInfo.size() > 1)
1777 mooseError(
1778 "Found multiple neighbors to current edge/face on surface when only one is allowed");
1779 face_info_comm_edge.push_back(thisElemInfo[0]);
1780 break;
1781 }
1782
1784 thisElemInfo, p_info, secondary_node, elems_connected_to_edge[i], edge_nodes);
1785 if (thisElemInfo.size() > 0 && !allowMultipleNeighbors)
1786 {
1787 if (thisElemInfo.size() > 1)
1788 mooseError(
1789 "Found multiple neighbors to current edge/face on surface when only one is allowed");
1790 face_info_comm_edge.push_back(thisElemInfo[0]);
1791 break;
1792 }
1793
1794 for (unsigned int j = 0; j < thisElemInfo.size(); ++j)
1795 face_info_comm_edge.push_back(thisElemInfo[j]);
1796 }
1797 }
1798}
unsigned int dim
virtual Elem * elemPtr(const dof_id_type i)
Definition MooseMesh.C:3214
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 getInfoForElem(std::vector< PenetrationInfo * > &thisElemInfo, std::vector< PenetrationInfo * > &p_info, const Elem *elem)
virtual bool is_vertex(const unsigned int i) const=0

Referenced by getSmoothingFacesAndWeights().

◆ getSideCornerNodes()

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

Definition at line 935 of file PenetrationThread.C.

936{
937 const ElemType t(side->type());
938 corner_nodes.clear();
939
940 corner_nodes.push_back(side->node_ptr(0));
941 corner_nodes.push_back(side->node_ptr(1));
942 switch (t)
943 {
944 case EDGE2:
945 case EDGE3:
946 case EDGE4:
947 {
948 break;
949 }
950
951 case TRI3:
952 case TRI6:
953 case TRI7:
954 {
955 corner_nodes.push_back(side->node_ptr(2));
956 break;
957 }
958
959 case QUAD4:
960 case QUAD8:
961 case QUAD9:
962 {
963 corner_nodes.push_back(side->node_ptr(2));
964 corner_nodes.push_back(side->node_ptr(3));
965 break;
966 }
967
968 default:
969 {
970 mooseError("Unsupported face type: ", t);
971 break;
972 }
973 }
974}
virtual ElemType type() const=0

Referenced by findRidgeContactPoint().

◆ getSidesOnPrimaryBoundary()

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

◆ getSmoothingEdgeNodesAndWeights()

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

Definition at line 1570 of file PenetrationThread.C.

1575{
1576 const ElemType t(side->type());
1577 const Real & xi = p(0);
1578 const Real & eta = p(1);
1579
1580 Real smooth_limit = 1.0 - _normal_smoothing_distance;
1581
1582 switch (t)
1583 {
1584 case EDGE2:
1585 case EDGE3:
1586 case EDGE4:
1587 {
1588 if (xi < -smooth_limit)
1589 {
1590 std::vector<const Node *> en;
1591 en.push_back(side->node_ptr(0));
1592 edge_nodes.push_back(en);
1593 Real fw = 0.5 - (1.0 + xi) / (2.0 * _normal_smoothing_distance);
1594 if (fw > 0.5)
1595 fw = 0.5;
1596 edge_face_weights.push_back(fw);
1597 }
1598 else if (xi > smooth_limit)
1599 {
1600 std::vector<const Node *> en;
1601 en.push_back(side->node_ptr(1));
1602 edge_nodes.push_back(en);
1603 Real fw = 0.5 - (1.0 - xi) / (2.0 * _normal_smoothing_distance);
1604 if (fw > 0.5)
1605 fw = 0.5;
1606 edge_face_weights.push_back(fw);
1607 }
1608 break;
1609 }
1610
1611 case TRI3:
1612 case TRI6:
1613 case TRI7:
1614 {
1615 if (eta < -smooth_limit)
1616 {
1617 std::vector<const Node *> en;
1618 en.push_back(side->node_ptr(0));
1619 en.push_back(side->node_ptr(1));
1620 edge_nodes.push_back(en);
1621 Real fw = 0.5 - (1.0 + eta) / (2.0 * _normal_smoothing_distance);
1622 if (fw > 0.5)
1623 fw = 0.5;
1624 edge_face_weights.push_back(fw);
1625 }
1626 if ((xi + eta) > smooth_limit)
1627 {
1628 std::vector<const Node *> en;
1629 en.push_back(side->node_ptr(1));
1630 en.push_back(side->node_ptr(2));
1631 edge_nodes.push_back(en);
1632 Real fw = 0.5 - (1.0 - xi - eta) / (2.0 * _normal_smoothing_distance);
1633 if (fw > 0.5)
1634 fw = 0.5;
1635 edge_face_weights.push_back(fw);
1636 }
1637 if (xi < -smooth_limit)
1638 {
1639 std::vector<const Node *> en;
1640 en.push_back(side->node_ptr(2));
1641 en.push_back(side->node_ptr(0));
1642 edge_nodes.push_back(en);
1643 Real fw = 0.5 - (1.0 + xi) / (2.0 * _normal_smoothing_distance);
1644 if (fw > 0.5)
1645 fw = 0.5;
1646 edge_face_weights.push_back(fw);
1647 }
1648 break;
1649 }
1650
1651 case QUAD4:
1652 case QUAD8:
1653 case QUAD9:
1654 {
1655 if (eta < -smooth_limit)
1656 {
1657 std::vector<const Node *> en;
1658 en.push_back(side->node_ptr(0));
1659 en.push_back(side->node_ptr(1));
1660 edge_nodes.push_back(en);
1661 Real fw = 0.5 - (1.0 + eta) / (2.0 * _normal_smoothing_distance);
1662 if (fw > 0.5)
1663 fw = 0.5;
1664 edge_face_weights.push_back(fw);
1665 }
1666 if (xi > smooth_limit)
1667 {
1668 std::vector<const Node *> en;
1669 en.push_back(side->node_ptr(1));
1670 en.push_back(side->node_ptr(2));
1671 edge_nodes.push_back(en);
1672 Real fw = 0.5 - (1.0 - xi) / (2.0 * _normal_smoothing_distance);
1673 if (fw > 0.5)
1674 fw = 0.5;
1675 edge_face_weights.push_back(fw);
1676 }
1677 if (eta > smooth_limit)
1678 {
1679 std::vector<const Node *> en;
1680 en.push_back(side->node_ptr(2));
1681 en.push_back(side->node_ptr(3));
1682 edge_nodes.push_back(en);
1683 Real fw = 0.5 - (1.0 - eta) / (2.0 * _normal_smoothing_distance);
1684 if (fw > 0.5)
1685 fw = 0.5;
1686 edge_face_weights.push_back(fw);
1687 }
1688 if (xi < -smooth_limit)
1689 {
1690 std::vector<const Node *> en;
1691 en.push_back(side->node_ptr(3));
1692 en.push_back(side->node_ptr(0));
1693 edge_nodes.push_back(en);
1694 Real fw = 0.5 - (1.0 + xi) / (2.0 * _normal_smoothing_distance);
1695 if (fw > 0.5)
1696 fw = 0.5;
1697 edge_face_weights.push_back(fw);
1698 }
1699 break;
1700 }
1701
1702 default:
1703 {
1704 mooseError("Unsupported face type: ", t);
1705 break;
1706 }
1707 }
1708}
Point eta
Definition MortarUtils.C:60
Point xi
Definition MortarUtils.C:59

Referenced by getSmoothingFacesAndWeights().

◆ 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 1475 of file PenetrationThread.C.

1480{
1481 const Elem * side = info->_side;
1482 const Point & p = info->_closest_point_ref;
1483 std::set<dof_id_type> elems_to_exclude;
1484 elems_to_exclude.insert(info->_elem->id());
1485
1486 std::vector<std::vector<const Node *>> edge_nodes;
1487
1488 // Get the pairs of nodes along every edge that we are close enough to smooth with
1489 getSmoothingEdgeNodesAndWeights(p, side, edge_nodes, edge_face_weights);
1490 std::vector<Elem *> edge_neighbor_elems;
1491 edge_face_info.resize(edge_nodes.size(), NULL);
1492
1493 std::vector<unsigned int> edges_without_neighbors;
1494
1495 for (unsigned int i = 0; i < edge_nodes.size(); ++i)
1496 {
1497 // Sort all sets of edge nodes (needed for comparing edges)
1498 std::sort(edge_nodes[i].begin(), edge_nodes[i].end());
1499
1500 std::vector<PenetrationInfo *> face_info_comm_edge;
1502 &secondary_node, elems_to_exclude, edge_nodes[i], face_info_comm_edge, p_info);
1503
1504 if (face_info_comm_edge.size() == 0)
1505 edges_without_neighbors.push_back(i);
1506 else if (face_info_comm_edge.size() > 1)
1507 mooseError("Only one neighbor allowed per edge");
1508 else
1509 edge_face_info[i] = face_info_comm_edge[0];
1510 }
1511
1512 // Remove edges without neighbors from the vector, starting from end
1513 std::vector<unsigned int>::reverse_iterator rit;
1514 for (rit = edges_without_neighbors.rbegin(); rit != edges_without_neighbors.rend(); ++rit)
1515 {
1516 unsigned int index = *rit;
1517 edge_nodes.erase(edge_nodes.begin() + index);
1518 edge_face_weights.erase(edge_face_weights.begin() + index);
1519 edge_face_info.erase(edge_face_info.begin() + index);
1520 }
1521
1522 // Handle corner case
1523 if (edge_nodes.size() > 1)
1524 {
1525 if (edge_nodes.size() != 2)
1526 mooseError("Invalid number of smoothing edges");
1527
1528 // find common node
1529 std::vector<const Node *> common_nodes;
1530 std::set_intersection(edge_nodes[0].begin(),
1531 edge_nodes[0].end(),
1532 edge_nodes[1].begin(),
1533 edge_nodes[1].end(),
1534 std::inserter(common_nodes, common_nodes.end()));
1535
1536 if (common_nodes.size() != 1)
1537 mooseError("Invalid number of common nodes");
1538
1539 for (const auto & pinfo : edge_face_info)
1540 elems_to_exclude.insert(pinfo->_elem->id());
1541
1542 std::vector<PenetrationInfo *> face_info_comm_edge;
1544 &secondary_node, elems_to_exclude, common_nodes, face_info_comm_edge, p_info);
1545
1546 unsigned int num_corner_neighbors = face_info_comm_edge.size();
1547
1548 if (num_corner_neighbors > 0)
1549 {
1550 Real fw0 = edge_face_weights[0];
1551 Real fw1 = edge_face_weights[1];
1552
1553 // Corner weight is product of edge weights. Spread out over multiple neighbors.
1554 Real fw_corner = (fw0 * fw1) / static_cast<Real>(num_corner_neighbors);
1555
1556 // Adjust original edge weights
1557 edge_face_weights[0] *= (1.0 - fw1);
1558 edge_face_weights[1] *= (1.0 - fw0);
1559
1560 for (unsigned int i = 0; i < num_corner_neighbors; ++i)
1561 {
1562 edge_face_weights.push_back(fw_corner);
1563 edge_face_info.push_back(face_info_comm_edge[i]);
1564 }
1565 }
1566 }
1567}
void getSmoothingEdgeNodesAndWeights(const libMesh::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)

Referenced by smoothNormal().

◆ interactionsOffCommonEdge()

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

Definition at line 775 of file PenetrationThread.C.

776{
777 CommonEdgeResult common_edge(NO_COMMON);
778 const std::vector<const Node *> & off_edge_nodes1 = pi1->_off_edge_nodes;
779 const std::vector<const Node *> & off_edge_nodes2 = pi2->_off_edge_nodes;
780 const unsigned dim1 = pi1->_side->dim();
781
782 if (dim1 == 1)
783 {
784 mooseAssert(pi2->_side->dim() == 1, "Incompatible dimensions.");
785 mooseAssert(off_edge_nodes1.size() < 2 && off_edge_nodes2.size() < 2,
786 "off_edge_nodes size should be <2 for 2D contact");
787 if (off_edge_nodes1.size() == 1 && off_edge_nodes2.size() == 1 &&
788 off_edge_nodes1[0] == off_edge_nodes2[0])
789 common_edge = COMMON_EDGE;
790 }
791 else
792 {
793 mooseAssert(dim1 == 2 && pi2->_side->dim() == 2, "Incompatible dimensions.");
794 mooseAssert(off_edge_nodes1.size() < 3 && off_edge_nodes2.size() < 3,
795 "off_edge_nodes size should be <3 for 3D contact");
796 if (off_edge_nodes1.size() == 1)
797 {
798 if (off_edge_nodes2.size() == 1)
799 {
800 if (off_edge_nodes1[0] == off_edge_nodes2[0])
801 common_edge = COMMON_NODE;
802 }
803 else if (off_edge_nodes2.size() == 2)
804 {
805 if (off_edge_nodes1[0] == off_edge_nodes2[0] || off_edge_nodes1[0] == off_edge_nodes2[1])
806 common_edge = EDGE_AND_COMMON_NODE;
807 }
808 }
809 else if (off_edge_nodes1.size() == 2)
810 {
811 if (off_edge_nodes2.size() == 1)
812 {
813 if (off_edge_nodes1[0] == off_edge_nodes2[0] || off_edge_nodes1[1] == off_edge_nodes2[0])
814 common_edge = EDGE_AND_COMMON_NODE;
815 }
816 else if (off_edge_nodes2.size() == 2)
817 {
818 if ((off_edge_nodes1[0] == off_edge_nodes2[0] &&
819 off_edge_nodes1[1] == off_edge_nodes2[1]) ||
820 (off_edge_nodes1[1] == off_edge_nodes2[0] && off_edge_nodes1[0] == off_edge_nodes2[1]))
821 common_edge = COMMON_EDGE;
822 }
823 }
824 }
825 return common_edge;
826}

Referenced by competeInteractions().

◆ isFaceReasonableCandidate()

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

Definition at line 1332 of file PenetrationThread.C.

1337{
1338 unsigned int dim = primary_elem->dim();
1339
1340 const std::vector<Point> & phys_point = fe->get_xyz();
1341
1342 const std::vector<RealGradient> & dxyz_dxi = fe->get_dxyzdxi();
1343 const std::vector<RealGradient> & dxyz_deta = fe->get_dxyzdeta();
1344
1345 Point ref_point;
1346
1347 std::vector<Point> points(1); // Default constructor gives us a point at 0,0,0
1348
1349 fe->reinit(side, &points);
1350
1351 RealGradient d = *secondary_point - phys_point[0];
1352
1353 const Real twosqrt2 = 2.8284; // way more precision than we actually need here
1354 Real max_face_length = side->hmax() + twosqrt2 * tangential_tolerance;
1355
1356 RealVectorValue normal;
1357 if (dim - 1 == 2)
1358 {
1359 normal = dxyz_dxi[0].cross(dxyz_deta[0]);
1360 }
1361 else if (dim - 1 == 1)
1362 {
1363 const Node * const * elem_nodes = primary_elem->get_nodes();
1364 const Point in_plane_vector1 = *elem_nodes[1] - *elem_nodes[0];
1365 const Point in_plane_vector2 = *elem_nodes[2] - *elem_nodes[0];
1366
1367 Point out_of_plane_normal = in_plane_vector1.cross(in_plane_vector2);
1368 out_of_plane_normal /= out_of_plane_normal.norm();
1369
1370 normal = dxyz_dxi[0].cross(out_of_plane_normal);
1371 }
1372 else
1373 {
1374 return true;
1375 }
1376 normal /= normal.norm();
1377
1378 const Real dot(d * normal);
1379
1380 const RealGradient normcomp = dot * normal;
1381 const RealGradient tangcomp = d - normcomp;
1382
1383 const Real tangdist = tangcomp.norm();
1384
1385 // Increase the size of the zone that we consider if the vector from the face
1386 // to the node has a larger normal component
1387 const Real faceExpansionFactor = 2.0 * (1.0 + normcomp.norm() / d.norm());
1388
1389 bool isReasonableCandidate = true;
1390 if (tangdist > faceExpansionFactor * max_face_length)
1391 {
1392 isReasonableCandidate = false;
1393 }
1394 return isReasonableCandidate;
1395}
virtual Real hmax() const
const Node *const * get_nodes() const
virtual_for_inffe const std::vector< RealGradient > & get_dxyzdeta() const
virtual_for_inffe const std::vector< RealGradient > & get_dxyzdxi() const
TypeVector< typename CompareTypes< T, T2 >::supertype > cross(const TypeVector< T2 > &v) const

Referenced by createInfoForElem().

◆ join()

void PenetrationThread::join ( const PenetrationThread other)

Definition at line 641 of file PenetrationThread.C.

642{
644 other._recheck_secondary_nodes.begin(),
645 other._recheck_secondary_nodes.end());
646}
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 159 of file PenetrationThread.C.

160{
161 ParallelUniqueId puid;
162 _tid = puid.id;
163
164 // Must get the variables every time this is run because _tid can change
167 {
171 }
172
173 const BoundaryInfo & boundary_info = _mesh.getMesh().get_boundary_info();
174 std::unique_ptr<PointLocatorBase> point_locator;
176 point_locator = _mesh.getPointLocator();
177
178 for (const auto & node_id : range)
179 {
180 const Node & node = _mesh.nodeRef(node_id);
181
182 // We're going to get a reference to the pointer for the pinfo for this node
183 // This will allow us to manipulate this pointer without having to go through
184 // the _penetration_info map... meaning this is the only mutex we'll have to do!
188
189 std::vector<PenetrationInfo *> p_info;
190 bool info_set(false);
191
192 // See if we already have info about this node
193 if (info)
194 {
195 FEBase * fe_elem = _fes[_tid][info->_elem->dim()];
196 FEBase * fe_side = _fes[_tid][info->_side->dim()];
197
198 if (!_update_location && (info->_distance >= 0 || info->isCaptured()))
199 {
200 const Point contact_ref = info->_closest_point_ref;
201 bool contact_point_on_side(false);
202
203 // Secondary position must be the previous contact point
204 // Use the previous reference coordinates
205 std::vector<Point> points(1);
206 points[0] = contact_ref;
207 const std::vector<Point> & secondary_pos = fe_side->get_xyz();
208 bool search_succeeded = false;
209
211 fe_elem,
212 fe_side,
213 _fe_type,
214 secondary_pos[0],
215 false,
217 contact_point_on_side,
218 search_succeeded);
219
220 // Restore the original reference coordinates
221 info->_closest_point_ref = contact_ref;
222 // Just calculated as the distance of the contact point off the surface (0). Set to 0 to
223 // avoid round-off.
224 info->_distance = 0.0;
225 info_set = true;
226 }
227 else
228 {
229 Real old_tangential_distance(info->_tangential_distance);
230 bool contact_point_on_side(false);
231 bool search_succeeded = false;
232
234 fe_elem,
235 fe_side,
236 _fe_type,
237 node,
238 false,
240 contact_point_on_side,
241 search_succeeded);
242
243 if (contact_point_on_side)
244 {
245 if (info->_tangential_distance <= 0.0) // on the face
246 {
247 info_set = true;
248 }
249 else if (info->_tangential_distance > 0.0 && old_tangential_distance > 0.0)
250 { // off the face but within tolerance, was that way on the last step too
251 if (info->_side->dim() == 2 && info->_off_edge_nodes.size() < 2)
252 { // Closest point on face is on a node rather than an edge. Another
253 // face might be a better candidate.
254 }
255 else
256 {
257 info_set = true;
258 }
259 }
260 }
261 }
262 }
263
264 if (!info_set)
265 {
266 const Node * closest_node = _nearest_node.nearestNode(node.id());
267
268 std::vector<dof_id_type> located_elem_ids;
269 const std::vector<dof_id_type> * closest_elems;
270
272 {
273 std::set<const Elem *> candidate_elements;
274 (*point_locator)(*closest_node, candidate_elements);
275
276 if (candidate_elements.empty())
277 mooseError("No proximate elements found at node ",
278 closest_node->id(),
279 " at ",
280 static_cast<const Point &>(*closest_node),
281 " on boundary ",
283 ". This should never happen.");
284
285 for (const Elem * elem : candidate_elements)
286 {
287 for (auto s : elem->side_index_range())
288 if (boundary_info.has_boundary_id(elem, s, _primary_boundary))
289 {
290 located_elem_ids.push_back(elem->id());
291 break;
292 }
293 }
294
295 if (located_elem_ids.empty())
296 mooseError("No proximate elements found at node ",
297 closest_node->id(),
298 " at ",
299 static_cast<const Point &>(*closest_node),
300 " on boundary ",
302 " share that boundary. This may happen if the mesh uses the same boundary id "
303 "for a nodeset and an unrelated sideset.");
304
305 closest_elems = &located_elem_ids;
306 }
307 else
308 {
309 auto node_to_elem_pair = _node_to_elem_map.find(closest_node->id());
310 mooseAssert(node_to_elem_pair != _node_to_elem_map.end(),
311 "Missing entry in node to elem map");
312 closest_elems = &(node_to_elem_pair->second);
313 }
314
315 for (const auto & elem_id : *closest_elems)
316 {
317 const Elem * elem = _mesh.elemPtr(elem_id);
318
319 std::vector<PenetrationInfo *> thisElemInfo;
320
321 std::vector<const Node *> nodesThatMustBeOnSide;
322 // If we have a disconnected mesh, we might not have *any*
323 // nodes that must be on a side we check; we'll rely on
324 // boundary info to find valid sides, then rely on comparing
325 // closest points from each to find the best.
326 //
327 // If we don't have a disconnected mesh, then for maximum
328 // backwards compatibility we're still using the older ridge
329 // and peak detection code, which depends on us ruling out
330 // sides that don't touch closest_node.
332 nodesThatMustBeOnSide.push_back(closest_node);
334 thisElemInfo, p_info, &node, elem, nodesThatMustBeOnSide, _check_whether_reasonable);
335 }
336
338 {
339 Real min_distance_sq = std::numeric_limits<Real>::max();
340 Point best_point;
341 unsigned int best_i = invalid_uint;
342
343 // Find closest point in all p_info to the node of interest
344 for (unsigned int i = 0; i < p_info.size(); ++i)
345 {
346 const Point closest_point = closest_point_to_side(node, *p_info[i]->_side);
347 const Real distance_sq = (closest_point - node).norm_sq();
348 if (distance_sq < min_distance_sq)
349 {
350 min_distance_sq = distance_sq;
351 best_point = closest_point;
352 best_i = i;
353 }
354 }
355
356 p_info[best_i]->_closest_point = best_point;
357 p_info[best_i]->_distance =
358 (p_info[best_i]->_distance >= 0.0 ? 1.0 : -1.0) * std::sqrt(min_distance_sq);
360 mooseError("Normal smoothing not implemented with point locator code");
361 Point normal = (best_point - node).unit();
362 const Real dot = normal * p_info[best_i]->_normal;
363 if (dot < 0)
364 normal *= -1;
365 p_info[best_i]->_normal = normal;
366
367 switchInfo(info, p_info[best_i]);
368 info_set = true;
369 }
370 else
371 {
372 if (p_info.size() == 1)
373 {
374 if (p_info[0]->_tangential_distance <= _tangential_tolerance)
375 {
376 switchInfo(info, p_info[0]);
377 info_set = true;
378 }
379 }
380 else if (p_info.size() > 1)
381 {
382 // Loop through all pairs of faces, and check for contact on ridge between each face pair
383 std::vector<RidgeData> ridgeDataVec;
384 for (unsigned int i = 0; i + 1 < p_info.size(); ++i)
385 for (unsigned int j = i + 1; j < p_info.size(); ++j)
386 {
387 Point closest_coor;
388 Real tangential_distance(0.0);
389 const Node * closest_node_on_ridge = NULL;
390 unsigned int index = 0;
391 Point closest_coor_ref;
392 bool found_ridge_contact_point = findRidgeContactPoint(closest_coor,
393 tangential_distance,
394 closest_node_on_ridge,
395 index,
396 closest_coor_ref,
397 p_info,
398 i,
399 j);
400 if (found_ridge_contact_point)
401 {
402 RidgeData rpd;
403 rpd._closest_coor = closest_coor;
404 rpd._tangential_distance = tangential_distance;
405 rpd._closest_node = closest_node_on_ridge;
406 rpd._index = index;
407 rpd._closest_coor_ref = closest_coor_ref;
408 ridgeDataVec.push_back(rpd);
409 }
410 }
411
412 if (ridgeDataVec.size() > 0) // Either find the ridge pair that is the best or find a peak
413 {
414 // Group together ridges for which we are off the edge of a common node.
415 // Those are peaks.
416 std::vector<RidgeSetData> ridgeSetDataVec;
417 for (unsigned int i = 0; i < ridgeDataVec.size(); ++i)
418 {
419 bool foundSetWithMatchingNode = false;
420 for (unsigned int j = 0; j < ridgeSetDataVec.size(); ++j)
421 {
422 if (ridgeDataVec[i]._closest_node != NULL &&
423 ridgeDataVec[i]._closest_node == ridgeSetDataVec[j]._closest_node)
424 {
425 foundSetWithMatchingNode = true;
426 ridgeSetDataVec[j]._ridge_data_vec.push_back(ridgeDataVec[i]);
427 break;
428 }
429 }
430 if (!foundSetWithMatchingNode)
431 {
432 RidgeSetData rsd;
433 rsd._distance = std::numeric_limits<Real>::max();
434 rsd._ridge_data_vec.push_back(ridgeDataVec[i]);
435 rsd._closest_node = ridgeDataVec[i]._closest_node;
436 ridgeSetDataVec.push_back(rsd);
437 }
438 }
439 // Compute distance to each set of ridges
440 for (unsigned int i = 0; i < ridgeSetDataVec.size(); ++i)
441 {
442 if (ridgeSetDataVec[i]._closest_node !=
443 NULL) // Either a peak or off the edge of single ridge
444 {
445 if (ridgeSetDataVec[i]._ridge_data_vec.size() == 1) // off edge of single ridge
446 {
447 if (ridgeSetDataVec[i]._ridge_data_vec[0]._tangential_distance <=
448 _tangential_tolerance) // off within tolerance
449 {
450 ridgeSetDataVec[i]._closest_coor =
451 ridgeSetDataVec[i]._ridge_data_vec[0]._closest_coor;
452 Point contact_point_vec = node - ridgeSetDataVec[i]._closest_coor;
453 ridgeSetDataVec[i]._distance = contact_point_vec.norm();
454 }
455 }
456 else // several ridges join at common node to make a peak. The common node is the
457 // contact point
458 {
459 ridgeSetDataVec[i]._closest_coor = *ridgeSetDataVec[i]._closest_node;
460 Point contact_point_vec = node - ridgeSetDataVec[i]._closest_coor;
461 ridgeSetDataVec[i]._distance = contact_point_vec.norm();
462 }
463 }
464 else // on a single ridge
465 {
466 ridgeSetDataVec[i]._closest_coor =
467 ridgeSetDataVec[i]._ridge_data_vec[0]._closest_coor;
468 Point contact_point_vec = node - ridgeSetDataVec[i]._closest_coor;
469 ridgeSetDataVec[i]._distance = contact_point_vec.norm();
470 }
471 }
472 // Find the set of ridges closest to us.
473 unsigned int closest_ridge_set_index(0);
474 Real closest_distance(ridgeSetDataVec[0]._distance);
475 Point closest_point(ridgeSetDataVec[0]._closest_coor);
476 for (unsigned int i = 1; i < ridgeSetDataVec.size(); ++i)
477 {
478 if (ridgeSetDataVec[i]._distance < closest_distance)
479 {
480 closest_ridge_set_index = i;
481 closest_distance = ridgeSetDataVec[i]._distance;
482 closest_point = ridgeSetDataVec[i]._closest_coor;
483 }
484 }
485
486 if (closest_distance <
487 std::numeric_limits<Real>::max()) // contact point is on the closest ridge set
488 {
489 // find the face in the ridge set with the smallest index, assign that one to the
490 // interaction
491 // TODO: We may need to select the face with the largest projected distance
492 // rather than the smallest index, similar to what is done when picking the
493 // face in findRidgeContactPoint() to better condition corner-case checks for
494 // sign changes. That's less likely to be a problem here, though, and the
495 // code to do that would be messier.
496 unsigned int face_index(std::numeric_limits<unsigned int>::max());
497 for (unsigned int i = 0;
498 i < ridgeSetDataVec[closest_ridge_set_index]._ridge_data_vec.size();
499 ++i)
500 {
501 if (ridgeSetDataVec[closest_ridge_set_index]._ridge_data_vec[i]._index < face_index)
502 face_index = ridgeSetDataVec[closest_ridge_set_index]._ridge_data_vec[i]._index;
503 }
504
505 mooseAssert(face_index < std::numeric_limits<unsigned int>::max(),
506 "face_index invalid");
507
508 p_info[face_index]->_closest_point = closest_point;
509 p_info[face_index]->_distance =
510 (p_info[face_index]->_distance >= 0.0 ? 1.0 : -1.0) * closest_distance;
511 // Calculate the normal as the vector from the ridge to the point only if we're not
512 // doing normal
513 // smoothing. Normal smoothing will average out the normals on its own.
515 {
516 Point normal(closest_point - node);
517 const Real len(normal.norm());
518 if (len > 0)
519 {
520 normal /= len;
521 }
522 const Real dot(normal * p_info[face_index]->_normal);
523 if (dot < 0)
524 normal *= -1;
525 p_info[face_index]->_normal = normal;
526 }
527 p_info[face_index]->_tangential_distance = 0.0;
528
529 Point closest_point_ref;
530 if (ridgeSetDataVec[closest_ridge_set_index]._ridge_data_vec.size() ==
531 1) // contact with a single ridge rather than a peak
532 {
533 p_info[face_index]->_tangential_distance = ridgeSetDataVec[closest_ridge_set_index]
534 ._ridge_data_vec[0]
535 ._tangential_distance;
536 p_info[face_index]->_closest_point_ref =
537 ridgeSetDataVec[closest_ridge_set_index]._ridge_data_vec[0]._closest_coor_ref;
538 }
539 else
540 { // peak
541 const Node * closest_node_on_face;
542 bool restricted = restrictPointToFace(p_info[face_index]->_closest_point_ref,
543 closest_node_on_face,
544 p_info[face_index]->_side);
545 if (restricted)
546 {
547 if (closest_node_on_face !=
548 ridgeSetDataVec[closest_ridge_set_index]._closest_node)
549 {
550 mooseError("Closest node when restricting point to face != closest node from "
551 "RidgeSetData");
552 }
553 }
554 }
555
556 FEBase * fe = _fes[_tid][p_info[face_index]->_side->dim()];
557 std::vector<Point> points(1);
558 points[0] = p_info[face_index]->_closest_point_ref;
559 fe->reinit(p_info[face_index]->_side, &points);
560 p_info[face_index]->_side_phi = fe->get_phi();
561 p_info[face_index]->_side_grad_phi = fe->get_dphi();
562 p_info[face_index]->_dxyzdxi = fe->get_dxyzdxi();
563 p_info[face_index]->_dxyzdeta = fe->get_dxyzdeta();
564 p_info[face_index]->_d2xyzdxideta = fe->get_d2xyzdxideta();
565
566 switchInfo(info, p_info[face_index]);
567 info_set = true;
568 }
569 else
570 { // todo:remove invalid ridge cases so they don't mess up individual face
571 // competition????
572 }
573 }
574
575 if (!info_set) // contact wasn't on a ridge -- compete individual interactions
576 {
577 unsigned int best(0), i(1);
578 do
579 {
580 CompeteInteractionResult CIResult = competeInteractions(p_info[best], p_info[i]);
581 if (CIResult == FIRST_WINS)
582 {
583 i++;
584 }
585 else if (CIResult == SECOND_WINS)
586 {
587 best = i;
588 i++;
589 }
590 else if (CIResult == NEITHER_WINS)
591 {
592 best = i + 1;
593 i += 2;
594 }
595 } while (i < p_info.size() && best < p_info.size());
596 if (best < p_info.size())
597 {
598 // Ensure final info is within the tangential tolerance
599 if (p_info[best]->_tangential_distance <= _tangential_tolerance)
600 {
601 switchInfo(info, p_info[best]);
602 info_set = true;
603 }
604 }
605 }
606 }
607 }
608 }
609
610 if (!info_set)
611 {
612 // If penetration is not detected within the saved patch, it is possible
613 // that the secondary node has moved outside the saved patch. So, the patch
614 // for the secondary nodes saved in _recheck_secondary_nodes has to be updated
615 // and the penetration detection has to be re-run on the updated patch.
616
617 _recheck_secondary_nodes.push_back(node_id);
618
619 delete info;
620 info = NULL;
621 }
622 else
623 {
624 smoothNormal(info, p_info, node);
625 FEBase * fe = _fes[_tid][info->_side->dim()];
626 computeSlip(*fe, *info);
627 }
628
629 for (unsigned int j = 0; j < p_info.size(); ++j)
630 {
631 if (p_info[j])
632 {
633 delete p_info[j];
634 p_info[j] = NULL;
635 }
636 }
637 }
638}
Threads::spin_mutex pinfo_mutex
virtual const Node & nodeRef(const dof_id_type i) const
Definition MooseMesh.C:841
virtual std::unique_ptr< libMesh::PointLocatorBase > getPointLocator() const
Proxy function to get a (sub)PointLocator from either the underlying libMesh mesh (default),...
Definition MooseMesh.C:3838
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.
void computeSlip(libMesh::FEBase &fe, PenetrationInfo &info)
MooseVariable * _nodal_normal_x
MooseVariable * _nodal_normal_z
MooseVariable * _nodal_normal_y
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)
void switchInfo(PenetrationInfo *&info, PenetrationInfo *&infoNew)
bool restrictPointToFace(libMesh::Point &p, const Node *&closest_node, const Elem *side)
void smoothNormal(PenetrationInfo *info, std::vector< PenetrationInfo * > &p_info, const Node &node)
CompeteInteractionResult competeInteractions(PenetrationInfo *pi1, PenetrationInfo *pi2)
When interactions are identified between a node and two faces, compete between the faces to determine...
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.
virtual_for_inffe const std::vector< RealGradient > & get_d2xyzdxideta() const
const std::vector< std::vector< OutputShape > > & get_phi() const
const std::vector< std::vector< OutputGradient > > & get_dphi() const
auto norm_sq(const T &a)
const unsigned int invalid_uint

◆ restrictPointToFace()

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

Definition at line 1151 of file PenetrationThread.C.

1152{
1153 const ElemType t(side->type());
1154 Real & xi = p(0);
1155 Real & eta = p(1);
1156 closest_node = NULL;
1157
1158 bool off_of_this_face(false);
1159
1160 switch (t)
1161 {
1162 case EDGE2:
1163 case EDGE3:
1164 case EDGE4:
1165 {
1166 if (xi < -1.0)
1167 {
1168 xi = -1.0;
1169 off_of_this_face = true;
1170 closest_node = side->node_ptr(0);
1171 }
1172 else if (xi > 1.0)
1173 {
1174 xi = 1.0;
1175 off_of_this_face = true;
1176 closest_node = side->node_ptr(1);
1177 }
1178 break;
1179 }
1180
1181 case TRI3:
1182 case TRI6:
1183 case TRI7:
1184 {
1185 if (eta < 0.0)
1186 {
1187 eta = 0.0;
1188 off_of_this_face = true;
1189 if (xi < 0.5)
1190 {
1191 closest_node = side->node_ptr(0);
1192 if (xi < 0.0)
1193 xi = 0.0;
1194 }
1195 else
1196 {
1197 closest_node = side->node_ptr(1);
1198 if (xi > 1.0)
1199 xi = 1.0;
1200 }
1201 }
1202 else if ((xi + eta) > 1.0)
1203 {
1204 Real delta = (xi + eta - 1.0) / 2.0;
1205 xi -= delta;
1206 eta -= delta;
1207 off_of_this_face = true;
1208 if (xi > 0.5)
1209 {
1210 closest_node = side->node_ptr(1);
1211 if (xi > 1.0)
1212 {
1213 xi = 1.0;
1214 eta = 0.0;
1215 }
1216 }
1217 else
1218 {
1219 closest_node = side->node_ptr(2);
1220 if (xi < 0.0)
1221 {
1222 xi = 0.0;
1223 eta = 1.0;
1224 }
1225 }
1226 }
1227 else if (xi < 0.0)
1228 {
1229 xi = 0.0;
1230 off_of_this_face = true;
1231 if (eta > 0.5)
1232 {
1233 closest_node = side->node_ptr(2);
1234 if (eta > 1.0)
1235 eta = 1.0;
1236 }
1237 else
1238 {
1239 closest_node = side->node_ptr(0);
1240 if (eta < 0.0)
1241 eta = 0.0;
1242 }
1243 }
1244 break;
1245 }
1246
1247 case QUAD4:
1248 case QUAD8:
1249 case QUAD9:
1250 {
1251 if (eta < -1.0)
1252 {
1253 eta = -1.0;
1254 off_of_this_face = true;
1255 if (xi < 0.0)
1256 {
1257 closest_node = side->node_ptr(0);
1258 if (xi < -1.0)
1259 xi = -1.0;
1260 }
1261 else
1262 {
1263 closest_node = side->node_ptr(1);
1264 if (xi > 1.0)
1265 xi = 1.0;
1266 }
1267 }
1268 else if (xi > 1.0)
1269 {
1270 xi = 1.0;
1271 off_of_this_face = true;
1272 if (eta < 0.0)
1273 {
1274 closest_node = side->node_ptr(1);
1275 if (eta < -1.0)
1276 eta = -1.0;
1277 }
1278 else
1279 {
1280 closest_node = side->node_ptr(2);
1281 if (eta > 1.0)
1282 eta = 1.0;
1283 }
1284 }
1285 else if (eta > 1.0)
1286 {
1287 eta = 1.0;
1288 off_of_this_face = true;
1289 if (xi < 0.0)
1290 {
1291 closest_node = side->node_ptr(3);
1292 if (xi < -1.0)
1293 xi = -1.0;
1294 }
1295 else
1296 {
1297 closest_node = side->node_ptr(2);
1298 if (xi > 1.0)
1299 xi = 1.0;
1300 }
1301 }
1302 else if (xi < -1.0)
1303 {
1304 xi = -1.0;
1305 off_of_this_face = true;
1306 if (eta < 0.0)
1307 {
1308 closest_node = side->node_ptr(0);
1309 if (eta < -1.0)
1310 eta = -1.0;
1311 }
1312 else
1313 {
1314 closest_node = side->node_ptr(3);
1315 if (eta > 1.0)
1316 eta = 1.0;
1317 }
1318 }
1319 break;
1320 }
1321
1322 default:
1323 {
1324 mooseError("Unsupported face type: ", t);
1325 break;
1326 }
1327 }
1328 return off_of_this_face;
1329}

Referenced by operator()().

◆ restrictPointToSpecifiedEdgeOfFace()

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

Definition at line 977 of file PenetrationThread.C.

981{
982 const ElemType t = side->type();
983 Real & xi = p(0);
984 Real & eta = p(1);
985 closest_node = NULL;
986
987 std::vector<unsigned int> local_node_indices;
988 for (const auto & edge_node : edge_nodes)
989 {
990 unsigned int local_index = side->get_node_index(edge_node);
991 if (local_index == libMesh::invalid_uint)
992 mooseError("Side does not contain node");
993 local_node_indices.push_back(local_index);
994 }
995 mooseAssert(local_node_indices.size() == side->dim(),
996 "Number of edge nodes must match side dimensionality");
997 std::sort(local_node_indices.begin(), local_node_indices.end());
998
999 bool off_of_this_edge = false;
1000
1001 switch (t)
1002 {
1003 case EDGE2:
1004 case EDGE3:
1005 case EDGE4:
1006 {
1007 if (local_node_indices[0] == 0)
1008 {
1009 if (xi <= -1.0)
1010 {
1011 xi = -1.0;
1012 off_of_this_edge = true;
1013 closest_node = side->node_ptr(0);
1014 }
1015 }
1016 else if (local_node_indices[0] == 1)
1017 {
1018 if (xi >= 1.0)
1019 {
1020 xi = 1.0;
1021 off_of_this_edge = true;
1022 closest_node = side->node_ptr(1);
1023 }
1024 }
1025 else
1026 {
1027 mooseError("Invalid local node indices");
1028 }
1029 break;
1030 }
1031
1032 case TRI3:
1033 case TRI6:
1034 case TRI7:
1035 {
1036 if ((local_node_indices[0] == 0) && (local_node_indices[1] == 1))
1037 {
1038 if (eta <= 0.0)
1039 {
1040 eta = 0.0;
1041 off_of_this_edge = true;
1042 if (xi < 0.0)
1043 closest_node = side->node_ptr(0);
1044 else if (xi > 1.0)
1045 closest_node = side->node_ptr(1);
1046 }
1047 }
1048 else if ((local_node_indices[0] == 1) && (local_node_indices[1] == 2))
1049 {
1050 if ((xi + eta) > 1.0)
1051 {
1052 Real delta = (xi + eta - 1.0) / 2.0;
1053 xi -= delta;
1054 eta -= delta;
1055 off_of_this_edge = true;
1056 if (xi > 1.0)
1057 closest_node = side->node_ptr(1);
1058 else if (xi < 0.0)
1059 closest_node = side->node_ptr(2);
1060 }
1061 }
1062 else if ((local_node_indices[0] == 0) && (local_node_indices[1] == 2))
1063 {
1064 if (xi <= 0.0)
1065 {
1066 xi = 0.0;
1067 off_of_this_edge = true;
1068 if (eta > 1.0)
1069 closest_node = side->node_ptr(2);
1070 else if (eta < 0.0)
1071 closest_node = side->node_ptr(0);
1072 }
1073 }
1074 else
1075 {
1076 mooseError("Invalid local node indices");
1077 }
1078
1079 break;
1080 }
1081
1082 case QUAD4:
1083 case QUAD8:
1084 case QUAD9:
1085 {
1086 if ((local_node_indices[0] == 0) && (local_node_indices[1] == 1))
1087 {
1088 if (eta <= -1.0)
1089 {
1090 eta = -1.0;
1091 off_of_this_edge = true;
1092 if (xi < -1.0)
1093 closest_node = side->node_ptr(0);
1094 else if (xi > 1.0)
1095 closest_node = side->node_ptr(1);
1096 }
1097 }
1098 else if ((local_node_indices[0] == 1) && (local_node_indices[1] == 2))
1099 {
1100 if (xi >= 1.0)
1101 {
1102 xi = 1.0;
1103 off_of_this_edge = true;
1104 if (eta < -1.0)
1105 closest_node = side->node_ptr(1);
1106 else if (eta > 1.0)
1107 closest_node = side->node_ptr(2);
1108 }
1109 }
1110 else if ((local_node_indices[0] == 2) && (local_node_indices[1] == 3))
1111 {
1112 if (eta >= 1.0)
1113 {
1114 eta = 1.0;
1115 off_of_this_edge = true;
1116 if (xi < -1.0)
1117 closest_node = side->node_ptr(3);
1118 else if (xi > 1.0)
1119 closest_node = side->node_ptr(2);
1120 }
1121 }
1122 else if ((local_node_indices[0] == 0) && (local_node_indices[1] == 3))
1123 {
1124 if (xi <= -1.0)
1125 {
1126 xi = -1.0;
1127 off_of_this_edge = true;
1128 if (eta < -1.0)
1129 closest_node = side->node_ptr(0);
1130 else if (eta > 1.0)
1131 closest_node = side->node_ptr(3);
1132 }
1133 }
1134 else
1135 {
1136 mooseError("Invalid local node indices");
1137 }
1138 break;
1139 }
1140
1141 default:
1142 {
1143 mooseError("Unsupported face type: ", t);
1144 break;
1145 }
1146 }
1147 return off_of_this_edge;
1148}
unsigned int get_node_index(const Node *node_ptr) const

Referenced by findRidgeContactPoint().

◆ smoothNormal()

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

Definition at line 1417 of file PenetrationThread.C.

1420{
1422 {
1424 {
1425 // If we are within the smoothing distance of any edges or corners, find the
1426 // corner nodes for those edges/corners, and weights from distance to edge/corner
1427 std::vector<Real> edge_face_weights;
1428 std::vector<PenetrationInfo *> edge_face_info;
1429
1430 getSmoothingFacesAndWeights(info, edge_face_info, edge_face_weights, p_info, node);
1431
1432 mooseAssert(edge_face_info.size() == edge_face_weights.size(),
1433 "edge_face_info.size() != edge_face_weights.size()");
1434
1435 if (edge_face_info.size() > 0)
1436 {
1437 // Smooth the normal using the weighting functions for all participating faces.
1438 RealVectorValue new_normal;
1439 Real this_face_weight = 1.0;
1440
1441 for (unsigned int efwi = 0; efwi < edge_face_weights.size(); ++efwi)
1442 {
1443 PenetrationInfo * npi = edge_face_info[efwi];
1444 if (npi)
1445 new_normal += npi->_normal * edge_face_weights[efwi];
1446
1447 this_face_weight -= edge_face_weights[efwi];
1448 }
1449 mooseAssert(this_face_weight >= (0.25 - 1e-8),
1450 "Sum of weights of other faces shouldn't exceed 0.75");
1451 new_normal += info->_normal * this_face_weight;
1452
1453 const Real len = new_normal.norm();
1454 if (len > 0)
1455 new_normal /= len;
1456
1457 info->_normal = new_normal;
1458 }
1459 }
1461 {
1462 // params.addParam<VariableName>("var_name","description");
1463 // getParam<VariableName>("var_name")
1464 info->_normal(0) = _nodal_normal_x->getValue(info->_side, info->_side_phi);
1465 info->_normal(1) = _nodal_normal_y->getValue(info->_side, info->_side_phi);
1466 info->_normal(2) = _nodal_normal_z->getValue(info->_side, info->_side_phi);
1467 const Real len(info->_normal.norm());
1468 if (len > 0)
1469 info->_normal /= len;
1470 }
1471 }
1472}
OutputType getValue(const Elem *elem, const std::vector< std::vector< OutputShape > > &phi) const
Compute the variable value at a point on an element.
RealVectorValue _normal
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)

Referenced by operator()().

◆ switchInfo()

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

Definition at line 649 of file PenetrationThread.C.

650{
651 mooseAssert(infoNew != NULL, "infoNew object is null");
652 if (info)
653 {
654 infoNew->_starting_elem = info->_starting_elem;
655 infoNew->_starting_side_num = info->_starting_side_num;
656 infoNew->_starting_closest_point_ref = info->_starting_closest_point_ref;
657 infoNew->_incremental_slip = info->_incremental_slip;
658 infoNew->_accumulated_slip = info->_accumulated_slip;
659 infoNew->_accumulated_slip_old = info->_accumulated_slip_old;
660 infoNew->_frictional_energy = info->_frictional_energy;
661 infoNew->_frictional_energy_old = info->_frictional_energy_old;
662 infoNew->_contact_force = info->_contact_force;
663 infoNew->_contact_force_old = info->_contact_force_old;
664 infoNew->_lagrange_multiplier = info->_lagrange_multiplier;
665 infoNew->_lagrange_multiplier_slip = info->_lagrange_multiplier_slip;
666 infoNew->_locked_this_step = info->_locked_this_step;
667 infoNew->_stick_locked_this_step = info->_stick_locked_this_step;
668 infoNew->_mech_status = info->_mech_status;
669 infoNew->_mech_status_old = info->_mech_status_old;
670 }
671 else
672 {
673 infoNew->_starting_elem = infoNew->_elem;
674 infoNew->_starting_side_num = infoNew->_side_num;
676 }
677 delete info;
678 info = infoNew;
679 infoNew = NULL; // Set this to NULL so that we don't delete it (now owned by _penetration_info).
680}
MECH_STATUS_ENUM _mech_status
RealVectorValue _contact_force_old
unsigned int _locked_this_step
MECH_STATUS_ENUM _mech_status_old
RealVectorValue _contact_force
unsigned int _starting_side_num
const Elem * _starting_elem
Point _starting_closest_point_ref
unsigned int _side_num
RealVectorValue _lagrange_multiplier_slip
unsigned int _stick_locked_this_step

Referenced by operator()().

Member Data Documentation

◆ _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

libMesh::ElemSideBuilder PenetrationThread::_elem_side_builder
protected

Helper for building element sides without extraneous allocation.

Definition at line 87 of file PenetrationThread.h.

Referenced by computeSlip().

◆ _fe_type

libMesh::FEType& PenetrationThread::_fe_type
protected

Definition at line 78 of file PenetrationThread.h.

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

◆ _fes

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

Definition at line 76 of file PenetrationThread.h.

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

◆ _mesh

const MooseMesh& PenetrationThread::_mesh
protected

◆ _nearest_node

NearestNodeLocator& PenetrationThread::_nearest_node
protected

Definition at line 80 of file PenetrationThread.h.

Referenced by operator()().

◆ _nodal_normal_x

MooseVariable* PenetrationThread::_nodal_normal_x
protected

Definition at line 72 of file PenetrationThread.h.

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

◆ _nodal_normal_y

MooseVariable* PenetrationThread::_nodal_normal_y
protected

Definition at line 73 of file PenetrationThread.h.

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

◆ _nodal_normal_z

MooseVariable* PenetrationThread::_nodal_normal_z
protected

Definition at line 74 of file PenetrationThread.h.

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

◆ _node_to_elem_map

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

Definition at line 82 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 createInfoForElem(), and operator()().

◆ _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 PenetrationLocator::detectPenetration(), 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 84 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()().

◆ _use_point_locator

bool PenetrationThread::_use_point_locator
protected

Definition at line 71 of file PenetrationThread.h.

Referenced by operator()().


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