fvbasediscretization.hh
Go to the documentation of this file.
1// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2// vi: set et ts=4 sw=4 sts=4:
3/*
4 This file is part of the Open Porous Media project (OPM).
5
6 OPM is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 2 of the License, or
9 (at your option) any later version.
10
11 OPM is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with OPM. If not, see <http://www.gnu.org/licenses/>.
18
19 Consult the COPYING file in the top-level source directory of this
20 module for the precise wording of the license and the list of
21 copyright holders.
22*/
28#ifndef EWOMS_FV_BASE_DISCRETIZATION_HH
29#define EWOMS_FV_BASE_DISCRETIZATION_HH
30
31#include <dune/common/fmatrix.hh>
32#include <dune/common/fvector.hh>
33#include <dune/common/version.hh>
34#include <dune/istl/bvector.hh>
35
36#include <opm/material/common/MathToolbox.hpp>
37#include <opm/material/common/Valgrind.hpp>
38#include <opm/material/densead/Math.hpp>
39
53
55
58
63
66
67#include <algorithm>
68#include <array>
69#include <cstddef>
70#include <exception>
71#include <list>
72#include <memory>
73#include <mutex>
74#include <stdexcept>
75#include <sstream>
76#include <string>
77#include <type_traits>
78#include <utility>
79#include <vector>
80
81namespace Opm {
82
83template<class TypeTag>
84class FvBaseDiscretizationNoAdapt;
85
86template<class TypeTag>
87class FvBaseDiscretization;
88
89} // namespace Opm
90
91namespace Opm::Properties {
92
94template<class TypeTag>
95struct Simulator<TypeTag, TTag::FvBaseDiscretization>
97
99template<class TypeTag>
100struct VertexMapper<TypeTag, TTag::FvBaseDiscretization>
101{ using type = Dune::MultipleCodimMultipleGeomTypeMapper<GetPropType<TypeTag, Properties::GridView>>; };
102
104template<class TypeTag>
106{ using type = Dune::MultipleCodimMultipleGeomTypeMapper<GetPropType<TypeTag, Properties::GridView>>; };
107
109template<class TypeTag>
111{
114
115public:
117};
118
119template<class TypeTag>
122
123template<class TypeTag>
126
127template<class TypeTag>
130
132template<class TypeTag>
135
139template<class TypeTag>
140struct EqVector<TypeTag, TTag::FvBaseDiscretization>
141{
142 using type = Dune::FieldVector<GetPropType<TypeTag, Properties::Scalar>,
143 getPropValue<TypeTag, Properties::NumEq>()>;
144};
145
151template<class TypeTag>
152struct RateVector<TypeTag, TTag::FvBaseDiscretization>
154
158template<class TypeTag>
161
165template<class TypeTag>
166struct Constraints<TypeTag, TTag::FvBaseDiscretization>
168
172template<class TypeTag>
174{ using type = Dune::BlockVector<GetPropType<TypeTag, Properties::EqVector>>; };
175
179template<class TypeTag>
181{ using type = Dune::BlockVector<GetPropType<TypeTag, Properties::EqVector>>; };
182
186template<class TypeTag>
189
193template<class TypeTag>
195{ using type = Dune::BlockVector<GetPropType<TypeTag, Properties::PrimaryVariables>>; };
196
202template<class TypeTag>
205
209template<class TypeTag>
212
213template<class TypeTag>
216
217template<class TypeTag>
220
224template<class TypeTag>
227
228template<class TypeTag>
230{ static constexpr bool value = true; };
231
235template<class TypeTag>
236struct Linearizer<TypeTag, TTag::FvBaseDiscretization>
238
240template<class TypeTag>
242{ static constexpr auto value = Dune::VTK::ascii; };
243
244// disable constraints by default
245template<class TypeTag>
247{ static constexpr bool value = false; };
248
250template<class TypeTag>
252{ static constexpr int value = 2; };
253
256template<class TypeTag>
258{ static constexpr bool value = false; };
259
260// use volumetric residuals is default
261template<class TypeTag>
263{ static constexpr bool value = true; };
264
267template<class TypeTag>
269{ static constexpr bool value = true; };
270
271template <class TypeTag, class MyTypeTag>
273
274#if !HAVE_DUNE_FEM
275template<class TypeTag>
278
279template<class TypeTag>
281{
284};
285#endif
286
287} // namespace Opm::Properties
288
289namespace Opm {
290
296template<class TypeTag>
298{
299 using Implementation = GetPropType<TypeTag, Properties::Model>;
326
329
330 enum {
331 numEq = getPropValue<TypeTag, Properties::NumEq>(),
332 historySize = getPropValue<TypeTag, Properties::TimeDiscHistorySize>(),
333 };
334
335 using IntensiveQuantitiesVector = std::vector<IntensiveQuantities,
336 aligned_allocator<IntensiveQuantities,
337 alignof(IntensiveQuantities)>>;
338
339 using Element = typename GridView::template Codim<0>::Entity;
340 using ElementIterator = typename GridView::template Codim<0>::Iterator;
341
342 using Toolbox = MathToolbox<Evaluation>;
343 using VectorBlock = Dune::FieldVector<Evaluation, numEq>;
344 using EvalEqVector = Dune::FieldVector<Evaluation, numEq>;
345
346 using LocalEvalBlockVector = typename LocalResidual::LocalEvalBlockVector;
347
348public:
350 {
351 protected:
352 SolutionVector blockVector_;
353 public:
354 BlockVectorWrapper(const std::string&, const std::size_t size)
355 : blockVector_(size)
356 {}
357
359
361 {
362 BlockVectorWrapper result("dummy", 3);
363 result.blockVector_[0] = 1.0;
364 result.blockVector_[1] = 2.0;
365 result.blockVector_[2] = 3.0;
366
367 return result;
368 }
369
370 SolutionVector& blockVector()
371 { return blockVector_; }
372
373 const SolutionVector& blockVector() const
374 { return blockVector_; }
375
376 bool operator==(const BlockVectorWrapper& wrapper) const
377 {
378 return std::ranges::equal(this->blockVector_, wrapper.blockVector_);
379 }
380
381 template<class Serializer>
382 void serializeOp(Serializer& serializer)
383 {
384 serializer(blockVector_);
385 }
386 };
387
388private:
391
392public:
393 explicit FvBaseDiscretization(Simulator& simulator)
394 : simulator_(simulator)
395 , gridView_(simulator.gridView())
396 , elementMapper_(gridView_, Dune::mcmgElementLayout())
397 , vertexMapper_(gridView_, Dune::mcmgVertexLayout())
398 , newtonMethod_(simulator)
399 , localLinearizer_(ThreadManager::maxThreads())
400 , linearizer_(std::make_unique<Linearizer>())
401 , enableGridAdaptation_(Parameters::Get<Parameters::EnableGridAdaptation>() )
402 , enableIntensiveQuantityCache_(Parameters::Get<Parameters::EnableIntensiveQuantityCache>())
403 , enableStorageCache_(Parameters::Get<Parameters::EnableStorageCache>())
404 , enableThermodynamicHints_(Parameters::Get<Parameters::EnableThermodynamicHints>())
405 , cachedIntensiveQuantityHistorySize_(static_cast<unsigned>(-1))
406 {
407 const bool isEcfv = std::is_same_v<Discretization, EcfvDiscretization<TypeTag>>;
408 if (enableGridAdaptation_ && !isEcfv) {
409 throw std::invalid_argument("Grid adaptation currently only works for the "
410 "element-centered finite volume discretization (is: " +
411 Dune::className<Discretization>() + ")");
412 }
413
414 PrimaryVariables::init();
415 // Setting up the intensive quantities cache and storage cache is done in finishInit()
416 // and applyInitialSolution() to ensure that the history size is correct.
417 asImp_().registerOutputModules_();
418 }
419
420 // copying a discretization object is not a good idea
422
426 static void registerParameters()
427 {
428 Linearizer::registerParameters();
429 LocalLinearizer::registerParameters();
430 LocalResidual::registerParameters();
431 GradientCalculator::registerParameters();
432 IntensiveQuantities::registerParameters();
433 ExtensiveQuantities::registerParameters();
435 Linearizer::registerParameters();
436 PrimaryVariables::registerParameters();
437 // register runtime parameters of the output modules
439
440 Parameters::Register<Parameters::EnableGridAdaptation>
441 ("Enable adaptive grid refinement/coarsening");
442 Parameters::Register<Parameters::EnableVtkOutput>
443 ("Global switch for turning on writing VTK files");
444 Parameters::Register<Parameters::EnableThermodynamicHints>
445 ("Enable thermodynamic hints");
446 Parameters::Register<Parameters::EnableIntensiveQuantityCache>
447 ("Turn on caching of intensive quantities");
448 Parameters::Register<Parameters::EnableStorageCache>
449 ("Store previous storage terms and avoid re-calculating them.");
450 Parameters::Register<Parameters::OutputDir>
451 ("The directory to which result files are written");
452 }
453
458 {
459 // initialize the volume of the finite volumes to zero
460 const std::size_t numDof = asImp_().numGridDof();
461 dofTotalVolume_.resize(numDof);
462 std::ranges::fill(dofTotalVolume_, 0.0);
463
464 ElementContext elemCtx(simulator_);
465 gridTotalVolume_ = 0.0;
466
467 // iterate through the grid and evaluate the initial condition
468 for (const auto& elem : elements(gridView_)) {
469 // ignore everything which is not in the interior if the
470 // current process' piece of the grid
471 if (elem.partitionType() != Dune::InteriorEntity) {
472 continue;
473 }
474
475 // deal with the current element
476 elemCtx.updateStencil(elem);
477 const auto& stencil = elemCtx.stencil(/*timeIdx=*/0);
478
479 // loop over all element vertices, i.e. sub control volumes
480 for (unsigned dofIdx = 0; dofIdx < elemCtx.numPrimaryDof(/*timeIdx=*/0); dofIdx++) {
481 // map the local degree of freedom index to the global one
482 const unsigned globalIdx = elemCtx.globalSpaceIndex(dofIdx, /*timeIdx=*/0);
483
484 const Scalar dofVolume = stencil.subControlVolume(dofIdx).volume();
485 dofTotalVolume_[globalIdx] += dofVolume;
486 gridTotalVolume_ += dofVolume;
487 }
488 }
489
490 // determine which DOFs should be considered to lie fully in the interior of the
491 // local process grid partition: those which do not have a non-zero volume
492 // before taking the peer processes into account...
493 isLocalDof_.resize(numDof);
494 for (unsigned dofIdx = 0; dofIdx < numDof; ++dofIdx) {
495 isLocalDof_[dofIdx] = (dofTotalVolume_[dofIdx] != 0.0);
496 }
497
498 // add the volumes of the DOFs on the process boundaries
499 const auto sumHandle =
500 GridCommHandleFactory::template sumHandle<Scalar>(dofTotalVolume_,
501 asImp_().dofMapper());
502 gridView_.communicate(*sumHandle,
503 Dune::InteriorBorder_All_Interface,
504 Dune::ForwardCommunication);
505
506 // sum up the volumes of the grid partitions
508
509 linearizer_->init(simulator_);
510 for (unsigned threadId = 0; threadId < ThreadManager::maxThreads(); ++threadId) {
511 localLinearizer_[threadId].init(simulator_);
512 }
513
515
516 newtonMethod_.finishInit();
517 }
518
523 { return enableGridAdaptation_; }
524
530 {
531 // first set the whole domain to zero
532 SolutionVector& uCur = asImp_().solution(/*timeIdx=*/0);
533 uCur = Scalar(0.0);
534
535 ElementContext elemCtx(simulator_);
536
537 // iterate through the grid and evaluate the initial condition
538 for (const auto& elem : elements(gridView_)) {
539 // ignore everything which is not in the interior if the
540 // current process' piece of the grid
541 if (elem.partitionType() != Dune::InteriorEntity) {
542 continue;
543 }
544
545 // deal with the current element
546 elemCtx.updateStencil(elem);
547
548 // loop over all element vertices, i.e. sub control volumes
549 for (unsigned dofIdx = 0; dofIdx < elemCtx.numPrimaryDof(/*timeIdx=*/0); ++dofIdx) {
550 // map the local degree of freedom index to the global one
551 const unsigned globalIdx = elemCtx.globalSpaceIndex(dofIdx, /*timeIdx=*/0);
552
553 // let the problem do the dirty work of nailing down
554 // the initial solution.
555 simulator_.problem().initial(uCur[globalIdx], elemCtx, dofIdx, /*timeIdx=*/0);
556 asImp_().supplementInitialSolution_(uCur[globalIdx], elemCtx, dofIdx, /*timeIdx=*/0);
557 uCur[globalIdx].checkDefined();
558 }
559 }
560
561 // synchronize the ghost DOFs (if necessary)
562 asImp_().syncOverlap();
563
564 // also set the solutions of the "previous" time steps to the initial solution.
565 for (unsigned timeIdx = 1; timeIdx < historySize; ++timeIdx) {
566 solution(timeIdx) = solution(/*timeIdx=*/0);
567 }
568
569 // Initialize intensive quantities cache now that all problem-specific parameters are available.
570 // This ensures intensiveQuantityHistorySize is correct based on recycleFirstIterationStorage().
571 // TODO: Where this is done should perhaps be changed once finishInit() is refactored.
573
574 simulator_.problem().initialSolutionApplied();
575
576#ifndef NDEBUG
577 for (unsigned timeIdx = 0; timeIdx < historySize; ++timeIdx) {
578 const auto& sol = solution(timeIdx);
579 for (unsigned dofIdx = 0; dofIdx < sol.size(); ++dofIdx) {
580 sol[dofIdx].checkDefined();
581 }
582 }
583#endif // NDEBUG
584 }
585
590 void prefetch(const Element&) const
591 {
592 // do nothing by default
593 }
594
598 NewtonMethod& newtonMethod()
599 { return newtonMethod_; }
600
604 const NewtonMethod& newtonMethod() const
605 { return newtonMethod_; }
606
622 const IntensiveQuantities* thermodynamicHint(unsigned globalIdx, unsigned timeIdx) const
623 {
625 return 0;
626 }
627
628 // the intensive quantities cache doubles as thermodynamic hint
629 return cachedIntensiveQuantities(globalIdx, timeIdx);
630 }
631
643 const IntensiveQuantities* cachedIntensiveQuantities(unsigned globalIdx, unsigned timeIdx) const
644 {
647 !intensiveQuantityCacheUpToDate_[timeIdx][globalIdx]) {
648 return nullptr;
649 }
650
651 // With the storage cache enabled, usually only the
652 // intensive quantities for the most recent time step are
653 // cached. However, this may be false for some Problem
654 // variants, so we should check if the cache exists for
655 // the timeIdx in question.
656 if (timeIdx > 0 && enableStorageCache_ && intensiveQuantityCache_[timeIdx].empty()) {
657 return nullptr;
658 }
659
660 return &intensiveQuantityCache_[timeIdx][globalIdx];
661 }
662
663 const IntensiveQuantities& intensiveQuantities(unsigned globalIdx, unsigned timeIdx) const
664 {
665 const auto* intQuants = cachedIntensiveQuantities(globalIdx, timeIdx);
666 if (!intQuants) {
667 throw std::logic_error("Intensive quantities are not cached; "
668 "--enable-intensive-quantity-cache=false is not "
669 "supported by this model");
670 }
671 return *intQuants;
672 }
673
674 const auto& intensiveQuantityCache() const
675 { return intensiveQuantityCache_; }
676
685 void updateCachedIntensiveQuantities(const IntensiveQuantities& intQuants,
686 unsigned globalIdx,
687 unsigned timeIdx) const
688 {
690 return;
691 }
692
693 intensiveQuantityCache_[timeIdx][globalIdx] = intQuants;
694 intensiveQuantityCacheUpToDate_[timeIdx][globalIdx] = true;
695 }
696
706 unsigned timeIdx,
707 bool newValue) const
708 {
710 return;
711 }
712
713 intensiveQuantityCacheUpToDate_[timeIdx][globalIdx] = newValue ? 1 : 0;
714 }
715
721
727 void invalidateIntensiveQuantitiesCache(unsigned timeIdx) const
728 {
730 return;
731 }
732
734 std::ranges::fill(intensiveQuantityCacheUpToDate_[timeIdx], /*value=*/0);
735 }
736 }
737
738 void invalidateAndUpdateIntensiveQuantities(unsigned timeIdx) const
739 {
741
742 // exceptions must not escape the parallel block below (that calls
743 // std::terminate()); tuck any exception away and rethrow it after the
744 // block, so that e.g. a failed flash in the property evaluation leads
745 // to a time step chop instead of an abort
746 std::mutex exceptionLock;
747 std::exception_ptr exceptionPtr = nullptr;
748
749 // loop over all elements...
750 ThreadedEntityIterator<GridView, /*codim=*/0> threadedElemIt(gridView_);
751#ifdef _OPENMP
752#pragma omp parallel
753#endif
754 {
755 try {
756 ElementContext elemCtx(simulator_);
757 for (ElementIterator elemIt = threadedElemIt.beginParallel();
758 !threadedElemIt.isFinished(elemIt);
759 elemIt = threadedElemIt.increment())
760 {
761 const Element& elem = *elemIt;
762 elemCtx.updatePrimaryStencil(elem);
763 elemCtx.updatePrimaryIntensiveQuantities(timeIdx);
764 }
765 }
766 catch (...) {
767 std::lock_guard<std::mutex> take(exceptionLock);
768 exceptionPtr = std::current_exception();
769 threadedElemIt.setFinished();
770 }
771 }
772
773 if (exceptionPtr) {
774 std::rethrow_exception(exceptionPtr);
775 }
776 }
777
778 template <class GridViewType>
779 void invalidateAndUpdateIntensiveQuantities(unsigned timeIdx, const GridViewType& gridView) const
780 {
781 // see the overload above for why exceptions are bridged out of the
782 // parallel block like this
783 std::mutex exceptionLock;
784 std::exception_ptr exceptionPtr = nullptr;
785
786 // loop over all elements...
787 ThreadedEntityIterator<GridViewType, /*codim=*/0> threadedElemIt(gridView);
788#ifdef _OPENMP
789#pragma omp parallel
790#endif
791 {
792 try {
793 ElementContext elemCtx(simulator_);
794 for (auto elemIt = threadedElemIt.beginParallel();
795 !threadedElemIt.isFinished(elemIt);
796 elemIt = threadedElemIt.increment())
797 {
798 if (elemIt->partitionType() != Dune::InteriorEntity) {
799 continue;
800 }
801 const Element& elem = *elemIt;
802 elemCtx.updatePrimaryStencil(elem);
803 // Mark cache for this element as invalid.
804 const std::size_t numPrimaryDof = elemCtx.numPrimaryDof(timeIdx);
805 for (unsigned dofIdx = 0; dofIdx < numPrimaryDof; ++dofIdx) {
806 const unsigned globalIndex = elemCtx.globalSpaceIndex(dofIdx, timeIdx);
807 setIntensiveQuantitiesCacheEntryValidity(globalIndex, timeIdx, false);
808 }
809 // Update for this element.
810 elemCtx.updatePrimaryIntensiveQuantities(timeIdx);
811 }
812 }
813 catch (...) {
814 std::lock_guard<std::mutex> take(exceptionLock);
815 exceptionPtr = std::current_exception();
816 threadedElemIt.setFinished();
817 }
818 }
819
820 if (exceptionPtr) {
821 std::rethrow_exception(exceptionPtr);
822 }
823 }
824
833 void shiftIntensiveQuantityCache(unsigned numSlots = 1)
834 {
835 if (!storeIntensiveQuantities() || numSlots <= 0) {
836 return;
837 }
838
839 if (enableStorageCache() && simulator_.problem().recycleFirstIterationStorage()) {
840 // If the storage term is cached, the intensive quantities of the previous
841 // time steps do not need to be accessed, and we can thus spare ourselves to
842 // copy the objects for the intensive quantities.
843 // However, if the storage term at the start of the timestep cannot be deduced
844 // from the primary variables, we must calculate it from the old intensive
845 // quantities, and need to shift them.
846 return;
847 }
848
849 const unsigned intensiveHistorySize = cachedIntensiveQuantityHistorySize_;
850 for (unsigned timeIdx = 0; timeIdx < intensiveHistorySize - numSlots; ++timeIdx) {
851 intensiveQuantityCache_[timeIdx + numSlots] = intensiveQuantityCache_[timeIdx];
853 }
854
855 // the cache for the most recent time indices do not need to be invalidated
856 // because the solution for them did not change (TODO: that assumes that there is
857 // no post-processing of the solution after a time step! fix it?)
858 }
859
867 { return enableStorageCache_; }
868
877
891 const EqVector& cachedStorage(unsigned globalIdx, unsigned timeIdx) const
892 {
893 if (!enableStorageCache_ ||
894 timeIdx >= historySize ||
895 !storageCacheUpToDate_[timeIdx][globalIdx]) {
896 throw std::logic_error("Cached storage is not available or up to date for the requested "
897 "global index and time index. Make sure storage cache is enabled "
898 "and the entry is valid before calling this method.");
899 }
900
901 return storageCache_[timeIdx][globalIdx];
902 }
903
915 void updateCachedStorage(unsigned globalIdx, unsigned timeIdx, const EqVector& value) const
916 {
917 if (!enableStorageCache_ || timeIdx >= historySize) {
918 return;
919 }
920
921 storageCache_[timeIdx][globalIdx] = value;
922 storageCacheUpToDate_[timeIdx][globalIdx] = 1;
923 }
924
931 bool storageCacheIsUpToDate(unsigned globalIdx, unsigned timeIdx) const
932 {
933 if (!enableStorageCache_ || timeIdx >= historySize) {
934 return false;
935 }
936 return storageCacheUpToDate_[timeIdx][globalIdx] != 0;
937 }
938
945 void invalidateStorageCacheEntry(unsigned globalIdx, unsigned timeIdx) const
946 {
947 if (enableStorageCache_ && timeIdx < historySize) {
948 storageCacheUpToDate_[timeIdx][globalIdx] = 0;
949 }
950 }
951
957 void invalidateStorageCache(unsigned timeIdx) const
958 {
959 if (enableStorageCache_ && timeIdx < historySize) {
960 std::ranges::fill(storageCacheUpToDate_[timeIdx], /*value=*/0);
961 }
962 }
963
975 void shiftStorageCache(unsigned numSlots = 1) const
976 {
977 // If we cannot recycle first iteration storage, it does not make sense to shift the storage cache.
978 if (enableStorageCache_ && !simulator_.problem().recycleFirstIterationStorage()) {
979 for (unsigned timeIdx = 0; timeIdx < historySize - numSlots; ++timeIdx) {
980 storageCache_[timeIdx + numSlots] = storageCache_[timeIdx];
981 storageCacheUpToDate_[timeIdx + numSlots] = storageCacheUpToDate_[timeIdx];
982 }
983
984 // should we invalidate the cache for the most recent time indices? (see shiftIntensiveQuantityCache)
985 }
986 }
987
995 Scalar globalResidual(GlobalEqVector& dest,
996 const SolutionVector& u) const
997 {
998 mutableSolution(/*timeIdx=*/0) = u;
999 const Scalar res = asImp_().globalResidual(dest);
1000 mutableSolution(/*timeIdx=*/0) = asImp_().solution(/*timeIdx=*/0);
1001 return res;
1002 }
1003
1010 Scalar globalResidual(GlobalEqVector& dest) const
1011 {
1012 dest = 0;
1013
1014 std::mutex mutex;
1015 ThreadedEntityIterator<GridView, /*codim=*/0> threadedElemIt(gridView_);
1016#ifdef _OPENMP
1017#pragma omp parallel
1018#endif
1019 {
1020 // Attention: the variables below are thread specific and thus cannot be
1021 // moved in front of the #pragma!
1022 const unsigned threadId = ThreadManager::threadId();
1023 ElementContext elemCtx(simulator_);
1024 ElementIterator elemIt = threadedElemIt.beginParallel();
1025 LocalEvalBlockVector residual, storageTerm;
1026
1027 for (; !threadedElemIt.isFinished(elemIt); elemIt = threadedElemIt.increment()) {
1028 const Element& elem = *elemIt;
1029 if (elem.partitionType() != Dune::InteriorEntity) {
1030 continue;
1031 }
1032
1033 elemCtx.updateAll(elem);
1034 residual.resize(elemCtx.numDof(/*timeIdx=*/0));
1035 storageTerm.resize(elemCtx.numPrimaryDof(/*timeIdx=*/0));
1036 asImp_().localResidual(threadId).eval(residual, elemCtx);
1037
1038 const std::size_t numPrimaryDof = elemCtx.numPrimaryDof(/*timeIdx=*/0);
1039 mutex.lock();
1040 for (unsigned dofIdx = 0; dofIdx < numPrimaryDof; ++dofIdx) {
1041 const unsigned globalI = elemCtx.globalSpaceIndex(dofIdx, /*timeIdx=*/0);
1042 for (unsigned eqIdx = 0; eqIdx < numEq; ++ eqIdx) {
1043 dest[globalI][eqIdx] += Toolbox::value(residual[dofIdx][eqIdx]);
1044 }
1045 }
1046 mutex.unlock();
1047 }
1048 }
1049
1050 // add up the residuals on the process borders
1051 const auto sumHandle =
1052 GridCommHandleFactory::template sumHandle<EqVector>(dest, asImp_().dofMapper());
1053 gridView_.communicate(*sumHandle,
1054 Dune::InteriorBorder_InteriorBorder_Interface,
1055 Dune::ForwardCommunication);
1056
1057 // calculate the square norm of the residual. this is not
1058 // entirely correct, since the residual for the finite volumes
1059 // which are on the boundary are counted once for every
1060 // process. As often in life: shit happens (, we don't care)...
1061 return std::sqrt(asImp_().gridView().comm().sum(dest.two_norm2()));
1062 }
1063
1070 void globalStorage(EqVector& storage, unsigned timeIdx = 0) const
1071 {
1072 storage = 0;
1073
1074 std::mutex mutex;
1075 forEachStorageTerm(timeIdx, [&storage, &mutex](const auto&, const EqVector& value) {
1076 std::lock_guard lock(mutex);
1077 storage += value;
1078 });
1079
1080 storage = gridView_.comm().sum(storage);
1081 }
1082
1083 void rebuildStorageCache(const unsigned timeIdx) const
1084 {
1085 if (!enableStorageCache() || timeIdx >= historySize) {
1086 return;
1087 }
1088
1089 forEachStorageTerm(timeIdx, [this, timeIdx](const auto& globalDofIdx, const EqVector& value) {
1090 updateCachedStorage(globalDofIdx, timeIdx, value);
1091 });
1092 }
1093
1094private:
1095 template<class Callback>
1096 void forEachStorageTerm(const unsigned timeIdx, Callback&& callback) const
1097 {
1098 ThreadedEntityIterator<GridView, /*codim=*/0> threadedElemIt(gridView_);
1099#ifdef _OPENMP
1100#pragma omp parallel
1101#endif
1102 {
1103 const unsigned threadId = ThreadManager::threadId();
1104 ElementContext elemCtx(simulator_);
1105 LocalEvalBlockVector elemStorage;
1106 elemCtx.setEnableStorageCache(false);
1107 auto elemIt = threadedElemIt.beginParallel();
1108 for (; !threadedElemIt.isFinished(elemIt); elemIt = threadedElemIt.increment()) {
1109 const auto& elem = *elemIt;
1110 if (elem.partitionType() != Dune::InteriorEntity) {
1111 continue;
1112 }
1113
1114 elemCtx.updateStencil(elem);
1115 elemCtx.updatePrimaryIntensiveQuantities(timeIdx);
1116 const std::size_t numPrimaryDof = elemCtx.numPrimaryDof(timeIdx);
1117 elemStorage.resize(numPrimaryDof);
1118 localResidual(threadId).evalStorage(elemStorage, elemCtx, timeIdx);
1119
1120 for (std::size_t dofIdx = 0; dofIdx < numPrimaryDof; ++dofIdx) {
1121 EqVector storage(0.0);
1122 for (unsigned eqIdx = 0; eqIdx < numEq; ++eqIdx) {
1123 storage[eqIdx] = Toolbox::value(elemStorage[dofIdx][eqIdx]);
1124 }
1125 callback(elemCtx.globalSpaceIndex(dofIdx, timeIdx), storage);
1126 }
1127 }
1128 }
1129 }
1130
1131public:
1132
1140 void checkConservativeness([[maybe_unused]] Scalar tolerance = -1,
1141 [[maybe_unused]] bool verbose = false) const
1142 {
1143#ifndef NDEBUG
1144 Scalar totalBoundaryArea(0.0);
1145 Scalar totalVolume(0.0);
1146 EvalEqVector totalRate(0.0);
1147
1148 // take the newton tolerance times the total volume of the grid if we're not
1149 // given an explicit tolerance...
1150 if (tolerance <= 0) {
1151 tolerance =
1152 simulator_.model().newtonMethod().tolerance() *
1153 simulator_.model().gridTotalVolume() *
1154 1000;
1155 }
1156
1157 // we assume the implicit Euler time discretization for now...
1158 assert(historySize == 2);
1159
1160 EqVector storageBeginTimeStep(0.0);
1161 globalStorage(storageBeginTimeStep, /*timeIdx=*/1);
1162
1163 EqVector storageEndTimeStep(0.0);
1164 globalStorage(storageEndTimeStep, /*timeIdx=*/0);
1165
1166 // calculate the rate at the boundary and the source rate
1167 ElementContext elemCtx(simulator_);
1168 elemCtx.setEnableStorageCache(false);
1169 for (const auto& elem : elements(simulator_.gridView())) {
1170 if (elem.partitionType() != Dune::InteriorEntity) {
1171 continue; // ignore ghost and overlap elements
1172 }
1173
1174 elemCtx.updateAll(elem);
1175
1176 // handle the boundary terms
1177 if (elemCtx.onBoundary()) {
1178 BoundaryContext boundaryCtx(elemCtx);
1179
1180 for (unsigned faceIdx = 0; faceIdx < boundaryCtx.numBoundaryFaces(/*timeIdx=*/0); ++faceIdx) {
1181 BoundaryRateVector values;
1182 simulator_.problem().boundary(values,
1183 boundaryCtx,
1184 faceIdx,
1185 /*timeIdx=*/0);
1186 Valgrind::CheckDefined(values);
1187
1188 const unsigned dofIdx = boundaryCtx.interiorScvIndex(faceIdx, /*timeIdx=*/0);
1189 const auto& insideIntQuants = elemCtx.intensiveQuantities(dofIdx, /*timeIdx=*/0);
1190
1191 const Scalar bfArea =
1192 boundaryCtx.boundarySegmentArea(faceIdx, /*timeIdx=*/0) *
1193 insideIntQuants.extrusionFactor();
1194
1195 for (unsigned i = 0; i < values.size(); ++i) {
1196 values[i] *= bfArea;
1197 }
1198
1199 totalBoundaryArea += bfArea;
1200 for (unsigned eqIdx = 0; eqIdx < numEq; ++eqIdx) {
1201 totalRate[eqIdx] += values[eqIdx];
1202 }
1203 }
1204 }
1205
1206 // deal with the source terms
1207 for (unsigned dofIdx = 0; dofIdx < elemCtx.numPrimaryDof(/*timeIdx=*/0); ++dofIdx) {
1208 RateVector values;
1209 simulator_.problem().source(values,
1210 elemCtx,
1211 dofIdx,
1212 /*timeIdx=*/0);
1213 Valgrind::CheckDefined(values);
1214
1215 const auto& intQuants = elemCtx.intensiveQuantities(dofIdx, /*timeIdx=*/0);
1216 Scalar dofVolume =
1217 elemCtx.dofVolume(dofIdx, /*timeIdx=*/0) *
1218 intQuants.extrusionFactor();
1219 for (unsigned eqIdx = 0; eqIdx < numEq; ++eqIdx) {
1220 totalRate[eqIdx] += -dofVolume*Toolbox::value(values[eqIdx]);
1221 }
1222 totalVolume += dofVolume;
1223 }
1224 }
1225
1226 // summarize everything over all processes
1227 const auto& comm = simulator_.gridView().comm();
1228 totalRate = comm.sum(totalRate);
1229 totalBoundaryArea = comm.sum(totalBoundaryArea);
1230 totalVolume = comm.sum(totalVolume);
1231
1232 if (comm.rank() == 0) {
1233 EqVector storageRate = storageBeginTimeStep;
1234 storageRate -= storageEndTimeStep;
1235 storageRate /= simulator_.timeStepSize();
1236 if (verbose) {
1237 std::cout << "storage at beginning of time step: " << storageBeginTimeStep << "\n";
1238 std::cout << "storage at end of time step: " << storageEndTimeStep << "\n";
1239 std::cout << "rate based on storage terms: " << storageRate << "\n";
1240 std::cout << "rate based on source and boundary terms: " << totalRate << "\n";
1241 std::cout << "difference in rates: ";
1242 for (unsigned eqIdx = 0; eqIdx < EqVector::dimension; ++eqIdx) {
1243 std::cout << (storageRate[eqIdx] - Toolbox::value(totalRate[eqIdx])) << " ";
1244 }
1245 std::cout << "\n";
1246 }
1247 for (unsigned eqIdx = 0; eqIdx < EqVector::dimension; ++eqIdx) {
1248 Scalar eps =
1249 (std::abs(storageRate[eqIdx]) + Toolbox::value(totalRate[eqIdx])) * tolerance;
1250 eps = std::max(tolerance, eps);
1251 assert(std::abs(storageRate[eqIdx] - Toolbox::value(totalRate[eqIdx])) <= eps);
1252 }
1253 }
1254#endif // NDEBUG
1255 }
1256
1262 Scalar dofTotalVolume(unsigned globalIdx) const
1263 { return dofTotalVolume_[globalIdx]; }
1264
1270 bool isLocalDof(unsigned globalIdx) const
1271 { return isLocalDof_[globalIdx]; }
1272
1273 size_t numDof() const
1274 { return asImp_().numGridDof(); }
1275
1280 Scalar gridTotalVolume() const
1281 { return gridTotalVolume_; }
1282
1288 const SolutionVector& solution(unsigned timeIdx) const
1289 { return solution_[timeIdx]->blockVector(); }
1290
1294 SolutionVector& solution(unsigned timeIdx)
1295 { return solution_[timeIdx]->blockVector(); }
1296
1297 protected:
1301 SolutionVector& mutableSolution(unsigned timeIdx) const
1302 { return solution_[timeIdx]->blockVector(); }
1303
1304 public:
1309 const Linearizer& linearizer() const
1310 { return *linearizer_; }
1311
1316 Linearizer& linearizer()
1317 { return *linearizer_; }
1318
1327 const LocalLinearizer& localLinearizer(unsigned openMpThreadId) const
1328 { return localLinearizer_[openMpThreadId]; }
1329
1333 LocalLinearizer& localLinearizer(unsigned openMpThreadId)
1334 { return localLinearizer_[openMpThreadId]; }
1335
1339 const LocalResidual& localResidual(unsigned openMpThreadId) const
1340 { return asImp_().localLinearizer(openMpThreadId).localResidual(); }
1341
1345 LocalResidual& localResidual(unsigned openMpThreadId)
1346 { return asImp_().localLinearizer(openMpThreadId).localResidual(); }
1347
1355 Scalar primaryVarWeight(unsigned globalDofIdx, unsigned pvIdx) const
1356 {
1357 const Scalar absPv = std::abs(asImp_().solution(/*timeIdx=*/1)[globalDofIdx][pvIdx]);
1358 return 1.0 / std::max(absPv, 1.0);
1359 }
1360
1367 Scalar eqWeight(unsigned, unsigned) const
1368 { return 1.0; }
1369
1379 Scalar relativeDofError(unsigned vertexIdx,
1380 const PrimaryVariables& pv1,
1381 const PrimaryVariables& pv2) const
1382 {
1383 Scalar result = 0.0;
1384 for (unsigned j = 0; j < numEq; ++j) {
1385 const Scalar weight = asImp_().primaryVarWeight(vertexIdx, j);
1386 const Scalar eqErr = std::abs((pv1[j] - pv2[j])*weight);
1387 //Scalar eqErr = std::abs(pv1[j] - pv2[j]);
1388 //eqErr *= std::max<Scalar>(1.0, std::abs(pv1[j] + pv2[j])/2);
1389
1390 result = std::max(result, eqErr);
1391 }
1392 return result;
1393 }
1394
1400 bool update()
1401 {
1402 const TimerGuard prePostProcessGuard(prePostProcessTimer_);
1403
1404#ifndef NDEBUG
1405 for (unsigned timeIdx = 0; timeIdx < historySize; ++timeIdx) {
1406 // Make sure that the primary variables are defined. Note that because of padding
1407 // bytes, we can't just simply ask valgrind to check the whole solution vectors
1408 // for definedness...
1409 for (std::size_t i = 0; i < asImp_().solution(/*timeIdx=*/0).size(); ++i) {
1410 asImp_().solution(timeIdx)[i].checkDefined();
1411 }
1412 }
1413#endif // NDEBUG
1414
1415 // make sure all timers are prestine
1418 solveTimer_.halt();
1420
1422 asImp_().updateBegin();
1424
1425 bool converged = false;
1426
1427 try {
1428 converged = newtonMethod_.apply();
1429 }
1430 catch(...) {
1431 prePostProcessTimer_ += newtonMethod_.prePostProcessTimer();
1432 linearizeTimer_ += newtonMethod_.linearizeTimer();
1433 solveTimer_ += newtonMethod_.solveTimer();
1434 updateTimer_ += newtonMethod_.updateTimer();
1435
1436 throw;
1437 }
1438
1439#ifndef NDEBUG
1440 for (unsigned timeIdx = 0; timeIdx < historySize; ++timeIdx) {
1441 // Make sure that the primary variables are defined. Note that because of padding
1442 // bytes, we can't just simply ask valgrind to check the whole solution vectors
1443 // for definedness...
1444 for (std::size_t i = 0; i < asImp_().solution(/*timeIdx=*/0).size(); ++i) {
1445 asImp_().solution(timeIdx)[i].checkDefined();
1446 }
1447 }
1448#endif // NDEBUG
1449
1450 prePostProcessTimer_ += newtonMethod_.prePostProcessTimer();
1451 linearizeTimer_ += newtonMethod_.linearizeTimer();
1452 solveTimer_ += newtonMethod_.solveTimer();
1453 updateTimer_ += newtonMethod_.updateTimer();
1454
1456 if (converged) {
1457 asImp_().updateSuccessful();
1458 }
1459 else {
1460 asImp_().updateFailed();
1461 }
1463
1464#ifndef NDEBUG
1465 for (unsigned timeIdx = 0; timeIdx < historySize; ++timeIdx) {
1466 // Make sure that the primary variables are defined. Note that because of padding
1467 // bytes, we can't just simply ask valgrind to check the whole solution vectors
1468 // for definedness...
1469 for (std::size_t i = 0; i < asImp_().solution(/*timeIdx=*/0).size(); ++i) {
1470 asImp_().solution(timeIdx)[i].checkDefined();
1471 }
1472 }
1473#endif // NDEBUG
1474
1475 return converged;
1476 }
1477
1486 {}
1487
1494 {}
1495
1501 {}
1502
1507 {
1508 throw std::invalid_argument("Grid adaptation need to be implemented for "
1509 "specific settings of grid and function spaces");
1510 }
1511
1518 {
1519 // Reset the current solution to the one of the
1520 // previous time step so that we can start the next
1521 // update at a physically meaningful solution.
1522 solution(/*timeIdx=*/0) = solution(/*timeIdx=*/1);
1524
1525#ifndef NDEBUG
1526 for (unsigned timeIdx = 0; timeIdx < historySize; ++timeIdx) {
1527 // Make sure that the primary variables are defined. Note that because of padding
1528 // bytes, we can't just simply ask valgrind to check the whole solution vectors
1529 // for definedness...
1530 for (std::size_t i = 0; i < asImp_().solution(/*timeIdx=*/0).size(); ++i) {
1531 asImp_().solution(timeIdx)[i].checkDefined();
1532 }
1533 }
1534#endif // NDEBUG
1535 }
1536
1545 {
1546 // at this point we can adapt the grid
1547 if (this->enableGridAdaptation_) {
1548 asImp_().adaptGrid();
1549 }
1550
1551 // make the current solution the previous one.
1552 solution(/*timeIdx=*/1) = solution(/*timeIdx=*/0);
1553
1554 // shift the storage cache by one position in the history
1555 asImp_().shiftStorageCache(/*numSlots=*/1);
1556
1557 // shift the intensive quantities cache by one position in the
1558 // history
1559 asImp_().shiftIntensiveQuantityCache(/*numSlots=*/1);
1560 }
1561
1569 template <class Restarter>
1570 void serialize(Restarter&)
1571 {
1572 throw std::runtime_error("Not implemented: The discretization chosen for this problem "
1573 "does not support restart files. (serialize() method unimplemented)");
1574 }
1575
1583 template <class Restarter>
1584 void deserialize(Restarter&)
1585 {
1586 throw std::runtime_error("Not implemented: The discretization chosen for this problem "
1587 "does not support restart files. (deserialize() method unimplemented)");
1588 }
1589
1598 template <class DofEntity>
1599 void serializeEntity(std::ostream& outstream,
1600 const DofEntity& dof)
1601 {
1602 const unsigned dofIdx = static_cast<unsigned>(asImp_().dofMapper().index(dof));
1603
1604 // write phase state
1605 if (!outstream.good()) {
1606 throw std::runtime_error("Could not serialize degree of freedom " +
1607 std::to_string(dofIdx));
1608 }
1609
1610 for (unsigned eqIdx = 0; eqIdx < numEq; ++eqIdx) {
1611 outstream << solution(/*timeIdx=*/0)[dofIdx][eqIdx] << " ";
1612 }
1613 }
1614
1623 template <class DofEntity>
1624 void deserializeEntity(std::istream& instream,
1625 const DofEntity& dof)
1626 {
1627 const unsigned dofIdx = static_cast<unsigned>(asImp_().dofMapper().index(dof));
1628
1629 for (unsigned eqIdx = 0; eqIdx < numEq; ++eqIdx) {
1630 if (!instream.good()) {
1631 throw std::runtime_error("Could not deserialize degree of freedom " +
1632 std::to_string(dofIdx));
1633 }
1634 instream >> solution(/*timeIdx=*/0)[dofIdx][eqIdx];
1635 }
1636 }
1637
1641 std::size_t numGridDof() const
1642 { throw std::logic_error("The discretization class must implement the numGridDof() method!"); }
1643
1647 std::size_t numAuxiliaryDof() const
1648 {
1649 return std::accumulate(auxEqModules_.begin(), auxEqModules_.end(),
1650 std::size_t{0},
1651 [](const auto acc, const auto& mod)
1652 { return acc + mod->numDofs(); });
1653 }
1654
1658 std::size_t numTotalDof() const
1659 { return asImp_().numGridDof() + numAuxiliaryDof(); }
1660
1665 const DofMapper& dofMapper() const
1666 { throw std::logic_error("The discretization class must implement the dofMapper() method!"); }
1667
1671 const VertexMapper& vertexMapper() const
1672 { return vertexMapper_; }
1673
1677 const ElementMapper& elementMapper() const
1678 { return elementMapper_; }
1679
1685 {
1686 linearizer_ = std::make_unique<Linearizer>();
1687 linearizer_->init(simulator_);
1688 }
1689
1693 static std::string discretizationName()
1694 { return ""; }
1695
1701 std::string primaryVarName(unsigned pvIdx) const
1702 {
1703 std::ostringstream oss;
1704 oss << "primary variable_" << pvIdx;
1705 return oss.str();
1706 }
1707
1713 std::string eqName(unsigned eqIdx) const
1714 {
1715 std::ostringstream oss;
1716 oss << "equation_" << eqIdx;
1717 return oss.str();
1718 }
1719
1726 void updatePVWeights(const ElementContext&) const
1727 {}
1728
1732 void addOutputModule(std::unique_ptr<BaseOutputModule<TypeTag>> newModule)
1733 { outputModules_.push_back(std::move(newModule)); }
1734
1743 template <class VtkMultiWriter>
1745 const SolutionVector& u,
1746 const GlobalEqVector& deltaU) const
1747 {
1748 using ScalarBuffer = std::vector<double>;
1749
1750 GlobalEqVector globalResid(u.size());
1751 asImp_().globalResidual(globalResid, u);
1752
1753 // create the required scalar fields
1754 const std::size_t numDof = asImp_().numGridDof();
1755
1756 // global defect of the two auxiliary equations
1757 std::array<ScalarBuffer*, numEq> def;
1758 std::array<ScalarBuffer*, numEq> delta;
1759 std::array<ScalarBuffer*, numEq> priVars;
1760 std::array<ScalarBuffer*, numEq> priVarWeight;
1761 ScalarBuffer* relError = writer.allocateManagedScalarBuffer(numDof);
1762 ScalarBuffer* normalizedRelError = writer.allocateManagedScalarBuffer(numDof);
1763 for (unsigned pvIdx = 0; pvIdx < numEq; ++pvIdx) {
1764 priVars[pvIdx] = writer.allocateManagedScalarBuffer(numDof);
1765 priVarWeight[pvIdx] = writer.allocateManagedScalarBuffer(numDof);
1766 delta[pvIdx] = writer.allocateManagedScalarBuffer(numDof);
1767 def[pvIdx] = writer.allocateManagedScalarBuffer(numDof);
1768 }
1769
1770 Scalar minRelErr = 1e30;
1771 Scalar maxRelErr = -1e30;
1772 for (unsigned globalIdx = 0; globalIdx < numDof; ++ globalIdx) {
1773 for (unsigned pvIdx = 0; pvIdx < numEq; ++pvIdx) {
1774 (*priVars[pvIdx])[globalIdx] = u[globalIdx][pvIdx];
1775 (*priVarWeight[pvIdx])[globalIdx] = asImp_().primaryVarWeight(globalIdx, pvIdx);
1776 (*delta[pvIdx])[globalIdx] = - deltaU[globalIdx][pvIdx];
1777 (*def[pvIdx])[globalIdx] = globalResid[globalIdx][pvIdx];
1778 }
1779
1780 PrimaryVariables uOld(u[globalIdx]);
1781 PrimaryVariables uNew(uOld);
1782 uNew -= deltaU[globalIdx];
1783
1784 const Scalar err = asImp_().relativeDofError(globalIdx, uOld, uNew);
1785 (*relError)[globalIdx] = err;
1786 (*normalizedRelError)[globalIdx] = err;
1787 minRelErr = std::min(err, minRelErr);
1788 maxRelErr = std::max(err, maxRelErr);
1789 }
1790
1791 // do the normalization of the relative error
1792 const Scalar alpha = std::max(Scalar{1e-20},
1793 std::max(std::abs(maxRelErr),
1794 std::abs(minRelErr)));
1795 for (unsigned globalIdx = 0; globalIdx < numDof; ++globalIdx) {
1796 (*normalizedRelError)[globalIdx] /= alpha;
1797 }
1798
1799 DiscBaseOutputModule::attachScalarDofData_(writer, *relError, "relative error");
1800 DiscBaseOutputModule::attachScalarDofData_(writer, *normalizedRelError, "normalized relative error");
1801
1802 for (unsigned i = 0; i < numEq; ++i) {
1803 std::ostringstream oss;
1804 oss.str(""); oss << "priVar_" << asImp_().primaryVarName(i);
1805 DiscBaseOutputModule::attachScalarDofData_(writer,
1806 *priVars[i],
1807 oss.str());
1808
1809 oss.str(""); oss << "delta_" << asImp_().primaryVarName(i);
1810 DiscBaseOutputModule::attachScalarDofData_(writer,
1811 *delta[i],
1812 oss.str());
1813
1814 oss.str(""); oss << "weight_" << asImp_().primaryVarName(i);
1815 DiscBaseOutputModule::attachScalarDofData_(writer,
1816 *priVarWeight[i],
1817 oss.str());
1818
1819 oss.str(""); oss << "defect_" << asImp_().eqName(i);
1820 DiscBaseOutputModule::attachScalarDofData_(writer,
1821 *def[i],
1822 oss.str());
1823 }
1824
1825 asImp_().prepareOutputFields();
1826 asImp_().appendOutputFields(writer);
1827 }
1828
1834 {
1835 const bool needFullContextUpdate =
1836 std::ranges::any_of(outputModules_,
1837 [](const auto& mod)
1838 { return mod->needExtensiveQuantities(); });
1839 std::ranges::for_each(outputModules_,
1840 [](auto& mod) { mod->allocBuffers(); });
1841
1842 // iterate over grid
1843 ThreadedEntityIterator<GridView, /*codim=*/0> threadedElemIt(gridView());
1844#ifdef _OPENMP
1845#pragma omp parallel
1846#endif
1847 {
1848 ElementContext elemCtx(simulator_);
1849 ElementIterator elemIt = threadedElemIt.beginParallel();
1850 for (; !threadedElemIt.isFinished(elemIt); elemIt = threadedElemIt.increment()) {
1851 const auto& elem = *elemIt;
1852 if (elem.partitionType() != Dune::InteriorEntity) {
1853 // ignore non-interior entities
1854 continue;
1855 }
1856
1857 if (needFullContextUpdate) {
1858 elemCtx.updateAll(elem);
1859 }
1860 else {
1861 elemCtx.updatePrimaryStencil(elem);
1862 elemCtx.updatePrimaryIntensiveQuantities(/*timeIdx=*/0);
1863 }
1864
1865 std::ranges::for_each(outputModules_,
1866 [&elemCtx](auto& mod) { mod->processElement(elemCtx); });
1867 }
1868 }
1869 }
1870
1876 {
1877 std::ranges::for_each(outputModules_,
1878 [&writer](auto& mod) { mod->commitBuffers(writer); });
1879 }
1880
1884 const GridView& gridView() const
1885 { return gridView_; }
1886
1899 {
1900 auxMod->setDofOffset(numTotalDof());
1901 auxEqModules_.push_back(auxMod);
1902
1903 // resize the solutions
1904 if (enableGridAdaptation_ && !std::is_same_v<DiscreteFunction, BlockVectorWrapper>) {
1905 throw std::invalid_argument("Problems which require auxiliary modules cannot be used in"
1906 " conjunction with dune-fem");
1907 }
1908
1909 const std::size_t numDof = numTotalDof();
1910 for (unsigned timeIdx = 0; timeIdx < historySize; ++timeIdx) {
1911 solution(timeIdx).resize(numDof);
1912 }
1913
1914 auxMod->applyInitial();
1915 }
1916
1923 {
1924 auxEqModules_.clear();
1925 linearizer_->eraseMatrix();
1926 newtonMethod_.eraseMatrix();
1927 }
1928
1932 std::size_t numAuxiliaryModules() const
1933 { return auxEqModules_.size(); }
1934
1939 { return auxEqModules_[auxEqModIdx]; }
1940
1944 const BaseAuxiliaryModule<TypeTag>* auxiliaryModule(unsigned auxEqModIdx) const
1945 { return auxEqModules_[auxEqModIdx]; }
1946
1952
1954 { return prePostProcessTimer_; }
1955
1956 const Timer& linearizeTimer() const
1957 { return linearizeTimer_; }
1958
1959 const Timer& solveTimer() const
1960 { return solveTimer_; }
1961
1962 const Timer& updateTimer() const
1963 { return updateTimer_; }
1964
1965 template<class Serializer>
1966 void serializeOp(Serializer& serializer)
1967 {
1969 using Helper = typename BaseDiscretization::template SerializeHelper<Serializer>;
1970 Helper::serializeOp(serializer, solution_);
1971 }
1972
1973 bool operator==(const FvBaseDiscretization& rhs) const
1974 {
1975 return std::ranges::equal(this->solution_, rhs.solution_,
1976 [](const auto& x, const auto& y)
1977 { return *x == *y; });
1978 }
1979
1980protected:
1982 {
1983 // allocate the storage cache
1984 if (enableStorageCache()) {
1985 const std::size_t numDof = asImp_().numGridDof();
1986 for (unsigned timeIdx = 0; timeIdx < historySize; ++timeIdx) {
1987 storageCache_[timeIdx].resize(numDof);
1988 storageCacheUpToDate_[timeIdx].resize(numDof, /*value=*/0);
1989 }
1990 }
1991
1992 // allocate the intensive quantities cache
1994 const std::size_t numDof = asImp_().numGridDof();
1995 cachedIntensiveQuantityHistorySize_ = simulator_.problem().intensiveQuantityHistorySize();
1996 const unsigned intensiveHistorySize = cachedIntensiveQuantityHistorySize_;
1997
1998 // resize the vectors based on runtime history size
1999 intensiveQuantityCache_.resize(intensiveHistorySize);
2000 intensiveQuantityCacheUpToDate_.resize(intensiveHistorySize);
2001
2002 for(unsigned timeIdx = 0; timeIdx < intensiveHistorySize; ++timeIdx) {
2003 intensiveQuantityCache_[timeIdx].resize(numDof);
2004 intensiveQuantityCacheUpToDate_[timeIdx].resize(numDof);
2006 }
2007 }
2008 }
2009
2010 template <class Context>
2011 void supplementInitialSolution_(PrimaryVariables&,
2012 const Context&,
2013 unsigned,
2014 unsigned)
2015 {}
2016
2025 {
2026 // add the output modules available on all model
2027 this->outputModules_.push_back(std::make_unique<VtkPrimaryVarsModule<TypeTag>>(simulator_));
2028 }
2029
2033 LocalResidual& localResidual_()
2034 { return localLinearizer_.localResidual(); }
2035
2039 bool verbose_() const
2040 { return gridView_.comm().rank() == 0; }
2041
2042 Implementation& asImp_()
2043 { return *static_cast<Implementation*>(this); }
2044
2045 const Implementation& asImp_() const
2046 { return *static_cast<const Implementation*>(this); }
2047
2048 // the problem we want to solve. defines the constitutive
2049 // relations, matxerial laws, etc.
2050 Simulator& simulator_;
2051
2052 // the representation of the spatial domain of the problem
2053 GridView gridView_;
2054
2055 // the mappers for element and vertex entities to global indices
2056 ElementMapper elementMapper_;
2057 VertexMapper vertexMapper_;
2058
2059 // a vector with all auxiliary equations to be considered
2060 std::vector<BaseAuxiliaryModule<TypeTag>*> auxEqModules_;
2061
2062 NewtonMethod newtonMethod_;
2063
2068
2069 // calculates the local jacobian matrix for a given element
2070 std::vector<LocalLinearizer> localLinearizer_;
2071 // Linearizes the problem at the current time step using the
2072 // local jacobian
2073 std::unique_ptr<Linearizer> linearizer_;
2074
2075 // cur is the current iterative solution, prev the converged
2076 // solution of the previous time step
2077 mutable std::vector<IntensiveQuantitiesVector> intensiveQuantityCache_;
2078
2079 // while these are logically bools, concurrent writes to vector<bool> are not thread safe.
2080 mutable std::vector<std::vector<unsigned char>> intensiveQuantityCacheUpToDate_;
2081
2082 std::array<std::unique_ptr<DiscreteFunction>, historySize> solution_;
2083
2084 std::list<std::unique_ptr<BaseOutputModule<TypeTag>>> outputModules_;
2085
2087 std::vector<Scalar> dofTotalVolume_;
2088 std::vector<bool> isLocalDof_;
2089
2090 mutable std::array<GlobalEqVector, historySize> storageCache_;
2091
2092 // while these are logically bools, concurrent writes to vector<bool> are not thread safe.
2093 mutable std::array<std::vector<unsigned char>, historySize> storageCacheUpToDate_;
2094
2099
2101};
2102
2108template<class TypeTag>
2110{
2114
2115 static constexpr unsigned historySize = getPropValue<TypeTag, Properties::TimeDiscHistorySize>();
2116
2117public:
2118 template<class Serializer>
2120 {
2121 template<class SolutionType>
2122 static void serializeOp(Serializer& serializer,
2123 SolutionType& solution)
2124 {
2125 for (auto& sol : solution) {
2126 serializer(*sol);
2127 }
2128 }
2129 };
2130
2131 explicit FvBaseDiscretizationNoAdapt(Simulator& simulator)
2132 : ParentType(simulator)
2133 {
2134 if (this->enableGridAdaptation_) {
2135 throw std::invalid_argument("Grid adaptation need to use"
2136 " BaseDiscretization = FvBaseDiscretizationFemAdapt"
2137 " which currently requires the presence of the"
2138 " dune-fem module");
2139 }
2140 const std::size_t numDof = this->asImp_().numGridDof();
2141 for (unsigned timeIdx = 0; timeIdx < historySize; ++timeIdx) {
2142 this->solution_[timeIdx] = std::make_unique<DiscreteFunction>("solution", numDof);
2143 }
2144 }
2145};
2146
2147} // namespace Opm
2148
2149#endif // EWOMS_FV_BASE_DISCRETIZATION_HH
This is a stand-alone version of boost::alignment::aligned_allocator from Boost 1....
Base class for specifying auxiliary equations.
Definition: baseauxiliarymodule.hh:56
virtual void applyInitial()=0
Set the initial condition of the auxiliary module in the solution vector.
void setDofOffset(int value)
Set the offset in the global system of equations for the first degree of freedom of this auxiliary mo...
Definition: baseauxiliarymodule.hh:78
The base class for writer modules.
Definition: baseoutputmodule.hh:68
The base class for all output writers.
Definition: baseoutputwriter.hh:46
Represents all quantities which available on boundary segments.
Definition: fvbaseboundarycontext.hh:46
Represents all quantities which available for calculating constraints.
Definition: fvbaseconstraintscontext.hh:44
Class to specify constraints for a finite volume spatial discretization.
Definition: fvbaseconstraints.hh:48
Definition: fvbasediscretization.hh:350
const SolutionVector & blockVector() const
Definition: fvbasediscretization.hh:373
SolutionVector blockVector_
Definition: fvbasediscretization.hh:352
void serializeOp(Serializer &serializer)
Definition: fvbasediscretization.hh:382
static BlockVectorWrapper serializationTestObject()
Definition: fvbasediscretization.hh:360
SolutionVector & blockVector()
Definition: fvbasediscretization.hh:370
bool operator==(const BlockVectorWrapper &wrapper) const
Definition: fvbasediscretization.hh:376
BlockVectorWrapper(const std::string &, const std::size_t size)
Definition: fvbasediscretization.hh:354
The base class for the finite volume discretization schemes without adaptation.
Definition: fvbasediscretization.hh:2110
FvBaseDiscretizationNoAdapt(Simulator &simulator)
Definition: fvbasediscretization.hh:2131
The base class for the finite volume discretization schemes.
Definition: fvbasediscretization.hh:298
Timer linearizeTimer_
Definition: fvbasediscretization.hh:2065
std::vector< IntensiveQuantitiesVector > intensiveQuantityCache_
Definition: fvbasediscretization.hh:2077
LocalLinearizer & localLinearizer(unsigned openMpThreadId)
Definition: fvbasediscretization.hh:1333
void prepareOutputFields() const
Prepare the quantities relevant for the current solution to be appended to the output writers.
Definition: fvbasediscretization.hh:1833
void shiftIntensiveQuantityCache(unsigned numSlots=1)
Move the intensive quantities for a given time index to the back.
Definition: fvbasediscretization.hh:833
void invalidateAndUpdateIntensiveQuantities(unsigned timeIdx) const
Definition: fvbasediscretization.hh:738
void adaptGrid()
Called by the update() method when the grid should be refined.
Definition: fvbasediscretization.hh:1506
std::vector< BaseAuxiliaryModule< TypeTag > * > auxEqModules_
Definition: fvbasediscretization.hh:2060
const Implementation & asImp_() const
Definition: fvbasediscretization.hh:2045
void addAuxiliaryModule(BaseAuxiliaryModule< TypeTag > *auxMod)
Add a module for an auxiliary equation.
Definition: fvbasediscretization.hh:1898
void setIntensiveQuantitiesCacheEntryValidity(unsigned globalIdx, unsigned timeIdx, bool newValue) const
Invalidate the cache for a given intensive quantities object.
Definition: fvbasediscretization.hh:705
void finishInit()
Apply the initial conditions to the model.
Definition: fvbasediscretization.hh:457
void prefetch(const Element &) const
Allows to improve the performance by prefetching all data which is associated with a given element.
Definition: fvbasediscretization.hh:590
bool enableStorageCache_
Definition: fvbasediscretization.hh:2097
void resizeAndResetIntensiveQuantitiesCache_()
Definition: fvbasediscretization.hh:1981
std::vector< Scalar > dofTotalVolume_
Definition: fvbasediscretization.hh:2087
void updateSuccessful()
Called by the update() method if it was successful.
Definition: fvbasediscretization.hh:1500
static std::string discretizationName()
Returns a string of discretization's human-readable name.
Definition: fvbasediscretization.hh:1693
unsigned cachedIntensiveQuantityHistorySize() const
Get the cached intensive quantity history size.
Definition: fvbasediscretization.hh:719
BaseAuxiliaryModule< TypeTag > * auxiliaryModule(unsigned auxEqModIdx)
Returns a given module for auxiliary equations.
Definition: fvbasediscretization.hh:1938
bool isLocalDof(unsigned globalIdx) const
Returns if the overlap of the volume ofa degree of freedom is non-zero.
Definition: fvbasediscretization.hh:1270
std::size_t numAuxiliaryModules() const
Returns the number of modules for auxiliary equations.
Definition: fvbasediscretization.hh:1932
bool operator==(const FvBaseDiscretization &rhs) const
Definition: fvbasediscretization.hh:1973
void serializeOp(Serializer &serializer)
Definition: fvbasediscretization.hh:1966
std::vector< bool > isLocalDof_
Definition: fvbasediscretization.hh:2088
LocalResidual & localResidual_()
Reference to the local residal object.
Definition: fvbasediscretization.hh:2033
void registerOutputModules_()
Register all output modules which make sense for the model.
Definition: fvbasediscretization.hh:2024
bool enableGridAdaptation() const
Returns whether the grid ought to be adapted to the solution during the simulation.
Definition: fvbasediscretization.hh:522
const NewtonMethod & newtonMethod() const
Returns the newton method object.
Definition: fvbasediscretization.hh:604
SolutionVector & mutableSolution(unsigned timeIdx) const
Definition: fvbasediscretization.hh:1301
void advanceTimeLevel()
Called by the problem if a time integration was successful, post processing of the solution is done a...
Definition: fvbasediscretization.hh:1544
NewtonMethod & newtonMethod()
Returns the newton method object.
Definition: fvbasediscretization.hh:598
const VertexMapper & vertexMapper() const
Returns the mapper for vertices to indices.
Definition: fvbasediscretization.hh:1671
const EqVector & cachedStorage(unsigned globalIdx, unsigned timeIdx) const
Retrieve an entry of the cache for the storage term.
Definition: fvbasediscretization.hh:891
void updatePVWeights(const ElementContext &) const
Update the weights of all primary variables within an element given the complete set of intensive qua...
Definition: fvbasediscretization.hh:1726
const Timer & solveTimer() const
Definition: fvbasediscretization.hh:1959
void updateFailed()
Called by the update() method if it was unsuccessful. This is primary a hook which the actual model c...
Definition: fvbasediscretization.hh:1517
void updateBegin()
Called by the update() method before it tries to apply the newton method. This is primary a hook whic...
Definition: fvbasediscretization.hh:1493
FvBaseDiscretization(const FvBaseDiscretization &)=delete
Scalar globalResidual(GlobalEqVector &dest) const
Compute the global residual for the current solution vector.
Definition: fvbasediscretization.hh:1010
LocalResidual & localResidual(unsigned openMpThreadId)
Definition: fvbasediscretization.hh:1345
void serializeEntity(std::ostream &outstream, const DofEntity &dof)
Write the current solution for a degree of freedom to a restart file.
Definition: fvbasediscretization.hh:1599
void setEnableStorageCache(bool enableStorageCache)
Set the value of enable storage cache.
Definition: fvbasediscretization.hh:875
std::string eqName(unsigned eqIdx) const
Given an equation index, return a human readable name.
Definition: fvbasediscretization.hh:1713
Scalar eqWeight(unsigned, unsigned) const
Returns the relative weight of an equation.
Definition: fvbasediscretization.hh:1367
std::array< std::vector< unsigned char >, historySize > storageCacheUpToDate_
Definition: fvbasediscretization.hh:2093
const Timer & prePostProcessTimer() const
Definition: fvbasediscretization.hh:1953
Scalar primaryVarWeight(unsigned globalDofIdx, unsigned pvIdx) const
Returns the relative weight of a primary variable for calculating relative errors.
Definition: fvbasediscretization.hh:1355
void deserialize(Restarter &)
Deserializes the state of the model.
Definition: fvbasediscretization.hh:1584
void checkConservativeness(Scalar tolerance=-1, bool verbose=false) const
Ensure that the difference between the storage terms of the last and of the current time step is cons...
Definition: fvbasediscretization.hh:1140
Scalar gridTotalVolume() const
Returns the volume of the whole grid which represents the spatial domain.
Definition: fvbasediscretization.hh:1280
Timer updateTimer_
Definition: fvbasediscretization.hh:2067
FvBaseDiscretization(Simulator &simulator)
Definition: fvbasediscretization.hh:393
const IntensiveQuantities * thermodynamicHint(unsigned globalIdx, unsigned timeIdx) const
Return the thermodynamic hint for a entity on the grid at given time.
Definition: fvbasediscretization.hh:622
bool storageCacheIsUpToDate(unsigned globalIdx, unsigned timeIdx) const
Returns true if the storage cache entry for a given DOF and time index is up to date.
Definition: fvbasediscretization.hh:931
const Timer & updateTimer() const
Definition: fvbasediscretization.hh:1962
const Linearizer & linearizer() const
Returns the operator linearizer for the global jacobian of the problem.
Definition: fvbasediscretization.hh:1309
void updateCachedStorage(unsigned globalIdx, unsigned timeIdx, const EqVector &value) const
Set an entry of the cache for the storage term.
Definition: fvbasediscretization.hh:915
void addConvergenceVtkFields(VtkMultiWriter &writer, const SolutionVector &u, const GlobalEqVector &deltaU) const
Add the vector fields for analysing the convergence of the newton method to the a VTK writer.
Definition: fvbasediscretization.hh:1744
Scalar relativeDofError(unsigned vertexIdx, const PrimaryVariables &pv1, const PrimaryVariables &pv2) const
Returns the relative error between two vectors of primary variables.
Definition: fvbasediscretization.hh:1379
bool enableGridAdaptation_
Definition: fvbasediscretization.hh:2095
const IntensiveQuantities & intensiveQuantities(unsigned globalIdx, unsigned timeIdx) const
Definition: fvbasediscretization.hh:663
Scalar globalResidual(GlobalEqVector &dest, const SolutionVector &u) const
Compute the global residual for an arbitrary solution vector.
Definition: fvbasediscretization.hh:995
SolutionVector & solution(unsigned timeIdx)
Definition: fvbasediscretization.hh:1294
std::array< GlobalEqVector, historySize > storageCache_
Definition: fvbasediscretization.hh:2090
Timer prePostProcessTimer_
Definition: fvbasediscretization.hh:2064
void deserializeEntity(std::istream &instream, const DofEntity &dof)
Reads the current solution variables for a degree of freedom from a restart file.
Definition: fvbasediscretization.hh:1624
Timer solveTimer_
Definition: fvbasediscretization.hh:2066
void supplementInitialSolution_(PrimaryVariables &, const Context &, unsigned, unsigned)
Definition: fvbasediscretization.hh:2011
const LocalLinearizer & localLinearizer(unsigned openMpThreadId) const
Returns the local jacobian which calculates the local stiffness matrix for an arbitrary element.
Definition: fvbasediscretization.hh:1327
std::array< std::unique_ptr< DiscreteFunction >, historySize > solution_
Definition: fvbasediscretization.hh:2082
unsigned cachedIntensiveQuantityHistorySize_
Definition: fvbasediscretization.hh:2100
const Timer & linearizeTimer() const
Definition: fvbasediscretization.hh:1956
void invalidateAndUpdateIntensiveQuantities(unsigned timeIdx, const GridViewType &gridView) const
Definition: fvbasediscretization.hh:779
bool update()
Try to progress the model to the next timestep.
Definition: fvbasediscretization.hh:1400
const auto & intensiveQuantityCache() const
Definition: fvbasediscretization.hh:674
std::size_t numAuxiliaryDof() const
Returns the number of degrees of freedom (DOFs) of the auxiliary equations.
Definition: fvbasediscretization.hh:1647
void clearAuxiliaryModules()
Causes the list of auxiliary equations to be cleared.
Definition: fvbasediscretization.hh:1922
bool enableIntensiveQuantityCache_
Definition: fvbasediscretization.hh:2096
std::unique_ptr< Linearizer > linearizer_
Definition: fvbasediscretization.hh:2073
const ElementMapper & elementMapper() const
Returns the mapper for elements to indices.
Definition: fvbasediscretization.hh:1677
void syncOverlap()
Syncronize the values of the primary variables on the degrees of freedom that overlap with the neighb...
Definition: fvbasediscretization.hh:1485
void appendOutputFields(BaseOutputWriter &writer) const
Append the quantities relevant for the current solution to an output writer.
Definition: fvbasediscretization.hh:1875
std::list< std::unique_ptr< BaseOutputModule< TypeTag > > > outputModules_
Definition: fvbasediscretization.hh:2084
ElementMapper elementMapper_
Definition: fvbasediscretization.hh:2056
NewtonMethod newtonMethod_
Definition: fvbasediscretization.hh:2062
std::size_t numTotalDof() const
Returns the total number of degrees of freedom (i.e., grid plux auxiliary DOFs)
Definition: fvbasediscretization.hh:1658
void applyInitialSolution()
Applies the initial solution for all degrees of freedom to which the model applies.
Definition: fvbasediscretization.hh:529
Implementation & asImp_()
Definition: fvbasediscretization.hh:2042
void updateCachedIntensiveQuantities(const IntensiveQuantities &intQuants, unsigned globalIdx, unsigned timeIdx) const
Update the intensive quantity cache for a entity on the grid at given time.
Definition: fvbasediscretization.hh:685
std::string primaryVarName(unsigned pvIdx) const
Given an primary variable index, return a human readable name.
Definition: fvbasediscretization.hh:1701
void invalidateIntensiveQuantitiesCache(unsigned timeIdx) const
Invalidate the whole intensive quantity cache for time index.
Definition: fvbasediscretization.hh:727
Linearizer & linearizer()
Returns the object which linearizes the global system of equations at the current solution.
Definition: fvbasediscretization.hh:1316
const BaseAuxiliaryModule< TypeTag > * auxiliaryModule(unsigned auxEqModIdx) const
Returns a given module for auxiliary equations.
Definition: fvbasediscretization.hh:1944
std::vector< std::vector< unsigned char > > intensiveQuantityCacheUpToDate_
Definition: fvbasediscretization.hh:2080
void globalStorage(EqVector &storage, unsigned timeIdx=0) const
Compute the integral over the domain of the storage terms of all conservation quantities.
Definition: fvbasediscretization.hh:1070
GridView gridView_
Definition: fvbasediscretization.hh:2053
Scalar dofTotalVolume(unsigned globalIdx) const
Returns the volume of a given control volume.
Definition: fvbasediscretization.hh:1262
static void registerParameters()
Register all run-time parameters for the model.
Definition: fvbasediscretization.hh:426
const SolutionVector & solution(unsigned timeIdx) const
Reference to the solution at a given history index as a block vector.
Definition: fvbasediscretization.hh:1288
bool verbose_() const
Returns whether messages should be printed.
Definition: fvbasediscretization.hh:2039
void shiftStorageCache(unsigned numSlots=1) const
Shift storage cache by a given number of time step slots.
Definition: fvbasediscretization.hh:975
Simulator & simulator_
Definition: fvbasediscretization.hh:2050
const LocalResidual & localResidual(unsigned openMpThreadId) const
Returns the object to calculate the local residual function.
Definition: fvbasediscretization.hh:1339
std::size_t numGridDof() const
Returns the number of degrees of freedom (DOFs) for the computational grid.
Definition: fvbasediscretization.hh:1641
Scalar gridTotalVolume_
Definition: fvbasediscretization.hh:2086
const DofMapper & dofMapper() const
Mapper to convert the Dune entities of the discretization's degrees of freedoms are to indices.
Definition: fvbasediscretization.hh:1665
bool storeIntensiveQuantities() const
Returns true if the cache for intensive quantities is enabled.
Definition: fvbasediscretization.hh:1950
std::vector< LocalLinearizer > localLinearizer_
Definition: fvbasediscretization.hh:2070
void invalidateStorageCache(unsigned timeIdx) const
Invalidate the whole storage cache for a given time index.
Definition: fvbasediscretization.hh:957
void serialize(Restarter &)
Serializes the current state of the model.
Definition: fvbasediscretization.hh:1570
bool enableThermodynamicHints_
Definition: fvbasediscretization.hh:2098
void rebuildStorageCache(const unsigned timeIdx) const
Definition: fvbasediscretization.hh:1083
void invalidateStorageCacheEntry(unsigned globalIdx, unsigned timeIdx) const
Invalidate the storage cache for a given DOF and time index.
Definition: fvbasediscretization.hh:945
VertexMapper vertexMapper_
Definition: fvbasediscretization.hh:2057
void resetLinearizer()
Resets the Jacobian matrix linearizer, so that the boundary types can be altered.
Definition: fvbasediscretization.hh:1684
bool enableStorageCache() const
Returns true iff the storage term is cached.
Definition: fvbasediscretization.hh:866
size_t numDof() const
Definition: fvbasediscretization.hh:1273
const GridView & gridView() const
Reference to the grid view of the spatial domain.
Definition: fvbasediscretization.hh:1884
void addOutputModule(std::unique_ptr< BaseOutputModule< TypeTag > > newModule)
Add an module for writing visualization output after a timestep.
Definition: fvbasediscretization.hh:1732
const IntensiveQuantities * cachedIntensiveQuantities(unsigned globalIdx, unsigned timeIdx) const
Return the cached intensive quantities for a entity on the grid at given time.
Definition: fvbasediscretization.hh:643
This class stores an array of IntensiveQuantities objects, one intensive quantities object for each o...
Definition: fvbaseelementcontext.hh:55
Provide the properties at a face which make sense independently of the conserved quantities.
Definition: fvbaseextensivequantities.hh:48
This class calculates gradients of arbitrary quantities at flux integration points using the two-poin...
Definition: fvbasegradientcalculator.hh:52
Base class for the model specific class which provides access to all intensive (i....
Definition: fvbaseintensivequantities.hh:45
The common code for the linearizers of non-linear systems of equations.
Definition: fvbaselinearizer.hh:78
Element-wise caculation of the residual matrix for models based on a finite volume spatial discretiza...
Definition: fvbaselocalresidual.hh:63
Represents the primary variables used by the a model.
Definition: fvbaseprimaryvariables.hh:54
This is a grid manager which does not create any border list.
Definition: nullborderlistmanager.hh:44
static void registerParameters()
Register all run-time parameters for the Newton method.
Definition: newtonmethod.hh:135
Manages the initializing and running of time dependent problems.
Definition: simulator.hh:87
Simplifies multi-threaded capabilities.
Definition: threadmanager.hpp:36
static unsigned maxThreads()
Return the maximum number of threads of the current process.
Definition: threadmanager.hpp:66
static unsigned threadId()
Return the index of the current OpenMP thread.
Provides an STL-iterator like interface to iterate over the enties of a GridView in OpenMP threaded a...
Definition: threadedentityiterator.hh:42
bool isFinished(const EntityIterator &it) const
Definition: threadedentityiterator.hh:67
void setFinished()
Definition: threadedentityiterator.hh:71
EntityIterator increment()
Definition: threadedentityiterator.hh:80
EntityIterator beginParallel()
Definition: threadedentityiterator.hh:54
A simple class which makes sure that a timer gets stopped if an exception is thrown.
Definition: timerguard.hh:42
Provides an encapsulation to measure the system time.
Definition: timer.hpp:46
void start()
Start counting the time resources used by the simulation.
void halt()
Stop the measurement reset all timing values.
double stop()
Stop counting the time resources.
Simplifies writing multi-file VTK datasets.
Definition: vtkmultiwriter.hh:65
ScalarBuffer * allocateManagedScalarBuffer(std::size_t numEntities)
Allocate a managed buffer for a scalar field.
Definition: vtkmultiwriter.hh:206
VTK output module for the fluid composition.
Definition: vtkprimaryvarsmodule.hpp:48
static void registerParameters()
Register all run-time parameters for the Vtk output module.
Definition: vtkprimaryvarsmodule.hpp:74
Definition: alignedallocator.hh:97
Declare the properties used by the infrastructure code of the finite volume discretizations.
Provides data handles for parallel communication which operate on DOFs.
Declares the parameters for the black oil model.
Definition: fvbaseprimaryvariables.hh:161
auto Get(bool errorIfNotRegistered=true)
Retrieve a runtime parameter.
Definition: parametersystem.hpp:192
Definition: blackoilmodel.hh:74
Definition: blackoilbioeffectsmodules.hh:45
typename Properties::Detail::GetPropImpl< TypeTag, Property >::type::type GetPropType
get the type alias defined in the property (equivalent to old macro GET_PROP_TYPE(....
Definition: propertysystem.hh:233
std::string to_string(const ConvergenceReport::ReservoirFailure::Type t)
Definition: fvbasediscretization.hh:2120
static void serializeOp(Serializer &serializer, SolutionType &solution)
Definition: fvbasediscretization.hh:2122
Definition: fvbasediscretization.hh:272
GetPropType< TypeTag, Properties::GridView > GridView
Definition: fvbasediscretization.hh:113
GetPropType< TypeTag, Properties::DofMapper > DofMapper
Definition: fvbasediscretization.hh:112
The class which marks the border indices associated with the degrees of freedom on a process boundary...
Definition: basicproperties.hh:129
The secondary variables of a boundary segment.
Definition: fvbaseproperties.hh:157
GetPropType< TypeTag, Properties::RateVector > type
Definition: fvbasediscretization.hh:160
Type of object for specifying boundary conditions.
Definition: fvbaseproperties.hh:124
The secondary variables of a constraint degree of freedom.
Definition: fvbaseproperties.hh:160
The class which represents a constraint degree of freedom.
Definition: fvbaseproperties.hh:127
The part of the extensive quantities which is specific to the spatial discretization.
Definition: fvbaseproperties.hh:174
Definition: fvbaseproperties.hh:150
The discretization specific part of the local residual.
Definition: fvbaseproperties.hh:96
typename BaseDiscretization::BlockVectorWrapper type
Definition: fvbasediscretization.hh:283
Definition: fvbaseproperties.hh:82
The secondary variables of all degrees of freedom in an element's stencil.
Definition: fvbaseproperties.hh:154
Dune::BlockVector< GetPropType< TypeTag, Properties::EqVector > > type
Definition: fvbasediscretization.hh:174
A vector of holding a quantity for each equation for each DOF of an element.
Definition: fvbaseproperties.hh:117
Dune::MultipleCodimMultipleGeomTypeMapper< GetPropType< TypeTag, Properties::GridView > > type
Definition: fvbasediscretization.hh:106
The mapper to find the global index of an element.
Definition: fvbaseproperties.hh:227
Specify whether the some degrees of fredom can be constraint.
Definition: fvbaseproperties.hh:213
Specify if experimental features should be enabled or not.
Definition: fvbaseproperties.hh:255
Dune::FieldVector< GetPropType< TypeTag, Properties::Scalar >, getPropValue< TypeTag, Properties::NumEq >()> type
Definition: fvbasediscretization.hh:143
A vector of holding a quantity for each equation (usually at a given spatial location)
Definition: fvbaseproperties.hh:114
Specify whether the storage terms use extensive quantities or not.
Definition: fvbaseproperties.hh:247
Dune::BlockVector< GetPropType< TypeTag, Properties::EqVector > > type
Definition: fvbasediscretization.hh:181
Vector containing a quantity of for equation for each DOF of the whole grid.
Definition: linalgproperties.hh:54
Calculates gradients of arbitrary quantities at flux integration points.
Definition: fvbaseproperties.hh:166
The secondary variables within a sub-control volume.
Definition: fvbaseproperties.hh:138
The class which linearizes the non-linear system of equations.
Definition: newtonmethodproperties.hh:36
A vector of primary variables within a sub-control volume.
Definition: fvbaseproperties.hh:135
GetPropType< TypeTag, Properties::EqVector > type
Definition: fvbasediscretization.hh:153
Vector containing volumetric or areal rates of quantities.
Definition: fvbaseproperties.hh:121
Manages the simulation time.
Definition: basicproperties.hh:120
Dune::BlockVector< GetPropType< TypeTag, Properties::PrimaryVariables > > type
Definition: fvbasediscretization.hh:195
Vector containing all primary variables of the grid.
Definition: fvbaseproperties.hh:131
The OpenMP threads manager.
Definition: fvbaseproperties.hh:188
The history size required by the time discretization.
Definition: fvbaseproperties.hh:239
a tag to mark properties as undefined
Definition: propertysystem.hh:38
Definition: fvbaseproperties.hh:195
Specify whether to use volumetric residuals or not.
Definition: fvbaseproperties.hh:251
Dune::MultipleCodimMultipleGeomTypeMapper< GetPropType< TypeTag, Properties::GridView > > type
Definition: fvbasediscretization.hh:101
The mapper to find the global index of a vertex.
Definition: fvbaseproperties.hh:221
Specify the format the VTK output is written to disk.
Definition: fvbaseproperties.hh:209