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

138 _mesh(x._mesh),
149 _fes(x._fes),
153{
154}
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 681 of file PenetrationThread.C.

682{
683
685
687 pi2->_tangential_distance > _tangential_tolerance) // out of tol on both faces
688 result = NEITHER_WINS;
689
690 else if (pi1->_tangential_distance == 0.0 &&
691 pi2->_tangential_distance > 0.0) // on face 1, off face 2
692 result = FIRST_WINS;
693
694 else if (pi2->_tangential_distance == 0.0 &&
695 pi1->_tangential_distance > 0.0) // on face 2, off face 1
696 result = SECOND_WINS;
697
699 pi2->_tangential_distance > _tangential_tolerance) // in face 1 tol, out of face 2 tol
700 result = FIRST_WINS;
701
703 pi1->_tangential_distance > _tangential_tolerance) // in face 2 tol, out of face 1 tol
704 result = SECOND_WINS;
705
706 else if (pi1->_tangential_distance == 0.0 && pi2->_tangential_distance == 0.0) // on both faces
707 result = competeInteractionsBothOnFace(pi1, pi2);
708
710 pi2->_tangential_distance <= _tangential_tolerance) // off but within tol of both faces
711 {
713 if (cer == COMMON_EDGE || cer == COMMON_NODE) // ridge case.
714 {
715 // We already checked for ridges, and it got rejected, so neither face must be valid
716 result = NEITHER_WINS;
717 // mooseError("Erroneously encountered ridge case");
718 }
719 else if (cer == EDGE_AND_COMMON_NODE) // off side of face, off corner of another face. Favor
720 // the off-side face
721 {
722 if (pi1->_off_edge_nodes.size() == pi2->_off_edge_nodes.size())
723 mooseError("Invalid off_edge_nodes counts");
724
725 else if (pi1->_off_edge_nodes.size() == 2)
726 result = FIRST_WINS;
727
728 else if (pi2->_off_edge_nodes.size() == 2)
729 result = SECOND_WINS;
730
731 else
732 mooseError("Invalid off_edge_nodes counts");
733 }
734 else // The node projects to both faces within tangential tolerance.
735 result = competeInteractionsBothOnFace(pi1, pi2);
736 }
737
738 return result;
739}
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 742 of file PenetrationThread.C.

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

Referenced by competeInteractions().

◆ computeSlip()

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

Definition at line 1396 of file PenetrationThread.C.

1397{
1398 // Slip is current projected position of secondary node minus
1399 // original projected position of secondary node
1400 std::vector<Point> points(1);
1401 points[0] = info._starting_closest_point_ref;
1402 const auto & side = _elem_side_builder(*info._starting_elem, info._starting_side_num);
1403 fe.reinit(&side, &points);
1404 const std::vector<Point> & starting_point = fe.get_xyz();
1405 info._incremental_slip = info._closest_point - starting_point[0];
1406 if (info.isCaptured())
1407 {
1408 info._frictional_energy =
1409 info._frictional_energy_old + info._contact_force * info._incremental_slip;
1410 info._accumulated_slip = info._accumulated_slip_old + info._incremental_slip.norm();
1411 }
1412}
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 1814 of file PenetrationThread.C.

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

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

Referenced by operator()().

◆ getInfoForElem()

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

Definition at line 1799 of file PenetrationThread.C.

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

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

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

Referenced by getSmoothingFacesAndWeights().

◆ getSideCornerNodes()

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

Definition at line 933 of file PenetrationThread.C.

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

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

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

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

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

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

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

Referenced by createInfoForElem().

◆ join()

void PenetrationThread::join ( const PenetrationThread other)

Definition at line 639 of file PenetrationThread.C.

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

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

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

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

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

Referenced by findRidgeContactPoint().

◆ smoothNormal()

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

Definition at line 1415 of file PenetrationThread.C.

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

648{
649 mooseAssert(infoNew != NULL, "infoNew object is null");
650 if (info)
651 {
652 infoNew->_starting_elem = info->_starting_elem;
653 infoNew->_starting_side_num = info->_starting_side_num;
654 infoNew->_starting_closest_point_ref = info->_starting_closest_point_ref;
655 infoNew->_incremental_slip = info->_incremental_slip;
656 infoNew->_accumulated_slip = info->_accumulated_slip;
657 infoNew->_accumulated_slip_old = info->_accumulated_slip_old;
658 infoNew->_frictional_energy = info->_frictional_energy;
659 infoNew->_frictional_energy_old = info->_frictional_energy_old;
660 infoNew->_contact_force = info->_contact_force;
661 infoNew->_contact_force_old = info->_contact_force_old;
662 infoNew->_lagrange_multiplier = info->_lagrange_multiplier;
663 infoNew->_lagrange_multiplier_slip = info->_lagrange_multiplier_slip;
664 infoNew->_locked_this_step = info->_locked_this_step;
665 infoNew->_stick_locked_this_step = info->_stick_locked_this_step;
666 infoNew->_mech_status = info->_mech_status;
667 infoNew->_mech_status_old = info->_mech_status_old;
668 }
669 else
670 {
671 infoNew->_starting_elem = infoNew->_elem;
672 infoNew->_starting_side_num = infoNew->_side_num;
674 }
675 delete info;
676 info = infoNew;
677 infoNew = NULL; // Set this to NULL so that we don't delete it (now owned by _penetration_info).
678}
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: