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 ThreadedEntityIterator<GridView, /*codim=*/0> threadedElemIt(gridView());
1065#ifdef _OPENMP
1066#pragma omp parallel
1067#endif
1068 {
1069 // Attention: the variables below are thread specific and thus cannot be
1070 // moved in front of the #pragma!
1071 const unsigned threadId = ThreadManager::threadId();
1072 ElementContext elemCtx(simulator_);
1073 ElementIterator elemIt = threadedElemIt.beginParallel();
1074 LocalEvalBlockVector elemStorage;
1075
1076 // in this method, we need to disable the storage cache because we want to
1077 // evaluate the storage term for other time indices than the most recent one
1078 elemCtx.setEnableStorageCache(false);
1079
1080 for (; !threadedElemIt.isFinished(elemIt); elemIt = threadedElemIt.increment()) {
1081 const Element& elem = *elemIt;
1082 if (elem.partitionType() != Dune::InteriorEntity) {
1083 continue; // ignore ghost and overlap elements
1084 }
1085
1086 elemCtx.updateStencil(elem);
1087 elemCtx.updatePrimaryIntensiveQuantities(timeIdx);
1088
1089 const std::size_t numPrimaryDof = elemCtx.numPrimaryDof(timeIdx);
1090 elemStorage.resize(numPrimaryDof);
1091
1092 localResidual(threadId).evalStorage(elemStorage, elemCtx, timeIdx);
1093
1094 mutex.lock();
1095 for (unsigned dofIdx = 0; dofIdx < numPrimaryDof; ++dofIdx) {
1096 for (unsigned eqIdx = 0; eqIdx < numEq; ++eqIdx) {
1097 storage[eqIdx] += Toolbox::value(elemStorage[dofIdx][eqIdx]);
1098 }
1099 }
1100 mutex.unlock();
1101 }
1102 }
1103
1104 storage = gridView_.comm().sum(storage);
1105 }
1106
1114 void checkConservativeness([[maybe_unused]] Scalar tolerance = -1,
1115 [[maybe_unused]] bool verbose = false) const
1116 {
1117#ifndef NDEBUG
1118 Scalar totalBoundaryArea(0.0);
1119 Scalar totalVolume(0.0);
1120 EvalEqVector totalRate(0.0);
1121
1122 // take the newton tolerance times the total volume of the grid if we're not
1123 // given an explicit tolerance...
1124 if (tolerance <= 0) {
1125 tolerance =
1126 simulator_.model().newtonMethod().tolerance() *
1127 simulator_.model().gridTotalVolume() *
1128 1000;
1129 }
1130
1131 // we assume the implicit Euler time discretization for now...
1132 assert(historySize == 2);
1133
1134 EqVector storageBeginTimeStep(0.0);
1135 globalStorage(storageBeginTimeStep, /*timeIdx=*/1);
1136
1137 EqVector storageEndTimeStep(0.0);
1138 globalStorage(storageEndTimeStep, /*timeIdx=*/0);
1139
1140 // calculate the rate at the boundary and the source rate
1141 ElementContext elemCtx(simulator_);
1142 elemCtx.setEnableStorageCache(false);
1143 for (const auto& elem : elements(simulator_.gridView())) {
1144 if (elem.partitionType() != Dune::InteriorEntity) {
1145 continue; // ignore ghost and overlap elements
1146 }
1147
1148 elemCtx.updateAll(elem);
1149
1150 // handle the boundary terms
1151 if (elemCtx.onBoundary()) {
1152 BoundaryContext boundaryCtx(elemCtx);
1153
1154 for (unsigned faceIdx = 0; faceIdx < boundaryCtx.numBoundaryFaces(/*timeIdx=*/0); ++faceIdx) {
1155 BoundaryRateVector values;
1156 simulator_.problem().boundary(values,
1157 boundaryCtx,
1158 faceIdx,
1159 /*timeIdx=*/0);
1160 Valgrind::CheckDefined(values);
1161
1162 const unsigned dofIdx = boundaryCtx.interiorScvIndex(faceIdx, /*timeIdx=*/0);
1163 const auto& insideIntQuants = elemCtx.intensiveQuantities(dofIdx, /*timeIdx=*/0);
1164
1165 const Scalar bfArea =
1166 boundaryCtx.boundarySegmentArea(faceIdx, /*timeIdx=*/0) *
1167 insideIntQuants.extrusionFactor();
1168
1169 for (unsigned i = 0; i < values.size(); ++i) {
1170 values[i] *= bfArea;
1171 }
1172
1173 totalBoundaryArea += bfArea;
1174 for (unsigned eqIdx = 0; eqIdx < numEq; ++eqIdx) {
1175 totalRate[eqIdx] += values[eqIdx];
1176 }
1177 }
1178 }
1179
1180 // deal with the source terms
1181 for (unsigned dofIdx = 0; dofIdx < elemCtx.numPrimaryDof(/*timeIdx=*/0); ++dofIdx) {
1182 RateVector values;
1183 simulator_.problem().source(values,
1184 elemCtx,
1185 dofIdx,
1186 /*timeIdx=*/0);
1187 Valgrind::CheckDefined(values);
1188
1189 const auto& intQuants = elemCtx.intensiveQuantities(dofIdx, /*timeIdx=*/0);
1190 Scalar dofVolume =
1191 elemCtx.dofVolume(dofIdx, /*timeIdx=*/0) *
1192 intQuants.extrusionFactor();
1193 for (unsigned eqIdx = 0; eqIdx < numEq; ++eqIdx) {
1194 totalRate[eqIdx] += -dofVolume*Toolbox::value(values[eqIdx]);
1195 }
1196 totalVolume += dofVolume;
1197 }
1198 }
1199
1200 // summarize everything over all processes
1201 const auto& comm = simulator_.gridView().comm();
1202 totalRate = comm.sum(totalRate);
1203 totalBoundaryArea = comm.sum(totalBoundaryArea);
1204 totalVolume = comm.sum(totalVolume);
1205
1206 if (comm.rank() == 0) {
1207 EqVector storageRate = storageBeginTimeStep;
1208 storageRate -= storageEndTimeStep;
1209 storageRate /= simulator_.timeStepSize();
1210 if (verbose) {
1211 std::cout << "storage at beginning of time step: " << storageBeginTimeStep << "\n";
1212 std::cout << "storage at end of time step: " << storageEndTimeStep << "\n";
1213 std::cout << "rate based on storage terms: " << storageRate << "\n";
1214 std::cout << "rate based on source and boundary terms: " << totalRate << "\n";
1215 std::cout << "difference in rates: ";
1216 for (unsigned eqIdx = 0; eqIdx < EqVector::dimension; ++eqIdx) {
1217 std::cout << (storageRate[eqIdx] - Toolbox::value(totalRate[eqIdx])) << " ";
1218 }
1219 std::cout << "\n";
1220 }
1221 for (unsigned eqIdx = 0; eqIdx < EqVector::dimension; ++eqIdx) {
1222 Scalar eps =
1223 (std::abs(storageRate[eqIdx]) + Toolbox::value(totalRate[eqIdx])) * tolerance;
1224 eps = std::max(tolerance, eps);
1225 assert(std::abs(storageRate[eqIdx] - Toolbox::value(totalRate[eqIdx])) <= eps);
1226 }
1227 }
1228#endif // NDEBUG
1229 }
1230
1236 Scalar dofTotalVolume(unsigned globalIdx) const
1237 { return dofTotalVolume_[globalIdx]; }
1238
1244 bool isLocalDof(unsigned globalIdx) const
1245 { return isLocalDof_[globalIdx]; }
1246
1247 size_t numDof() const
1248 { return asImp_().numGridDof(); }
1249
1254 Scalar gridTotalVolume() const
1255 { return gridTotalVolume_; }
1256
1262 const SolutionVector& solution(unsigned timeIdx) const
1263 { return solution_[timeIdx]->blockVector(); }
1264
1268 SolutionVector& solution(unsigned timeIdx)
1269 { return solution_[timeIdx]->blockVector(); }
1270
1271 protected:
1275 SolutionVector& mutableSolution(unsigned timeIdx) const
1276 { return solution_[timeIdx]->blockVector(); }
1277
1278 public:
1283 const Linearizer& linearizer() const
1284 { return *linearizer_; }
1285
1290 Linearizer& linearizer()
1291 { return *linearizer_; }
1292
1301 const LocalLinearizer& localLinearizer(unsigned openMpThreadId) const
1302 { return localLinearizer_[openMpThreadId]; }
1303
1307 LocalLinearizer& localLinearizer(unsigned openMpThreadId)
1308 { return localLinearizer_[openMpThreadId]; }
1309
1313 const LocalResidual& localResidual(unsigned openMpThreadId) const
1314 { return asImp_().localLinearizer(openMpThreadId).localResidual(); }
1315
1319 LocalResidual& localResidual(unsigned openMpThreadId)
1320 { return asImp_().localLinearizer(openMpThreadId).localResidual(); }
1321
1329 Scalar primaryVarWeight(unsigned globalDofIdx, unsigned pvIdx) const
1330 {
1331 const Scalar absPv = std::abs(asImp_().solution(/*timeIdx=*/1)[globalDofIdx][pvIdx]);
1332 return 1.0 / std::max(absPv, 1.0);
1333 }
1334
1341 Scalar eqWeight(unsigned, unsigned) const
1342 { return 1.0; }
1343
1353 Scalar relativeDofError(unsigned vertexIdx,
1354 const PrimaryVariables& pv1,
1355 const PrimaryVariables& pv2) const
1356 {
1357 Scalar result = 0.0;
1358 for (unsigned j = 0; j < numEq; ++j) {
1359 const Scalar weight = asImp_().primaryVarWeight(vertexIdx, j);
1360 const Scalar eqErr = std::abs((pv1[j] - pv2[j])*weight);
1361 //Scalar eqErr = std::abs(pv1[j] - pv2[j]);
1362 //eqErr *= std::max<Scalar>(1.0, std::abs(pv1[j] + pv2[j])/2);
1363
1364 result = std::max(result, eqErr);
1365 }
1366 return result;
1367 }
1368
1374 bool update()
1375 {
1376 const TimerGuard prePostProcessGuard(prePostProcessTimer_);
1377
1378#ifndef NDEBUG
1379 for (unsigned timeIdx = 0; timeIdx < historySize; ++timeIdx) {
1380 // Make sure that the primary variables are defined. Note that because of padding
1381 // bytes, we can't just simply ask valgrind to check the whole solution vectors
1382 // for definedness...
1383 for (std::size_t i = 0; i < asImp_().solution(/*timeIdx=*/0).size(); ++i) {
1384 asImp_().solution(timeIdx)[i].checkDefined();
1385 }
1386 }
1387#endif // NDEBUG
1388
1389 // make sure all timers are prestine
1392 solveTimer_.halt();
1394
1396 asImp_().updateBegin();
1398
1399 bool converged = false;
1400
1401 try {
1402 converged = newtonMethod_.apply();
1403 }
1404 catch(...) {
1405 prePostProcessTimer_ += newtonMethod_.prePostProcessTimer();
1406 linearizeTimer_ += newtonMethod_.linearizeTimer();
1407 solveTimer_ += newtonMethod_.solveTimer();
1408 updateTimer_ += newtonMethod_.updateTimer();
1409
1410 throw;
1411 }
1412
1413#ifndef NDEBUG
1414 for (unsigned timeIdx = 0; timeIdx < historySize; ++timeIdx) {
1415 // Make sure that the primary variables are defined. Note that because of padding
1416 // bytes, we can't just simply ask valgrind to check the whole solution vectors
1417 // for definedness...
1418 for (std::size_t i = 0; i < asImp_().solution(/*timeIdx=*/0).size(); ++i) {
1419 asImp_().solution(timeIdx)[i].checkDefined();
1420 }
1421 }
1422#endif // NDEBUG
1423
1424 prePostProcessTimer_ += newtonMethod_.prePostProcessTimer();
1425 linearizeTimer_ += newtonMethod_.linearizeTimer();
1426 solveTimer_ += newtonMethod_.solveTimer();
1427 updateTimer_ += newtonMethod_.updateTimer();
1428
1430 if (converged) {
1431 asImp_().updateSuccessful();
1432 }
1433 else {
1434 asImp_().updateFailed();
1435 }
1437
1438#ifndef NDEBUG
1439 for (unsigned timeIdx = 0; timeIdx < historySize; ++timeIdx) {
1440 // Make sure that the primary variables are defined. Note that because of padding
1441 // bytes, we can't just simply ask valgrind to check the whole solution vectors
1442 // for definedness...
1443 for (std::size_t i = 0; i < asImp_().solution(/*timeIdx=*/0).size(); ++i) {
1444 asImp_().solution(timeIdx)[i].checkDefined();
1445 }
1446 }
1447#endif // NDEBUG
1448
1449 return converged;
1450 }
1451
1460 {}
1461
1468 {}
1469
1475 {}
1476
1481 {
1482 throw std::invalid_argument("Grid adaptation need to be implemented for "
1483 "specific settings of grid and function spaces");
1484 }
1485
1492 {
1493 // Reset the current solution to the one of the
1494 // previous time step so that we can start the next
1495 // update at a physically meaningful solution.
1496 solution(/*timeIdx=*/0) = solution(/*timeIdx=*/1);
1498
1499#ifndef NDEBUG
1500 for (unsigned timeIdx = 0; timeIdx < historySize; ++timeIdx) {
1501 // Make sure that the primary variables are defined. Note that because of padding
1502 // bytes, we can't just simply ask valgrind to check the whole solution vectors
1503 // for definedness...
1504 for (std::size_t i = 0; i < asImp_().solution(/*timeIdx=*/0).size(); ++i) {
1505 asImp_().solution(timeIdx)[i].checkDefined();
1506 }
1507 }
1508#endif // NDEBUG
1509 }
1510
1519 {
1520 // at this point we can adapt the grid
1521 if (this->enableGridAdaptation_) {
1522 asImp_().adaptGrid();
1523 }
1524
1525 // make the current solution the previous one.
1526 solution(/*timeIdx=*/1) = solution(/*timeIdx=*/0);
1527
1528 // shift the storage cache by one position in the history
1529 asImp_().shiftStorageCache(/*numSlots=*/1);
1530
1531 // shift the intensive quantities cache by one position in the
1532 // history
1533 asImp_().shiftIntensiveQuantityCache(/*numSlots=*/1);
1534 }
1535
1543 template <class Restarter>
1544 void serialize(Restarter&)
1545 {
1546 throw std::runtime_error("Not implemented: The discretization chosen for this problem "
1547 "does not support restart files. (serialize() method unimplemented)");
1548 }
1549
1557 template <class Restarter>
1558 void deserialize(Restarter&)
1559 {
1560 throw std::runtime_error("Not implemented: The discretization chosen for this problem "
1561 "does not support restart files. (deserialize() method unimplemented)");
1562 }
1563
1572 template <class DofEntity>
1573 void serializeEntity(std::ostream& outstream,
1574 const DofEntity& dof)
1575 {
1576 const unsigned dofIdx = static_cast<unsigned>(asImp_().dofMapper().index(dof));
1577
1578 // write phase state
1579 if (!outstream.good()) {
1580 throw std::runtime_error("Could not serialize degree of freedom " +
1581 std::to_string(dofIdx));
1582 }
1583
1584 for (unsigned eqIdx = 0; eqIdx < numEq; ++eqIdx) {
1585 outstream << solution(/*timeIdx=*/0)[dofIdx][eqIdx] << " ";
1586 }
1587 }
1588
1597 template <class DofEntity>
1598 void deserializeEntity(std::istream& instream,
1599 const DofEntity& dof)
1600 {
1601 const unsigned dofIdx = static_cast<unsigned>(asImp_().dofMapper().index(dof));
1602
1603 for (unsigned eqIdx = 0; eqIdx < numEq; ++eqIdx) {
1604 if (!instream.good()) {
1605 throw std::runtime_error("Could not deserialize degree of freedom " +
1606 std::to_string(dofIdx));
1607 }
1608 instream >> solution(/*timeIdx=*/0)[dofIdx][eqIdx];
1609 }
1610 }
1611
1615 std::size_t numGridDof() const
1616 { throw std::logic_error("The discretization class must implement the numGridDof() method!"); }
1617
1621 std::size_t numAuxiliaryDof() const
1622 {
1623 return std::accumulate(auxEqModules_.begin(), auxEqModules_.end(),
1624 std::size_t{0},
1625 [](const auto acc, const auto& mod)
1626 { return acc + mod->numDofs(); });
1627 }
1628
1632 std::size_t numTotalDof() const
1633 { return asImp_().numGridDof() + numAuxiliaryDof(); }
1634
1639 const DofMapper& dofMapper() const
1640 { throw std::logic_error("The discretization class must implement the dofMapper() method!"); }
1641
1645 const VertexMapper& vertexMapper() const
1646 { return vertexMapper_; }
1647
1651 const ElementMapper& elementMapper() const
1652 { return elementMapper_; }
1653
1659 {
1660 linearizer_ = std::make_unique<Linearizer>();
1661 linearizer_->init(simulator_);
1662 }
1663
1667 static std::string discretizationName()
1668 { return ""; }
1669
1675 std::string primaryVarName(unsigned pvIdx) const
1676 {
1677 std::ostringstream oss;
1678 oss << "primary variable_" << pvIdx;
1679 return oss.str();
1680 }
1681
1687 std::string eqName(unsigned eqIdx) const
1688 {
1689 std::ostringstream oss;
1690 oss << "equation_" << eqIdx;
1691 return oss.str();
1692 }
1693
1700 void updatePVWeights(const ElementContext&) const
1701 {}
1702
1706 void addOutputModule(std::unique_ptr<BaseOutputModule<TypeTag>> newModule)
1707 { outputModules_.push_back(std::move(newModule)); }
1708
1717 template <class VtkMultiWriter>
1719 const SolutionVector& u,
1720 const GlobalEqVector& deltaU) const
1721 {
1722 using ScalarBuffer = std::vector<double>;
1723
1724 GlobalEqVector globalResid(u.size());
1725 asImp_().globalResidual(globalResid, u);
1726
1727 // create the required scalar fields
1728 const std::size_t numDof = asImp_().numGridDof();
1729
1730 // global defect of the two auxiliary equations
1731 std::array<ScalarBuffer*, numEq> def;
1732 std::array<ScalarBuffer*, numEq> delta;
1733 std::array<ScalarBuffer*, numEq> priVars;
1734 std::array<ScalarBuffer*, numEq> priVarWeight;
1735 ScalarBuffer* relError = writer.allocateManagedScalarBuffer(numDof);
1736 ScalarBuffer* normalizedRelError = writer.allocateManagedScalarBuffer(numDof);
1737 for (unsigned pvIdx = 0; pvIdx < numEq; ++pvIdx) {
1738 priVars[pvIdx] = writer.allocateManagedScalarBuffer(numDof);
1739 priVarWeight[pvIdx] = writer.allocateManagedScalarBuffer(numDof);
1740 delta[pvIdx] = writer.allocateManagedScalarBuffer(numDof);
1741 def[pvIdx] = writer.allocateManagedScalarBuffer(numDof);
1742 }
1743
1744 Scalar minRelErr = 1e30;
1745 Scalar maxRelErr = -1e30;
1746 for (unsigned globalIdx = 0; globalIdx < numDof; ++ globalIdx) {
1747 for (unsigned pvIdx = 0; pvIdx < numEq; ++pvIdx) {
1748 (*priVars[pvIdx])[globalIdx] = u[globalIdx][pvIdx];
1749 (*priVarWeight[pvIdx])[globalIdx] = asImp_().primaryVarWeight(globalIdx, pvIdx);
1750 (*delta[pvIdx])[globalIdx] = - deltaU[globalIdx][pvIdx];
1751 (*def[pvIdx])[globalIdx] = globalResid[globalIdx][pvIdx];
1752 }
1753
1754 PrimaryVariables uOld(u[globalIdx]);
1755 PrimaryVariables uNew(uOld);
1756 uNew -= deltaU[globalIdx];
1757
1758 const Scalar err = asImp_().relativeDofError(globalIdx, uOld, uNew);
1759 (*relError)[globalIdx] = err;
1760 (*normalizedRelError)[globalIdx] = err;
1761 minRelErr = std::min(err, minRelErr);
1762 maxRelErr = std::max(err, maxRelErr);
1763 }
1764
1765 // do the normalization of the relative error
1766 const Scalar alpha = std::max(Scalar{1e-20},
1767 std::max(std::abs(maxRelErr),
1768 std::abs(minRelErr)));
1769 for (unsigned globalIdx = 0; globalIdx < numDof; ++globalIdx) {
1770 (*normalizedRelError)[globalIdx] /= alpha;
1771 }
1772
1773 DiscBaseOutputModule::attachScalarDofData_(writer, *relError, "relative error");
1774 DiscBaseOutputModule::attachScalarDofData_(writer, *normalizedRelError, "normalized relative error");
1775
1776 for (unsigned i = 0; i < numEq; ++i) {
1777 std::ostringstream oss;
1778 oss.str(""); oss << "priVar_" << asImp_().primaryVarName(i);
1779 DiscBaseOutputModule::attachScalarDofData_(writer,
1780 *priVars[i],
1781 oss.str());
1782
1783 oss.str(""); oss << "delta_" << asImp_().primaryVarName(i);
1784 DiscBaseOutputModule::attachScalarDofData_(writer,
1785 *delta[i],
1786 oss.str());
1787
1788 oss.str(""); oss << "weight_" << asImp_().primaryVarName(i);
1789 DiscBaseOutputModule::attachScalarDofData_(writer,
1790 *priVarWeight[i],
1791 oss.str());
1792
1793 oss.str(""); oss << "defect_" << asImp_().eqName(i);
1794 DiscBaseOutputModule::attachScalarDofData_(writer,
1795 *def[i],
1796 oss.str());
1797 }
1798
1799 asImp_().prepareOutputFields();
1800 asImp_().appendOutputFields(writer);
1801 }
1802
1808 {
1809 const bool needFullContextUpdate =
1810 std::ranges::any_of(outputModules_,
1811 [](const auto& mod)
1812 { return mod->needExtensiveQuantities(); });
1813 std::ranges::for_each(outputModules_,
1814 [](auto& mod) { mod->allocBuffers(); });
1815
1816 // iterate over grid
1817 ThreadedEntityIterator<GridView, /*codim=*/0> threadedElemIt(gridView());
1818#ifdef _OPENMP
1819#pragma omp parallel
1820#endif
1821 {
1822 ElementContext elemCtx(simulator_);
1823 ElementIterator elemIt = threadedElemIt.beginParallel();
1824 for (; !threadedElemIt.isFinished(elemIt); elemIt = threadedElemIt.increment()) {
1825 const auto& elem = *elemIt;
1826 if (elem.partitionType() != Dune::InteriorEntity) {
1827 // ignore non-interior entities
1828 continue;
1829 }
1830
1831 if (needFullContextUpdate) {
1832 elemCtx.updateAll(elem);
1833 }
1834 else {
1835 elemCtx.updatePrimaryStencil(elem);
1836 elemCtx.updatePrimaryIntensiveQuantities(/*timeIdx=*/0);
1837 }
1838
1839 std::ranges::for_each(outputModules_,
1840 [&elemCtx](auto& mod) { mod->processElement(elemCtx); });
1841 }
1842 }
1843 }
1844
1850 {
1851 std::ranges::for_each(outputModules_,
1852 [&writer](auto& mod) { mod->commitBuffers(writer); });
1853 }
1854
1858 const GridView& gridView() const
1859 { return gridView_; }
1860
1873 {
1874 auxMod->setDofOffset(numTotalDof());
1875 auxEqModules_.push_back(auxMod);
1876
1877 // resize the solutions
1878 if (enableGridAdaptation_ && !std::is_same_v<DiscreteFunction, BlockVectorWrapper>) {
1879 throw std::invalid_argument("Problems which require auxiliary modules cannot be used in"
1880 " conjunction with dune-fem");
1881 }
1882
1883 const std::size_t numDof = numTotalDof();
1884 for (unsigned timeIdx = 0; timeIdx < historySize; ++timeIdx) {
1885 solution(timeIdx).resize(numDof);
1886 }
1887
1888 auxMod->applyInitial();
1889 }
1890
1897 {
1898 auxEqModules_.clear();
1899 linearizer_->eraseMatrix();
1900 newtonMethod_.eraseMatrix();
1901 }
1902
1906 std::size_t numAuxiliaryModules() const
1907 { return auxEqModules_.size(); }
1908
1913 { return auxEqModules_[auxEqModIdx]; }
1914
1918 const BaseAuxiliaryModule<TypeTag>* auxiliaryModule(unsigned auxEqModIdx) const
1919 { return auxEqModules_[auxEqModIdx]; }
1920
1926
1928 { return prePostProcessTimer_; }
1929
1930 const Timer& linearizeTimer() const
1931 { return linearizeTimer_; }
1932
1933 const Timer& solveTimer() const
1934 { return solveTimer_; }
1935
1936 const Timer& updateTimer() const
1937 { return updateTimer_; }
1938
1939 template<class Serializer>
1940 void serializeOp(Serializer& serializer)
1941 {
1943 using Helper = typename BaseDiscretization::template SerializeHelper<Serializer>;
1944 Helper::serializeOp(serializer, solution_);
1945 }
1946
1947 bool operator==(const FvBaseDiscretization& rhs) const
1948 {
1949 return std::ranges::equal(this->solution_, rhs.solution_,
1950 [](const auto& x, const auto& y)
1951 { return *x == *y; });
1952 }
1953
1954protected:
1956 {
1957 // allocate the storage cache
1958 if (enableStorageCache()) {
1959 const std::size_t numDof = asImp_().numGridDof();
1960 for (unsigned timeIdx = 0; timeIdx < historySize; ++timeIdx) {
1961 storageCache_[timeIdx].resize(numDof);
1962 storageCacheUpToDate_[timeIdx].resize(numDof, /*value=*/0);
1963 }
1964 }
1965
1966 // allocate the intensive quantities cache
1968 const std::size_t numDof = asImp_().numGridDof();
1969 cachedIntensiveQuantityHistorySize_ = simulator_.problem().intensiveQuantityHistorySize();
1970 const unsigned intensiveHistorySize = cachedIntensiveQuantityHistorySize_;
1971
1972 // resize the vectors based on runtime history size
1973 intensiveQuantityCache_.resize(intensiveHistorySize);
1974 intensiveQuantityCacheUpToDate_.resize(intensiveHistorySize);
1975
1976 for(unsigned timeIdx = 0; timeIdx < intensiveHistorySize; ++timeIdx) {
1977 intensiveQuantityCache_[timeIdx].resize(numDof);
1978 intensiveQuantityCacheUpToDate_[timeIdx].resize(numDof);
1980 }
1981 }
1982 }
1983
1984 template <class Context>
1985 void supplementInitialSolution_(PrimaryVariables&,
1986 const Context&,
1987 unsigned,
1988 unsigned)
1989 {}
1990
1999 {
2000 // add the output modules available on all model
2001 this->outputModules_.push_back(std::make_unique<VtkPrimaryVarsModule<TypeTag>>(simulator_));
2002 }
2003
2007 LocalResidual& localResidual_()
2008 { return localLinearizer_.localResidual(); }
2009
2013 bool verbose_() const
2014 { return gridView_.comm().rank() == 0; }
2015
2016 Implementation& asImp_()
2017 { return *static_cast<Implementation*>(this); }
2018
2019 const Implementation& asImp_() const
2020 { return *static_cast<const Implementation*>(this); }
2021
2022 // the problem we want to solve. defines the constitutive
2023 // relations, matxerial laws, etc.
2024 Simulator& simulator_;
2025
2026 // the representation of the spatial domain of the problem
2027 GridView gridView_;
2028
2029 // the mappers for element and vertex entities to global indices
2030 ElementMapper elementMapper_;
2031 VertexMapper vertexMapper_;
2032
2033 // a vector with all auxiliary equations to be considered
2034 std::vector<BaseAuxiliaryModule<TypeTag>*> auxEqModules_;
2035
2036 NewtonMethod newtonMethod_;
2037
2042
2043 // calculates the local jacobian matrix for a given element
2044 std::vector<LocalLinearizer> localLinearizer_;
2045 // Linearizes the problem at the current time step using the
2046 // local jacobian
2047 std::unique_ptr<Linearizer> linearizer_;
2048
2049 // cur is the current iterative solution, prev the converged
2050 // solution of the previous time step
2051 mutable std::vector<IntensiveQuantitiesVector> intensiveQuantityCache_;
2052
2053 // while these are logically bools, concurrent writes to vector<bool> are not thread safe.
2054 mutable std::vector<std::vector<unsigned char>> intensiveQuantityCacheUpToDate_;
2055
2056 std::array<std::unique_ptr<DiscreteFunction>, historySize> solution_;
2057
2058 std::list<std::unique_ptr<BaseOutputModule<TypeTag>>> outputModules_;
2059
2061 std::vector<Scalar> dofTotalVolume_;
2062 std::vector<bool> isLocalDof_;
2063
2064 mutable std::array<GlobalEqVector, historySize> storageCache_;
2065
2066 // while these are logically bools, concurrent writes to vector<bool> are not thread safe.
2067 mutable std::array<std::vector<unsigned char>, historySize> storageCacheUpToDate_;
2068
2073
2075};
2076
2082template<class TypeTag>
2084{
2088
2089 static constexpr unsigned historySize = getPropValue<TypeTag, Properties::TimeDiscHistorySize>();
2090
2091public:
2092 template<class Serializer>
2094 {
2095 template<class SolutionType>
2096 static void serializeOp(Serializer& serializer,
2097 SolutionType& solution)
2098 {
2099 for (auto& sol : solution) {
2100 serializer(*sol);
2101 }
2102 }
2103 };
2104
2105 explicit FvBaseDiscretizationNoAdapt(Simulator& simulator)
2106 : ParentType(simulator)
2107 {
2108 if (this->enableGridAdaptation_) {
2109 throw std::invalid_argument("Grid adaptation need to use"
2110 " BaseDiscretization = FvBaseDiscretizationFemAdapt"
2111 " which currently requires the presence of the"
2112 " dune-fem module");
2113 }
2114 const std::size_t numDof = this->asImp_().numGridDof();
2115 for (unsigned timeIdx = 0; timeIdx < historySize; ++timeIdx) {
2116 this->solution_[timeIdx] = std::make_unique<DiscreteFunction>("solution", numDof);
2117 }
2118 }
2119};
2120
2121} // namespace Opm
2122
2123#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:2084
FvBaseDiscretizationNoAdapt(Simulator &simulator)
Definition: fvbasediscretization.hh:2105
The base class for the finite volume discretization schemes.
Definition: fvbasediscretization.hh:298
Timer linearizeTimer_
Definition: fvbasediscretization.hh:2039
std::vector< IntensiveQuantitiesVector > intensiveQuantityCache_
Definition: fvbasediscretization.hh:2051
LocalLinearizer & localLinearizer(unsigned openMpThreadId)
Definition: fvbasediscretization.hh:1307
void prepareOutputFields() const
Prepare the quantities relevant for the current solution to be appended to the output writers.
Definition: fvbasediscretization.hh:1807
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:1480
std::vector< BaseAuxiliaryModule< TypeTag > * > auxEqModules_
Definition: fvbasediscretization.hh:2034
const Implementation & asImp_() const
Definition: fvbasediscretization.hh:2019
void addAuxiliaryModule(BaseAuxiliaryModule< TypeTag > *auxMod)
Add a module for an auxiliary equation.
Definition: fvbasediscretization.hh:1872
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:2071
void resizeAndResetIntensiveQuantitiesCache_()
Definition: fvbasediscretization.hh:1955
std::vector< Scalar > dofTotalVolume_
Definition: fvbasediscretization.hh:2061
void updateSuccessful()
Called by the update() method if it was successful.
Definition: fvbasediscretization.hh:1474
static std::string discretizationName()
Returns a string of discretization's human-readable name.
Definition: fvbasediscretization.hh:1667
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:1912
bool isLocalDof(unsigned globalIdx) const
Returns if the overlap of the volume ofa degree of freedom is non-zero.
Definition: fvbasediscretization.hh:1244
std::size_t numAuxiliaryModules() const
Returns the number of modules for auxiliary equations.
Definition: fvbasediscretization.hh:1906
bool operator==(const FvBaseDiscretization &rhs) const
Definition: fvbasediscretization.hh:1947
void serializeOp(Serializer &serializer)
Definition: fvbasediscretization.hh:1940
std::vector< bool > isLocalDof_
Definition: fvbasediscretization.hh:2062
LocalResidual & localResidual_()
Reference to the local residal object.
Definition: fvbasediscretization.hh:2007
void registerOutputModules_()
Register all output modules which make sense for the model.
Definition: fvbasediscretization.hh:1998
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:1275
void advanceTimeLevel()
Called by the problem if a time integration was successful, post processing of the solution is done a...
Definition: fvbasediscretization.hh:1518
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:1645
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:1700
const Timer & solveTimer() const
Definition: fvbasediscretization.hh:1933
void updateFailed()
Called by the update() method if it was unsuccessful. This is primary a hook which the actual model c...
Definition: fvbasediscretization.hh:1491
void updateBegin()
Called by the update() method before it tries to apply the newton method. This is primary a hook whic...
Definition: fvbasediscretization.hh:1467
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:1319
void serializeEntity(std::ostream &outstream, const DofEntity &dof)
Write the current solution for a degree of freedom to a restart file.
Definition: fvbasediscretization.hh:1573
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:1687
Scalar eqWeight(unsigned, unsigned) const
Returns the relative weight of an equation.
Definition: fvbasediscretization.hh:1341
std::array< std::vector< unsigned char >, historySize > storageCacheUpToDate_
Definition: fvbasediscretization.hh:2067
const Timer & prePostProcessTimer() const
Definition: fvbasediscretization.hh:1927
Scalar primaryVarWeight(unsigned globalDofIdx, unsigned pvIdx) const
Returns the relative weight of a primary variable for calculating relative errors.
Definition: fvbasediscretization.hh:1329
void deserialize(Restarter &)
Deserializes the state of the model.
Definition: fvbasediscretization.hh:1558
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:1114
Scalar gridTotalVolume() const
Returns the volume of the whole grid which represents the spatial domain.
Definition: fvbasediscretization.hh:1254
Timer updateTimer_
Definition: fvbasediscretization.hh:2041
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:1936
const Linearizer & linearizer() const
Returns the operator linearizer for the global jacobian of the problem.
Definition: fvbasediscretization.hh:1283
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:1718
Scalar relativeDofError(unsigned vertexIdx, const PrimaryVariables &pv1, const PrimaryVariables &pv2) const
Returns the relative error between two vectors of primary variables.
Definition: fvbasediscretization.hh:1353
bool enableGridAdaptation_
Definition: fvbasediscretization.hh:2069
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:1268
std::array< GlobalEqVector, historySize > storageCache_
Definition: fvbasediscretization.hh:2064
Timer prePostProcessTimer_
Definition: fvbasediscretization.hh:2038
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:1598
Timer solveTimer_
Definition: fvbasediscretization.hh:2040
void supplementInitialSolution_(PrimaryVariables &, const Context &, unsigned, unsigned)
Definition: fvbasediscretization.hh:1985
const LocalLinearizer & localLinearizer(unsigned openMpThreadId) const
Returns the local jacobian which calculates the local stiffness matrix for an arbitrary element.
Definition: fvbasediscretization.hh:1301
std::array< std::unique_ptr< DiscreteFunction >, historySize > solution_
Definition: fvbasediscretization.hh:2056
unsigned cachedIntensiveQuantityHistorySize_
Definition: fvbasediscretization.hh:2074
const Timer & linearizeTimer() const
Definition: fvbasediscretization.hh:1930
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:1374
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:1621
void clearAuxiliaryModules()
Causes the list of auxiliary equations to be cleared.
Definition: fvbasediscretization.hh:1896
bool enableIntensiveQuantityCache_
Definition: fvbasediscretization.hh:2070
std::unique_ptr< Linearizer > linearizer_
Definition: fvbasediscretization.hh:2047
const ElementMapper & elementMapper() const
Returns the mapper for elements to indices.
Definition: fvbasediscretization.hh:1651
void syncOverlap()
Syncronize the values of the primary variables on the degrees of freedom that overlap with the neighb...
Definition: fvbasediscretization.hh:1459
void appendOutputFields(BaseOutputWriter &writer) const
Append the quantities relevant for the current solution to an output writer.
Definition: fvbasediscretization.hh:1849
std::list< std::unique_ptr< BaseOutputModule< TypeTag > > > outputModules_
Definition: fvbasediscretization.hh:2058
ElementMapper elementMapper_
Definition: fvbasediscretization.hh:2030
NewtonMethod newtonMethod_
Definition: fvbasediscretization.hh:2036
std::size_t numTotalDof() const
Returns the total number of degrees of freedom (i.e., grid plux auxiliary DOFs)
Definition: fvbasediscretization.hh:1632
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:2016
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:1675
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:1290
const BaseAuxiliaryModule< TypeTag > * auxiliaryModule(unsigned auxEqModIdx) const
Returns a given module for auxiliary equations.
Definition: fvbasediscretization.hh:1918
std::vector< std::vector< unsigned char > > intensiveQuantityCacheUpToDate_
Definition: fvbasediscretization.hh:2054
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:2027
Scalar dofTotalVolume(unsigned globalIdx) const
Returns the volume of a given control volume.
Definition: fvbasediscretization.hh:1236
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:1262
bool verbose_() const
Returns whether messages should be printed.
Definition: fvbasediscretization.hh:2013
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:2024
const LocalResidual & localResidual(unsigned openMpThreadId) const
Returns the object to calculate the local residual function.
Definition: fvbasediscretization.hh:1313
std::size_t numGridDof() const
Returns the number of degrees of freedom (DOFs) for the computational grid.
Definition: fvbasediscretization.hh:1615
Scalar gridTotalVolume_
Definition: fvbasediscretization.hh:2060
const DofMapper & dofMapper() const
Mapper to convert the Dune entities of the discretization's degrees of freedoms are to indices.
Definition: fvbasediscretization.hh:1639
bool storeIntensiveQuantities() const
Returns true if the cache for intensive quantities is enabled.
Definition: fvbasediscretization.hh:1924
std::vector< LocalLinearizer > localLinearizer_
Definition: fvbasediscretization.hh:2044
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:1544
bool enableThermodynamicHints_
Definition: fvbasediscretization.hh:2072
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:2031
void resetLinearizer()
Resets the Jacobian matrix linearizer, so that the boundary types can be altered.
Definition: fvbasediscretization.hh:1658
bool enableStorageCache() const
Returns true iff the storage term is cached.
Definition: fvbasediscretization.hh:855
size_t numDof() const
Definition: fvbasediscretization.hh:1247
const GridView & gridView() const
Reference to the grid view of the spatial domain.
Definition: fvbasediscretization.hh:1858
void addOutputModule(std::unique_ptr< BaseOutputModule< TypeTag > > newModule)
Add an module for writing visualization output after a timestep.
Definition: fvbasediscretization.hh:1706
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:84
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:191
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:2094
static void serializeOp(Serializer &serializer, SolutionType &solution)
Definition: fvbasediscretization.hh:2096
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