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 
19 // C++
20 #include <cstring> // for "Jacobian" exception test
21 
25 template <typename RangeType>
27 {
28 public:
30 
32 
33  virtual ~ThreadedElementLoopBase();
34 
35  virtual void operator()(const RangeType & range, bool bypass_threading = false);
36 
40  virtual void pre();
41 
45  virtual void post();
46 
52  virtual void onElement(const Elem * elem);
53 
59  virtual void preElement(const Elem * elem);
60 
66  virtual void postElement(const Elem * elem);
67 
76  virtual void preBoundary(const Elem * elem,
77  unsigned int side,
78  BoundaryID bnd_id,
79  const Elem * lower_d_elem = nullptr);
80 
89  virtual void onBoundary(const Elem * elem,
90  unsigned int side,
91  BoundaryID bnd_id,
92  const Elem * lower_d_elem = nullptr);
93 
100  virtual void preInternalSide(const Elem * elem, unsigned int side);
101 
108  virtual void postInternalSide(const Elem * elem, unsigned int side);
109 
116  virtual void onInternalSide(const Elem * elem, unsigned int side);
117 
124  virtual void onExternalSide(const Elem * elem, unsigned int side);
125 
133  virtual void onInterface(const Elem * elem, unsigned int side, BoundaryID bnd_id);
134 
141  virtual void subdomainChanged();
142 
149  virtual void neighborSubdomainChanged();
150 
156 
162  virtual bool keepGoing() { return true; }
163 
164 protected:
167 
170 
173 
176 
179 
181  virtual void printGeneralExecutionInformation() const {}
182 
184  virtual void printBlockExecutionInformation() const {}
185 
187  virtual void printBoundaryExecutionInformation(const unsigned int /*bid*/) const {}
188 
190  mutable std::set<SubdomainID> _blocks_exec_printed;
191 
193  mutable std::set<BoundaryID> _boundaries_exec_printed;
194 
196  void resetExecPrintedSets() const;
197 
204  virtual bool shouldComputeInternalSide(const Elem & elem, const Elem & neighbor) const;
205 };
206 
207 template <typename RangeType>
209 {
210 }
211 
212 template <typename RangeType>
214  Threads::split /*split*/)
215  : _mesh(x._mesh)
216 {
217 }
218 
219 template <typename RangeType>
221 {
222 }
223 
224 template <typename RangeType>
225 void
226 ThreadedElementLoopBase<RangeType>::operator()(const RangeType & range, bool bypass_threading)
227 {
228  try
229  {
230  try
231  {
232  ParallelUniqueId puid;
233  _tid = bypass_threading ? 0 : puid.id;
234 
235  pre();
236  printGeneralExecutionInformation();
237 
238  _subdomain = Moose::INVALID_BLOCK_ID;
239  _neighbor_subdomain = Moose::INVALID_BLOCK_ID;
240  typename RangeType::const_iterator el = range.begin();
241  for (el = range.begin(); el != range.end(); ++el)
242  {
243  if (!keepGoing())
244  break;
245 
246  const Elem * elem = *el;
247 
248  preElement(elem);
249 
250  _old_subdomain = _subdomain;
251  _subdomain = elem->subdomain_id();
252  if (_subdomain != _old_subdomain)
253  {
254  subdomainChanged();
255  printBlockExecutionInformation();
256  }
257 
258  onElement(elem);
259 
260  if (_mesh.interiorLowerDBlocks().count(elem->subdomain_id()) > 0 ||
261  _mesh.boundaryLowerDBlocks().count(elem->subdomain_id()) > 0)
262  {
263  postElement(elem);
264  continue;
265  }
266 
267  for (unsigned int side = 0; side < elem->n_sides(); side++)
268  {
269  std::vector<BoundaryID> boundary_ids = _mesh.getBoundaryIDs(elem, side);
270  const Elem * lower_d_elem = _mesh.getLowerDElem(elem, side);
271 
272  if (boundary_ids.size() > 0)
273  for (std::vector<BoundaryID>::iterator it = boundary_ids.begin();
274  it != boundary_ids.end();
275  ++it)
276  {
277  preBoundary(elem, side, *it, lower_d_elem);
278  printBoundaryExecutionInformation(*it);
279  onBoundary(elem, side, *it, lower_d_elem);
280  }
281 
282  const Elem * neighbor = elem->neighbor_ptr(side);
283  if (neighbor)
284  {
285  preInternalSide(elem, side);
286 
287  _old_neighbor_subdomain = _neighbor_subdomain;
288  _neighbor_subdomain = neighbor->subdomain_id();
289  if (_neighbor_subdomain != _old_neighbor_subdomain)
290  neighborSubdomainChanged();
291 
292  if (shouldComputeInternalSide(*elem, *neighbor))
293  onInternalSide(elem, side);
294 
295  if (boundary_ids.size() > 0)
296  for (std::vector<BoundaryID>::iterator it = boundary_ids.begin();
297  it != boundary_ids.end();
298  ++it)
299  onInterface(elem, side, *it);
300 
301  postInternalSide(elem, side);
302  }
303  else
304  onExternalSide(elem, side);
305  } // sides
306 
307  postElement(elem);
308  } // range
309 
310  post();
311  resetExecPrintedSets();
312  }
313  catch (MetaPhysicL::LogicError & e)
314  {
316  }
317  catch (std::exception & e)
318  {
319  // Continue if we find a libMesh degenerate map exception, but
320  // just re-throw for any real error
321  if (!strstr(e.what(), "Jacobian") && !strstr(e.what(), "singular") &&
322  !strstr(e.what(), "det != 0"))
323  throw; // not "throw e;" - that destroys type info!
324 
325  mooseException("We caught a libMesh degeneracy exception in ThreadedElementLoopBase:\n",
326  e.what());
327  }
328  }
329  catch (MooseException & e)
330  {
331  caughtMooseException(e);
332  }
333 }
334 
335 template <typename RangeType>
336 void
338 {
339 }
340 
341 template <typename RangeType>
342 void
344 {
345 }
346 
347 template <typename RangeType>
348 void
350 {
351 }
352 
353 template <typename RangeType>
354 void
356 {
357 }
358 
359 template <typename RangeType>
360 void
362 {
363 }
364 
365 template <typename RangeType>
366 void
368  unsigned int /*side*/,
369  BoundaryID /*bnd_id*/,
370  const Elem * /*lower_d_elem = nullptr*/)
371 {
372 }
373 
374 template <typename RangeType>
375 void
377  unsigned int /*side*/,
378  BoundaryID /*bnd_id*/,
379  const Elem * /*lower_d_elem = nullptr*/)
380 {
381 }
382 
383 template <typename RangeType>
384 void
385 ThreadedElementLoopBase<RangeType>::preInternalSide(const Elem * /*elem*/, unsigned int /*side*/)
386 {
387 }
388 
389 template <typename RangeType>
390 void
391 ThreadedElementLoopBase<RangeType>::postInternalSide(const Elem * /*elem*/, unsigned int /*side*/)
392 {
393 }
394 
395 template <typename RangeType>
396 void
397 ThreadedElementLoopBase<RangeType>::onInternalSide(const Elem * /*elem*/, unsigned int /*side*/)
398 {
399 }
400 
401 template <typename RangeType>
402 void
403 ThreadedElementLoopBase<RangeType>::onExternalSide(const Elem * /*elem*/, unsigned int /*side*/)
404 {
405 }
406 
407 template <typename RangeType>
408 void
410  unsigned int /*side*/,
411  BoundaryID /*bnd_id*/)
412 {
413 }
414 
415 template <typename RangeType>
416 void
418 {
419 }
420 
421 template <typename RangeType>
422 void
424 {
425 }
426 
427 template <typename RangeType>
428 bool
430  const Elem & neighbor) const
431 {
432  auto level = [this](const auto & elem_arg)
433  {
434  if (_mesh.doingPRefinement())
435  return elem_arg.p_level();
436  else
437  return elem_arg.level();
438  };
439  const auto elem_id = elem.id(), neighbor_id = neighbor.id();
440  const auto elem_level = level(elem), neighbor_level = level(neighbor);
441 
442  // When looping over elements and then sides, we need to make sure that we do not duplicate
443  // effort, e.g. if a face is shared by element 1 and element 2, then we do not want to do compute
444  // work both when we are visiting element 1 *and* then later when visiting element 2. Our rule is
445  // to only compute when we are visiting the element that has the lower element id when element and
446  // neighbor are of the same adaptivity level, and then if they are not of the same level, then
447  // we only compute when we are visiting the finer element
448  return (neighbor.active() && (neighbor_level == elem_level) && (elem_id < neighbor_id)) ||
449  (neighbor_level < elem_level);
450 }
451 
452 template <typename RangeType>
453 void
455 {
456  _blocks_exec_printed.clear();
457  _boundaries_exec_printed.clear();
458 }
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:141
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:92
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:237