https://mooseframework.inl.gov
PenetrationLocator.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://mooseframework.inl.gov
3 //*
4 //* All rights reserved, see COPYRIGHT for full restrictions
5 //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 //*
7 //* Licensed under LGPL 2.1, please see LICENSE for details
8 //* https://www.gnu.org/licenses/lgpl-2.1.html
9 
10 #include "PenetrationLocator.h"
11 
12 #include "ArbitraryQuadrature.h"
13 #include "Conversion.h"
14 #include "GeometricSearchData.h"
15 #include "LineSegment.h"
16 #include "MooseMesh.h"
17 #include "NearestNodeLocator.h"
18 #include "PenetrationThread.h"
19 #include "SubProblem.h"
20 #include "MooseApp.h"
21 
22 using namespace libMesh;
23 
25  GeometricSearchData & /*geom_search_data*/,
26  MooseMesh & mesh,
27  const unsigned int primary_id,
28  const unsigned int secondary_id,
29  Order order,
30  NearestNodeLocator & nearest_node)
31  : Restartable(subproblem.getMooseApp(),
32  Moose::stringify(primary_id) + "to" + Moose::stringify(secondary_id),
33  "PenetrationLocator",
34  0),
35  PerfGraphInterface(subproblem.getMooseApp().perfGraph(),
36  "PenetrationLocator_" + Moose::stringify(primary_id) + "_" +
37  Moose::stringify(secondary_id)),
38  _subproblem(subproblem),
39  _mesh(mesh),
40  _primary_boundary(primary_id),
41  _secondary_boundary(secondary_id),
42  _fe_type(order),
43  _nearest_node(nearest_node),
44  _penetration_info(declareRestartableDataWithContext<std::map<dof_id_type, PenetrationInfo *>>(
45  "penetration_info", &_mesh)),
46  _has_penetrated(declareRestartableData<std::set<dof_id_type>>("has_penetrated")),
47  _check_whether_reasonable(true),
48  _update_location(declareRestartableData<bool>("update_location", true)),
49  _tangential_tolerance(0.0),
50  _do_normal_smoothing(false),
51  _normal_smoothing_distance(0.0),
52  _normal_smoothing_method(NSM_EDGE_BASED),
53  _patch_update_strategy(_mesh.getPatchUpdateStrategy())
54 {
55  // Preconstruct an FE object for each thread we're going to use and for each lower-dimensional
56  // element
57  // This is a time savings so that the thread objects don't do this themselves multiple times
58  _fe.resize(libMesh::n_threads());
59  for (unsigned int i = 0; i < libMesh::n_threads(); i++)
60  {
61  unsigned int n_dims = _mesh.dimension();
62  _fe[i].resize(n_dims + 1);
63  for (unsigned int dim = 0; dim <= n_dims; ++dim)
64  {
65  _fe[i][dim] = FEBase::build(dim, _fe_type).release();
66  _fe[i][dim]->get_xyz();
67  _fe[i][dim]->get_phi();
68  _fe[i][dim]->get_dphi();
69  _fe[i][dim]->get_dxyzdxi();
70  _fe[i][dim]->get_d2xyzdxi2();
71  _fe[i][dim]->get_d2xyzdxideta();
72  _fe[i][dim]->get_dxyzdeta();
73  _fe[i][dim]->get_d2xyzdeta2();
74  _fe[i][dim]->get_d2xyzdxideta();
75  }
76  }
77 
79  {
80  if (!((_subproblem.hasVariable("nodal_normal_x")) &&
81  (_subproblem.hasVariable("nodal_normal_y")) &&
82  (_subproblem.hasVariable("nodal_normal_z"))))
83  {
84  mooseError(
85  "To use nodal-normal-based smoothing, the nodal_normal_x, nodal_normal_y, and "
86  "nodal_normal_z variables must exist. Are you missing the \\[NodalNormals\\] block?");
87  }
88  }
89 }
90 
92 {
93  for (unsigned int i = 0; i < libMesh::n_threads(); i++)
94  for (unsigned int dim = 0; dim < _fe[i].size(); dim++)
95  delete _fe[i][dim];
96 
97  for (auto & it : _penetration_info)
98  delete it.second;
99 }
100 
101 void
103 {
104  TIME_SECTION("detectPenetration", 3, "Detecting Penetration");
105 
106  // Get list of boundary (elem, side, id) tuples.
107  std::vector<std::tuple<dof_id_type, unsigned short int, boundary_id_type>> bc_tuples =
109 
110  // Grab the secondary nodes we need to worry about from the NearestNodeLocator
111  NodeIdRange & secondary_node_range = _nearest_node.secondaryNodeRange();
112 
114  _mesh,
124  _fe,
125  _fe_type,
128  bc_tuples);
129 
130  Threads::parallel_reduce(secondary_node_range, pt);
131 
132  std::vector<dof_id_type> recheck_secondary_nodes = pt._recheck_secondary_nodes;
133 
134  // Update the patch for the secondary nodes in recheck_secondary_nodes and re-run penetration
135  // thread on these nodes at every nonlinear iteration if patch update strategy is set to
136  // "iteration".
137  if (recheck_secondary_nodes.size() > 0 && _patch_update_strategy == Moose::Iteration &&
139  {
140  // Update the patch for this subset of secondary nodes and calculate the nearest neighbor_nodes
141  _nearest_node.updatePatch(recheck_secondary_nodes);
142 
143  // Re-run the penetration thread to see if these nodes are in contact with the updated patch
144  NodeIdRange recheck_secondary_node_range(
145  recheck_secondary_nodes.begin(), recheck_secondary_nodes.end(), 1);
146 
147  Threads::parallel_reduce(recheck_secondary_node_range, pt);
148  }
149 
150  if (recheck_secondary_nodes.size() > 0 && _patch_update_strategy != Moose::Iteration &&
152  mooseDoOnce(mooseWarning("Warning in PenetrationLocator. Penetration is not "
153  "detected for one or more secondary nodes. This could be because "
154  "those secondary nodes simply do not project to faces on the primary "
155  "surface. However, this could also be because contact should be "
156  "enforced on those nodes, but the faces that they project to "
157  "are outside the contact patch, which will give an erroneous "
158  "result. Use appropriate options for 'patch_size' and "
159  "'patch_update_strategy' in the Mesh block to avoid this issue. "
160  "Setting 'patch_update_strategy=iteration' is recommended because "
161  "it completely avoids this potential issue. Also note that this "
162  "warning is printed only once, so a similar situation could occur "
163  "multiple times during the simulation but this warning is printed "
164  "only at the first occurrence."));
165 }
166 
167 void
169 {
170  TIME_SECTION("reinit", 3, "Reinitializing PenetrationLocator");
171 
172  // Delete the PenetrationInfo objects we own before clearing the
173  // map, or we have a memory leak.
174  for (auto & it : _penetration_info)
175  delete it.second;
176 
177  _penetration_info.clear();
178 
179  _has_penetrated.clear();
180 
182 }
183 
184 Real
186 {
188 
189  if (info)
190  return info->_distance;
191  else
192  return 0;
193 }
194 
197 {
198  std::map<dof_id_type, PenetrationInfo *>::const_iterator found_it =
199  _penetration_info.find(node_id);
200 
201  if (found_it != _penetration_info.end())
202  return found_it->second->_normal;
203  else
204  return RealVectorValue(0, 0, 0);
205 }
206 
207 void
209 {
211 }
212 
213 void
215 {
216  _update_location = update;
217 }
218 
219 void
221 {
222  _tangential_tolerance = tangential_tolerance;
223 }
224 
225 void
226 PenetrationLocator::setNormalSmoothingDistance(Real normal_smoothing_distance)
227 {
228  _normal_smoothing_distance = normal_smoothing_distance;
229  if (_normal_smoothing_distance > 0.0)
230  _do_normal_smoothing = true;
231 }
232 
233 void
235 {
236  if (nsmString == "edge_based")
238  else if (nsmString == "nodal_normal_based")
240  else
241  mooseError("Invalid normal_smoothing_method: ", nsmString);
242  _do_normal_smoothing = true;
243 }
const Moose::PatchUpdateType _patch_update_strategy
std::unique_ptr< FEGenericBase< Real > > build(const unsigned int dim, const FEType &fet)
Order
A class for creating restricted objects.
Definition: Restartable.h:28
unsigned int n_threads()
BoundaryID _secondary_boundary
MPI_Info info
RealVectorValue penetrationNormal(dof_id_type node_id)
std::vector< std::tuple< dof_id_type, unsigned short int, boundary_id_type > > buildActiveSideList() const
Calls BoundaryInfo::build_active_side_list.
Definition: MooseMesh.C:3010
void setNormalSmoothingDistance(Real normal_smoothing_distance)
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:302
Data structure used to hold penetration information.
Finds the nearest node to each node in boundary1 to each node in boundary2 and the other way around...
libMesh::FEType _fe_type
void updatePatch(std::vector< dof_id_type > &secondary_nodes)
Reconstructs the KDtree, updates the patch for the nodes in secondary_nodes, and updates the closest ...
void mooseWarning(Args &&... args)
Emit a warning message with the given stringified, concatenated args.
Definition: MooseError.h:336
MeshBase & mesh
static constexpr std::size_t dim
This is the dimension of all vector and tensor datastructures used in MOOSE.
Definition: Moose.h:153
The following methods are specializations for using the libMesh::Parallel::packed_range_* routines fo...
std::map< dof_id_type, PenetrationInfo * > & _penetration_info
Data structure of nodes and their associated penetration information.
void setTangentialTolerance(Real tangential_tolerance)
NodeIdRange & secondaryNodeRange()
Returns the NodeIdRange of secondary nodes to be used for calling threaded functions operating on the...
bool _check_whether_reasonable
Check whether found candidates are reasonable.
virtual unsigned int dimension() const
Returns MeshBase::mesh_dimension(), (not MeshBase::spatial_dimension()!) of the underlying libMesh me...
Definition: MooseMesh.C:2923
MooseMesh wraps a libMesh::Mesh object and enhances its capabilities by caching additional data and s...
Definition: MooseMesh.h:88
std::string stringify(const T &t)
conversion to string
Definition: Conversion.h:64
virtual bool hasVariable(const std::string &var_name) const =0
Whether or not this problem has the variable.
Interface for objects interacting with the PerfGraph.
SubProblem & _subproblem
void setUpdate(bool update)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
PenetrationLocator(SubProblem &subproblem, GeometricSearchData &geom_search_data, MooseMesh &mesh, const unsigned int primary_id, const unsigned int secondary_id, Order order, NearestNodeLocator &nearest_node)
Generic class for solving transient nonlinear problems.
Definition: SubProblem.h:78
Real penetrationDistance(dof_id_type node_id)
MOOSE now contains C++17 code, so give a reasonable error message stating what the user can do to add...
void setNormalSmoothingMethod(std::string nsmString)
const bool & currentlyComputingJacobian() const
Returns true if the problem is in the process of computing the Jacobian.
Definition: SubProblem.h:684
void reinit()
Completely redo the search from scratch.
std::set< dof_id_type > & _has_penetrated
void setCheckWhetherReasonable(bool state)
BoundaryID _primary_boundary
NORMAL_SMOOTHING_METHOD _normal_smoothing_method
uint8_t dof_id_type
NearestNodeLocator & _nearest_node
const std::map< dof_id_type, std::vector< dof_id_type > > & nodeToElemMap()
If not already created, creates a map from every node to all elements to which they are connected...
Definition: MooseMesh.C:1175
std::vector< std::vector< libMesh::FEBase * > > _fe