https://mooseframework.inl.gov
Loading...
Searching...
No Matches
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"
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
31class 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
74template <typename RangeType>
76{
77public:
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
114
117 {
118 Threads::spin_mutex::scoped_lock lock(threaded_element_mutex);
119 std::string what(e.what());
121 }
122
123protected:
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();
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
173private:
175 const bool _zeroth_copy;
176
180};
181
182template <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{
198}
199
200template <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
213template <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
225template <typename RangeType>
226void
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.
239template <typename RangeType>
240void
241ThreadedFaceLoop<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
352template <typename RangeType, typename AttributeTagType>
353class ComputeFVFluxThread : public ThreadedFaceLoop<RangeType>
354{
355public:
357 const unsigned int nl_system_num,
358 const std::set<TagID> & tags,
359 bool on_displaced);
360
362
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
374protected:
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
395 using ThreadedFaceLoop<RangeType>::_fe_problem;
396 using ThreadedFaceLoop<RangeType>::_mesh;
397 using ThreadedFaceLoop<RangeType>::_tid;
398 using ThreadedFaceLoop<RangeType>::_tags;
399 using ThreadedFaceLoop<RangeType>::_nl_system_num;
400 using ThreadedFaceLoop<RangeType>::_on_displaced;
401 using ThreadedFaceLoop<RangeType>::_subdomain;
405
406private:
407 void reinitVariables(const FaceInfo & fi);
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
444};
445
446template <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
457template <typename RangeType, typename AttributeTagType>
459 Threads::split split)
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
467template <typename RangeType, typename AttributeTagType>
471
472template <typename RangeType, typename AttributeTagType>
473void
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
518template <typename RangeType, typename AttributeTagType>
519void
521{
522 reinitVariables(fi);
523
524 for (auto * const k : _fv_flux_kernels)
525 compute(*k, fi);
526}
527
528template <typename RangeType, typename AttributeTagType>
529void
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
564template <typename RangeType, typename AttributeTagType>
565void
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
576template <typename RangeType, typename AttributeTagType>
577void
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
632template <typename RangeType, typename AttributeTagType>
633void
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
692template <typename RangeType, typename AttributeTagType>
693void
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
755template <typename RangeType, typename AttributeTagType>
756void
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
817template <typename RangeType>
818class ComputeFVFluxResidualThread : public ComputeFVFluxThread<RangeType, AttribVectorTags>
819{
820public:
822 const unsigned int nl_system_num,
823 const std::set<TagID> & tags,
824 bool on_displaced);
825
827
828protected:
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
841template <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
851template <typename RangeType>
857
858template <typename RangeType>
859void
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
870template <typename RangeType>
871class ComputeFVFluxJacobianThread : public ComputeFVFluxThread<RangeType, AttribMatrixTags>
872{
873public:
875 const unsigned int nl_system_num,
876 const std::set<TagID> & tags,
877 bool on_displaced);
878
880
881protected:
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
892template <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
902template <typename RangeType>
908
909template <typename RangeType>
910void
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
924template <typename RangeType>
925class ComputeFVFluxRJThread : public ComputeFVFluxThread<RangeType, AttribVectorTags>
926{
927public:
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
936protected:
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
954template <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
965template <typename RangeType>
971
972template <typename RangeType>
973void
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
991template <typename RangeType, typename AttributeTagType>
992void
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
1007template <typename RangeType, typename AttributeTagType>
1008void
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
1036template <typename RangeType, typename AttributeTagType>
1037void
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
1093template <typename RangeType, typename AttributeTagType>
1094std::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}
boundary_id_type BoundaryID
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
Definition MooseError.h:311
unsigned int THREAD_ID
Definition MooseTypes.h:237
static Threads::spin_mutex threaded_element_mutex
This mutex is used by all derived classes of the ThreadedElementLoop.
void addCached() override
call either addCachedJacobian or addCachedResidual or both depending on what derived class of this cl...
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...
void setup(SetupInterface &obj) override
call either residualSetup or jacobianSetup depending on what derived class of this class is instantia...
ComputeFVFluxJacobianThread(FEProblemBase &fe_problem, const unsigned int nl_system_num, const std::set< TagID > &tags, bool on_displaced)
void compute(FVFaceResidualObject &ro, const FaceInfo &fi) override
call either computeResidual, computeJacobian, or computeResidualAndJacobian on the provided residual ...
void compute(FVFaceResidualObject &ro, const FaceInfo &fi) override
call either computeResidual, computeJacobian, or computeResidualAndJacobian on the provided residual ...
void setup(SetupInterface &obj) override
call either residualSetup or jacobianSetup depending on what derived class of this class is instantia...
ComputeFVFluxRJThread(FEProblemBase &fe_problem, const unsigned int nl_system_num, const std::set< TagID > &vector_tags, const std::set< TagID > &, bool on_displaced)
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...
void addCached() override
call either addCachedJacobian or addCachedResidual or both depending on what derived class of this cl...
void addCached() override
call either addCachedJacobian or addCachedResidual or both depending on what derived class of this cl...
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...
void compute(FVFaceResidualObject &ro, const FaceInfo &fi) override
call either computeResidual, computeJacobian, or computeResidualAndJacobian on the provided residual ...
ComputeFVFluxResidualThread(FEProblemBase &fe_problem, const unsigned int nl_system_num, const std::set< TagID > &tags, bool on_displaced)
void setup(SetupInterface &obj) override
call either residualSetup or jacobianSetup depending on what derived class of this class is instantia...
Base class for assembly-like calculations.
void reinitVariables(const FaceInfo &fi)
std::vector< std::shared_ptr< MaterialBase > > _elem_face_mats
Element face materials.
ComputeFVFluxThread(ComputeFVFluxThread &x, Threads::split split)
virtual void pre() override
This is called once before all face-looping.
virtual void subdomainChanged() override
Called every time the current subdomain changes (i.e.
std::vector< std::shared_ptr< MaterialBase > > _neigh_sub_elem_face_mats
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.
virtual void addCached()=0
call either addCachedJacobian or addCachedResidual or both depending on what derived class of this cl...
std::set< MooseVariableFieldBase * > _neigh_sub_fv_vars
ComputeFVFluxThread(FEProblemBase &fe_problem, const unsigned int nl_system_num, const std::set< TagID > &tags, bool on_displaced)
virtual void setup(SetupInterface &obj)=0
call either residualSetup or jacobianSetup depending on what derived class of this class is instantia...
std::vector< std::shared_ptr< MaterialBase > > _elem_sub_elem_face_mats
virtual void printGeneralExecutionInformation() const override
Print list of object types executed and in which order.
std::pair< SubdomainName, SubdomainName > getBlockNames() const
Utility to get the subdomain names from the ids.
std::set< FVFluxKernel * > _fv_flux_kernels
FVFluxKernels.
virtual void neighborSubdomainChanged() override
Called every time the neighbor subdomain changes (i.e.
std::set< MooseVariableFieldBase * > _fv_vars
Variables.
virtual void printBlockExecutionInformation() const override
Print ordering of objects executed on each block.
std::set< FVFluxKernel * > _neigh_sub_fv_flux_kernels
std::set< MooseVariableFieldBase * > _elem_sub_fv_vars
std::vector< std::shared_ptr< MaterialBase > > _neigh_face_mats
virtual void compute(FVFaceResidualObject &ro, const FaceInfo &fi)=0
call either computeResidual, computeJacobian, or computeResidualAndJacobian on the provided residual ...
virtual void onFace(const FaceInfo &fi) override
virtual void printBoundaryExecutionInformation(const BoundaryID bnd_id) const override
Print ordering of objects exected on each boundary.
std::vector< std::shared_ptr< MaterialBase > > _neigh_sub_neigh_face_mats
std::vector< std::shared_ptr< MaterialBase > > _elem_sub_neigh_face_mats
virtual void post() override
This is called once after all face-looping is finished.
std::set< FVFluxKernel * > _elem_sub_fv_flux_kernels
Specialization of SubProblem for solving nonlinear equations plus auxiliary equations.
virtual void neighborSubdomainSetup(SubdomainID subdomain, const THREAD_ID tid)
virtual void setException(const std::string &message)
Set an exception, which is stored at this point by toggling a member variable in this class,...
virtual void subdomainSetup(SubdomainID subdomain, const THREAD_ID tid)
Interface class for a finite volume residual object whose residuals are based on faces.
virtual void computeResidualAndJacobian(const FaceInfo &fi)=0
Compute the residual and Jacobian on the supplied face.
virtual void computeJacobian(const FaceInfo &fi)=0
Compute the jacobian on the supplied face.
virtual void computeResidual(const FaceInfo &fi)=0
Compute the residual on the supplied face.
This data structure is used to store geometric and variable related metadata about each cell face in ...
Definition FaceInfo.h:38
const Elem * neighborPtr() const
Definition FaceInfo.h:88
Provides a way for users to bail out of the current solve.
virtual const char * what() const
Get out the error message.
MooseMesh wraps a libMesh::Mesh object and enhances its capabilities by caching additional data and s...
Definition MooseMesh.h:95
Every object that can be built by the factory should be derived from this class.
Definition MooseObject.h:31
virtual void residualSetup()
Gets called just before the residual is computed and before this object is asked to do its job.
virtual void jacobianSetup()
Gets called just before the Jacobian is computed and before this object is asked to do its job.
Generic class for solving transient nonlinear problems.
Definition SubProblem.h:79
This loops over a set of mesh faces (i.e.
virtual void subdomainChanged()
Called every time the current subdomain changes (i.e.
SubdomainID _old_subdomain
The subdomain for the last element.
virtual void post()
This is called once after all face-looping is finished.
FEProblemBase & _fe_problem
virtual void printBlockExecutionInformation() const
Print ordering of objects executed on each block.
virtual void pre()
This is called once before all face-looping.
const bool _incoming_throw_on_error
The value of Moose::_throw_on_error at the time of construction.
SubdomainID _subdomain
The subdomain for the current element.
const bool _zeroth_copy
Whether this is the zeroth threaded copy of this body.
virtual void postFace(const FaceInfo &)
This is called once for each face after all face and boundary callbacks have been finished for that f...
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.
const unsigned int _nl_system_num
virtual void printBoundaryExecutionInformation(const BoundaryID) const
Print ordering of objects exected on each boundary.
SubdomainID _neighbor_subdomain
The subdomain for the current neighbor.
std::set< BoundaryID > _boundaries_exec_printed
Set to keep track of boundaries for which we have printed the execution pattern.
void join(const ThreadedFaceLoop &y)
ThreadedFaceLoop(FEProblemBase &fe_problem, const unsigned int nl_system_num, const std::set< TagID > &tags, bool on_displaced)
virtual void onFace(const FaceInfo &fi)=0
const std::set< TagID > & _tags
virtual void operator()(const RangeType &range, bool bypass_threading=false)
const bool _on_displaced
Whether this loop is operating on the displaced mesh.
virtual void printGeneralExecutionInformation() const
Print list of object types executed and in which order.
std::string _error_message
Holds caught runtime error messages.
void caughtMooseException(MooseException &e)
Called if a MooseException is caught anywhere during the computation.
SubProblem & _subproblem
FEProblemBase or DisplacedProblem depending on _on_displaced.
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.
SubdomainID _old_neighbor_subdomain
The subdomain for the last neighbor.
void resetExecutionPrinting()
Reset lists of blocks and boundaries for which execution printing has been done.
virtual void neighborSubdomainChanged()
Called every time the neighbor subdomain changes (i.e.
void setup(EquationSystems &systems, Mesh &mesh, GetPot &args)
MeshBase & mesh
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...
std::string mooseObjectVectorToString(const std::vector< MooseObject * > &objs, const std::string &sep=" ")
Routine to output the name of MooseObjects in a string.
MOOSE now contains C++17 code, so give a reasonable error message stating what the user can do to add...
bool _throw_on_error
Variable to turn on exceptions during mooseError(), should only be used within MOOSE unit tests or wh...
Definition Moose.C:896
std::string stringify(const T &t)
conversion to string
Definition Conversion.h:64
@ NEIGHBOR_MATERIAL_DATA
Definition MooseTypes.h:750
@ FACE_MATERIAL_DATA
Definition MooseTypes.h:749
const SubdomainID INVALID_BLOCK_ID
Definition MooseTypes.C:20
spin_mutex spin_mtx
void translateMetaPhysicLError(const MetaPhysicL::LogicError &)
emit a relatively clear error message when we catch a MetaPhysicL logic error
Definition MooseError.C:155
This works like the Sentinel helper classes in MOOSE, except it is more flexible and concise to use.
OnScopeExit & operator=(OnScopeExit &&other)
OnScopeExit(std::function< void()> f) noexcept
std::function< void()> _f
OnScopeExit(OnScopeExit &&other)