https://mooseframework.inl.gov
ComputeFVFluxThread.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 "MooseVariableFieldBase.h"
17 #include "FVFluxKernel.h"
18 #include "FVFluxBC.h"
19 #include "FVInterfaceKernel.h"
20 #include "FEProblem.h"
21 #include "DisplacedProblem.h"
22 #include "SwapBackSentinel.h"
23 #include "MaterialBase.h"
24 #include "libmesh/libmesh_exceptions.h"
25 #include "libmesh/elem.h"
26 
27 // C++
28 #include <cstring> // for "Jacobian" exception test
29 #include <set>
30 
31 class MooseVariableFVBase;
32 
53 {
54  std::function<void()> _f;
55  OnScopeExit(std::function<void()> f) noexcept : _f(std::move(f)) {}
56  OnScopeExit(OnScopeExit && other) : _f(std::move(other._f)) {}
58  {
59  _f = std::move(other._f);
60  return *this;
61  }
63  {
64  if (_f)
65  _f();
66  }
67 };
68 
74 template <typename RangeType>
76 {
77 public:
78  ThreadedFaceLoop(FEProblemBase & fe_problem,
79  const unsigned int nl_system_num,
80  const std::set<TagID> & tags,
81  bool on_displaced);
82 
84 
85  virtual ~ThreadedFaceLoop();
86 
87  virtual void operator()(const RangeType & range, bool bypass_threading = false);
88 
89  void join(const ThreadedFaceLoop & y);
90 
91  virtual void onFace(const FaceInfo & fi) = 0;
94  virtual void postFace(const FaceInfo & /*fi*/) {}
96  virtual void pre() {}
98  virtual void post() {}
99 
102  virtual void onBoundary(const FaceInfo & fi, BoundaryID boundary) = 0;
103 
107 
111  {
113  }
114 
117  {
118  Threads::spin_mutex::scoped_lock lock(threaded_element_mutex);
119  std::string what(e.what());
121  }
122 
123 protected:
125  virtual void printGeneralExecutionInformation() const {}
126 
128  virtual void printBlockExecutionInformation() const {}
129 
131  virtual void printBoundaryExecutionInformation(const BoundaryID /* bnd_id */) const {}
132 
135  {
136  _blocks_exec_printed.clear();
137  _boundaries_exec_printed.clear();
138  }
139 
142  const std::set<TagID> & _tags;
144  const unsigned int _nl_system_num;
145 
147  const bool _on_displaced;
148 
151 
154 
157 
160 
163 
165  mutable std::set<std::pair<const SubdomainID, const SubdomainID>> _blocks_exec_printed;
166 
168  mutable std::set<BoundaryID> _boundaries_exec_printed;
169 
171  std::string _error_message;
172 
173 private:
175  const bool _zeroth_copy;
176 
180 };
181 
182 template <typename RangeType>
184  const unsigned int nl_system_num,
185  const std::set<TagID> & tags,
186  const bool on_displaced)
187  : _fe_problem(fe_problem),
188  _mesh(fe_problem.mesh()),
189  _tags(tags),
190  _nl_system_num(nl_system_num),
191  _on_displaced(on_displaced),
192  _subproblem(_on_displaced ? static_cast<SubProblem &>(*_fe_problem.getDisplacedProblem())
193  : static_cast<SubProblem &>(_fe_problem)),
194  _zeroth_copy(true),
195  _incoming_throw_on_error(Moose::_throw_on_error)
196 {
197  Moose::_throw_on_error = true;
198 }
199 
200 template <typename RangeType>
202  : _fe_problem(x._fe_problem),
203  _mesh(x._mesh),
204  _tags(x._tags),
205  _nl_system_num(x._nl_system_num),
206  _on_displaced(x._on_displaced),
207  _subproblem(x._subproblem),
208  _zeroth_copy(false),
209  _incoming_throw_on_error(false)
210 {
211 }
212 
213 template <typename RangeType>
215 {
216  if (_zeroth_copy)
217  {
218  Moose::_throw_on_error = _incoming_throw_on_error;
219 
220  if (!_error_message.empty())
221  mooseError(_error_message);
222  }
223 }
224 
225 template <typename RangeType>
226 void
228 {
229  if (_error_message.empty() && !y._error_message.empty())
230  _error_message = y._error_message;
231 }
232 
233 // TODO: ensure the vector<faceinfo> data structure needs to be built such
234 // that for all sides on an interface between two subdomains, the elements of
235 // the same subdomain are used consistently for all the "elem" (i.e. not
236 // "neighbor") parameters in order to avoid jumping back and forth along the
237 // boundary between using one or the other subdomains' FV kernels
238 // unpredictably.
239 template <typename RangeType>
240 void
241 ThreadedFaceLoop<RangeType>::operator()(const RangeType & range, bool bypass_threading)
242 {
243  // TODO: make this query fv flux kernel specific or somehow integrate the
244  // fv source kernels into this loop. Also this check will need to increase
245  // in generality if/when other systems and objects besides FV stuff get
246  // added to this loop.
247  std::vector<FVKernel *> kernels;
248  _fe_problem.theWarehouse()
249  .query()
250  .template condition<AttribSysNum>(_nl_system_num)
251  .template condition<AttribSystem>("FVFluxKernel")
252  .template condition<AttribDisplaced>(_on_displaced)
253  .queryInto(kernels);
254  if (kernels.size() == 0)
255  return;
256 
257  try
258  {
259  try
260  {
261  ParallelUniqueId puid;
262  _tid = bypass_threading ? 0 : puid.id;
263 
264  pre();
265  printGeneralExecutionInformation();
266 
267  _subdomain = Moose::INVALID_BLOCK_ID;
268  _neighbor_subdomain = Moose::INVALID_BLOCK_ID;
269 
270  typename RangeType::const_iterator faceinfo = range.begin();
271  for (faceinfo = range.begin(); faceinfo != range.end(); ++faceinfo)
272  {
273  const Elem & elem = (*faceinfo)->elem();
274 
275  _fe_problem.setCurrentSubdomainID(&elem, _tid);
276 
277  _old_subdomain = _subdomain;
278  _subdomain = elem.subdomain_id();
279  if (_subdomain != _old_subdomain)
280  {
281  subdomainChanged();
282  printBlockExecutionInformation();
283  }
284 
285  _old_neighbor_subdomain = _neighbor_subdomain;
286  if (const Elem * const neighbor = (*faceinfo)->neighborPtr())
287  {
288  _fe_problem.setNeighborSubdomainID(neighbor, _tid);
289  _neighbor_subdomain = neighbor->subdomain_id();
290  }
291  else
292  _neighbor_subdomain = Moose::INVALID_BLOCK_ID;
293 
294  if (_neighbor_subdomain != _old_neighbor_subdomain)
295  {
296  neighborSubdomainChanged();
297  // This is going to cause a lot more printing
298  printBlockExecutionInformation();
299  }
300 
301  onFace(**faceinfo);
302  // Cache data now because onBoundary may clear it. E.g. there was a nasty bug for two
303  // variable FV systems where if one variable was executing an FVFluxKernel on a boundary
304  // while the other was executing an FVFluxBC, the FVFluxKernel data would get lost because
305  // onBoundary would clear the residual/Jacobian data before it was cached
306  postFace(**faceinfo);
307 
308  const std::set<BoundaryID> boundary_ids = (*faceinfo)->boundaryIDs();
309  for (auto & it : boundary_ids)
310  {
311  printBoundaryExecutionInformation(it);
312  onBoundary(**faceinfo, it);
313  }
314 
315  postFace(**faceinfo);
316 
317  } // range
318  post();
319 
320  // Clear execution printing sets to start printing on every block and boundary again
321  resetExecutionPrinting();
322  }
323  catch (MetaPhysicL::LogicError & e)
324  {
326  }
327  catch (std::exception & e)
328  {
329  // Continue if we find a libMesh degenerate map exception, but
330  // just throw for any real error
331  if (!strstr(e.what(), "Jacobian") && !strstr(e.what(), "singular") &&
332  !strstr(e.what(), "det != 0"))
333  throw;
334 
335  mooseException("We caught a libMesh degeneracy exception in ComputeFVFluxThread:\n",
336  e.what());
337  }
338  }
339  catch (MooseException & e)
340  {
341  caughtMooseException(e);
342  }
343  catch (std::runtime_error & e)
344  {
345  _error_message = e.what();
346  }
347 }
348 
352 template <typename RangeType, typename AttributeTagType>
353 class ComputeFVFluxThread : public ThreadedFaceLoop<RangeType>
354 {
355 public:
356  ComputeFVFluxThread(FEProblemBase & fe_problem,
357  const unsigned int nl_system_num,
358  const std::set<TagID> & tags,
359  bool on_displaced);
360 
362 
363  virtual ~ComputeFVFluxThread();
364 
365  virtual void onFace(const FaceInfo & fi) override;
366  virtual void pre() override;
367  virtual void post() override;
368 
369  virtual void onBoundary(const FaceInfo & fi, BoundaryID boundary) override;
370 
371  virtual void subdomainChanged() override;
372  virtual void neighborSubdomainChanged() override;
373 
374 protected:
379  virtual void compute(FVFaceResidualObject & ro, const FaceInfo & fi) = 0;
380 
385  virtual void setup(SetupInterface & obj) = 0;
386 
391  virtual void addCached() = 0;
392 
393  unsigned int _num_cached = 0;
394 
405 
406 private:
407  void reinitVariables(const FaceInfo & fi);
408  void finalizeContainers();
409 
411  virtual void printGeneralExecutionInformation() const override;
412 
414  virtual void printBlockExecutionInformation() const override;
415 
417  virtual void printBoundaryExecutionInformation(const BoundaryID bnd_id) const override;
418 
420  std::pair<SubdomainName, SubdomainName> getBlockNames() const;
421 
423  std::set<MooseVariableFieldBase *> _fv_vars;
424  std::set<MooseVariableFieldBase *> _elem_sub_fv_vars;
425  std::set<MooseVariableFieldBase *> _neigh_sub_fv_vars;
426 
428  std::set<FVFluxKernel *> _fv_flux_kernels;
429  std::set<FVFluxKernel *> _elem_sub_fv_flux_kernels;
430  std::set<FVFluxKernel *> _neigh_sub_fv_flux_kernels;
431 
433  std::vector<std::shared_ptr<MaterialBase>> _elem_face_mats;
434  std::vector<std::shared_ptr<MaterialBase>> _elem_sub_elem_face_mats;
435  std::vector<std::shared_ptr<MaterialBase>> _neigh_sub_elem_face_mats;
436 
437  // Neighbor face materials
438  std::vector<std::shared_ptr<MaterialBase>> _neigh_face_mats;
439  std::vector<std::shared_ptr<MaterialBase>> _elem_sub_neigh_face_mats;
440  std::vector<std::shared_ptr<MaterialBase>> _neigh_sub_neigh_face_mats;
441 
442  const bool _scaling_jacobian;
443  const bool _scaling_residual;
444 };
445 
446 template <typename RangeType, typename AttributeTagType>
448  unsigned int nl_system_num,
449  const std::set<TagID> & tags,
450  bool on_displaced)
451  : ThreadedFaceLoop<RangeType>(fe_problem, nl_system_num, tags, on_displaced),
452  _scaling_jacobian(fe_problem.computingScalingJacobian()),
453  _scaling_residual(fe_problem.computingScalingResidual())
454 {
455 }
456 
457 template <typename RangeType, typename AttributeTagType>
460  : ThreadedFaceLoop<RangeType>(x, split),
461  _fv_vars(x._fv_vars),
462  _scaling_jacobian(x._scaling_jacobian),
463  _scaling_residual(x._scaling_residual)
464 {
465 }
466 
467 template <typename RangeType, typename AttributeTagType>
469 {
470 }
471 
472 template <typename RangeType, typename AttributeTagType>
473 void
475 {
476  // TODO: this skips necessary FE reinit. In addition to this call, we need
477  // to conditionally do some FE-specific reinit here if we have any active FE
478  // variables. However, we still want to keep/do FV-style quadrature.
479  // Figure out how to do all this some day.
480  this->_subproblem.reinitFVFace(_tid, fi);
481 
482  // TODO: for FE variables, this is handled via setting needed vars through
483  // fe problem API which passes the value on to the system class. Then
484  // reinit is called on fe problem which forwards its calls to the system
485  // function and then fe problem also calls displaced problem reinit. All
486  // the call forwarding seems silly, but it does allow the displaced problem
487  // to be easily kept in sync. However, the displaced problem has different
488  // pointers for its own face info objects, etc, we can't just pass in fe
489  // problem's face info down to the sub-problem -- centroids are different,
490  // volumes are different, etc. To support displaced meshes correctly, we
491  // need to be able to reinit the subproblems variables using its equivalent
492  // face info object. How? See https://github.com/idaholab/moose/issues/15064
493 
494  for (auto var : _fv_vars)
495  var->computeFaceValues(fi);
496 
497  _fe_problem.resizeMaterialData(Moose::MaterialDataType::FACE_MATERIAL_DATA, /*nqp=*/1, _tid);
498 
499  for (std::shared_ptr<MaterialBase> mat : _elem_face_mats)
500  {
501  mat->setFaceInfo(fi);
502  mat->computeProperties();
503  }
504 
505  if (fi.neighborPtr())
506  {
507  _fe_problem.resizeMaterialData(
509 
510  for (std::shared_ptr<MaterialBase> mat : _neigh_face_mats)
511  {
512  mat->setFaceInfo(fi);
513  mat->computeProperties();
514  }
515  }
516 }
517 
518 template <typename RangeType, typename AttributeTagType>
519 void
521 {
522  reinitVariables(fi);
523 
524  for (auto * const k : _fv_flux_kernels)
525  compute(*k, fi);
526 }
527 
528 template <typename RangeType, typename AttributeTagType>
529 void
531 {
532  if (_scaling_jacobian || _scaling_residual)
533  return;
534 
535  std::vector<FVFluxBC *> bcs;
536  _fe_problem.theWarehouse()
537  .query()
538  .template condition<AttribSysNum>(_nl_system_num)
539  .template condition<AttribSystem>("FVFluxBC")
540  .template condition<AttribDisplaced>(_on_displaced)
541  .template condition<AttribThread>(_tid)
542  .template condition<AttributeTagType>(_tags)
543  .template condition<AttribBoundaries>(bnd_id)
544  .queryInto(bcs);
545 
546  for (auto * const bc : bcs)
547  compute(*bc, fi);
548 
549  std::vector<FVInterfaceKernel *> iks;
550  _fe_problem.theWarehouse()
551  .query()
552  .template condition<AttribSysNum>(_nl_system_num)
553  .template condition<AttribSystem>("FVInterfaceKernel")
554  .template condition<AttribDisplaced>(_on_displaced)
555  .template condition<AttribThread>(_tid)
556  .template condition<AttributeTagType>(_tags)
557  .template condition<AttribBoundaries>(bnd_id)
558  .queryInto(iks);
559 
560  for (auto * const ik : iks)
561  compute(*ik, fi);
562 }
563 
564 template <typename RangeType, typename AttributeTagType>
565 void
567 {
568  // make sure we add any remaining cached residuals/jacobians to add/record
569  Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
570  addCached();
571 
572  _fe_problem.clearActiveElementalMooseVariables(_tid);
573  _fe_problem.clearActiveMaterialProperties(_tid);
574 }
575 
576 template <typename RangeType, typename AttributeTagType>
577 void
579 {
580  //
581  // Finalize our variables
582  //
583  std::set_union(_elem_sub_fv_vars.begin(),
584  _elem_sub_fv_vars.end(),
585  _neigh_sub_fv_vars.begin(),
586  _neigh_sub_fv_vars.end(),
587  std::inserter(_fv_vars, _fv_vars.begin()));
588 
589  //
590  // Finalize our kernels
591  //
592  const bool same_kernels = _elem_sub_fv_flux_kernels == _neigh_sub_fv_flux_kernels;
593  if (same_kernels)
594  _fv_flux_kernels = _elem_sub_fv_flux_kernels;
595  else
596  std::set_union(_elem_sub_fv_flux_kernels.begin(),
597  _elem_sub_fv_flux_kernels.end(),
598  _neigh_sub_fv_flux_kernels.begin(),
599  _neigh_sub_fv_flux_kernels.end(),
600  std::inserter(_fv_flux_kernels, _fv_flux_kernels.begin()));
601  const bool need_ghosting = !same_kernels;
602 
603  //
604  // Finalize our element face materials
605  //
606  _elem_face_mats = _elem_sub_elem_face_mats;
607 
608  if (need_ghosting)
609  // Add any element face materials from the neighboring subdomain that do not exist on the
610  // element subdomain
611  for (std::shared_ptr<MaterialBase> neigh_sub_elem_face_mat : _neigh_sub_elem_face_mats)
612  if (std::find(_elem_sub_elem_face_mats.begin(),
613  _elem_sub_elem_face_mats.end(),
614  neigh_sub_elem_face_mat) == _elem_sub_elem_face_mats.end())
615  _elem_face_mats.push_back(neigh_sub_elem_face_mat);
616 
617  //
618  // Finalize our neighbor face materials
619  //
620  _neigh_face_mats = _neigh_sub_neigh_face_mats;
621 
622  if (need_ghosting)
623  // Add any neighbor face materials from the element subdomain that do not exist on the
624  // neighbor subdomain
625  for (std::shared_ptr<MaterialBase> elem_sub_neigh_face_mat : _elem_sub_neigh_face_mats)
626  if (std::find(_neigh_sub_neigh_face_mats.begin(),
627  _neigh_sub_neigh_face_mats.end(),
628  elem_sub_neigh_face_mat) == _neigh_sub_neigh_face_mats.end())
629  _neigh_face_mats.push_back(elem_sub_neigh_face_mat);
630 }
631 
632 template <typename RangeType, typename AttributeTagType>
633 void
635 {
637 
638  // Clear variables
639  _fv_vars.clear();
640  _elem_sub_fv_vars.clear();
641 
642  // Clear kernels
643  _fv_flux_kernels.clear();
644  _elem_sub_fv_flux_kernels.clear();
645 
646  // Clear element face materials
647  _elem_face_mats.clear();
648  _elem_sub_elem_face_mats.clear();
649 
650  // Clear neighbor face materials
651  _neigh_face_mats.clear();
652  _elem_sub_neigh_face_mats.clear();
653 
654  // TODO: do this for other relevant objects - like FV BCs, FV source term
655  // kernels, etc. - but we don't need to add them for other types of objects
656  // like FE or DG kernels because those kernels don't run in this loop. Do we
657  // really want to integrate fv source kernels into this loop?
658  std::vector<FVFluxKernel *> kernels;
659  _fe_problem.theWarehouse()
660  .query()
661  .template condition<AttribSysNum>(_nl_system_num)
662  .template condition<AttribSystem>("FVFluxKernel")
663  .template condition<AttribDisplaced>(_on_displaced)
664  .template condition<AttribSubdomains>(_subdomain)
665  .template condition<AttribThread>(_tid)
666  .template condition<AttributeTagType>(_tags)
667  .queryInto(kernels);
668 
669  _elem_sub_fv_flux_kernels = std::set<FVFluxKernel *>(kernels.begin(), kernels.end());
670 
671  for (auto * k : _elem_sub_fv_flux_kernels)
672  {
673  // TODO: we need a better way to do this - especially when FE objects begin to
674  // couple to FV vars. This code shoud be refactored out into one place
675  // where it is easy for users to say initialize all materials and
676  // variables needed by these objects for me.
677  const auto & deps = k->getMooseVariableDependencies();
678  for (auto var : deps)
679  {
680  mooseAssert(var->isFV(),
681  "We do not currently support coupling of FE variables into FV objects");
682  _elem_sub_fv_vars.insert(var);
683  }
684  }
685 
686  _fe_problem.getFVMatsAndDependencies(
687  _subdomain, _elem_sub_elem_face_mats, _elem_sub_neigh_face_mats, _elem_sub_fv_vars, _tid);
688 
689  finalizeContainers();
690 }
691 
692 template <typename RangeType, typename AttributeTagType>
693 void
695 {
697 
698  // Clear variables
699  _fv_vars.clear();
700  _neigh_sub_fv_vars.clear();
701 
702  // Clear kernels
703  _fv_flux_kernels.clear();
704  _neigh_sub_fv_flux_kernels.clear();
705 
706  // Clear element face materials
707  _elem_face_mats.clear();
708  _neigh_sub_elem_face_mats.clear();
709 
710  // Clear neighbor face materials
711  _neigh_face_mats.clear();
712  _neigh_sub_neigh_face_mats.clear();
713 
714  // TODO: do this for other relevant objects - like FV BCs, FV source term
715  // kernels, etc. - but we don't need to add them for other types of objects
716  // like FE or DG kernels because those kernels don't run in this loop. Do we
717  // really want to integrate fv source kernels into this loop?
718  std::vector<FVFluxKernel *> kernels;
719  _fe_problem.theWarehouse()
720  .query()
721  .template condition<AttribSysNum>(_nl_system_num)
722  .template condition<AttribSystem>("FVFluxKernel")
723  .template condition<AttribDisplaced>(_on_displaced)
724  .template condition<AttribSubdomains>(_neighbor_subdomain)
725  .template condition<AttribThread>(_tid)
726  .template condition<AttributeTagType>(_tags)
727  .queryInto(kernels);
728 
729  _neigh_sub_fv_flux_kernels = std::set<FVFluxKernel *>(kernels.begin(), kernels.end());
730 
731  for (auto * k : _neigh_sub_fv_flux_kernels)
732  {
733  // TODO: we need a better way to do this - especially when FE objects begin to
734  // couple to FV vars. This code shoud be refactored out into one place
735  // where it is easy for users to say initialize all materials and
736  // variables needed by these objects for me.
737  const auto & deps = k->getMooseVariableDependencies();
738  for (auto var : deps)
739  {
740  mooseAssert(var->isFV(),
741  "We do not currently support coupling of FE variables into FV objects");
742  _neigh_sub_fv_vars.insert(var);
743  }
744  }
745 
746  _fe_problem.getFVMatsAndDependencies(_neighbor_subdomain,
747  _neigh_sub_elem_face_mats,
748  _neigh_sub_neigh_face_mats,
749  _neigh_sub_fv_vars,
750  _tid);
751 
752  finalizeContainers();
753 }
754 
755 template <typename RangeType, typename AttributeTagType>
756 void
758 {
759  std::vector<FVFluxBC *> bcs;
760  _fe_problem.theWarehouse()
761  .query()
762  .template condition<AttribSysNum>(_nl_system_num)
763  .template condition<AttribSystem>("FVFluxBC")
764  .template condition<AttribDisplaced>(_on_displaced)
765  .template condition<AttribThread>(_tid)
766  .template condition<AttributeTagType>(_tags)
767  .queryInto(bcs);
768 
769  std::vector<FVInterfaceKernel *> iks;
770  _fe_problem.theWarehouse()
771  .query()
772  .template condition<AttribSysNum>(_nl_system_num)
773  .template condition<AttribSystem>("FVInterfaceKernel")
774  .template condition<AttribDisplaced>(_on_displaced)
775  .template condition<AttribThread>(_tid)
776  .template condition<AttributeTagType>(_tags)
777  .queryInto(iks);
778 
779  std::vector<FVFluxKernel *> kernels;
780  _fe_problem.theWarehouse()
781  .query()
782  .template condition<AttribSysNum>(_nl_system_num)
783  .template condition<AttribSystem>("FVFluxKernel")
784  .template condition<AttribDisplaced>(_on_displaced)
785  .template condition<AttribThread>(_tid)
786  .template condition<AttributeTagType>(_tags)
787  .queryInto(kernels);
788 
789  for (auto * const bc : bcs)
790  setup(*bc);
791  for (auto * const ik : iks)
792  setup(*ik);
793  for (auto * const kernel : kernels)
794  setup(*kernel);
795 
796  // Clear variables
797  _fv_vars.clear();
798  _elem_sub_fv_vars.clear();
799  _neigh_sub_fv_vars.clear();
800 
801  // Clear kernels
802  _fv_flux_kernels.clear();
803  _elem_sub_fv_flux_kernels.clear();
804  _neigh_sub_fv_flux_kernels.clear();
805 
806  // Clear element face materials
807  _elem_face_mats.clear();
808  _elem_sub_elem_face_mats.clear();
809  _neigh_sub_elem_face_mats.clear();
810 
811  // Clear neighbor face materials
812  _neigh_face_mats.clear();
813  _elem_sub_neigh_face_mats.clear();
814  _neigh_sub_neigh_face_mats.clear();
815 }
816 
817 template <typename RangeType>
818 class ComputeFVFluxResidualThread : public ComputeFVFluxThread<RangeType, AttribVectorTags>
819 {
820 public:
822  const unsigned int nl_system_num,
823  const std::set<TagID> & tags,
824  bool on_displaced);
825 
827 
828 protected:
834 
835  void postFace(const FaceInfo & fi) override;
836  void compute(FVFaceResidualObject & ro, const FaceInfo & fi) override { ro.computeResidual(fi); }
837  void setup(SetupInterface & obj) override { obj.residualSetup(); }
838  void addCached() override { this->_subproblem.SubProblem::addCachedResidual(_tid); }
839 };
840 
841 template <typename RangeType>
843  FEProblemBase & fe_problem,
844  const unsigned int nl_system_num,
845  const std::set<TagID> & tags,
846  bool on_displaced)
847  : ComputeFVFluxThread<RangeType, AttribVectorTags>(fe_problem, nl_system_num, tags, on_displaced)
848 {
849 }
850 
851 template <typename RangeType>
854  : ComputeFVFluxThread<RangeType, AttribVectorTags>(x, split)
855 {
856 }
857 
858 template <typename RangeType>
859 void
861 {
862  _num_cached++;
863  // TODO: do we need both calls - or just the neighbor one? - confirm this
864  this->_subproblem.SubProblem::cacheResidual(_tid);
865  this->_subproblem.SubProblem::cacheResidualNeighbor(_tid);
866 
867  this->_subproblem.SubProblem::addCachedResidual(_tid);
868 }
869 
870 template <typename RangeType>
871 class ComputeFVFluxJacobianThread : public ComputeFVFluxThread<RangeType, AttribMatrixTags>
872 {
873 public:
875  const unsigned int nl_system_num,
876  const std::set<TagID> & tags,
877  bool on_displaced);
878 
880 
881 protected:
885 
886  void postFace(const FaceInfo & fi) override;
887  void compute(FVFaceResidualObject & ro, const FaceInfo & fi) override { ro.computeJacobian(fi); }
888  void setup(SetupInterface & obj) override { obj.jacobianSetup(); }
889  void addCached() override { this->_subproblem.SubProblem::addCachedJacobian(_tid); }
890 };
891 
892 template <typename RangeType>
894  FEProblemBase & fe_problem,
895  const unsigned int nl_system_num,
896  const std::set<TagID> & tags,
897  bool on_displaced)
898  : ComputeFVFluxThread<RangeType, AttribMatrixTags>(fe_problem, nl_system_num, tags, on_displaced)
899 {
900 }
901 
902 template <typename RangeType>
905  : ComputeFVFluxThread<RangeType, AttribMatrixTags>(x, split)
906 {
907 }
908 
909 template <typename RangeType>
910 void
912 {
913  _num_cached++;
914  // FV objects do not store their Jacobian data in TaggingInterface data structures; instead they
915  // add into the cache directly. So we do not need the same cache calls for the Jacobian that we
916  // need for the residual
917  if (_num_cached % 20 == 0)
918  {
919  Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
920  this->_subproblem.SubProblem::addCachedJacobian(_tid);
921  }
922 }
923 
924 template <typename RangeType>
925 class ComputeFVFluxRJThread : public ComputeFVFluxThread<RangeType, AttribVectorTags>
926 {
927 public:
929  const unsigned int nl_system_num,
930  const std::set<TagID> & vector_tags,
931  const std::set<TagID> & /*matrix_tags*/,
932  bool on_displaced);
933 
935 
936 protected:
940 
941  void postFace(const FaceInfo & fi) override;
942  void compute(FVFaceResidualObject & ro, const FaceInfo & fi) override
943  {
945  }
946  void setup(SetupInterface & obj) override { obj.residualSetup(); }
947  void addCached() override
948  {
949  this->_subproblem.SubProblem::addCachedResidual(_tid);
950  this->_subproblem.SubProblem::addCachedJacobian(_tid);
951  }
952 };
953 
954 template <typename RangeType>
956  const unsigned int nl_system_num,
957  const std::set<TagID> & vector_tags,
958  const std::set<TagID> & /*matrix_tags*/,
959  bool on_displaced)
961  fe_problem, nl_system_num, vector_tags, on_displaced)
962 {
963 }
964 
965 template <typename RangeType>
968  : ComputeFVFluxThread<RangeType, AttribVectorTags>(x, split)
969 {
970 }
971 
972 template <typename RangeType>
973 void
975 {
976  _num_cached++;
977  // TODO: do we need both calls - or just the neighbor one? - confirm this
978  this->_subproblem.SubProblem::cacheResidual(_tid);
979  this->_subproblem.SubProblem::cacheResidualNeighbor(_tid);
980  // FV objects do not store their Jacobian data in TaggingInterface data structures; instead they
981  // add into the cache directly. So we do not need the same cache calls for the Jacobian that we
982  // need for the residual
983  if (_num_cached % 20 == 0)
984  {
985  Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
986  this->_subproblem.SubProblem::addCachedResidual(_tid);
987  this->_subproblem.SubProblem::addCachedJacobian(_tid);
988  }
989 }
990 
991 template <typename RangeType, typename AttributeTagType>
992 void
994 {
995  if (!_fe_problem.shouldPrintExecution(_tid))
996  return;
997  auto & console = _fe_problem.console();
998  auto execute_on = _fe_problem.getCurrentExecuteOnFlag();
999  console << "[DBG] Beginning finite volume flux objects loop on " << execute_on << std::endl;
1000  mooseDoOnce(console << "[DBG] Loop on faces (FaceInfo), objects ordered on each face: "
1001  << std::endl;
1002  console << "[DBG] - (finite volume) flux kernels" << std::endl;
1003  console << "[DBG] - (finite volume) flux boundary conditions" << std::endl;
1004  console << "[DBG] - (finite volume) interface kernels" << std::endl;);
1005 }
1006 
1007 template <typename RangeType, typename AttributeTagType>
1008 void
1010 {
1011  if (!_fe_problem.shouldPrintExecution(_tid) || !_fv_flux_kernels.size())
1012  return;
1013 
1014  // Print the location of the execution
1015  const auto block_pair = std::make_pair(_subdomain, _neighbor_subdomain);
1016  const auto block_pair_names = this->getBlockNames();
1017  if (_blocks_exec_printed.count(block_pair))
1018  return;
1019  auto & console = _fe_problem.console();
1020  console << "[DBG] Flux kernels on block " << block_pair_names.first;
1021  if (_neighbor_subdomain != Moose::INVALID_BLOCK_ID)
1022  console << " and neighbor " << block_pair_names.second << std::endl;
1023  else
1024  console << " with no neighbor block" << std::endl;
1025 
1026  // Print the list of objects
1027  std::vector<MooseObject *> fv_flux_kernels;
1028  for (const auto & fv_kernel : _fv_flux_kernels)
1029  fv_flux_kernels.push_back(dynamic_cast<MooseObject *>(fv_kernel));
1031  "[DBG]")
1032  << std::endl;
1033  _blocks_exec_printed.insert(block_pair);
1034 }
1035 
1036 template <typename RangeType, typename AttributeTagType>
1037 void
1039  const BoundaryID bnd_id) const
1040 {
1041  if (!_fe_problem.shouldPrintExecution(_tid))
1042  return;
1043  if (_boundaries_exec_printed.count(bnd_id))
1044  return;
1045  std::vector<MooseObject *> bcs;
1046  _fe_problem.theWarehouse()
1047  .query()
1048  .template condition<AttribSystem>("FVFluxBC")
1049  .template condition<AttribDisplaced>(_on_displaced)
1050  .template condition<AttribThread>(_tid)
1051  .template condition<AttributeTagType>(_tags)
1052  .template condition<AttribBoundaries>(bnd_id)
1053  .queryInto(bcs);
1054 
1055  std::vector<MooseObject *> iks;
1056  _fe_problem.theWarehouse()
1057  .query()
1058  .template condition<AttribSystem>("FVInterfaceKernel")
1059  .template condition<AttribDisplaced>(_on_displaced)
1060  .template condition<AttribThread>(_tid)
1061  .template condition<AttributeTagType>(_tags)
1062  .template condition<AttribBoundaries>(bnd_id)
1063  .queryInto(iks);
1064 
1065  const auto block_pair_names = this->getBlockNames();
1066  if (bcs.size())
1067  {
1068  auto & console = _fe_problem.console();
1069  console << "[DBG] FVBCs on boundary " << bnd_id << " between subdomain "
1070  << block_pair_names.first;
1071  if (_neighbor_subdomain != Moose::INVALID_BLOCK_ID)
1072  console << " and neighbor " << block_pair_names.second << std::endl;
1073  else
1074  console << " and the exterior of the mesh " << std::endl;
1075  const std::string fv_bcs = ConsoleUtils::mooseObjectVectorToString(bcs);
1076  console << ConsoleUtils::formatString(fv_bcs, "[DBG]") << std::endl;
1077  }
1078  if (iks.size())
1079  {
1080  auto & console = _fe_problem.console();
1081  console << "[DBG] FVIKs on boundary " << bnd_id << " between subdomain "
1082  << block_pair_names.first;
1083  if (_neighbor_subdomain != Moose::INVALID_BLOCK_ID)
1084  console << " and neighbor " << block_pair_names.second << std::endl;
1085  else
1086  console << " and the exterior of the mesh " << std::endl;
1087  const std::string fv_iks = ConsoleUtils::mooseObjectVectorToString(iks);
1088  console << ConsoleUtils::formatString(fv_iks, "[DBG]") << std::endl;
1089  }
1090  _boundaries_exec_printed.insert(bnd_id);
1091 }
1092 
1093 template <typename RangeType, typename AttributeTagType>
1094 std::pair<SubdomainName, SubdomainName>
1096 {
1097  auto block_names = std::make_pair(_mesh.getSubdomainName(_subdomain),
1098  _mesh.getSubdomainName(_neighbor_subdomain));
1099  if (block_names.first == "")
1100  block_names.first = Moose::stringify(_subdomain);
1101  if (block_names.second == "")
1102  block_names.second = Moose::stringify(_neighbor_subdomain);
1103  return block_names;
1104 }
void setup(SetupInterface &obj) override
call either residualSetup or jacobianSetup depending on what derived class of this class is instantia...
void compute(FVFaceResidualObject &ro, const FaceInfo &fi) override
call either computeResidual, computeJacobian, or computeResidualAndJacobian on the provided residual ...
virtual void post() override
This is called once after all face-looping is finished.
void postFace(const FaceInfo &fi) override
This is called once for each face after all face and boundary callbacks have been finished for that f...
std::vector< std::shared_ptr< MaterialBase > > _neigh_face_mats
const bool _incoming_throw_on_error
The value of Moose::_throw_on_error at the time of construction.
std::string mooseObjectVectorToString(const std::vector< MooseObject *> &objs, const std::string &sep=" ")
Routine to output the name of MooseObjects in a string.
Definition: ConsoleUtils.C:597
KOKKOS_INLINE_FUNCTION const T * find(const T &target, const T *const begin, const T *const end)
Find a value in an array.
Definition: KokkosUtils.h:42
virtual void neighborSubdomainChanged() override
Called every time the neighbor subdomain changes (i.e.
virtual void computeResidualAndJacobian(const FaceInfo &fi)=0
Compute the residual and Jacobian on the supplied face.
void setup(SetupInterface &obj) override
call either residualSetup or jacobianSetup depending on what derived class of this class is instantia...
const unsigned int _nl_system_num
std::set< FVFluxKernel * > _neigh_sub_fv_flux_kernels
ComputeFVFluxRJThread(FEProblemBase &fe_problem, const unsigned int nl_system_num, const std::set< TagID > &vector_tags, const std::set< TagID > &, bool on_displaced)
virtual const char * what() const
Get out the error message.
std::vector< std::shared_ptr< MaterialBase > > _neigh_sub_neigh_face_mats
std::string _error_message
Holds caught runtime error messages.
std::set< BoundaryID > _boundaries_exec_printed
Set to keep track of boundaries for which we have printed the execution pattern.
virtual void computeResidual(const FaceInfo &fi)=0
Compute the residual on the supplied face.
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:323
std::vector< std::shared_ptr< MaterialBase > > _elem_sub_neigh_face_mats
virtual void computeJacobian(const FaceInfo &fi)=0
Compute the jacobian on the supplied face.
const bool _zeroth_copy
Whether this is the zeroth threaded copy of this body.
void compute(FVFaceResidualObject &ro, const FaceInfo &fi) override
call either computeResidual, computeJacobian, or computeResidualAndJacobian on the provided residual ...
FEProblemBase & _fe_problem
void translateMetaPhysicLError(const MetaPhysicL::LogicError &)
emit a relatively clear error message when we catch a MetaPhysicL logic error
Definition: MooseError.C:141
SubdomainID _subdomain
The subdomain for the current element.
virtual void postFace(const FaceInfo &)
This is called once for each face after all face and boundary callbacks have been finished for that f...
virtual void printBoundaryExecutionInformation(const BoundaryID bnd_id) const override
Print ordering of objects exected on each boundary.
void resetExecutionPrinting()
Reset lists of blocks and boundaries for which execution printing has been done.
virtual void setException(const std::string &message)
Set an exception, which is stored at this point by toggling a member variable in this class...
std::vector< std::shared_ptr< MaterialBase > > _neigh_sub_elem_face_mats
std::set< MooseVariableFieldBase * > _neigh_sub_fv_vars
MeshBase & mesh
Interface class for a finite volume residual object whose residuals are based on faces.
void postFace(const FaceInfo &fi) override
This is called once for each face after all face and boundary callbacks have been finished for that f...
virtual void onBoundary(const FaceInfo &fi, BoundaryID boundary) override
This is called once for every face that is on a boundary after onFace is called for the face...
void compute(FVFaceResidualObject &ro, const FaceInfo &fi) override
call either computeResidual, computeJacobian, or computeResidualAndJacobian on the provided residual ...
ThreadedFaceLoop(FEProblemBase &fe_problem, const unsigned int nl_system_num, const std::set< TagID > &tags, bool on_displaced)
ComputeFVFluxThread(FEProblemBase &fe_problem, const unsigned int nl_system_num, const std::set< TagID > &tags, bool on_displaced)
virtual void post()
This is called once after all face-looping is finished.
virtual void printBoundaryExecutionInformation(const BoundaryID) const
Print ordering of objects exected on each boundary.
std::function< void()> _f
std::pair< SubdomainName, SubdomainName > getBlockNames() const
Utility to get the subdomain names from the ids.
Specialization of SubProblem for solving nonlinear equations plus auxiliary equations.
virtual void compute(FVFaceResidualObject &ro, const FaceInfo &fi)=0
call either computeResidual, computeJacobian, or computeResidualAndJacobian on the provided residual ...
const std::set< TagID > & _tags
SubdomainID _neighbor_subdomain
The subdomain for the current neighbor.
const SubdomainID INVALID_BLOCK_ID
Definition: MooseTypes.C:20
virtual void neighborSubdomainChanged()
Called every time the neighbor subdomain changes (i.e.
virtual void onBoundary(const FaceInfo &fi, BoundaryID boundary)=0
This is called once for every face that is on a boundary after onFace is called for the face...
This data structure is used to store geometric and variable related metadata about each cell face in ...
Definition: FaceInfo.h:36
Base class for assembly-like calculations.
const Elem * neighborPtr() const
Definition: FaceInfo.h:84
ComputeFVFluxResidualThread(FEProblemBase &fe_problem, const unsigned int nl_system_num, const std::set< TagID > &tags, bool on_displaced)
std::string formatString(std::string message, const std::string &prefix)
Add new lines and prefixes to a string for pretty display in output NOTE: This makes a copy of the st...
Definition: ConsoleUtils.C:581
boundary_id_type BoundaryID
This works like the Sentinel helper classes in MOOSE, except it is more flexible and concise to use...
MooseMesh wraps a libMesh::Mesh object and enhances its capabilities by caching additional data and s...
Definition: MooseMesh.h:92
ComputeFVFluxJacobianThread(FEProblemBase &fe_problem, const unsigned int nl_system_num, const std::set< TagID > &tags, bool on_displaced)
OnScopeExit(OnScopeExit &&other)
std::vector< std::shared_ptr< MaterialBase > > _elem_face_mats
Element face materials.
SubProblem & _subproblem
FEProblemBase or DisplacedProblem depending on _on_displaced.
virtual void printGeneralExecutionInformation() const
Print list of object types executed and in which order.
std::vector< std::shared_ptr< MaterialBase > > _elem_sub_elem_face_mats
std::string stringify(const T &t)
conversion to string
Definition: Conversion.h:64
virtual void pre()
This is called once before all face-looping.
virtual void onFace(const FaceInfo &fi)=0
virtual void printGeneralExecutionInformation() const override
Print list of object types executed and in which order.
std::set< FVFluxKernel * > _fv_flux_kernels
FVFluxKernels.
std::set< MooseVariableFieldBase * > _elem_sub_fv_vars
virtual void operator()(const RangeType &range, bool bypass_threading=false)
std::set< MooseVariableFieldBase * > _fv_vars
Variables.
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
tbb::split split
std::set< FVFluxKernel * > _elem_sub_fv_flux_kernels
void postFace(const FaceInfo &fi) override
This is called once for each face after all face and boundary callbacks have been finished for that f...
This loops over a set of mesh faces (i.e.
void addCached() override
call either addCachedJacobian or addCachedResidual or both depending on what derived class of this cl...
Provides a way for users to bail out of the current solve.
virtual void setup(SetupInterface &obj)=0
call either residualSetup or jacobianSetup depending on what derived class of this class is instantia...
void setup(SetupInterface &obj) override
call either residualSetup or jacobianSetup depending on what derived class of this class is instantia...
Generic class for solving transient nonlinear problems.
Definition: SubProblem.h:78
void caughtMooseException(MooseException &e)
Called if a MooseException is caught anywhere during the computation.
virtual void subdomainSetup(SubdomainID subdomain, const THREAD_ID tid)
OnScopeExit & operator=(OnScopeExit &&other)
void setup(EquationSystems &systems, Mesh &mesh, GetPot &args)
virtual void subdomainChanged()
Called every time the current subdomain changes (i.e.
const bool _on_displaced
Whether this loop is operating on the displaced mesh.
static Threads::spin_mutex threaded_element_mutex
This mutex is used by all derived classes of the ThreadedElementLoop.
virtual void subdomainChanged() override
Called every time the current subdomain changes (i.e.
virtual void onFace(const FaceInfo &fi) override
MOOSE now contains C++17 code, so give a reasonable error message stating what the user can do to add...
void join(const ThreadedFaceLoop &y)
void addCached() override
call either addCachedJacobian or addCachedResidual or both depending on what derived class of this cl...
void reinitVariables(const FaceInfo &fi)
virtual void printBlockExecutionInformation() const
Print ordering of objects executed on each block.
virtual void addCached()=0
call either addCachedJacobian or addCachedResidual or both depending on what derived class of this cl...
virtual void jacobianSetup()
Gets called just before the Jacobian is computed and before this object is asked to do its job...
virtual void pre() override
This is called once before all face-looping.
OnScopeExit(std::function< void()> f) noexcept
virtual void residualSetup()
Gets called just before the residual is computed and before this object is asked to do its job...
virtual void printBlockExecutionInformation() const override
Print ordering of objects executed on each block.
bool _throw_on_error
Variable to turn on exceptions during mooseError(), should only be used within MOOSE unit tests or wh...
Definition: Moose.C:797
std::set< std::pair< const SubdomainID, const SubdomainID > > _blocks_exec_printed
Set to keep track of blocks for which we have printed the execution pattern.
SubdomainID _old_subdomain
The subdomain for the last element.
unsigned int THREAD_ID
Definition: MooseTypes.h:237
SubdomainID _old_neighbor_subdomain
The subdomain for the last neighbor.
virtual void neighborSubdomainSetup(SubdomainID subdomain, const THREAD_ID tid)
void addCached() override
call either addCachedJacobian or addCachedResidual or both depending on what derived class of this cl...