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 auto& intensiveQuantityCache() const
664 { return intensiveQuantityCache_; }
665
674 void updateCachedIntensiveQuantities(const IntensiveQuantities& intQuants,
675 unsigned globalIdx,
676 unsigned timeIdx) const
677 {
679 return;
680 }
681
682 intensiveQuantityCache_[timeIdx][globalIdx] = intQuants;
683 intensiveQuantityCacheUpToDate_[timeIdx][globalIdx] = true;
684 }
685
695 unsigned timeIdx,
696 bool newValue) const
697 {
699 return;
700 }
701
702 intensiveQuantityCacheUpToDate_[timeIdx][globalIdx] = newValue ? 1 : 0;
703 }
704
710
716 void invalidateIntensiveQuantitiesCache(unsigned timeIdx) const
717 {
719 return;
720 }
721
723 std::ranges::fill(intensiveQuantityCacheUpToDate_[timeIdx], /*value=*/0);
724 }
725 }
726
727 void invalidateAndUpdateIntensiveQuantities(unsigned timeIdx) const
728 {
730
731 // exceptions must not escape the parallel block below (that calls
732 // std::terminate()); tuck any exception away and rethrow it after the
733 // block, so that e.g. a failed flash in the property evaluation leads
734 // to a time step chop instead of an abort
735 std::mutex exceptionLock;
736 std::exception_ptr exceptionPtr = nullptr;
737
738 // loop over all elements...
739 ThreadedEntityIterator<GridView, /*codim=*/0> threadedElemIt(gridView_);
740#ifdef _OPENMP
741#pragma omp parallel
742#endif
743 {
744 try {
745 ElementContext elemCtx(simulator_);
746 for (ElementIterator elemIt = threadedElemIt.beginParallel();
747 !threadedElemIt.isFinished(elemIt);
748 elemIt = threadedElemIt.increment())
749 {
750 const Element& elem = *elemIt;
751 elemCtx.updatePrimaryStencil(elem);
752 elemCtx.updatePrimaryIntensiveQuantities(timeIdx);
753 }
754 }
755 catch (...) {
756 std::lock_guard<std::mutex> take(exceptionLock);
757 exceptionPtr = std::current_exception();
758 threadedElemIt.setFinished();
759 }
760 }
761
762 if (exceptionPtr) {
763 std::rethrow_exception(exceptionPtr);
764 }
765 }
766
767 template <class GridViewType>
768 void invalidateAndUpdateIntensiveQuantities(unsigned timeIdx, const GridViewType& gridView) const
769 {
770 // see the overload above for why exceptions are bridged out of the
771 // parallel block like this
772 std::mutex exceptionLock;
773 std::exception_ptr exceptionPtr = nullptr;
774
775 // loop over all elements...
776 ThreadedEntityIterator<GridViewType, /*codim=*/0> threadedElemIt(gridView);
777#ifdef _OPENMP
778#pragma omp parallel
779#endif
780 {
781 try {
782 ElementContext elemCtx(simulator_);
783 for (auto elemIt = threadedElemIt.beginParallel();
784 !threadedElemIt.isFinished(elemIt);
785 elemIt = threadedElemIt.increment())
786 {
787 if (elemIt->partitionType() != Dune::InteriorEntity) {
788 continue;
789 }
790 const Element& elem = *elemIt;
791 elemCtx.updatePrimaryStencil(elem);
792 // Mark cache for this element as invalid.
793 const std::size_t numPrimaryDof = elemCtx.numPrimaryDof(timeIdx);
794 for (unsigned dofIdx = 0; dofIdx < numPrimaryDof; ++dofIdx) {
795 const unsigned globalIndex = elemCtx.globalSpaceIndex(dofIdx, timeIdx);
796 setIntensiveQuantitiesCacheEntryValidity(globalIndex, timeIdx, false);
797 }
798 // Update for this element.
799 elemCtx.updatePrimaryIntensiveQuantities(timeIdx);
800 }
801 }
802 catch (...) {
803 std::lock_guard<std::mutex> take(exceptionLock);
804 exceptionPtr = std::current_exception();
805 threadedElemIt.setFinished();
806 }
807 }
808
809 if (exceptionPtr) {
810 std::rethrow_exception(exceptionPtr);
811 }
812 }
813
822 void shiftIntensiveQuantityCache(unsigned numSlots = 1)
823 {
824 if (!storeIntensiveQuantities() || numSlots <= 0) {
825 return;
826 }
827
828 if (enableStorageCache() && simulator_.problem().recycleFirstIterationStorage()) {
829 // If the storage term is cached, the intensive quantities of the previous
830 // time steps do not need to be accessed, and we can thus spare ourselves to
831 // copy the objects for the intensive quantities.
832 // However, if the storage term at the start of the timestep cannot be deduced
833 // from the primary variables, we must calculate it from the old intensive
834 // quantities, and need to shift them.
835 return;
836 }
837
838 const unsigned intensiveHistorySize = cachedIntensiveQuantityHistorySize_;
839 for (unsigned timeIdx = 0; timeIdx < intensiveHistorySize - numSlots; ++timeIdx) {
840 intensiveQuantityCache_[timeIdx + numSlots] = intensiveQuantityCache_[timeIdx];
842 }
843
844 // the cache for the most recent time indices do not need to be invalidated
845 // because the solution for them did not change (TODO: that assumes that there is
846 // no post-processing of the solution after a time step! fix it?)
847 }
848
856 { return enableStorageCache_; }
857
866
880 const EqVector& cachedStorage(unsigned globalIdx, unsigned timeIdx) const
881 {
882 if (!enableStorageCache_ ||
883 timeIdx >= historySize ||
884 !storageCacheUpToDate_[timeIdx][globalIdx]) {
885 throw std::logic_error("Cached storage is not available or up to date for the requested "
886 "global index and time index. Make sure storage cache is enabled "
887 "and the entry is valid before calling this method.");
888 }
889
890 return storageCache_[timeIdx][globalIdx];
891 }
892
904 void updateCachedStorage(unsigned globalIdx, unsigned timeIdx, const EqVector& value) const
905 {
906 if (!enableStorageCache_ || timeIdx >= historySize) {
907 return;
908 }
909
910 storageCache_[timeIdx][globalIdx] = value;
911 storageCacheUpToDate_[timeIdx][globalIdx] = 1;
912 }
913
920 bool storageCacheIsUpToDate(unsigned globalIdx, unsigned timeIdx) const
921 {
922 if (!enableStorageCache_ || timeIdx >= historySize) {
923 return false;
924 }
925 return storageCacheUpToDate_[timeIdx][globalIdx] != 0;
926 }
927
934 void invalidateStorageCacheEntry(unsigned globalIdx, unsigned timeIdx) const
935 {
936 if (enableStorageCache_ && timeIdx < historySize) {
937 storageCacheUpToDate_[timeIdx][globalIdx] = 0;
938 }
939 }
940
946 void invalidateStorageCache(unsigned timeIdx) const
947 {
948 if (enableStorageCache_ && timeIdx < historySize) {
949 std::ranges::fill(storageCacheUpToDate_[timeIdx], /*value=*/0);
950 }
951 }
952
964 void shiftStorageCache(unsigned numSlots = 1) const
965 {
966 // If we cannot recycle first iteration storage, it does not make sense to shift the storage cache.
967 if (enableStorageCache_ && !simulator_.problem().recycleFirstIterationStorage()) {
968 for (unsigned timeIdx = 0; timeIdx < historySize - numSlots; ++timeIdx) {
969 storageCache_[timeIdx + numSlots] = storageCache_[timeIdx];
970 storageCacheUpToDate_[timeIdx + numSlots] = storageCacheUpToDate_[timeIdx];
971 }
972
973 // should we invalidate the cache for the most recent time indices? (see shiftIntensiveQuantityCache)
974 }
975 }
976
984 Scalar globalResidual(GlobalEqVector& dest,
985 const SolutionVector& u) const
986 {
987 mutableSolution(/*timeIdx=*/0) = u;
988 const Scalar res = asImp_().globalResidual(dest);
989 mutableSolution(/*timeIdx=*/0) = asImp_().solution(/*timeIdx=*/0);
990 return res;
991 }
992
999 Scalar globalResidual(GlobalEqVector& dest) const
1000 {
1001 dest = 0;
1002
1003 std::mutex mutex;
1004 ThreadedEntityIterator<GridView, /*codim=*/0> threadedElemIt(gridView_);
1005#ifdef _OPENMP
1006#pragma omp parallel
1007#endif
1008 {
1009 // Attention: the variables below are thread specific and thus cannot be
1010 // moved in front of the #pragma!
1011 const unsigned threadId = ThreadManager::threadId();
1012 ElementContext elemCtx(simulator_);
1013 ElementIterator elemIt = threadedElemIt.beginParallel();
1014 LocalEvalBlockVector residual, storageTerm;
1015
1016 for (; !threadedElemIt.isFinished(elemIt); elemIt = threadedElemIt.increment()) {
1017 const Element& elem = *elemIt;
1018 if (elem.partitionType() != Dune::InteriorEntity) {
1019 continue;
1020 }
1021
1022 elemCtx.updateAll(elem);
1023 residual.resize(elemCtx.numDof(/*timeIdx=*/0));
1024 storageTerm.resize(elemCtx.numPrimaryDof(/*timeIdx=*/0));
1025 asImp_().localResidual(threadId).eval(residual, elemCtx);
1026
1027 const std::size_t numPrimaryDof = elemCtx.numPrimaryDof(/*timeIdx=*/0);
1028 mutex.lock();
1029 for (unsigned dofIdx = 0; dofIdx < numPrimaryDof; ++dofIdx) {
1030 const unsigned globalI = elemCtx.globalSpaceIndex(dofIdx, /*timeIdx=*/0);
1031 for (unsigned eqIdx = 0; eqIdx < numEq; ++ eqIdx) {
1032 dest[globalI][eqIdx] += Toolbox::value(residual[dofIdx][eqIdx]);
1033 }
1034 }
1035 mutex.unlock();
1036 }
1037 }
1038
1039 // add up the residuals on the process borders
1040 const auto sumHandle =
1041 GridCommHandleFactory::template sumHandle<EqVector>(dest, asImp_().dofMapper());
1042 gridView_.communicate(*sumHandle,
1043 Dune::InteriorBorder_InteriorBorder_Interface,
1044 Dune::ForwardCommunication);
1045
1046 // calculate the square norm of the residual. this is not
1047 // entirely correct, since the residual for the finite volumes
1048 // which are on the boundary are counted once for every
1049 // process. As often in life: shit happens (, we don't care)...
1050 return std::sqrt(asImp_().gridView().comm().sum(dest.two_norm2()));
1051 }
1052
1059 void globalStorage(EqVector& storage, unsigned timeIdx = 0) const
1060 {
1061 storage = 0;
1062
1063 std::mutex mutex;
1064 forEachStorageTerm(timeIdx, [&storage, &mutex](const auto&, const EqVector& value) {
1065 std::lock_guard lock(mutex);
1066 storage += value;
1067 });
1068
1069 storage = gridView_.comm().sum(storage);
1070 }
1071
1072 void rebuildStorageCache(const unsigned timeIdx) const
1073 {
1074 if (!enableStorageCache() || timeIdx >= historySize) {
1075 return;
1076 }
1077
1078 forEachStorageTerm(timeIdx, [this, timeIdx](const auto& globalDofIdx, const EqVector& value) {
1079 updateCachedStorage(globalDofIdx, timeIdx, value);
1080 });
1081 }
1082
1083private:
1084 template<class Callback>
1085 void forEachStorageTerm(const unsigned timeIdx, Callback&& callback) const
1086 {
1087 ThreadedEntityIterator<GridView, /*codim=*/0> threadedElemIt(gridView_);
1088#ifdef _OPENMP
1089#pragma omp parallel
1090#endif
1091 {
1092 const unsigned threadId = ThreadManager::threadId();
1093 ElementContext elemCtx(simulator_);
1094 LocalEvalBlockVector elemStorage;
1095 elemCtx.setEnableStorageCache(false);
1096 auto elemIt = threadedElemIt.beginParallel();
1097 for (; !threadedElemIt.isFinished(elemIt); elemIt = threadedElemIt.increment()) {
1098 const auto& elem = *elemIt;
1099 if (elem.partitionType() != Dune::InteriorEntity) {
1100 continue;
1101 }
1102
1103 elemCtx.updateStencil(elem);
1104 elemCtx.updatePrimaryIntensiveQuantities(timeIdx);
1105 const std::size_t numPrimaryDof = elemCtx.numPrimaryDof(timeIdx);
1106 elemStorage.resize(numPrimaryDof);
1107 localResidual(threadId).evalStorage(elemStorage, elemCtx, timeIdx);
1108
1109 for (std::size_t dofIdx = 0; dofIdx < numPrimaryDof; ++dofIdx) {
1110 EqVector storage(0.0);
1111 for (unsigned eqIdx = 0; eqIdx < numEq; ++eqIdx) {
1112 storage[eqIdx] = Toolbox::value(elemStorage[dofIdx][eqIdx]);
1113 }
1114 callback(elemCtx.globalSpaceIndex(dofIdx, timeIdx), storage);
1115 }
1116 }
1117 }
1118 }
1119
1120public:
1121
1129 void checkConservativeness([[maybe_unused]] Scalar tolerance = -1,
1130 [[maybe_unused]] bool verbose = false) const
1131 {
1132#ifndef NDEBUG
1133 Scalar totalBoundaryArea(0.0);
1134 Scalar totalVolume(0.0);
1135 EvalEqVector totalRate(0.0);
1136
1137 // take the newton tolerance times the total volume of the grid if we're not
1138 // given an explicit tolerance...
1139 if (tolerance <= 0) {
1140 tolerance =
1141 simulator_.model().newtonMethod().tolerance() *
1142 simulator_.model().gridTotalVolume() *
1143 1000;
1144 }
1145
1146 // we assume the implicit Euler time discretization for now...
1147 assert(historySize == 2);
1148
1149 EqVector storageBeginTimeStep(0.0);
1150 globalStorage(storageBeginTimeStep, /*timeIdx=*/1);
1151
1152 EqVector storageEndTimeStep(0.0);
1153 globalStorage(storageEndTimeStep, /*timeIdx=*/0);
1154
1155 // calculate the rate at the boundary and the source rate
1156 ElementContext elemCtx(simulator_);
1157 elemCtx.setEnableStorageCache(false);
1158 for (const auto& elem : elements(simulator_.gridView())) {
1159 if (elem.partitionType() != Dune::InteriorEntity) {
1160 continue; // ignore ghost and overlap elements
1161 }
1162
1163 elemCtx.updateAll(elem);
1164
1165 // handle the boundary terms
1166 if (elemCtx.onBoundary()) {
1167 BoundaryContext boundaryCtx(elemCtx);
1168
1169 for (unsigned faceIdx = 0; faceIdx < boundaryCtx.numBoundaryFaces(/*timeIdx=*/0); ++faceIdx) {
1170 BoundaryRateVector values;
1171 simulator_.problem().boundary(values,
1172 boundaryCtx,
1173 faceIdx,
1174 /*timeIdx=*/0);
1175 Valgrind::CheckDefined(values);
1176
1177 const unsigned dofIdx = boundaryCtx.interiorScvIndex(faceIdx, /*timeIdx=*/0);
1178 const auto& insideIntQuants = elemCtx.intensiveQuantities(dofIdx, /*timeIdx=*/0);
1179
1180 const Scalar bfArea =
1181 boundaryCtx.boundarySegmentArea(faceIdx, /*timeIdx=*/0) *
1182 insideIntQuants.extrusionFactor();
1183
1184 for (unsigned i = 0; i < values.size(); ++i) {
1185 values[i] *= bfArea;
1186 }
1187
1188 totalBoundaryArea += bfArea;
1189 for (unsigned eqIdx = 0; eqIdx < numEq; ++eqIdx) {
1190 totalRate[eqIdx] += values[eqIdx];
1191 }
1192 }
1193 }
1194
1195 // deal with the source terms
1196 for (unsigned dofIdx = 0; dofIdx < elemCtx.numPrimaryDof(/*timeIdx=*/0); ++dofIdx) {
1197 RateVector values;
1198 simulator_.problem().source(values,
1199 elemCtx,
1200 dofIdx,
1201 /*timeIdx=*/0);
1202 Valgrind::CheckDefined(values);
1203
1204 const auto& intQuants = elemCtx.intensiveQuantities(dofIdx, /*timeIdx=*/0);
1205 Scalar dofVolume =
1206 elemCtx.dofVolume(dofIdx, /*timeIdx=*/0) *
1207 intQuants.extrusionFactor();
1208 for (unsigned eqIdx = 0; eqIdx < numEq; ++eqIdx) {
1209 totalRate[eqIdx] += -dofVolume*Toolbox::value(values[eqIdx]);
1210 }
1211 totalVolume += dofVolume;
1212 }
1213 }
1214
1215 // summarize everything over all processes
1216 const auto& comm = simulator_.gridView().comm();
1217 totalRate = comm.sum(totalRate);
1218 totalBoundaryArea = comm.sum(totalBoundaryArea);
1219 totalVolume = comm.sum(totalVolume);
1220
1221 if (comm.rank() == 0) {
1222 EqVector storageRate = storageBeginTimeStep;
1223 storageRate -= storageEndTimeStep;
1224 storageRate /= simulator_.timeStepSize();
1225 if (verbose) {
1226 std::cout << "storage at beginning of time step: " << storageBeginTimeStep << "\n";
1227 std::cout << "storage at end of time step: " << storageEndTimeStep << "\n";
1228 std::cout << "rate based on storage terms: " << storageRate << "\n";
1229 std::cout << "rate based on source and boundary terms: " << totalRate << "\n";
1230 std::cout << "difference in rates: ";
1231 for (unsigned eqIdx = 0; eqIdx < EqVector::dimension; ++eqIdx) {
1232 std::cout << (storageRate[eqIdx] - Toolbox::value(totalRate[eqIdx])) << " ";
1233 }
1234 std::cout << "\n";
1235 }
1236 for (unsigned eqIdx = 0; eqIdx < EqVector::dimension; ++eqIdx) {
1237 Scalar eps =
1238 (std::abs(storageRate[eqIdx]) + Toolbox::value(totalRate[eqIdx])) * tolerance;
1239 eps = std::max(tolerance, eps);
1240 assert(std::abs(storageRate[eqIdx] - Toolbox::value(totalRate[eqIdx])) <= eps);
1241 }
1242 }
1243#endif // NDEBUG
1244 }
1245
1251 Scalar dofTotalVolume(unsigned globalIdx) const
1252 { return dofTotalVolume_[globalIdx]; }
1253
1259 bool isLocalDof(unsigned globalIdx) const
1260 { return isLocalDof_[globalIdx]; }
1261
1262 size_t numDof() const
1263 { return asImp_().numGridDof(); }
1264
1269 Scalar gridTotalVolume() const
1270 { return gridTotalVolume_; }
1271
1277 const SolutionVector& solution(unsigned timeIdx) const
1278 { return solution_[timeIdx]->blockVector(); }
1279
1283 SolutionVector& solution(unsigned timeIdx)
1284 { return solution_[timeIdx]->blockVector(); }
1285
1286 protected:
1290 SolutionVector& mutableSolution(unsigned timeIdx) const
1291 { return solution_[timeIdx]->blockVector(); }
1292
1293 public:
1298 const Linearizer& linearizer() const
1299 { return *linearizer_; }
1300
1305 Linearizer& linearizer()
1306 { return *linearizer_; }
1307
1316 const LocalLinearizer& localLinearizer(unsigned openMpThreadId) const
1317 { return localLinearizer_[openMpThreadId]; }
1318
1322 LocalLinearizer& localLinearizer(unsigned openMpThreadId)
1323 { return localLinearizer_[openMpThreadId]; }
1324
1328 const LocalResidual& localResidual(unsigned openMpThreadId) const
1329 { return asImp_().localLinearizer(openMpThreadId).localResidual(); }
1330
1334 LocalResidual& localResidual(unsigned openMpThreadId)
1335 { return asImp_().localLinearizer(openMpThreadId).localResidual(); }
1336
1344 Scalar primaryVarWeight(unsigned globalDofIdx, unsigned pvIdx) const
1345 {
1346 const Scalar absPv = std::abs(asImp_().solution(/*timeIdx=*/1)[globalDofIdx][pvIdx]);
1347 return 1.0 / std::max(absPv, 1.0);
1348 }
1349
1356 Scalar eqWeight(unsigned, unsigned) const
1357 { return 1.0; }
1358
1368 Scalar relativeDofError(unsigned vertexIdx,
1369 const PrimaryVariables& pv1,
1370 const PrimaryVariables& pv2) const
1371 {
1372 Scalar result = 0.0;
1373 for (unsigned j = 0; j < numEq; ++j) {
1374 const Scalar weight = asImp_().primaryVarWeight(vertexIdx, j);
1375 const Scalar eqErr = std::abs((pv1[j] - pv2[j])*weight);
1376 //Scalar eqErr = std::abs(pv1[j] - pv2[j]);
1377 //eqErr *= std::max<Scalar>(1.0, std::abs(pv1[j] + pv2[j])/2);
1378
1379 result = std::max(result, eqErr);
1380 }
1381 return result;
1382 }
1383
1389 bool update()
1390 {
1391 const TimerGuard prePostProcessGuard(prePostProcessTimer_);
1392
1393#ifndef NDEBUG
1394 for (unsigned timeIdx = 0; timeIdx < historySize; ++timeIdx) {
1395 // Make sure that the primary variables are defined. Note that because of padding
1396 // bytes, we can't just simply ask valgrind to check the whole solution vectors
1397 // for definedness...
1398 for (std::size_t i = 0; i < asImp_().solution(/*timeIdx=*/0).size(); ++i) {
1399 asImp_().solution(timeIdx)[i].checkDefined();
1400 }
1401 }
1402#endif // NDEBUG
1403
1404 // make sure all timers are prestine
1407 solveTimer_.halt();
1409
1411 asImp_().updateBegin();
1413
1414 bool converged = false;
1415
1416 try {
1417 converged = newtonMethod_.apply();
1418 }
1419 catch(...) {
1420 prePostProcessTimer_ += newtonMethod_.prePostProcessTimer();
1421 linearizeTimer_ += newtonMethod_.linearizeTimer();
1422 solveTimer_ += newtonMethod_.solveTimer();
1423 updateTimer_ += newtonMethod_.updateTimer();
1424
1425 throw;
1426 }
1427
1428#ifndef NDEBUG
1429 for (unsigned timeIdx = 0; timeIdx < historySize; ++timeIdx) {
1430 // Make sure that the primary variables are defined. Note that because of padding
1431 // bytes, we can't just simply ask valgrind to check the whole solution vectors
1432 // for definedness...
1433 for (std::size_t i = 0; i < asImp_().solution(/*timeIdx=*/0).size(); ++i) {
1434 asImp_().solution(timeIdx)[i].checkDefined();
1435 }
1436 }
1437#endif // NDEBUG
1438
1439 prePostProcessTimer_ += newtonMethod_.prePostProcessTimer();
1440 linearizeTimer_ += newtonMethod_.linearizeTimer();
1441 solveTimer_ += newtonMethod_.solveTimer();
1442 updateTimer_ += newtonMethod_.updateTimer();
1443
1445 if (converged) {
1446 asImp_().updateSuccessful();
1447 }
1448 else {
1449 asImp_().updateFailed();
1450 }
1452
1453#ifndef NDEBUG
1454 for (unsigned timeIdx = 0; timeIdx < historySize; ++timeIdx) {
1455 // Make sure that the primary variables are defined. Note that because of padding
1456 // bytes, we can't just simply ask valgrind to check the whole solution vectors
1457 // for definedness...
1458 for (std::size_t i = 0; i < asImp_().solution(/*timeIdx=*/0).size(); ++i) {
1459 asImp_().solution(timeIdx)[i].checkDefined();
1460 }
1461 }
1462#endif // NDEBUG
1463
1464 return converged;
1465 }
1466
1475 {}
1476
1483 {}
1484
1490 {}
1491
1496 {
1497 throw std::invalid_argument("Grid adaptation need to be implemented for "
1498 "specific settings of grid and function spaces");
1499 }
1500
1507 {
1508 // Reset the current solution to the one of the
1509 // previous time step so that we can start the next
1510 // update at a physically meaningful solution.
1511 solution(/*timeIdx=*/0) = solution(/*timeIdx=*/1);
1513
1514#ifndef NDEBUG
1515 for (unsigned timeIdx = 0; timeIdx < historySize; ++timeIdx) {
1516 // Make sure that the primary variables are defined. Note that because of padding
1517 // bytes, we can't just simply ask valgrind to check the whole solution vectors
1518 // for definedness...
1519 for (std::size_t i = 0; i < asImp_().solution(/*timeIdx=*/0).size(); ++i) {
1520 asImp_().solution(timeIdx)[i].checkDefined();
1521 }
1522 }
1523#endif // NDEBUG
1524 }
1525
1534 {
1535 // at this point we can adapt the grid
1536 if (this->enableGridAdaptation_) {
1537 asImp_().adaptGrid();
1538 }
1539
1540 // make the current solution the previous one.
1541 solution(/*timeIdx=*/1) = solution(/*timeIdx=*/0);
1542
1543 // shift the storage cache by one position in the history
1544 asImp_().shiftStorageCache(/*numSlots=*/1);
1545
1546 // shift the intensive quantities cache by one position in the
1547 // history
1548 asImp_().shiftIntensiveQuantityCache(/*numSlots=*/1);
1549 }
1550
1558 template <class Restarter>
1559 void serialize(Restarter&)
1560 {
1561 throw std::runtime_error("Not implemented: The discretization chosen for this problem "
1562 "does not support restart files. (serialize() method unimplemented)");
1563 }
1564
1572 template <class Restarter>
1573 void deserialize(Restarter&)
1574 {
1575 throw std::runtime_error("Not implemented: The discretization chosen for this problem "
1576 "does not support restart files. (deserialize() method unimplemented)");
1577 }
1578
1587 template <class DofEntity>
1588 void serializeEntity(std::ostream& outstream,
1589 const DofEntity& dof)
1590 {
1591 const unsigned dofIdx = static_cast<unsigned>(asImp_().dofMapper().index(dof));
1592
1593 // write phase state
1594 if (!outstream.good()) {
1595 throw std::runtime_error("Could not serialize degree of freedom " +
1596 std::to_string(dofIdx));
1597 }
1598
1599 for (unsigned eqIdx = 0; eqIdx < numEq; ++eqIdx) {
1600 outstream << solution(/*timeIdx=*/0)[dofIdx][eqIdx] << " ";
1601 }
1602 }
1603
1612 template <class DofEntity>
1613 void deserializeEntity(std::istream& instream,
1614 const DofEntity& dof)
1615 {
1616 const unsigned dofIdx = static_cast<unsigned>(asImp_().dofMapper().index(dof));
1617
1618 for (unsigned eqIdx = 0; eqIdx < numEq; ++eqIdx) {
1619 if (!instream.good()) {
1620 throw std::runtime_error("Could not deserialize degree of freedom " +
1621 std::to_string(dofIdx));
1622 }
1623 instream >> solution(/*timeIdx=*/0)[dofIdx][eqIdx];
1624 }
1625 }
1626
1630 std::size_t numGridDof() const
1631 { throw std::logic_error("The discretization class must implement the numGridDof() method!"); }
1632
1636 std::size_t numAuxiliaryDof() const
1637 {
1638 return std::accumulate(auxEqModules_.begin(), auxEqModules_.end(),
1639 std::size_t{0},
1640 [](const auto acc, const auto& mod)
1641 { return acc + mod->numDofs(); });
1642 }
1643
1647 std::size_t numTotalDof() const
1648 { return asImp_().numGridDof() + numAuxiliaryDof(); }
1649
1654 const DofMapper& dofMapper() const
1655 { throw std::logic_error("The discretization class must implement the dofMapper() method!"); }
1656
1660 const VertexMapper& vertexMapper() const
1661 { return vertexMapper_; }
1662
1666 const ElementMapper& elementMapper() const
1667 { return elementMapper_; }
1668
1674 {
1675 linearizer_ = std::make_unique<Linearizer>();
1676 linearizer_->init(simulator_);
1677 }
1678
1682 static std::string discretizationName()
1683 { return ""; }
1684
1690 std::string primaryVarName(unsigned pvIdx) const
1691 {
1692 std::ostringstream oss;
1693 oss << "primary variable_" << pvIdx;
1694 return oss.str();
1695 }
1696
1702 std::string eqName(unsigned eqIdx) const
1703 {
1704 std::ostringstream oss;
1705 oss << "equation_" << eqIdx;
1706 return oss.str();
1707 }
1708
1715 void updatePVWeights(const ElementContext&) const
1716 {}
1717
1721 void addOutputModule(std::unique_ptr<BaseOutputModule<TypeTag>> newModule)
1722 { outputModules_.push_back(std::move(newModule)); }
1723
1732 template <class VtkMultiWriter>
1734 const SolutionVector& u,
1735 const GlobalEqVector& deltaU) const
1736 {
1737 using ScalarBuffer = std::vector<double>;
1738
1739 GlobalEqVector globalResid(u.size());
1740 asImp_().globalResidual(globalResid, u);
1741
1742 // create the required scalar fields
1743 const std::size_t numDof = asImp_().numGridDof();
1744
1745 // global defect of the two auxiliary equations
1746 std::array<ScalarBuffer*, numEq> def;
1747 std::array<ScalarBuffer*, numEq> delta;
1748 std::array<ScalarBuffer*, numEq> priVars;
1749 std::array<ScalarBuffer*, numEq> priVarWeight;
1750 ScalarBuffer* relError = writer.allocateManagedScalarBuffer(numDof);
1751 ScalarBuffer* normalizedRelError = writer.allocateManagedScalarBuffer(numDof);
1752 for (unsigned pvIdx = 0; pvIdx < numEq; ++pvIdx) {
1753 priVars[pvIdx] = writer.allocateManagedScalarBuffer(numDof);
1754 priVarWeight[pvIdx] = writer.allocateManagedScalarBuffer(numDof);
1755 delta[pvIdx] = writer.allocateManagedScalarBuffer(numDof);
1756 def[pvIdx] = writer.allocateManagedScalarBuffer(numDof);
1757 }
1758
1759 Scalar minRelErr = 1e30;
1760 Scalar maxRelErr = -1e30;
1761 for (unsigned globalIdx = 0; globalIdx < numDof; ++ globalIdx) {
1762 for (unsigned pvIdx = 0; pvIdx < numEq; ++pvIdx) {
1763 (*priVars[pvIdx])[globalIdx] = u[globalIdx][pvIdx];
1764 (*priVarWeight[pvIdx])[globalIdx] = asImp_().primaryVarWeight(globalIdx, pvIdx);
1765 (*delta[pvIdx])[globalIdx] = - deltaU[globalIdx][pvIdx];
1766 (*def[pvIdx])[globalIdx] = globalResid[globalIdx][pvIdx];
1767 }
1768
1769 PrimaryVariables uOld(u[globalIdx]);
1770 PrimaryVariables uNew(uOld);
1771 uNew -= deltaU[globalIdx];
1772
1773 const Scalar err = asImp_().relativeDofError(globalIdx, uOld, uNew);
1774 (*relError)[globalIdx] = err;
1775 (*normalizedRelError)[globalIdx] = err;
1776 minRelErr = std::min(err, minRelErr);
1777 maxRelErr = std::max(err, maxRelErr);
1778 }
1779
1780 // do the normalization of the relative error
1781 const Scalar alpha = std::max(Scalar{1e-20},
1782 std::max(std::abs(maxRelErr),
1783 std::abs(minRelErr)));
1784 for (unsigned globalIdx = 0; globalIdx < numDof; ++globalIdx) {
1785 (*normalizedRelError)[globalIdx] /= alpha;
1786 }
1787
1788 DiscBaseOutputModule::attachScalarDofData_(writer, *relError, "relative error");
1789 DiscBaseOutputModule::attachScalarDofData_(writer, *normalizedRelError, "normalized relative error");
1790
1791 for (unsigned i = 0; i < numEq; ++i) {
1792 std::ostringstream oss;
1793 oss.str(""); oss << "priVar_" << asImp_().primaryVarName(i);
1794 DiscBaseOutputModule::attachScalarDofData_(writer,
1795 *priVars[i],
1796 oss.str());
1797
1798 oss.str(""); oss << "delta_" << asImp_().primaryVarName(i);
1799 DiscBaseOutputModule::attachScalarDofData_(writer,
1800 *delta[i],
1801 oss.str());
1802
1803 oss.str(""); oss << "weight_" << asImp_().primaryVarName(i);
1804 DiscBaseOutputModule::attachScalarDofData_(writer,
1805 *priVarWeight[i],
1806 oss.str());
1807
1808 oss.str(""); oss << "defect_" << asImp_().eqName(i);
1809 DiscBaseOutputModule::attachScalarDofData_(writer,
1810 *def[i],
1811 oss.str());
1812 }
1813
1814 asImp_().prepareOutputFields();
1815 asImp_().appendOutputFields(writer);
1816 }
1817
1823 {
1824 const bool needFullContextUpdate =
1825 std::ranges::any_of(outputModules_,
1826 [](const auto& mod)
1827 { return mod->needExtensiveQuantities(); });
1828 std::ranges::for_each(outputModules_,
1829 [](auto& mod) { mod->allocBuffers(); });
1830
1831 // iterate over grid
1832 ThreadedEntityIterator<GridView, /*codim=*/0> threadedElemIt(gridView());
1833#ifdef _OPENMP
1834#pragma omp parallel
1835#endif
1836 {
1837 ElementContext elemCtx(simulator_);
1838 ElementIterator elemIt = threadedElemIt.beginParallel();
1839 for (; !threadedElemIt.isFinished(elemIt); elemIt = threadedElemIt.increment()) {
1840 const auto& elem = *elemIt;
1841 if (elem.partitionType() != Dune::InteriorEntity) {
1842 // ignore non-interior entities
1843 continue;
1844 }
1845
1846 if (needFullContextUpdate) {
1847 elemCtx.updateAll(elem);
1848 }
1849 else {
1850 elemCtx.updatePrimaryStencil(elem);
1851 elemCtx.updatePrimaryIntensiveQuantities(/*timeIdx=*/0);
1852 }
1853
1854 std::ranges::for_each(outputModules_,
1855 [&elemCtx](auto& mod) { mod->processElement(elemCtx); });
1856 }
1857 }
1858 }
1859
1865 {
1866 std::ranges::for_each(outputModules_,
1867 [&writer](auto& mod) { mod->commitBuffers(writer); });
1868 }
1869
1873 const GridView& gridView() const
1874 { return gridView_; }
1875
1888 {
1889 auxMod->setDofOffset(numTotalDof());
1890 auxEqModules_.push_back(auxMod);
1891
1892 // resize the solutions
1893 if (enableGridAdaptation_ && !std::is_same_v<DiscreteFunction, BlockVectorWrapper>) {
1894 throw std::invalid_argument("Problems which require auxiliary modules cannot be used in"
1895 " conjunction with dune-fem");
1896 }
1897
1898 const std::size_t numDof = numTotalDof();
1899 for (unsigned timeIdx = 0; timeIdx < historySize; ++timeIdx) {
1900 solution(timeIdx).resize(numDof);
1901 }
1902
1903 auxMod->applyInitial();
1904 }
1905
1912 {
1913 auxEqModules_.clear();
1914 linearizer_->eraseMatrix();
1915 newtonMethod_.eraseMatrix();
1916 }
1917
1921 std::size_t numAuxiliaryModules() const
1922 { return auxEqModules_.size(); }
1923
1928 { return auxEqModules_[auxEqModIdx]; }
1929
1933 const BaseAuxiliaryModule<TypeTag>* auxiliaryModule(unsigned auxEqModIdx) const
1934 { return auxEqModules_[auxEqModIdx]; }
1935
1941
1943 { return prePostProcessTimer_; }
1944
1945 const Timer& linearizeTimer() const
1946 { return linearizeTimer_; }
1947
1948 const Timer& solveTimer() const
1949 { return solveTimer_; }
1950
1951 const Timer& updateTimer() const
1952 { return updateTimer_; }
1953
1954 template<class Serializer>
1955 void serializeOp(Serializer& serializer)
1956 {
1958 using Helper = typename BaseDiscretization::template SerializeHelper<Serializer>;
1959 Helper::serializeOp(serializer, solution_);
1960 }
1961
1962 bool operator==(const FvBaseDiscretization& rhs) const
1963 {
1964 return std::ranges::equal(this->solution_, rhs.solution_,
1965 [](const auto& x, const auto& y)
1966 { return *x == *y; });
1967 }
1968
1969protected:
1971 {
1972 // allocate the storage cache
1973 if (enableStorageCache()) {
1974 const std::size_t numDof = asImp_().numGridDof();
1975 for (unsigned timeIdx = 0; timeIdx < historySize; ++timeIdx) {
1976 storageCache_[timeIdx].resize(numDof);
1977 storageCacheUpToDate_[timeIdx].resize(numDof, /*value=*/0);
1978 }
1979 }
1980
1981 // allocate the intensive quantities cache
1983 const std::size_t numDof = asImp_().numGridDof();
1984 cachedIntensiveQuantityHistorySize_ = simulator_.problem().intensiveQuantityHistorySize();
1985 const unsigned intensiveHistorySize = cachedIntensiveQuantityHistorySize_;
1986
1987 // resize the vectors based on runtime history size
1988 intensiveQuantityCache_.resize(intensiveHistorySize);
1989 intensiveQuantityCacheUpToDate_.resize(intensiveHistorySize);
1990
1991 for(unsigned timeIdx = 0; timeIdx < intensiveHistorySize; ++timeIdx) {
1992 intensiveQuantityCache_[timeIdx].resize(numDof);
1993 intensiveQuantityCacheUpToDate_[timeIdx].resize(numDof);
1995 }
1996 }
1997 }
1998
1999 template <class Context>
2000 void supplementInitialSolution_(PrimaryVariables&,
2001 const Context&,
2002 unsigned,
2003 unsigned)
2004 {}
2005
2014 {
2015 // add the output modules available on all model
2016 this->outputModules_.push_back(std::make_unique<VtkPrimaryVarsModule<TypeTag>>(simulator_));
2017 }
2018
2022 LocalResidual& localResidual_()
2023 { return localLinearizer_.localResidual(); }
2024
2028 bool verbose_() const
2029 { return gridView_.comm().rank() == 0; }
2030
2031 Implementation& asImp_()
2032 { return *static_cast<Implementation*>(this); }
2033
2034 const Implementation& asImp_() const
2035 { return *static_cast<const Implementation*>(this); }
2036
2037 // the problem we want to solve. defines the constitutive
2038 // relations, matxerial laws, etc.
2039 Simulator& simulator_;
2040
2041 // the representation of the spatial domain of the problem
2042 GridView gridView_;
2043
2044 // the mappers for element and vertex entities to global indices
2045 ElementMapper elementMapper_;
2046 VertexMapper vertexMapper_;
2047
2048 // a vector with all auxiliary equations to be considered
2049 std::vector<BaseAuxiliaryModule<TypeTag>*> auxEqModules_;
2050
2051 NewtonMethod newtonMethod_;
2052
2057
2058 // calculates the local jacobian matrix for a given element
2059 std::vector<LocalLinearizer> localLinearizer_;
2060 // Linearizes the problem at the current time step using the
2061 // local jacobian
2062 std::unique_ptr<Linearizer> linearizer_;
2063
2064 // cur is the current iterative solution, prev the converged
2065 // solution of the previous time step
2066 mutable std::vector<IntensiveQuantitiesVector> intensiveQuantityCache_;
2067
2068 // while these are logically bools, concurrent writes to vector<bool> are not thread safe.
2069 mutable std::vector<std::vector<unsigned char>> intensiveQuantityCacheUpToDate_;
2070
2071 std::array<std::unique_ptr<DiscreteFunction>, historySize> solution_;
2072
2073 std::list<std::unique_ptr<BaseOutputModule<TypeTag>>> outputModules_;
2074
2076 std::vector<Scalar> dofTotalVolume_;
2077 std::vector<bool> isLocalDof_;
2078
2079 mutable std::array<GlobalEqVector, historySize> storageCache_;
2080
2081 // while these are logically bools, concurrent writes to vector<bool> are not thread safe.
2082 mutable std::array<std::vector<unsigned char>, historySize> storageCacheUpToDate_;
2083
2088
2090};
2091
2097template<class TypeTag>
2099{
2103
2104 static constexpr unsigned historySize = getPropValue<TypeTag, Properties::TimeDiscHistorySize>();
2105
2106public:
2107 template<class Serializer>
2109 {
2110 template<class SolutionType>
2111 static void serializeOp(Serializer& serializer,
2112 SolutionType& solution)
2113 {
2114 for (auto& sol : solution) {
2115 serializer(*sol);
2116 }
2117 }
2118 };
2119
2120 explicit FvBaseDiscretizationNoAdapt(Simulator& simulator)
2121 : ParentType(simulator)
2122 {
2123 if (this->enableGridAdaptation_) {
2124 throw std::invalid_argument("Grid adaptation need to use"
2125 " BaseDiscretization = FvBaseDiscretizationFemAdapt"
2126 " which currently requires the presence of the"
2127 " dune-fem module");
2128 }
2129 const std::size_t numDof = this->asImp_().numGridDof();
2130 for (unsigned timeIdx = 0; timeIdx < historySize; ++timeIdx) {
2131 this->solution_[timeIdx] = std::make_unique<DiscreteFunction>("solution", numDof);
2132 }
2133 }
2134};
2135
2136} // namespace Opm
2137
2138#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:2099
FvBaseDiscretizationNoAdapt(Simulator &simulator)
Definition: fvbasediscretization.hh:2120
The base class for the finite volume discretization schemes.
Definition: fvbasediscretization.hh:298
Timer linearizeTimer_
Definition: fvbasediscretization.hh:2054
std::vector< IntensiveQuantitiesVector > intensiveQuantityCache_
Definition: fvbasediscretization.hh:2066
LocalLinearizer & localLinearizer(unsigned openMpThreadId)
Definition: fvbasediscretization.hh:1322
void prepareOutputFields() const
Prepare the quantities relevant for the current solution to be appended to the output writers.
Definition: fvbasediscretization.hh:1822
void shiftIntensiveQuantityCache(unsigned numSlots=1)
Move the intensive quantities for a given time index to the back.
Definition: fvbasediscretization.hh:822
void invalidateAndUpdateIntensiveQuantities(unsigned timeIdx) const
Definition: fvbasediscretization.hh:727
void adaptGrid()
Called by the update() method when the grid should be refined.
Definition: fvbasediscretization.hh:1495
std::vector< BaseAuxiliaryModule< TypeTag > * > auxEqModules_
Definition: fvbasediscretization.hh:2049
const Implementation & asImp_() const
Definition: fvbasediscretization.hh:2034
void addAuxiliaryModule(BaseAuxiliaryModule< TypeTag > *auxMod)
Add a module for an auxiliary equation.
Definition: fvbasediscretization.hh:1887
void setIntensiveQuantitiesCacheEntryValidity(unsigned globalIdx, unsigned timeIdx, bool newValue) const
Invalidate the cache for a given intensive quantities object.
Definition: fvbasediscretization.hh:694
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:2086
void resizeAndResetIntensiveQuantitiesCache_()
Definition: fvbasediscretization.hh:1970
std::vector< Scalar > dofTotalVolume_
Definition: fvbasediscretization.hh:2076
void updateSuccessful()
Called by the update() method if it was successful.
Definition: fvbasediscretization.hh:1489
static std::string discretizationName()
Returns a string of discretization's human-readable name.
Definition: fvbasediscretization.hh:1682
unsigned cachedIntensiveQuantityHistorySize() const
Get the cached intensive quantity history size.
Definition: fvbasediscretization.hh:708
BaseAuxiliaryModule< TypeTag > * auxiliaryModule(unsigned auxEqModIdx)
Returns a given module for auxiliary equations.
Definition: fvbasediscretization.hh:1927
bool isLocalDof(unsigned globalIdx) const
Returns if the overlap of the volume ofa degree of freedom is non-zero.
Definition: fvbasediscretization.hh:1259
std::size_t numAuxiliaryModules() const
Returns the number of modules for auxiliary equations.
Definition: fvbasediscretization.hh:1921
bool operator==(const FvBaseDiscretization &rhs) const
Definition: fvbasediscretization.hh:1962
void serializeOp(Serializer &serializer)
Definition: fvbasediscretization.hh:1955
std::vector< bool > isLocalDof_
Definition: fvbasediscretization.hh:2077
LocalResidual & localResidual_()
Reference to the local residal object.
Definition: fvbasediscretization.hh:2022
void registerOutputModules_()
Register all output modules which make sense for the model.
Definition: fvbasediscretization.hh:2013
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:1290
void advanceTimeLevel()
Called by the problem if a time integration was successful, post processing of the solution is done a...
Definition: fvbasediscretization.hh:1533
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:1660
const EqVector & cachedStorage(unsigned globalIdx, unsigned timeIdx) const
Retrieve an entry of the cache for the storage term.
Definition: fvbasediscretization.hh:880
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:1715
const Timer & solveTimer() const
Definition: fvbasediscretization.hh:1948
void updateFailed()
Called by the update() method if it was unsuccessful. This is primary a hook which the actual model c...
Definition: fvbasediscretization.hh:1506
void updateBegin()
Called by the update() method before it tries to apply the newton method. This is primary a hook whic...
Definition: fvbasediscretization.hh:1482
FvBaseDiscretization(const FvBaseDiscretization &)=delete
Scalar globalResidual(GlobalEqVector &dest) const
Compute the global residual for the current solution vector.
Definition: fvbasediscretization.hh:999
LocalResidual & localResidual(unsigned openMpThreadId)
Definition: fvbasediscretization.hh:1334
void serializeEntity(std::ostream &outstream, const DofEntity &dof)
Write the current solution for a degree of freedom to a restart file.
Definition: fvbasediscretization.hh:1588
void setEnableStorageCache(bool enableStorageCache)
Set the value of enable storage cache.
Definition: fvbasediscretization.hh:864
std::string eqName(unsigned eqIdx) const
Given an equation index, return a human readable name.
Definition: fvbasediscretization.hh:1702
Scalar eqWeight(unsigned, unsigned) const
Returns the relative weight of an equation.
Definition: fvbasediscretization.hh:1356
std::array< std::vector< unsigned char >, historySize > storageCacheUpToDate_
Definition: fvbasediscretization.hh:2082
const Timer & prePostProcessTimer() const
Definition: fvbasediscretization.hh:1942
Scalar primaryVarWeight(unsigned globalDofIdx, unsigned pvIdx) const
Returns the relative weight of a primary variable for calculating relative errors.
Definition: fvbasediscretization.hh:1344
void deserialize(Restarter &)
Deserializes the state of the model.
Definition: fvbasediscretization.hh:1573
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:1129
Scalar gridTotalVolume() const
Returns the volume of the whole grid which represents the spatial domain.
Definition: fvbasediscretization.hh:1269
Timer updateTimer_
Definition: fvbasediscretization.hh:2056
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:920
const Timer & updateTimer() const
Definition: fvbasediscretization.hh:1951
const Linearizer & linearizer() const
Returns the operator linearizer for the global jacobian of the problem.
Definition: fvbasediscretization.hh:1298
void updateCachedStorage(unsigned globalIdx, unsigned timeIdx, const EqVector &value) const
Set an entry of the cache for the storage term.
Definition: fvbasediscretization.hh:904
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:1733
Scalar relativeDofError(unsigned vertexIdx, const PrimaryVariables &pv1, const PrimaryVariables &pv2) const
Returns the relative error between two vectors of primary variables.
Definition: fvbasediscretization.hh:1368
bool enableGridAdaptation_
Definition: fvbasediscretization.hh:2084
Scalar globalResidual(GlobalEqVector &dest, const SolutionVector &u) const
Compute the global residual for an arbitrary solution vector.
Definition: fvbasediscretization.hh:984
SolutionVector & solution(unsigned timeIdx)
Definition: fvbasediscretization.hh:1283
std::array< GlobalEqVector, historySize > storageCache_
Definition: fvbasediscretization.hh:2079
Timer prePostProcessTimer_
Definition: fvbasediscretization.hh:2053
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:1613
Timer solveTimer_
Definition: fvbasediscretization.hh:2055
void supplementInitialSolution_(PrimaryVariables &, const Context &, unsigned, unsigned)
Definition: fvbasediscretization.hh:2000
const LocalLinearizer & localLinearizer(unsigned openMpThreadId) const
Returns the local jacobian which calculates the local stiffness matrix for an arbitrary element.
Definition: fvbasediscretization.hh:1316
std::array< std::unique_ptr< DiscreteFunction >, historySize > solution_
Definition: fvbasediscretization.hh:2071
unsigned cachedIntensiveQuantityHistorySize_
Definition: fvbasediscretization.hh:2089
const Timer & linearizeTimer() const
Definition: fvbasediscretization.hh:1945
void invalidateAndUpdateIntensiveQuantities(unsigned timeIdx, const GridViewType &gridView) const
Definition: fvbasediscretization.hh:768
bool update()
Try to progress the model to the next timestep.
Definition: fvbasediscretization.hh:1389
const auto & intensiveQuantityCache() const
Definition: fvbasediscretization.hh:663
std::size_t numAuxiliaryDof() const
Returns the number of degrees of freedom (DOFs) of the auxiliary equations.
Definition: fvbasediscretization.hh:1636
void clearAuxiliaryModules()
Causes the list of auxiliary equations to be cleared.
Definition: fvbasediscretization.hh:1911
bool enableIntensiveQuantityCache_
Definition: fvbasediscretization.hh:2085
std::unique_ptr< Linearizer > linearizer_
Definition: fvbasediscretization.hh:2062
const ElementMapper & elementMapper() const
Returns the mapper for elements to indices.
Definition: fvbasediscretization.hh:1666
void syncOverlap()
Syncronize the values of the primary variables on the degrees of freedom that overlap with the neighb...
Definition: fvbasediscretization.hh:1474
void appendOutputFields(BaseOutputWriter &writer) const
Append the quantities relevant for the current solution to an output writer.
Definition: fvbasediscretization.hh:1864
std::list< std::unique_ptr< BaseOutputModule< TypeTag > > > outputModules_
Definition: fvbasediscretization.hh:2073
ElementMapper elementMapper_
Definition: fvbasediscretization.hh:2045
NewtonMethod newtonMethod_
Definition: fvbasediscretization.hh:2051
std::size_t numTotalDof() const
Returns the total number of degrees of freedom (i.e., grid plux auxiliary DOFs)
Definition: fvbasediscretization.hh:1647
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:2031
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:674
std::string primaryVarName(unsigned pvIdx) const
Given an primary variable index, return a human readable name.
Definition: fvbasediscretization.hh:1690
void invalidateIntensiveQuantitiesCache(unsigned timeIdx) const
Invalidate the whole intensive quantity cache for time index.
Definition: fvbasediscretization.hh:716
Linearizer & linearizer()
Returns the object which linearizes the global system of equations at the current solution.
Definition: fvbasediscretization.hh:1305
const BaseAuxiliaryModule< TypeTag > * auxiliaryModule(unsigned auxEqModIdx) const
Returns a given module for auxiliary equations.
Definition: fvbasediscretization.hh:1933
std::vector< std::vector< unsigned char > > intensiveQuantityCacheUpToDate_
Definition: fvbasediscretization.hh:2069
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:1059
GridView gridView_
Definition: fvbasediscretization.hh:2042
Scalar dofTotalVolume(unsigned globalIdx) const
Returns the volume of a given control volume.
Definition: fvbasediscretization.hh:1251
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:1277
bool verbose_() const
Returns whether messages should be printed.
Definition: fvbasediscretization.hh:2028
void shiftStorageCache(unsigned numSlots=1) const
Shift storage cache by a given number of time step slots.
Definition: fvbasediscretization.hh:964
Simulator & simulator_
Definition: fvbasediscretization.hh:2039
const LocalResidual & localResidual(unsigned openMpThreadId) const
Returns the object to calculate the local residual function.
Definition: fvbasediscretization.hh:1328
std::size_t numGridDof() const
Returns the number of degrees of freedom (DOFs) for the computational grid.
Definition: fvbasediscretization.hh:1630
Scalar gridTotalVolume_
Definition: fvbasediscretization.hh:2075
const DofMapper & dofMapper() const
Mapper to convert the Dune entities of the discretization's degrees of freedoms are to indices.
Definition: fvbasediscretization.hh:1654
bool storeIntensiveQuantities() const
Returns true if the cache for intensive quantities is enabled.
Definition: fvbasediscretization.hh:1939
std::vector< LocalLinearizer > localLinearizer_
Definition: fvbasediscretization.hh:2059
void invalidateStorageCache(unsigned timeIdx) const
Invalidate the whole storage cache for a given time index.
Definition: fvbasediscretization.hh:946
void serialize(Restarter &)
Serializes the current state of the model.
Definition: fvbasediscretization.hh:1559
bool enableThermodynamicHints_
Definition: fvbasediscretization.hh:2087
void rebuildStorageCache(const unsigned timeIdx) const
Definition: fvbasediscretization.hh:1072
void invalidateStorageCacheEntry(unsigned globalIdx, unsigned timeIdx) const
Invalidate the storage cache for a given DOF and time index.
Definition: fvbasediscretization.hh:934
VertexMapper vertexMapper_
Definition: fvbasediscretization.hh:2046
void resetLinearizer()
Resets the Jacobian matrix linearizer, so that the boundary types can be altered.
Definition: fvbasediscretization.hh:1673
bool enableStorageCache() const
Returns true iff the storage term is cached.
Definition: fvbasediscretization.hh:855
size_t numDof() const
Definition: fvbasediscretization.hh:1262
const GridView & gridView() const
Reference to the grid view of the spatial domain.
Definition: fvbasediscretization.hh:1873
void addOutputModule(std::unique_ptr< BaseOutputModule< TypeTag > > newModule)
Add an module for writing visualization output after a timestep.
Definition: fvbasediscretization.hh:1721
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:2109
static void serializeOp(Serializer &serializer, SolutionType &solution)
Definition: fvbasediscretization.hh:2111
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