https://mooseframework.inl.gov
GeometricSearchData.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 "GeometricSearchData.h"
11 // Moose includes
12 #include "NearestNodeLocator.h"
13 #include "PenetrationLocator.h"
14 #include "ElementPairLocator.h"
15 #include "SubProblem.h"
16 #include "MooseMesh.h"
17 #include "Assembly.h"
18 
19 #include "libmesh/elem.h"
20 #include "libmesh/node.h"
21 #include "libmesh/int_range.h"
22 
24  : _subproblem(subproblem), _mesh(mesh), _first(true), _search_using_point_locator(false)
25 {
26  // do a check on the boundary IDs to see if any conflict will rise from computing QP node set IDs
27  const auto & nodeset_ids = _mesh.meshNodesetIds();
28  for (const auto id : nodeset_ids)
29  if (nodeset_ids.find(-id - 1) != nodeset_ids.end())
30  mooseError("Your mesh contains nodesets with negative IDs that interfere with QP nodeset IDs "
31  "potentially generated by the GeometricSearch system.");
32 }
33 
35 {
36  for (auto & it : _penetration_locators)
37  delete it.second;
38 
39  for (auto & it : _nearest_node_locators)
40  delete it.second;
41 }
42 
43 void
45 {
46  if (type == ALL || type == QUADRATURE || type == NEAREST_NODE)
47  {
48  if (_first) // Only do this once
49  {
50  _first = false;
51 
52  for (const auto & it : _secondary_to_qsecondary)
53  generateQuadratureNodes(it.first, it.second);
54 
55  // reinit on displaced mesh before update
56  for (const auto & epl_it : _element_pair_locators)
57  {
58  ElementPairLocator & epl = *(epl_it.second);
59  epl.reinit();
60  }
61  }
62 
63  // Update the position of quadrature nodes first
64  for (const auto & qbnd : _quadrature_boundaries)
66  }
67 
68  if (type == ALL || type == NEAREST_NODE)
69  {
70  for (const auto & nnl_it : _nearest_node_locators)
71  {
72  NearestNodeLocator * nnl = nnl_it.second;
73  nnl->findNodes();
74  }
75  }
76 
77  if (type == ALL || type == PENETRATION)
78  {
79  for (const auto & pl_it : _penetration_locators)
80  {
81  PenetrationLocator * pl = pl_it.second;
82  pl->detectPenetration();
83  }
84  }
85 
86  if (type == ALL || type == PENETRATION)
87  {
88  for (auto & elem_pair_locator_pair : _element_pair_locators)
89  {
90  ElementPairLocator & epl = (*elem_pair_locator_pair.second);
91  epl.update();
92  }
93  }
94 }
95 
96 void
98 {
100  // Update the position of quadrature nodes first
101  for (const auto & qbnd : _quadrature_boundaries)
102  reinitQuadratureNodes(qbnd);
103 
104  for (const auto & nnl_it : _nearest_node_locators)
105  {
106  NearestNodeLocator * nnl = nnl_it.second;
107  nnl->reinit();
108  }
109 
110  for (const auto & pl_it : _penetration_locators)
111  {
112  PenetrationLocator * pl = pl_it.second;
113  pl->reinit();
114  }
115 
116  for (const auto & epl_it : _element_pair_locators)
117  {
118  ElementPairLocator & epl = *(epl_it.second);
119  epl.reinit();
120  }
121 }
122 
123 void
125 {
126  for (const auto & nnl_it : _nearest_node_locators)
127  {
128  NearestNodeLocator * nnl = nnl_it.second;
129  nnl->reinit();
130  }
131 }
132 
133 Real
135 {
136  Real max = 0.0;
137 
138  for (const auto & nnl_it : _nearest_node_locators)
139  {
140  NearestNodeLocator * nnl = nnl_it.second;
141 
142  if (nnl->_max_patch_percentage > max)
143  max = nnl->_max_patch_percentage;
144  }
145 
146  return max;
147 }
148 
150 GeometricSearchData::getPenetrationLocator(const BoundaryName & primary,
151  const BoundaryName & secondary,
152  Order order)
153 {
154  auto primary_id = _mesh.getBoundaryID(primary);
155  auto secondary_id = _mesh.getBoundaryID(secondary);
156 
157  _subproblem.addGhostedBoundary(primary_id);
158  _subproblem.addGhostedBoundary(secondary_id);
159 
160  PenetrationLocator * pl =
161  _penetration_locators[std::pair<BoundaryID, BoundaryID>(primary_id, secondary_id)];
162 
163  if (!pl)
164  {
166  *this,
167  _mesh,
168  primary_id,
169  secondary_id,
170  order,
171  getNearestNodeLocator(primary_id, secondary_id));
172 
174  pl->setUsePointLocator(true);
175 
176  _penetration_locators[std::pair<BoundaryID, BoundaryID>(primary_id, secondary_id)] = pl;
177  }
178 
179  return *pl;
180 }
181 
184  const BoundaryName & secondary,
185  Order order)
186 {
187  const auto primary_id = _mesh.getBoundaryID(primary);
188  const auto secondary_id = _mesh.getBoundaryID(secondary);
189 
190  _subproblem.addGhostedBoundary(primary_id);
191  _subproblem.addGhostedBoundary(secondary_id);
192 
193  // Generate a new boundary id (we use the negative numbers and subtract 1 to disambiguate id=0)
194  const auto qsecondary_id = -secondary_id - 1;
195 
196  _secondary_to_qsecondary[secondary_id] = qsecondary_id;
197 
198  PenetrationLocator * pl =
199  _penetration_locators[std::pair<BoundaryID, BoundaryID>(primary_id, qsecondary_id)];
200 
201  if (!pl)
202  {
204  *this,
205  _mesh,
206  primary_id,
207  qsecondary_id,
208  order,
209  getQuadratureNearestNodeLocator(primary_id, secondary_id));
210 
212  pl->setUsePointLocator(true);
213 
214  _penetration_locators[std::pair<BoundaryID, BoundaryID>(primary_id, qsecondary_id)] = pl;
215  }
216 
217  return *pl;
218 }
219 
221 GeometricSearchData::getNearestNodeLocator(const BoundaryName & primary,
222  const BoundaryName & secondary)
223 {
224  const auto primary_id = _mesh.getBoundaryID(primary);
225  const auto secondary_id = _mesh.getBoundaryID(secondary);
226 
227  _subproblem.addGhostedBoundary(primary_id);
228  _subproblem.addGhostedBoundary(secondary_id);
229 
230  return getNearestNodeLocator(primary_id, secondary_id);
231 }
232 
235  const BoundaryID secondary_id)
236 {
237  NearestNodeLocator * nnl =
238  _nearest_node_locators[std::pair<BoundaryID, BoundaryID>(primary_id, secondary_id)];
239 
240  _subproblem.addGhostedBoundary(primary_id);
241  _subproblem.addGhostedBoundary(secondary_id);
242 
243  if (!nnl)
244  {
245  nnl = new NearestNodeLocator(_subproblem, _mesh, primary_id, secondary_id);
246  _nearest_node_locators[std::pair<BoundaryID, BoundaryID>(primary_id, secondary_id)] = nnl;
247  }
248 
249  return *nnl;
250 }
251 
254  const BoundaryName & secondary)
255 {
256  const auto primary_id = _mesh.getBoundaryID(primary);
257  const auto secondary_id = _mesh.getBoundaryID(secondary);
258 
259  _subproblem.addGhostedBoundary(primary_id);
260  _subproblem.addGhostedBoundary(secondary_id);
261 
262  return getQuadratureNearestNodeLocator(primary_id, secondary_id);
263 }
264 
267  const BoundaryID secondary_id)
268 {
269  // Generate a new boundary id (we use the negative numbers and subtract 1 to disambiguate id=0)
270  const auto qsecondary_id = -secondary_id - 1;
271 
272  _secondary_to_qsecondary[secondary_id] = qsecondary_id;
273  return getNearestNodeLocator(primary_id, qsecondary_id);
274 }
275 
276 void
278  const BoundaryID qsecondary_id,
279  bool reiniting)
280 {
281  // Have we already generated quadrature nodes for this boundary id?
282  if (_quadrature_boundaries.find(secondary_id) != _quadrature_boundaries.end())
283  {
284  if (!reiniting)
285  return;
286  }
287  else
288  _quadrature_boundaries.insert(secondary_id);
289 
290  const MooseArray<Point> & points_face = _subproblem.assembly(0, 0).qPointsFace();
291 
293  for (const auto & belem : range)
294  {
295  const Elem * elem = belem->_elem;
296  const auto side = belem->_side;
297  const auto boundary_id = belem->_bnd_id;
298 
299  if (elem->processor_id() == _subproblem.processor_id())
300  {
301  if (boundary_id == (BoundaryID)secondary_id)
302  {
303  // All we should need to do here is reinit the underlying libMesh::FE object because that
304  // will get us the correct points for the current element and side
306  _subproblem.assembly(0, 0).reinit(elem, side);
307 
308  for (const auto qp : index_range(points_face))
309  _mesh.addQuadratureNode(elem, side, qp, qsecondary_id, points_face[qp]);
310  }
311  }
312  }
313 }
314 
315 void
317  std::shared_ptr<ElementPairLocator> epl)
318 {
319  _element_pair_locators[interface_id] = epl;
320 }
321 
322 void
324 {
325  if (state != _search_using_point_locator)
326  {
327  for (auto & [key, val] : _penetration_locators)
328  {
329  libmesh_ignore(key);
330  if (val)
331  val->setUsePointLocator(state);
332  }
333  }
334 
336 }
337 
338 void
340 {
341  const MooseArray<Point> & points_face = _subproblem.assembly(0, 0).qPointsFace();
342 
344  for (const auto & belem : range)
345  {
346  const Elem * elem = belem->_elem;
347  const auto side = belem->_side;
348  const auto boundary_id = belem->_bnd_id;
349 
350  if (elem->processor_id() == _subproblem.processor_id())
351  {
352  if (boundary_id == (BoundaryID)secondary_id)
353  {
354  // All we should need to do here is reinit the underlying libMesh::FE object because that
355  // will get us the correct points for the current element and side
357  _subproblem.assembly(0, 0).reinit(elem, side);
358 
359  for (const auto qp : index_range(points_face))
360  (*_mesh.getQuadratureNode(elem, side, qp)) = points_face[qp];
361  }
362  }
363  }
364 }
365 
366 void
368 {
369  // Regenerate the quadrature nodes
370  for (const auto & it : _secondary_to_qsecondary)
371  generateQuadratureNodes(it.first, it.second, /*reiniting=*/true);
372 }
373 
374 void
376 {
377  for (const auto & nnl_it : _nearest_node_locators)
378  {
379  NearestNodeLocator * nnl = nnl_it.second;
380  nnl->updateGhostedElems();
381  }
382 }
Node * addQuadratureNode(const Elem *elem, const unsigned short int side, const unsigned int qp, BoundaryID bid, const Point &point)
Adds a fictitious "QuadratureNode".
Definition: MooseMesh.C:1648
const std::set< BoundaryID > & meshNodesetIds() const
Returns a read-only reference to the set of nodesets currently present in the Mesh.
Definition: MooseMesh.C:3229
std::map< std::pair< BoundaryID, BoundaryID >, PenetrationLocator * > _penetration_locators
void findNodes()
This is the main method that is going to start the search.
Order
virtual void reinit()
virtual void update()
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:323
bool _first
Denotes whether this is the first time the geometric search objects have been updated.
NearestNodeLocator & getNearestNodeLocator(const BoundaryName &primary, const BoundaryName &secondary)
Finds the nearest node to each node in boundary1 to each node in boundary2 and the other way around...
std::set< BoundaryID > _quadrature_boundaries
These are real boundaries that have quadrature nodes on them.
MeshBase & mesh
virtual void setCurrentSubdomainID(const Elem *elem, const THREAD_ID tid)=0
void reinit()
Completely redo the search from scratch.
void reinit(const Elem *elem)
Reinitialize objects (JxW, q_points, ...) for an elements.
auto max(const L &left, const R &right)
void updateGhostedElems()
Updates the list of ghosted elements at the start of each time step for the nonlinear iteration patch...
void setUsePointLocator(bool state)
Real maxPatchPercentage()
Maximum percentage through the search patch that any NearestNodeLocator had to look.
std::map< std::pair< BoundaryID, BoundaryID >, NearestNodeLocator * > _nearest_node_locators
void libmesh_ignore(const Args &...)
void clearQuadratureNodes()
Clear out any existing quadrature nodes.
Definition: MooseMesh.C:1718
void reinitQuadratureNodes(const BoundaryID secondary_id)
Completely redo quadrature nodes.
bool _search_using_point_locator
Denotes whether the PenetrationLocator objects should use a point locator rather than cheaper node-to...
void addElementPairLocator(BoundaryID interface_id, std::shared_ptr< ElementPairLocator > epl)
std::map< BoundaryID, BoundaryID > _secondary_to_qsecondary
A mapping of the real boundary id to the secondary boundary ids.
boundary_id_type BoundaryID
MooseMesh wraps a libMesh::Mesh object and enhances its capabilities by caching additional data and s...
Definition: MooseMesh.h:92
NearestNodeLocator & getQuadratureNearestNodeLocator(const BoundaryName &primary, const BoundaryName &secondary)
void reinit()
Completely redo all geometric search objects.
void updateGhostedElems()
Updates the ghosted elements at the start of the time step for iteration patch update strategy...
This is the ElementPairLocator class.
std::map< BoundaryID, std::shared_ptr< ElementPairLocator > > _element_pair_locators
GeometricSearchType
Used to select groups of geometric search objects to update.
Node * getQuadratureNode(const Elem *elem, const unsigned short int side, const unsigned int qp)
Get a specified quadrature node.
Definition: MooseMesh.C:1700
void setSearchUsingPointLocator(bool state)
void updateQuadratureNodes(const BoundaryID secondary_id)
Update the positions of the quadrature nodes.
PenetrationLocator & getQuadraturePenetrationLocator(const BoundaryName &primary, const BoundaryName &secondary, libMesh::Order order=libMesh::FIRST)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
Generic class for solving transient nonlinear problems.
Definition: SubProblem.h:78
virtual void addGhostedBoundary(BoundaryID boundary_id)=0
Will make sure that all necessary elements from boundary_id are ghosted to this processor.
const MooseArray< Point > & qPointsFace() const
Returns the reference to the current quadrature being used.
Definition: Assembly.h:345
virtual Assembly & assembly(const THREAD_ID tid, const unsigned int sys_num)=0
void update(GeometricSearchType type=ALL)
Update all of the search objects.
libMesh::StoredRange< MooseMesh::const_bnd_elem_iterator, const BndElement * > * getBoundaryElementRange()
Definition: MooseMesh.C:1341
void reinit()
Completely redo the search from scratch.
processor_id_type processor_id() const
void clearNearestNodeLocators()
Clear out the Penetration Locators so they will redo the search.
auto index_range(const T &sizable)
BoundaryID getBoundaryID(const BoundaryName &boundary_name) const
Get the associated BoundaryID for the boundary name.
Definition: MooseMesh.C:1730
PenetrationLocator & getPenetrationLocator(const BoundaryName &primary, const BoundaryName &secondary, libMesh::Order order=libMesh::FIRST)
void generateQuadratureNodes(const BoundaryID secondary_id, const BoundaryID qsecondary_id, bool reiniting=false)
Add Quadrature Nodes to the Mesh in support of Quadrature based penetration location and nearest node...
GeometricSearchData(SubProblem &subproblem, MooseMesh &mesh)