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  const auto elem_boundary_ids = _mesh.getBoundaryIDs(elem);
268  for (unsigned int side = 0; side < elem->n_sides(); side++)
269  {
270  const auto & boundary_ids = elem_boundary_ids[side];
271  const Elem * lower_d_elem = _mesh.getLowerDElem(elem, side);
272 
273  for (const auto bnd_id : boundary_ids)
274  {
275  preBoundary(elem, side, bnd_id, lower_d_elem);
276  printBoundaryExecutionInformation(bnd_id);
277  onBoundary(elem, side, bnd_id, lower_d_elem);
278  }
279 
280  const Elem * neighbor = elem->neighbor_ptr(side);
281  if (neighbor)
282  {
283  preInternalSide(elem, side);
284 
285  _old_neighbor_subdomain = _neighbor_subdomain;
286  _neighbor_subdomain = neighbor->subdomain_id();
287  if (_neighbor_subdomain != _old_neighbor_subdomain)
288  neighborSubdomainChanged();
289 
290  if (shouldComputeInternalSide(*elem, *neighbor))
291  onInternalSide(elem, side);
292 
293  for (const auto bnd_id : boundary_ids)
294  onInterface(elem, side, bnd_id);
295 
296  postInternalSide(elem, side);
297  }
298  else
299  onExternalSide(elem, side);
300  } // sides
301 
302  postElement(elem);
303  } // range
304 
305  post();
306  resetExecPrintedSets();
307  }
308  catch (MetaPhysicL::LogicError & e)
309  {
311  }
312  catch (std::exception & e)
313  {
314  // Continue if we find a libMesh degenerate map exception, but
315  // just re-throw for any real error
316  if (!strstr(e.what(), "Jacobian") && !strstr(e.what(), "singular") &&
317  !strstr(e.what(), "det != 0"))
318  throw; // not "throw e;" - that destroys type info!
319 
320  mooseException("We caught a libMesh degeneracy exception in ThreadedElementLoopBase:\n",
321  e.what());
322  }
323  }
324  catch (MooseException & e)
325  {
326  caughtMooseException(e);
327  }
328 }
329 
330 template <typename RangeType>
331 void
333 {
334 }
335 
336 template <typename RangeType>
337 void
339 {
340 }
341 
342 template <typename RangeType>
343 void
345 {
346 }
347 
348 template <typename RangeType>
349 void
351 {
352 }
353 
354 template <typename RangeType>
355 void
357 {
358 }
359 
360 template <typename RangeType>
361 void
363  unsigned int /*side*/,
364  BoundaryID /*bnd_id*/,
365  const Elem * /*lower_d_elem = nullptr*/)
366 {
367 }
368 
369 template <typename RangeType>
370 void
372  unsigned int /*side*/,
373  BoundaryID /*bnd_id*/,
374  const Elem * /*lower_d_elem = nullptr*/)
375 {
376 }
377 
378 template <typename RangeType>
379 void
380 ThreadedElementLoopBase<RangeType>::preInternalSide(const Elem * /*elem*/, unsigned int /*side*/)
381 {
382 }
383 
384 template <typename RangeType>
385 void
386 ThreadedElementLoopBase<RangeType>::postInternalSide(const Elem * /*elem*/, unsigned int /*side*/)
387 {
388 }
389 
390 template <typename RangeType>
391 void
392 ThreadedElementLoopBase<RangeType>::onInternalSide(const Elem * /*elem*/, unsigned int /*side*/)
393 {
394 }
395 
396 template <typename RangeType>
397 void
398 ThreadedElementLoopBase<RangeType>::onExternalSide(const Elem * /*elem*/, unsigned int /*side*/)
399 {
400 }
401 
402 template <typename RangeType>
403 void
405  unsigned int /*side*/,
406  BoundaryID /*bnd_id*/)
407 {
408 }
409 
410 template <typename RangeType>
411 void
413 {
414 }
415 
416 template <typename RangeType>
417 void
419 {
420 }
421 
422 template <typename RangeType>
423 bool
425  const Elem & neighbor) const
426 {
427  // If we're going to compute the internal side with this elem-neighbor pair, then they must both
428  // be active. Note that if elem is an active coarse element at an interface with finer elements,
429  // then its neighbor will be an equal-level inactive element, hence the following
430  // neighbor.active() check. In that case we'll catch current 'elem' when we come around and
431  // examine one of the finer elements as 'elem'
432  mooseAssert(elem.active(), "This method should never be called with an inactive element");
433  if (!neighbor.active())
434  return false;
435 
436  //
437  // Define an ordering: first prefer finer by h (higher level()), then prefer finer by p (higher
438  // p_level()), then prefer smaller id()"
439  //
440 
441  const auto elem_level = elem.level(), neighbor_level = neighbor.level();
442  if (elem_level != neighbor_level)
443  return elem_level > neighbor_level;
444 
445  const auto elem_p_level = elem.p_level(), neighbor_p_level = neighbor.p_level();
446  if (elem_p_level != neighbor_p_level)
447  return elem_p_level > neighbor_p_level;
448 
449  return elem.id() < neighbor.id();
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:155
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:93
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:1174
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