https://mooseframework.inl.gov
ThreadedElementLoopBase.h
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 #pragma once
11 
12 #include "ParallelUniqueId.h"
13 #include "MooseMesh.h"
14 #include "MooseTypes.h"
15 #include "MooseException.h"
16 #include "libmesh/libmesh_exceptions.h"
17 #include "libmesh/elem.h"
18 
22 template <typename RangeType>
24 {
25 public:
27 
29 
30  virtual ~ThreadedElementLoopBase();
31 
32  virtual void operator()(const RangeType & range, bool bypass_threading = false);
33 
37  virtual void pre();
38 
42  virtual void post();
43 
49  virtual void onElement(const Elem * elem);
50 
56  virtual void preElement(const Elem * elem);
57 
63  virtual void postElement(const Elem * elem);
64 
73  virtual void preBoundary(const Elem * elem,
74  unsigned int side,
75  BoundaryID bnd_id,
76  const Elem * lower_d_elem = nullptr);
77 
86  virtual void onBoundary(const Elem * elem,
87  unsigned int side,
88  BoundaryID bnd_id,
89  const Elem * lower_d_elem = nullptr);
90 
97  virtual void preInternalSide(const Elem * elem, unsigned int side);
98 
105  virtual void postInternalSide(const Elem * elem, unsigned int side);
106 
113  virtual void onInternalSide(const Elem * elem, unsigned int side);
114 
121  virtual void onExternalSide(const Elem * elem, unsigned int side);
122 
130  virtual void onInterface(const Elem * elem, unsigned int side, BoundaryID bnd_id);
131 
138  virtual void subdomainChanged();
139 
146  virtual void neighborSubdomainChanged();
147 
153 
159  virtual bool keepGoing() { return true; }
160 
161 protected:
164 
167 
170 
173 
176 
178  virtual void printGeneralExecutionInformation() const {}
179 
181  virtual void printBlockExecutionInformation() const {}
182 
184  virtual void printBoundaryExecutionInformation(const unsigned int /*bid*/) const {}
185 
187  mutable std::set<SubdomainID> _blocks_exec_printed;
188 
190  mutable std::set<BoundaryID> _boundaries_exec_printed;
191 
193  void resetExecPrintedSets() const;
194 
201  virtual bool shouldComputeInternalSide(const Elem & elem, const Elem & neighbor) const;
202 };
203 
204 template <typename RangeType>
206 {
207 }
208 
209 template <typename RangeType>
211  Threads::split /*split*/)
212  : _mesh(x._mesh)
213 {
214 }
215 
216 template <typename RangeType>
218 {
219 }
220 
221 template <typename RangeType>
222 void
223 ThreadedElementLoopBase<RangeType>::operator()(const RangeType & range, bool bypass_threading)
224 {
225  try
226  {
227  try
228  {
229  ParallelUniqueId puid;
230  _tid = bypass_threading ? 0 : puid.id;
231 
232  pre();
233  printGeneralExecutionInformation();
234 
235  _subdomain = Moose::INVALID_BLOCK_ID;
236  _neighbor_subdomain = Moose::INVALID_BLOCK_ID;
237  typename RangeType::const_iterator el = range.begin();
238  for (el = range.begin(); el != range.end(); ++el)
239  {
240  if (!keepGoing())
241  break;
242 
243  const Elem * elem = *el;
244 
245  preElement(elem);
246 
247  _old_subdomain = _subdomain;
248  _subdomain = elem->subdomain_id();
249  if (_subdomain != _old_subdomain)
250  {
251  subdomainChanged();
252  printBlockExecutionInformation();
253  }
254 
255  onElement(elem);
256 
257  if (_mesh.interiorLowerDBlocks().count(elem->subdomain_id()) > 0 ||
258  _mesh.boundaryLowerDBlocks().count(elem->subdomain_id()) > 0)
259  {
260  postElement(elem);
261  continue;
262  }
263 
264  for (unsigned int side = 0; side < elem->n_sides(); side++)
265  {
266  std::vector<BoundaryID> boundary_ids = _mesh.getBoundaryIDs(elem, side);
267  const Elem * lower_d_elem = _mesh.getLowerDElem(elem, side);
268 
269  if (boundary_ids.size() > 0)
270  for (std::vector<BoundaryID>::iterator it = boundary_ids.begin();
271  it != boundary_ids.end();
272  ++it)
273  {
274  preBoundary(elem, side, *it, lower_d_elem);
275  printBoundaryExecutionInformation(*it);
276  onBoundary(elem, side, *it, lower_d_elem);
277  }
278 
279  const Elem * neighbor = elem->neighbor_ptr(side);
280  if (neighbor)
281  {
282  preInternalSide(elem, side);
283 
284  _old_neighbor_subdomain = _neighbor_subdomain;
285  _neighbor_subdomain = neighbor->subdomain_id();
286  if (_neighbor_subdomain != _old_neighbor_subdomain)
287  neighborSubdomainChanged();
288 
289  if (shouldComputeInternalSide(*elem, *neighbor))
290  onInternalSide(elem, side);
291 
292  if (boundary_ids.size() > 0)
293  for (std::vector<BoundaryID>::iterator it = boundary_ids.begin();
294  it != boundary_ids.end();
295  ++it)
296  onInterface(elem, side, *it);
297 
298  postInternalSide(elem, side);
299  }
300  else
301  onExternalSide(elem, side);
302  } // sides
303 
304  postElement(elem);
305  } // range
306 
307  post();
308  resetExecPrintedSets();
309  }
310  catch (libMesh::LogicError & e)
311  {
312  mooseException("We caught a libMesh error in ThreadedElementLoopBase:", e.what());
313  }
314  catch (MetaPhysicL::LogicError & e)
315  {
317  }
318  }
319  catch (MooseException & e)
320  {
321  caughtMooseException(e);
322  }
323 }
324 
325 template <typename RangeType>
326 void
328 {
329 }
330 
331 template <typename RangeType>
332 void
334 {
335 }
336 
337 template <typename RangeType>
338 void
340 {
341 }
342 
343 template <typename RangeType>
344 void
346 {
347 }
348 
349 template <typename RangeType>
350 void
352 {
353 }
354 
355 template <typename RangeType>
356 void
358  unsigned int /*side*/,
359  BoundaryID /*bnd_id*/,
360  const Elem * /*lower_d_elem = nullptr*/)
361 {
362 }
363 
364 template <typename RangeType>
365 void
367  unsigned int /*side*/,
368  BoundaryID /*bnd_id*/,
369  const Elem * /*lower_d_elem = nullptr*/)
370 {
371 }
372 
373 template <typename RangeType>
374 void
375 ThreadedElementLoopBase<RangeType>::preInternalSide(const Elem * /*elem*/, unsigned int /*side*/)
376 {
377 }
378 
379 template <typename RangeType>
380 void
381 ThreadedElementLoopBase<RangeType>::postInternalSide(const Elem * /*elem*/, unsigned int /*side*/)
382 {
383 }
384 
385 template <typename RangeType>
386 void
387 ThreadedElementLoopBase<RangeType>::onInternalSide(const Elem * /*elem*/, unsigned int /*side*/)
388 {
389 }
390 
391 template <typename RangeType>
392 void
393 ThreadedElementLoopBase<RangeType>::onExternalSide(const Elem * /*elem*/, unsigned int /*side*/)
394 {
395 }
396 
397 template <typename RangeType>
398 void
400  unsigned int /*side*/,
401  BoundaryID /*bnd_id*/)
402 {
403 }
404 
405 template <typename RangeType>
406 void
408 {
409 }
410 
411 template <typename RangeType>
412 void
414 {
415 }
416 
417 template <typename RangeType>
418 bool
420  const Elem & neighbor) const
421 {
422  auto level = [this](const auto & elem_arg)
423  {
424  if (_mesh.doingPRefinement())
425  return elem_arg.p_level();
426  else
427  return elem_arg.level();
428  };
429  const auto elem_id = elem.id(), neighbor_id = neighbor.id();
430  const auto elem_level = level(elem), neighbor_level = level(neighbor);
431 
432  // When looping over elements and then sides, we need to make sure that we do not duplicate
433  // effort, e.g. if a face is shared by element 1 and element 2, then we do not want to do compute
434  // work both when we are visiting element 1 *and* then later when visiting element 2. Our rule is
435  // to only compute when we are visiting the element that has the lower element id when element and
436  // neighbor are of the same adaptivity level, and then if they are not of the same level, then
437  // we only compute when we are visiting the finer element
438  return (neighbor.active() && (neighbor_level == elem_level) && (elem_id < neighbor_id)) ||
439  (neighbor_level < elem_level);
440 }
441 
442 template <typename RangeType>
443 void
445 {
446  _blocks_exec_printed.clear();
447  _boundaries_exec_printed.clear();
448 }
virtual void onExternalSide(const Elem *elem, unsigned int side)
Called when iterating over external sides (no side neighbor)
virtual bool keepGoing()
Whether or not the loop should continue.
void resetExecPrintedSets() const
Resets the set of blocks and boundaries visited.
virtual bool shouldComputeInternalSide(const Elem &elem, const Elem &neighbor) const
Whether to compute the internal side for the provided element-neighbor pair.
virtual void onElement(const Elem *elem)
Assembly of the element (not including surface assembly)
void translateMetaPhysicLError(const MetaPhysicL::LogicError &)
emit a relatively clear error message when we catch a MetaPhysicL logic error
Definition: MooseError.C:112
virtual void printBoundaryExecutionInformation(const unsigned int) const
Print information about the particular ordering of objects on each boundary.
virtual void pre()
Called before the element range loop.
MeshBase & mesh
virtual void subdomainChanged()
Called every time the current subdomain changes (i.e.
virtual void neighborSubdomainChanged()
Called every time the neighbor subdomain changes (i.e.
virtual void preInternalSide(const Elem *elem, unsigned int side)
Called before evaluations on an element internal side.
virtual void postInternalSide(const Elem *elem, unsigned int side)
Called after evaluations on an element internal side.
const SubdomainID INVALID_BLOCK_ID
Definition: MooseTypes.C:20
virtual void onBoundary(const Elem *elem, unsigned int side, BoundaryID bnd_id, const Elem *lower_d_elem=nullptr)
Called when doing boundary assembling.
virtual void postElement(const Elem *elem)
Called after the element assembly is done (including surface assembling)
virtual void printGeneralExecutionInformation() const
Print information about the loop ordering.
boundary_id_type BoundaryID
MooseMesh wraps a libMesh::Mesh object and enhances its capabilities by caching additional data and s...
Definition: MooseMesh.h:88
virtual void onInterface(const Elem *elem, unsigned int side, BoundaryID bnd_id)
Called when doing interface assembling.
SubdomainID _old_neighbor_subdomain
The subdomain for the last neighbor.
virtual void operator()(const RangeType &range, bool bypass_threading=false)
virtual void onInternalSide(const Elem *elem, unsigned int side)
Called when doing internal edge assembling.
bool onBoundary(const SubdomainRestrictable &obj, const FaceInfo &fi)
Return whether the supplied face is on a boundary of the object&#39;s execution.
Definition: MathFVUtils.h:1169
std::set< SubdomainID > _blocks_exec_printed
Keep track of which blocks were visited.
tbb::split split
Provides a way for users to bail out of the current solve.
std::set< BoundaryID > _boundaries_exec_printed
Keep track of which boundaries were visited.
virtual void caughtMooseException(MooseException &)
Called if a MooseException is caught anywhere during the computation.
Base class for assembly-like calculations.
SubdomainID _subdomain
The subdomain for the current element.
SubdomainID _old_subdomain
The subdomain for the last element.
virtual void post()
Called after the element range loop.
virtual void printBlockExecutionInformation() const
Print information about the particular ordering of objects on each block.
virtual void preElement(const Elem *elem)
Called before the element assembly.
virtual void preBoundary(const Elem *elem, unsigned int side, BoundaryID bnd_id, const Elem *lower_d_elem=nullptr)
Called before the boundary assembly.
ThreadedElementLoopBase(MooseMesh &mesh)
SubdomainID _neighbor_subdomain
The subdomain for the current neighbor.
unsigned int THREAD_ID
Definition: MooseTypes.h:209