opm-simulators
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 
55 
57 
60 
65 
68 
69 #include <algorithm>
70 #include <array>
71 #include <cstddef>
72 #include <list>
73 #include <memory>
74 #include <stdexcept>
75 #include <sstream>
76 #include <string>
77 #include <type_traits>
78 #include <utility>
79 #include <vector>
80 
81 namespace Opm {
82 
83 template<class TypeTag>
85 
86 template<class TypeTag>
88 
89 } // namespace Opm
90 
91 namespace Opm::Properties {
92 
94 template<class TypeTag>
95 struct Simulator<TypeTag, TTag::FvBaseDiscretization>
96 { using type = ::Opm::Simulator<TypeTag>; };
97 
99 template<class TypeTag>
100 struct VertexMapper<TypeTag, TTag::FvBaseDiscretization>
101 { using type = Dune::MultipleCodimMultipleGeomTypeMapper<GetPropType<TypeTag, Properties::GridView>>; };
102 
104 template<class TypeTag>
105 struct ElementMapper<TypeTag, TTag::FvBaseDiscretization>
106 { using type = Dune::MultipleCodimMultipleGeomTypeMapper<GetPropType<TypeTag, Properties::GridView>>; };
107 
109 template<class TypeTag>
111 {
114 
115 public:
117 };
118 
119 template<class TypeTag>
122 
123 template<class TypeTag>
126 
127 template<class TypeTag>
130 
132 template<class TypeTag>
135 
139 template<class TypeTag>
140 struct EqVector<TypeTag, TTag::FvBaseDiscretization>
141 {
142  using type = Dune::FieldVector<GetPropType<TypeTag, Properties::Scalar>,
143  getPropValue<TypeTag, Properties::NumEq>()>;
144 };
145 
151 template<class TypeTag>
152 struct RateVector<TypeTag, TTag::FvBaseDiscretization>
154 
158 template<class TypeTag>
161 
165 template<class TypeTag>
166 struct Constraints<TypeTag, TTag::FvBaseDiscretization>
167 { using type = FvBaseConstraints<TypeTag>; };
168 
172 template<class TypeTag>
173 struct ElementEqVector<TypeTag, TTag::FvBaseDiscretization>
174 { using type = Dune::BlockVector<GetPropType<TypeTag, Properties::EqVector>>; };
175 
179 template<class TypeTag>
180 struct GlobalEqVector<TypeTag, TTag::FvBaseDiscretization>
181 { using type = Dune::BlockVector<GetPropType<TypeTag, Properties::EqVector>>; };
182 
186 template<class TypeTag>
189 
193 template<class TypeTag>
194 struct SolutionVector<TypeTag, TTag::FvBaseDiscretization>
195 { using type = Dune::BlockVector<GetPropType<TypeTag, Properties::PrimaryVariables>>; };
196 
202 template<class TypeTag>
205 
209 template<class TypeTag>
210 struct ElementContext<TypeTag, TTag::FvBaseDiscretization>
212 
213 template<class TypeTag>
214 struct BoundaryContext<TypeTag, TTag::FvBaseDiscretization>
216 
217 template<class TypeTag>
220 
224 template<class TypeTag>
225 struct ThreadManager<TypeTag, TTag::FvBaseDiscretization>
226 { using type = ::Opm::ThreadManager; };
227 
228 template<class TypeTag>
230 { static constexpr bool value = true; };
231 
235 template<class TypeTag>
236 struct Linearizer<TypeTag, TTag::FvBaseDiscretization>
237 { using type = FvBaseLinearizer<TypeTag>; };
238 
240 template<class TypeTag>
241 struct VtkOutputFormat<TypeTag, TTag::FvBaseDiscretization>
242 { static constexpr auto value = Dune::VTK::ascii; };
243 
244 // disable constraints by default
245 template<class TypeTag>
247 { static constexpr bool value = false; };
248 
250 template<class TypeTag>
252 { static constexpr int value = 2; };
253 
256 template<class TypeTag>
258 { static constexpr bool value = false; };
259 
260 // use volumetric residuals is default
261 template<class TypeTag>
263 { static constexpr bool value = true; };
264 
267 template<class TypeTag>
269 { static constexpr bool value = true; };
270 
271 template <class TypeTag, class MyTypeTag>
273 
274 #if !HAVE_DUNE_FEM
275 template<class TypeTag>
278 
279 template<class TypeTag>
281 {
283  using type = typename BaseDiscretization::BlockVectorWrapper;
284 };
285 #endif
286 
287 } // namespace Opm::Properties
288 
289 namespace Opm {
290 
296 template<class TypeTag>
298 {
299  using Implementation = GetPropType<TypeTag, Properties::Model>;
313  using BoundaryRateVector = GetPropType<TypeTag, Properties::BoundaryRateVector>;
318  using IntensiveQuantities = GetPropType<TypeTag, Properties::IntensiveQuantities>;
319  using ExtensiveQuantities = GetPropType<TypeTag, Properties::ExtensiveQuantities>;
320  using GradientCalculator = GetPropType<TypeTag, Properties::GradientCalculator>;
322  using DiscBaseOutputModule = GetPropType<TypeTag, Properties::DiscBaseOutputModule>;
323  using GridCommHandleFactory = GetPropType<TypeTag, Properties::GridCommHandleFactory>;
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 
348 public:
350  {
351  protected:
352  SolutionVector blockVector_;
353  public:
354  BlockVectorWrapper(const std::string&, const std::size_t size)
355  : blockVector_(size)
356  {}
357 
358  BlockVectorWrapper() = default;
359 
360  static BlockVectorWrapper serializationTestObject()
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 
388 private:
389  using DiscreteFunctionSpace = GetPropType<TypeTag, Properties::DiscreteFunctionSpace>;
391 
392 public:
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
421  FvBaseDiscretization(const FvBaseDiscretization&) = delete;
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 
457  void finishInit()
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
507  gridTotalVolume_ = gridView_.comm().sum(gridTotalVolume_);
508 
509  linearizer_->init(simulator_);
510  for (unsigned threadId = 0; threadId < ThreadManager::maxThreads(); ++threadId) {
511  localLinearizer_[threadId].init(simulator_);
512  }
513 
514  resizeAndResetIntensiveQuantitiesCache_();
515 
516  newtonMethod_.finishInit();
517  }
518 
522  bool enableGridAdaptation() const
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.
572  resizeAndResetIntensiveQuantitiesCache_();
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  {
624  if (!enableThermodynamicHints_) {
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  {
645  if (!enableIntensiveQuantityCache_ ||
646  timeIdx >= cachedIntensiveQuantityHistorySize_ ||
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  {
678  if (!storeIntensiveQuantities() || timeIdx >= cachedIntensiveQuantityHistorySize_) {
679  return;
680  }
681 
682  intensiveQuantityCache_[timeIdx][globalIdx] = intQuants;
683  intensiveQuantityCacheUpToDate_[timeIdx][globalIdx] = true;
684  }
685 
695  unsigned timeIdx,
696  bool newValue) const
697  {
698  if (!storeIntensiveQuantities()) {
699  return;
700  }
701 
702  intensiveQuantityCacheUpToDate_[timeIdx][globalIdx] = newValue ? 1 : 0;
703  }
704 
709  { return cachedIntensiveQuantityHistorySize_; }
710 
716  void invalidateIntensiveQuantitiesCache(unsigned timeIdx) const
717  {
718  if (timeIdx >= cachedIntensiveQuantityHistorySize_) {
719  return;
720  }
721 
722  if (storeIntensiveQuantities()) {
723  std::ranges::fill(intensiveQuantityCacheUpToDate_[timeIdx], /*value=*/0);
724  }
725  }
726 
727  void invalidateAndUpdateIntensiveQuantities(unsigned timeIdx) const
728  {
730 
731  // loop over all elements...
732  ThreadedEntityIterator<GridView, /*codim=*/0> threadedElemIt(gridView_);
733 #ifdef _OPENMP
734 #pragma omp parallel
735 #endif
736  {
737  ElementContext elemCtx(simulator_);
738  ElementIterator elemIt = threadedElemIt.beginParallel();
739  for (; !threadedElemIt.isFinished(elemIt); elemIt = threadedElemIt.increment()) {
740  const Element& elem = *elemIt;
741  elemCtx.updatePrimaryStencil(elem);
742  elemCtx.updatePrimaryIntensiveQuantities(timeIdx);
743  }
744  }
745  }
746 
747  template <class GridViewType>
748  void invalidateAndUpdateIntensiveQuantities(unsigned timeIdx, const GridViewType& gridView) const
749  {
750  // loop over all elements...
751  ThreadedEntityIterator<GridViewType, /*codim=*/0> threadedElemIt(gridView);
752 #ifdef _OPENMP
753 #pragma omp parallel
754 #endif
755  {
756 
757  ElementContext elemCtx(simulator_);
758  auto elemIt = threadedElemIt.beginParallel();
759  for (; !threadedElemIt.isFinished(elemIt); elemIt = threadedElemIt.increment()) {
760  if (elemIt->partitionType() != Dune::InteriorEntity) {
761  continue;
762  }
763  const Element& elem = *elemIt;
764  elemCtx.updatePrimaryStencil(elem);
765  // Mark cache for this element as invalid.
766  const std::size_t numPrimaryDof = elemCtx.numPrimaryDof(timeIdx);
767  for (unsigned dofIdx = 0; dofIdx < numPrimaryDof; ++dofIdx) {
768  const unsigned globalIndex = elemCtx.globalSpaceIndex(dofIdx, timeIdx);
769  setIntensiveQuantitiesCacheEntryValidity(globalIndex, timeIdx, false);
770  }
771  // Update for this element.
772  elemCtx.updatePrimaryIntensiveQuantities(timeIdx);
773  }
774  }
775  }
776 
785  void shiftIntensiveQuantityCache(unsigned numSlots = 1)
786  {
787  if (!storeIntensiveQuantities() || numSlots <= 0) {
788  return;
789  }
790 
791  if (enableStorageCache() && simulator_.problem().recycleFirstIterationStorage()) {
792  // If the storage term is cached, the intensive quantities of the previous
793  // time steps do not need to be accessed, and we can thus spare ourselves to
794  // copy the objects for the intensive quantities.
795  // However, if the storage term at the start of the timestep cannot be deduced
796  // from the primary variables, we must calculate it from the old intensive
797  // quantities, and need to shift them.
798  return;
799  }
800 
801  const unsigned intensiveHistorySize = cachedIntensiveQuantityHistorySize_;
802  for (unsigned timeIdx = 0; timeIdx < intensiveHistorySize - numSlots; ++timeIdx) {
803  intensiveQuantityCache_[timeIdx + numSlots] = intensiveQuantityCache_[timeIdx];
804  intensiveQuantityCacheUpToDate_[timeIdx + numSlots] = intensiveQuantityCacheUpToDate_[timeIdx];
805  }
806 
807  // the cache for the most recent time indices do not need to be invalidated
808  // because the solution for them did not change (TODO: that assumes that there is
809  // no post-processing of the solution after a time step! fix it?)
810  }
811 
818  bool enableStorageCache() const
819  { return enableStorageCache_; }
820 
828  { enableStorageCache_= enableStorageCache; }
829 
843  const EqVector& cachedStorage(unsigned globalIdx, unsigned timeIdx) const
844  {
845  if (!enableStorageCache_ ||
846  timeIdx >= historySize ||
847  !storageCacheUpToDate_[timeIdx][globalIdx]) {
848  throw std::logic_error("Cached storage is not available or up to date for the requested "
849  "global index and time index. Make sure storage cache is enabled "
850  "and the entry is valid before calling this method.");
851  }
852 
853  return storageCache_[timeIdx][globalIdx];
854  }
855 
867  void updateCachedStorage(unsigned globalIdx, unsigned timeIdx, const EqVector& value) const
868  {
869  if (!enableStorageCache_ || timeIdx >= historySize) {
870  return;
871  }
872 
873  storageCache_[timeIdx][globalIdx] = value;
874  storageCacheUpToDate_[timeIdx][globalIdx] = 1;
875  }
876 
883  bool storageCacheIsUpToDate(unsigned globalIdx, unsigned timeIdx) const
884  {
885  if (!enableStorageCache_ || timeIdx >= historySize) {
886  return false;
887  }
888  return storageCacheUpToDate_[timeIdx][globalIdx] != 0;
889  }
890 
897  void invalidateStorageCacheEntry(unsigned globalIdx, unsigned timeIdx) const
898  {
899  if (enableStorageCache_ && timeIdx < historySize) {
900  storageCacheUpToDate_[timeIdx][globalIdx] = 0;
901  }
902  }
903 
909  void invalidateStorageCache(unsigned timeIdx) const
910  {
911  if (enableStorageCache_ && timeIdx < historySize) {
912  std::ranges::fill(storageCacheUpToDate_[timeIdx], /*value=*/0);
913  }
914  }
915 
927  void shiftStorageCache(unsigned numSlots = 1) const
928  {
929  // If we cannot recycle first iteration storage, it does not make sense to shift the storage cache.
930  if (enableStorageCache_ && !simulator_.problem().recycleFirstIterationStorage()) {
931  for (unsigned timeIdx = 0; timeIdx < historySize - numSlots; ++timeIdx) {
932  storageCache_[timeIdx + numSlots] = storageCache_[timeIdx];
933  storageCacheUpToDate_[timeIdx + numSlots] = storageCacheUpToDate_[timeIdx];
934  }
935 
936  // should we invalidate the cache for the most recent time indices? (see shiftIntensiveQuantityCache)
937  }
938  }
939 
947  Scalar globalResidual(GlobalEqVector& dest,
948  const SolutionVector& u) const
949  {
950  mutableSolution(/*timeIdx=*/0) = u;
951  const Scalar res = asImp_().globalResidual(dest);
952  mutableSolution(/*timeIdx=*/0) = asImp_().solution(/*timeIdx=*/0);
953  return res;
954  }
955 
962  Scalar globalResidual(GlobalEqVector& dest) const
963  {
964  dest = 0;
965 
966  std::mutex mutex;
967  ThreadedEntityIterator<GridView, /*codim=*/0> threadedElemIt(gridView_);
968 #ifdef _OPENMP
969 #pragma omp parallel
970 #endif
971  {
972  // Attention: the variables below are thread specific and thus cannot be
973  // moved in front of the #pragma!
974  const unsigned threadId = ThreadManager::threadId();
975  ElementContext elemCtx(simulator_);
976  ElementIterator elemIt = threadedElemIt.beginParallel();
977  LocalEvalBlockVector residual, storageTerm;
978 
979  for (; !threadedElemIt.isFinished(elemIt); elemIt = threadedElemIt.increment()) {
980  const Element& elem = *elemIt;
981  if (elem.partitionType() != Dune::InteriorEntity) {
982  continue;
983  }
984 
985  elemCtx.updateAll(elem);
986  residual.resize(elemCtx.numDof(/*timeIdx=*/0));
987  storageTerm.resize(elemCtx.numPrimaryDof(/*timeIdx=*/0));
988  asImp_().localResidual(threadId).eval(residual, elemCtx);
989 
990  const std::size_t numPrimaryDof = elemCtx.numPrimaryDof(/*timeIdx=*/0);
991  mutex.lock();
992  for (unsigned dofIdx = 0; dofIdx < numPrimaryDof; ++dofIdx) {
993  const unsigned globalI = elemCtx.globalSpaceIndex(dofIdx, /*timeIdx=*/0);
994  for (unsigned eqIdx = 0; eqIdx < numEq; ++ eqIdx) {
995  dest[globalI][eqIdx] += Toolbox::value(residual[dofIdx][eqIdx]);
996  }
997  }
998  mutex.unlock();
999  }
1000  }
1001 
1002  // add up the residuals on the process borders
1003  const auto sumHandle =
1004  GridCommHandleFactory::template sumHandle<EqVector>(dest, asImp_().dofMapper());
1005  gridView_.communicate(*sumHandle,
1006  Dune::InteriorBorder_InteriorBorder_Interface,
1007  Dune::ForwardCommunication);
1008 
1009  // calculate the square norm of the residual. this is not
1010  // entirely correct, since the residual for the finite volumes
1011  // which are on the boundary are counted once for every
1012  // process. As often in life: shit happens (, we don't care)...
1013  return std::sqrt(asImp_().gridView().comm().sum(dest.two_norm2()));
1014  }
1015 
1022  void globalStorage(EqVector& storage, unsigned timeIdx = 0) const
1023  {
1024  storage = 0;
1025 
1026  std::mutex mutex;
1027  ThreadedEntityIterator<GridView, /*codim=*/0> threadedElemIt(gridView());
1028 #ifdef _OPENMP
1029 #pragma omp parallel
1030 #endif
1031  {
1032  // Attention: the variables below are thread specific and thus cannot be
1033  // moved in front of the #pragma!
1034  const unsigned threadId = ThreadManager::threadId();
1035  ElementContext elemCtx(simulator_);
1036  ElementIterator elemIt = threadedElemIt.beginParallel();
1037  LocalEvalBlockVector elemStorage;
1038 
1039  // in this method, we need to disable the storage cache because we want to
1040  // evaluate the storage term for other time indices than the most recent one
1041  elemCtx.setEnableStorageCache(false);
1042 
1043  for (; !threadedElemIt.isFinished(elemIt); elemIt = threadedElemIt.increment()) {
1044  const Element& elem = *elemIt;
1045  if (elem.partitionType() != Dune::InteriorEntity) {
1046  continue; // ignore ghost and overlap elements
1047  }
1048 
1049  elemCtx.updateStencil(elem);
1050  elemCtx.updatePrimaryIntensiveQuantities(timeIdx);
1051 
1052  const std::size_t numPrimaryDof = elemCtx.numPrimaryDof(timeIdx);
1053  elemStorage.resize(numPrimaryDof);
1054 
1055  localResidual(threadId).evalStorage(elemStorage, elemCtx, timeIdx);
1056 
1057  mutex.lock();
1058  for (unsigned dofIdx = 0; dofIdx < numPrimaryDof; ++dofIdx) {
1059  for (unsigned eqIdx = 0; eqIdx < numEq; ++eqIdx) {
1060  storage[eqIdx] += Toolbox::value(elemStorage[dofIdx][eqIdx]);
1061  }
1062  }
1063  mutex.unlock();
1064  }
1065  }
1066 
1067  storage = gridView_.comm().sum(storage);
1068  }
1069 
1077  void checkConservativeness([[maybe_unused]] Scalar tolerance = -1,
1078  [[maybe_unused]] bool verbose = false) const
1079  {
1080 #ifndef NDEBUG
1081  Scalar totalBoundaryArea(0.0);
1082  Scalar totalVolume(0.0);
1083  EvalEqVector totalRate(0.0);
1084 
1085  // take the newton tolerance times the total volume of the grid if we're not
1086  // given an explicit tolerance...
1087  if (tolerance <= 0) {
1088  tolerance =
1089  simulator_.model().newtonMethod().tolerance() *
1090  simulator_.model().gridTotalVolume() *
1091  1000;
1092  }
1093 
1094  // we assume the implicit Euler time discretization for now...
1095  assert(historySize == 2);
1096 
1097  EqVector storageBeginTimeStep(0.0);
1098  globalStorage(storageBeginTimeStep, /*timeIdx=*/1);
1099 
1100  EqVector storageEndTimeStep(0.0);
1101  globalStorage(storageEndTimeStep, /*timeIdx=*/0);
1102 
1103  // calculate the rate at the boundary and the source rate
1104  ElementContext elemCtx(simulator_);
1105  elemCtx.setEnableStorageCache(false);
1106  for (const auto& elem : elements(simulator_.gridView())) {
1107  if (elem.partitionType() != Dune::InteriorEntity) {
1108  continue; // ignore ghost and overlap elements
1109  }
1110 
1111  elemCtx.updateAll(elem);
1112 
1113  // handle the boundary terms
1114  if (elemCtx.onBoundary()) {
1115  BoundaryContext boundaryCtx(elemCtx);
1116 
1117  for (unsigned faceIdx = 0; faceIdx < boundaryCtx.numBoundaryFaces(/*timeIdx=*/0); ++faceIdx) {
1118  BoundaryRateVector values;
1119  simulator_.problem().boundary(values,
1120  boundaryCtx,
1121  faceIdx,
1122  /*timeIdx=*/0);
1123  Valgrind::CheckDefined(values);
1124 
1125  const unsigned dofIdx = boundaryCtx.interiorScvIndex(faceIdx, /*timeIdx=*/0);
1126  const auto& insideIntQuants = elemCtx.intensiveQuantities(dofIdx, /*timeIdx=*/0);
1127 
1128  const Scalar bfArea =
1129  boundaryCtx.boundarySegmentArea(faceIdx, /*timeIdx=*/0) *
1130  insideIntQuants.extrusionFactor();
1131 
1132  for (unsigned i = 0; i < values.size(); ++i) {
1133  values[i] *= bfArea;
1134  }
1135 
1136  totalBoundaryArea += bfArea;
1137  for (unsigned eqIdx = 0; eqIdx < numEq; ++eqIdx) {
1138  totalRate[eqIdx] += values[eqIdx];
1139  }
1140  }
1141  }
1142 
1143  // deal with the source terms
1144  for (unsigned dofIdx = 0; dofIdx < elemCtx.numPrimaryDof(/*timeIdx=*/0); ++dofIdx) {
1145  RateVector values;
1146  simulator_.problem().source(values,
1147  elemCtx,
1148  dofIdx,
1149  /*timeIdx=*/0);
1150  Valgrind::CheckDefined(values);
1151 
1152  const auto& intQuants = elemCtx.intensiveQuantities(dofIdx, /*timeIdx=*/0);
1153  Scalar dofVolume =
1154  elemCtx.dofVolume(dofIdx, /*timeIdx=*/0) *
1155  intQuants.extrusionFactor();
1156  for (unsigned eqIdx = 0; eqIdx < numEq; ++eqIdx) {
1157  totalRate[eqIdx] += -dofVolume*Toolbox::value(values[eqIdx]);
1158  }
1159  totalVolume += dofVolume;
1160  }
1161  }
1162 
1163  // summarize everything over all processes
1164  const auto& comm = simulator_.gridView().comm();
1165  totalRate = comm.sum(totalRate);
1166  totalBoundaryArea = comm.sum(totalBoundaryArea);
1167  totalVolume = comm.sum(totalVolume);
1168 
1169  if (comm.rank() == 0) {
1170  EqVector storageRate = storageBeginTimeStep;
1171  storageRate -= storageEndTimeStep;
1172  storageRate /= simulator_.timeStepSize();
1173  if (verbose) {
1174  std::cout << "storage at beginning of time step: " << storageBeginTimeStep << "\n";
1175  std::cout << "storage at end of time step: " << storageEndTimeStep << "\n";
1176  std::cout << "rate based on storage terms: " << storageRate << "\n";
1177  std::cout << "rate based on source and boundary terms: " << totalRate << "\n";
1178  std::cout << "difference in rates: ";
1179  for (unsigned eqIdx = 0; eqIdx < EqVector::dimension; ++eqIdx) {
1180  std::cout << (storageRate[eqIdx] - Toolbox::value(totalRate[eqIdx])) << " ";
1181  }
1182  std::cout << "\n";
1183  }
1184  for (unsigned eqIdx = 0; eqIdx < EqVector::dimension; ++eqIdx) {
1185  Scalar eps =
1186  (std::abs(storageRate[eqIdx]) + Toolbox::value(totalRate[eqIdx])) * tolerance;
1187  eps = std::max(tolerance, eps);
1188  assert(std::abs(storageRate[eqIdx] - Toolbox::value(totalRate[eqIdx])) <= eps);
1189  }
1190  }
1191 #endif // NDEBUG
1192  }
1193 
1199  Scalar dofTotalVolume(unsigned globalIdx) const
1200  { return dofTotalVolume_[globalIdx]; }
1201 
1207  bool isLocalDof(unsigned globalIdx) const
1208  { return isLocalDof_[globalIdx]; }
1209 
1210  size_t numDof() const
1211  { return asImp_().numGridDof(); }
1212 
1217  Scalar gridTotalVolume() const
1218  { return gridTotalVolume_; }
1219 
1225  const SolutionVector& solution(unsigned timeIdx) const
1226  { return solution_[timeIdx]->blockVector(); }
1227 
1231  SolutionVector& solution(unsigned timeIdx)
1232  { return solution_[timeIdx]->blockVector(); }
1233 
1234  protected:
1238  SolutionVector& mutableSolution(unsigned timeIdx) const
1239  { return solution_[timeIdx]->blockVector(); }
1240 
1241  public:
1246  const Linearizer& linearizer() const
1247  { return *linearizer_; }
1248 
1253  Linearizer& linearizer()
1254  { return *linearizer_; }
1255 
1264  const LocalLinearizer& localLinearizer(unsigned openMpThreadId) const
1265  { return localLinearizer_[openMpThreadId]; }
1266 
1270  LocalLinearizer& localLinearizer(unsigned openMpThreadId)
1271  { return localLinearizer_[openMpThreadId]; }
1272 
1276  const LocalResidual& localResidual(unsigned openMpThreadId) const
1277  { return asImp_().localLinearizer(openMpThreadId).localResidual(); }
1278 
1282  LocalResidual& localResidual(unsigned openMpThreadId)
1283  { return asImp_().localLinearizer(openMpThreadId).localResidual(); }
1284 
1292  Scalar primaryVarWeight(unsigned globalDofIdx, unsigned pvIdx) const
1293  {
1294  const Scalar absPv = std::abs(asImp_().solution(/*timeIdx=*/1)[globalDofIdx][pvIdx]);
1295  return 1.0 / std::max(absPv, 1.0);
1296  }
1297 
1304  Scalar eqWeight(unsigned, unsigned) const
1305  { return 1.0; }
1306 
1316  Scalar relativeDofError(unsigned vertexIdx,
1317  const PrimaryVariables& pv1,
1318  const PrimaryVariables& pv2) const
1319  {
1320  Scalar result = 0.0;
1321  for (unsigned j = 0; j < numEq; ++j) {
1322  const Scalar weight = asImp_().primaryVarWeight(vertexIdx, j);
1323  const Scalar eqErr = std::abs((pv1[j] - pv2[j])*weight);
1324  //Scalar eqErr = std::abs(pv1[j] - pv2[j]);
1325  //eqErr *= std::max<Scalar>(1.0, std::abs(pv1[j] + pv2[j])/2);
1326 
1327  result = std::max(result, eqErr);
1328  }
1329  return result;
1330  }
1331 
1337  bool update()
1338  {
1339  const TimerGuard prePostProcessGuard(prePostProcessTimer_);
1340 
1341 #ifndef NDEBUG
1342  for (unsigned timeIdx = 0; timeIdx < historySize; ++timeIdx) {
1343  // Make sure that the primary variables are defined. Note that because of padding
1344  // bytes, we can't just simply ask valgrind to check the whole solution vectors
1345  // for definedness...
1346  for (std::size_t i = 0; i < asImp_().solution(/*timeIdx=*/0).size(); ++i) {
1347  asImp_().solution(timeIdx)[i].checkDefined();
1348  }
1349  }
1350 #endif // NDEBUG
1351 
1352  // make sure all timers are prestine
1353  prePostProcessTimer_.halt();
1354  linearizeTimer_.halt();
1355  solveTimer_.halt();
1356  updateTimer_.halt();
1357 
1358  prePostProcessTimer_.start();
1359  asImp_().updateBegin();
1360  prePostProcessTimer_.stop();
1361 
1362  bool converged = false;
1363 
1364  try {
1365  converged = newtonMethod_.apply();
1366  }
1367  catch(...) {
1368  prePostProcessTimer_ += newtonMethod_.prePostProcessTimer();
1369  linearizeTimer_ += newtonMethod_.linearizeTimer();
1370  solveTimer_ += newtonMethod_.solveTimer();
1371  updateTimer_ += newtonMethod_.updateTimer();
1372 
1373  throw;
1374  }
1375 
1376 #ifndef NDEBUG
1377  for (unsigned timeIdx = 0; timeIdx < historySize; ++timeIdx) {
1378  // Make sure that the primary variables are defined. Note that because of padding
1379  // bytes, we can't just simply ask valgrind to check the whole solution vectors
1380  // for definedness...
1381  for (std::size_t i = 0; i < asImp_().solution(/*timeIdx=*/0).size(); ++i) {
1382  asImp_().solution(timeIdx)[i].checkDefined();
1383  }
1384  }
1385 #endif // NDEBUG
1386 
1387  prePostProcessTimer_ += newtonMethod_.prePostProcessTimer();
1388  linearizeTimer_ += newtonMethod_.linearizeTimer();
1389  solveTimer_ += newtonMethod_.solveTimer();
1390  updateTimer_ += newtonMethod_.updateTimer();
1391 
1392  prePostProcessTimer_.start();
1393  if (converged) {
1394  asImp_().updateSuccessful();
1395  }
1396  else {
1397  asImp_().updateFailed();
1398  }
1399  prePostProcessTimer_.stop();
1400 
1401 #ifndef NDEBUG
1402  for (unsigned timeIdx = 0; timeIdx < historySize; ++timeIdx) {
1403  // Make sure that the primary variables are defined. Note that because of padding
1404  // bytes, we can't just simply ask valgrind to check the whole solution vectors
1405  // for definedness...
1406  for (std::size_t i = 0; i < asImp_().solution(/*timeIdx=*/0).size(); ++i) {
1407  asImp_().solution(timeIdx)[i].checkDefined();
1408  }
1409  }
1410 #endif // NDEBUG
1411 
1412  return converged;
1413  }
1414 
1423  {}
1424 
1431  {}
1432 
1438  {}
1439 
1443  void adaptGrid()
1444  {
1445  throw std::invalid_argument("Grid adaptation need to be implemented for "
1446  "specific settings of grid and function spaces");
1447  }
1448 
1455  {
1456  // Reset the current solution to the one of the
1457  // previous time step so that we can start the next
1458  // update at a physically meaningful solution.
1459  solution(/*timeIdx=*/0) = solution(/*timeIdx=*/1);
1460  invalidateAndUpdateIntensiveQuantities(/*timeIdx=*/0);
1461 
1462 #ifndef NDEBUG
1463  for (unsigned timeIdx = 0; timeIdx < historySize; ++timeIdx) {
1464  // Make sure that the primary variables are defined. Note that because of padding
1465  // bytes, we can't just simply ask valgrind to check the whole solution vectors
1466  // for definedness...
1467  for (std::size_t i = 0; i < asImp_().solution(/*timeIdx=*/0).size(); ++i) {
1468  asImp_().solution(timeIdx)[i].checkDefined();
1469  }
1470  }
1471 #endif // NDEBUG
1472  }
1473 
1482  {
1483  // at this point we can adapt the grid
1484  if (this->enableGridAdaptation_) {
1485  asImp_().adaptGrid();
1486  }
1487 
1488  // make the current solution the previous one.
1489  solution(/*timeIdx=*/1) = solution(/*timeIdx=*/0);
1490 
1491  // shift the storage cache by one position in the history
1492  asImp_().shiftStorageCache(/*numSlots=*/1);
1493 
1494  // shift the intensive quantities cache by one position in the
1495  // history
1496  asImp_().shiftIntensiveQuantityCache(/*numSlots=*/1);
1497  }
1498 
1506  template <class Restarter>
1507  void serialize(Restarter&)
1508  {
1509  throw std::runtime_error("Not implemented: The discretization chosen for this problem "
1510  "does not support restart files. (serialize() method unimplemented)");
1511  }
1512 
1520  template <class Restarter>
1521  void deserialize(Restarter&)
1522  {
1523  throw std::runtime_error("Not implemented: The discretization chosen for this problem "
1524  "does not support restart files. (deserialize() method unimplemented)");
1525  }
1526 
1535  template <class DofEntity>
1536  void serializeEntity(std::ostream& outstream,
1537  const DofEntity& dof)
1538  {
1539  const unsigned dofIdx = static_cast<unsigned>(asImp_().dofMapper().index(dof));
1540 
1541  // write phase state
1542  if (!outstream.good()) {
1543  throw std::runtime_error("Could not serialize degree of freedom " +
1544  std::to_string(dofIdx));
1545  }
1546 
1547  for (unsigned eqIdx = 0; eqIdx < numEq; ++eqIdx) {
1548  outstream << solution(/*timeIdx=*/0)[dofIdx][eqIdx] << " ";
1549  }
1550  }
1551 
1560  template <class DofEntity>
1561  void deserializeEntity(std::istream& instream,
1562  const DofEntity& dof)
1563  {
1564  const unsigned dofIdx = static_cast<unsigned>(asImp_().dofMapper().index(dof));
1565 
1566  for (unsigned eqIdx = 0; eqIdx < numEq; ++eqIdx) {
1567  if (!instream.good()) {
1568  throw std::runtime_error("Could not deserialize degree of freedom " +
1569  std::to_string(dofIdx));
1570  }
1571  instream >> solution(/*timeIdx=*/0)[dofIdx][eqIdx];
1572  }
1573  }
1574 
1578  std::size_t numGridDof() const
1579  { throw std::logic_error("The discretization class must implement the numGridDof() method!"); }
1580 
1584  std::size_t numAuxiliaryDof() const
1585  {
1586  return std::accumulate(auxEqModules_.begin(), auxEqModules_.end(),
1587  std::size_t{0},
1588  [](const auto acc, const auto& mod)
1589  { return acc + mod->numDofs(); });
1590  }
1591 
1595  std::size_t numTotalDof() const
1596  { return asImp_().numGridDof() + numAuxiliaryDof(); }
1597 
1602  const DofMapper& dofMapper() const
1603  { throw std::logic_error("The discretization class must implement the dofMapper() method!"); }
1604 
1608  const VertexMapper& vertexMapper() const
1609  { return vertexMapper_; }
1610 
1614  const ElementMapper& elementMapper() const
1615  { return elementMapper_; }
1616 
1622  {
1623  linearizer_ = std::make_unique<Linearizer>();
1624  linearizer_->init(simulator_);
1625  }
1626 
1630  static std::string discretizationName()
1631  { return ""; }
1632 
1638  std::string primaryVarName(unsigned pvIdx) const
1639  {
1640  std::ostringstream oss;
1641  oss << "primary variable_" << pvIdx;
1642  return oss.str();
1643  }
1644 
1650  std::string eqName(unsigned eqIdx) const
1651  {
1652  std::ostringstream oss;
1653  oss << "equation_" << eqIdx;
1654  return oss.str();
1655  }
1656 
1663  void updatePVWeights(const ElementContext&) const
1664  {}
1665 
1669  void addOutputModule(std::unique_ptr<BaseOutputModule<TypeTag>> newModule)
1670  { outputModules_.push_back(std::move(newModule)); }
1671 
1680  template <class VtkMultiWriter>
1682  const SolutionVector& u,
1683  const GlobalEqVector& deltaU) const
1684  {
1685  using ScalarBuffer = std::vector<double>;
1686 
1687  GlobalEqVector globalResid(u.size());
1688  asImp_().globalResidual(globalResid, u);
1689 
1690  // create the required scalar fields
1691  const std::size_t numDof = asImp_().numGridDof();
1692 
1693  // global defect of the two auxiliary equations
1694  std::array<ScalarBuffer*, numEq> def;
1695  std::array<ScalarBuffer*, numEq> delta;
1696  std::array<ScalarBuffer*, numEq> priVars;
1697  std::array<ScalarBuffer*, numEq> priVarWeight;
1698  ScalarBuffer* relError = writer.allocateManagedScalarBuffer(numDof);
1699  ScalarBuffer* normalizedRelError = writer.allocateManagedScalarBuffer(numDof);
1700  for (unsigned pvIdx = 0; pvIdx < numEq; ++pvIdx) {
1701  priVars[pvIdx] = writer.allocateManagedScalarBuffer(numDof);
1702  priVarWeight[pvIdx] = writer.allocateManagedScalarBuffer(numDof);
1703  delta[pvIdx] = writer.allocateManagedScalarBuffer(numDof);
1704  def[pvIdx] = writer.allocateManagedScalarBuffer(numDof);
1705  }
1706 
1707  Scalar minRelErr = 1e30;
1708  Scalar maxRelErr = -1e30;
1709  for (unsigned globalIdx = 0; globalIdx < numDof; ++ globalIdx) {
1710  for (unsigned pvIdx = 0; pvIdx < numEq; ++pvIdx) {
1711  (*priVars[pvIdx])[globalIdx] = u[globalIdx][pvIdx];
1712  (*priVarWeight[pvIdx])[globalIdx] = asImp_().primaryVarWeight(globalIdx, pvIdx);
1713  (*delta[pvIdx])[globalIdx] = - deltaU[globalIdx][pvIdx];
1714  (*def[pvIdx])[globalIdx] = globalResid[globalIdx][pvIdx];
1715  }
1716 
1717  PrimaryVariables uOld(u[globalIdx]);
1718  PrimaryVariables uNew(uOld);
1719  uNew -= deltaU[globalIdx];
1720 
1721  const Scalar err = asImp_().relativeDofError(globalIdx, uOld, uNew);
1722  (*relError)[globalIdx] = err;
1723  (*normalizedRelError)[globalIdx] = err;
1724  minRelErr = std::min(err, minRelErr);
1725  maxRelErr = std::max(err, maxRelErr);
1726  }
1727 
1728  // do the normalization of the relative error
1729  const Scalar alpha = std::max(Scalar{1e-20},
1730  std::max(std::abs(maxRelErr),
1731  std::abs(minRelErr)));
1732  for (unsigned globalIdx = 0; globalIdx < numDof; ++globalIdx) {
1733  (*normalizedRelError)[globalIdx] /= alpha;
1734  }
1735 
1736  DiscBaseOutputModule::attachScalarDofData_(writer, *relError, "relative error");
1737  DiscBaseOutputModule::attachScalarDofData_(writer, *normalizedRelError, "normalized relative error");
1738 
1739  for (unsigned i = 0; i < numEq; ++i) {
1740  std::ostringstream oss;
1741  oss.str(""); oss << "priVar_" << asImp_().primaryVarName(i);
1742  DiscBaseOutputModule::attachScalarDofData_(writer,
1743  *priVars[i],
1744  oss.str());
1745 
1746  oss.str(""); oss << "delta_" << asImp_().primaryVarName(i);
1747  DiscBaseOutputModule::attachScalarDofData_(writer,
1748  *delta[i],
1749  oss.str());
1750 
1751  oss.str(""); oss << "weight_" << asImp_().primaryVarName(i);
1752  DiscBaseOutputModule::attachScalarDofData_(writer,
1753  *priVarWeight[i],
1754  oss.str());
1755 
1756  oss.str(""); oss << "defect_" << asImp_().eqName(i);
1757  DiscBaseOutputModule::attachScalarDofData_(writer,
1758  *def[i],
1759  oss.str());
1760  }
1761 
1762  asImp_().prepareOutputFields();
1763  asImp_().appendOutputFields(writer);
1764  }
1765 
1770  void prepareOutputFields() const
1771  {
1772  const bool needFullContextUpdate =
1773  std::ranges::any_of(outputModules_,
1774  [](const auto& mod)
1775  { return mod->needExtensiveQuantities(); });
1776  std::ranges::for_each(outputModules_,
1777  [](auto& mod) { mod->allocBuffers(); });
1778 
1779  // iterate over grid
1780  ThreadedEntityIterator<GridView, /*codim=*/0> threadedElemIt(gridView());
1781 #ifdef _OPENMP
1782 #pragma omp parallel
1783 #endif
1784  {
1785  ElementContext elemCtx(simulator_);
1786  ElementIterator elemIt = threadedElemIt.beginParallel();
1787  for (; !threadedElemIt.isFinished(elemIt); elemIt = threadedElemIt.increment()) {
1788  const auto& elem = *elemIt;
1789  if (elem.partitionType() != Dune::InteriorEntity) {
1790  // ignore non-interior entities
1791  continue;
1792  }
1793 
1794  if (needFullContextUpdate) {
1795  elemCtx.updateAll(elem);
1796  }
1797  else {
1798  elemCtx.updatePrimaryStencil(elem);
1799  elemCtx.updatePrimaryIntensiveQuantities(/*timeIdx=*/0);
1800  }
1801 
1802  std::ranges::for_each(outputModules_,
1803  [&elemCtx](auto& mod) { mod->processElement(elemCtx); });
1804  }
1805  }
1806  }
1807 
1813  {
1814  std::ranges::for_each(outputModules_,
1815  [&writer](auto& mod) { mod->commitBuffers(writer); });
1816  }
1817 
1821  const GridView& gridView() const
1822  { return gridView_; }
1823 
1836  {
1837  auxMod->setDofOffset(numTotalDof());
1838  auxEqModules_.push_back(auxMod);
1839 
1840  // resize the solutions
1841  if (enableGridAdaptation_ && !std::is_same_v<DiscreteFunction, BlockVectorWrapper>) {
1842  throw std::invalid_argument("Problems which require auxiliary modules cannot be used in"
1843  " conjunction with dune-fem");
1844  }
1845 
1846  const std::size_t numDof = numTotalDof();
1847  for (unsigned timeIdx = 0; timeIdx < historySize; ++timeIdx) {
1848  solution(timeIdx).resize(numDof);
1849  }
1850 
1851  auxMod->applyInitial();
1852  }
1853 
1860  {
1861  auxEqModules_.clear();
1862  linearizer_->eraseMatrix();
1863  newtonMethod_.eraseMatrix();
1864  }
1865 
1869  std::size_t numAuxiliaryModules() const
1870  { return auxEqModules_.size(); }
1871 
1876  { return auxEqModules_[auxEqModIdx]; }
1877 
1881  const BaseAuxiliaryModule<TypeTag>* auxiliaryModule(unsigned auxEqModIdx) const
1882  { return auxEqModules_[auxEqModIdx]; }
1883 
1888  { return enableIntensiveQuantityCache_ || enableThermodynamicHints_; }
1889 
1890  const Timer& prePostProcessTimer() const
1891  { return prePostProcessTimer_; }
1892 
1893  const Timer& linearizeTimer() const
1894  { return linearizeTimer_; }
1895 
1896  const Timer& solveTimer() const
1897  { return solveTimer_; }
1898 
1899  const Timer& updateTimer() const
1900  { return updateTimer_; }
1901 
1902  template<class Serializer>
1903  void serializeOp(Serializer& serializer)
1904  {
1905  using BaseDiscretization = GetPropType<TypeTag, Properties::BaseDiscretizationType>;
1906  using Helper = typename BaseDiscretization::template SerializeHelper<Serializer>;
1907  Helper::serializeOp(serializer, solution_);
1908  }
1909 
1910  bool operator==(const FvBaseDiscretization& rhs) const
1911  {
1912  return std::ranges::equal(this->solution_, rhs.solution_,
1913  [](const auto& x, const auto& y)
1914  { return *x == *y; });
1915  }
1916 
1917 protected:
1918  void resizeAndResetIntensiveQuantitiesCache_()
1919  {
1920  // allocate the storage cache
1921  if (enableStorageCache()) {
1922  const std::size_t numDof = asImp_().numGridDof();
1923  for (unsigned timeIdx = 0; timeIdx < historySize; ++timeIdx) {
1924  storageCache_[timeIdx].resize(numDof);
1925  storageCacheUpToDate_[timeIdx].resize(numDof, /*value=*/0);
1926  }
1927  }
1928 
1929  // allocate the intensive quantities cache
1930  if (storeIntensiveQuantities()) {
1931  const std::size_t numDof = asImp_().numGridDof();
1932  cachedIntensiveQuantityHistorySize_ = simulator_.problem().intensiveQuantityHistorySize();
1933  const unsigned intensiveHistorySize = cachedIntensiveQuantityHistorySize_;
1934 
1935  // resize the vectors based on runtime history size
1936  intensiveQuantityCache_.resize(intensiveHistorySize);
1937  intensiveQuantityCacheUpToDate_.resize(intensiveHistorySize);
1938 
1939  for(unsigned timeIdx = 0; timeIdx < intensiveHistorySize; ++timeIdx) {
1940  intensiveQuantityCache_[timeIdx].resize(numDof);
1941  intensiveQuantityCacheUpToDate_[timeIdx].resize(numDof);
1943  }
1944  }
1945  }
1946 
1947  template <class Context>
1948  void supplementInitialSolution_(PrimaryVariables&,
1949  const Context&,
1950  unsigned,
1951  unsigned)
1952  {}
1953 
1962  {
1963  // add the output modules available on all model
1964  this->outputModules_.push_back(std::make_unique<VtkPrimaryVarsModule<TypeTag>>(simulator_));
1965  }
1966 
1970  LocalResidual& localResidual_()
1971  { return localLinearizer_.localResidual(); }
1972 
1976  bool verbose_() const
1977  { return gridView_.comm().rank() == 0; }
1978 
1979  Implementation& asImp_()
1980  { return *static_cast<Implementation*>(this); }
1981 
1982  const Implementation& asImp_() const
1983  { return *static_cast<const Implementation*>(this); }
1984 
1985  // the problem we want to solve. defines the constitutive
1986  // relations, matxerial laws, etc.
1987  Simulator& simulator_;
1988 
1989  // the representation of the spatial domain of the problem
1990  GridView gridView_;
1991 
1992  // the mappers for element and vertex entities to global indices
1993  ElementMapper elementMapper_;
1994  VertexMapper vertexMapper_;
1995 
1996  // a vector with all auxiliary equations to be considered
1997  std::vector<BaseAuxiliaryModule<TypeTag>*> auxEqModules_;
1998 
1999  NewtonMethod newtonMethod_;
2000 
2001  Timer prePostProcessTimer_;
2002  Timer linearizeTimer_;
2003  Timer solveTimer_;
2004  Timer updateTimer_;
2005 
2006  // calculates the local jacobian matrix for a given element
2007  std::vector<LocalLinearizer> localLinearizer_;
2008  // Linearizes the problem at the current time step using the
2009  // local jacobian
2010  std::unique_ptr<Linearizer> linearizer_;
2011 
2012  // cur is the current iterative solution, prev the converged
2013  // solution of the previous time step
2014  mutable std::vector<IntensiveQuantitiesVector> intensiveQuantityCache_;
2015 
2016  // while these are logically bools, concurrent writes to vector<bool> are not thread safe.
2017  mutable std::vector<std::vector<unsigned char>> intensiveQuantityCacheUpToDate_;
2018 
2019  std::array<std::unique_ptr<DiscreteFunction>, historySize> solution_;
2020 
2021  std::list<std::unique_ptr<BaseOutputModule<TypeTag>>> outputModules_;
2022 
2023  Scalar gridTotalVolume_;
2024  std::vector<Scalar> dofTotalVolume_;
2025  std::vector<bool> isLocalDof_;
2026 
2027  mutable std::array<GlobalEqVector, historySize> storageCache_;
2028 
2029  // while these are logically bools, concurrent writes to vector<bool> are not thread safe.
2030  mutable std::array<std::vector<unsigned char>, historySize> storageCacheUpToDate_;
2031 
2032  bool enableGridAdaptation_;
2033  bool enableIntensiveQuantityCache_;
2034  bool enableStorageCache_;
2035  bool enableThermodynamicHints_;
2036 
2037  mutable unsigned cachedIntensiveQuantityHistorySize_;
2038 };
2039 
2045 template<class TypeTag>
2046 class FvBaseDiscretizationNoAdapt : public FvBaseDiscretization<TypeTag>
2047 {
2048  using ParentType = FvBaseDiscretization<TypeTag>;
2049  using Simulator = GetPropType<TypeTag, Properties::Simulator>;
2050  using DiscreteFunction = GetPropType<TypeTag, Properties::DiscreteFunction>;
2051 
2052  static constexpr unsigned historySize = getPropValue<TypeTag, Properties::TimeDiscHistorySize>();
2053 
2054 public:
2055  template<class Serializer>
2057  {
2058  template<class SolutionType>
2059  static void serializeOp(Serializer& serializer,
2060  SolutionType& solution)
2061  {
2062  for (auto& sol : solution) {
2063  serializer(*sol);
2064  }
2065  }
2066  };
2067 
2068  explicit FvBaseDiscretizationNoAdapt(Simulator& simulator)
2069  : ParentType(simulator)
2070  {
2071  if (this->enableGridAdaptation_) {
2072  throw std::invalid_argument("Grid adaptation need to use"
2073  " BaseDiscretization = FvBaseDiscretizationFemAdapt"
2074  " which currently requires the presence of the"
2075  " dune-fem module");
2076  }
2077  const std::size_t numDof = this->asImp_().numGridDof();
2078  for (unsigned timeIdx = 0; timeIdx < historySize; ++timeIdx) {
2079  this->solution_[timeIdx] = std::make_unique<DiscreteFunction>("solution", numDof);
2080  }
2081  }
2082 };
2083 
2084 } // namespace Opm
2085 
2086 #endif // EWOMS_FV_BASE_DISCRETIZATION_HH
Definition: fvbasediscretization.hh:2056
void registerOutputModules_()
Register all output modules which make sense for the model.
Definition: fvbasediscretization.hh:1961
Simplifies multi-threaded capabilities.
Definition: threadmanager.hpp:35
std::string eqName(unsigned eqIdx) const
Given an equation index, return a human readable name.
Definition: fvbasediscretization.hh:1650
This is a stand-alone version of boost::alignment::aligned_allocator from Boost 1...
void setIntensiveQuantitiesCacheEntryValidity(unsigned globalIdx, unsigned timeIdx, bool newValue) const
Invalidate the cache for a given intensive quantities object.
Definition: fvbasediscretization.hh:694
Calculates gradients of arbitrary quantities at flux integration points.
Definition: fvbaseproperties.hh:167
Definition: fvbasediscretization.hh:349
Manages the initializing and running of time dependent problems.
The multi-dimensional Newton method.
Definition: newtonmethod.hh:64
void finishInit()
Apply the initial conditions to the model.
Definition: fvbasediscretization.hh:457
static void registerParameters()
Register all run-time parameters for the Newton method.
Definition: newtonmethod.hh:135
Provide the properties at a face which make sense independently of the conserved quantities.
Definition: fvbaseextensivequantities.hh:47
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
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
void setEnableStorageCache(bool enableStorageCache)
Set the value of enable storage cache.
Definition: fvbasediscretization.hh:827
static unsigned maxThreads()
Return the maximum number of threads of the current process.
Definition: threadmanager.hpp:66
void shiftIntensiveQuantityCache(unsigned numSlots=1)
Move the intensive quantities for a given time index to the back.
Definition: fvbasediscretization.hh:785
Element-wise caculation of the residual matrix for models based on a finite volume spatial discretiza...
Definition: fvbaselocalresidual.hh:62
const BaseAuxiliaryModule< TypeTag > * auxiliaryModule(unsigned auxEqModIdx) const
Returns a given module for auxiliary equations.
Definition: fvbasediscretization.hh:1881
The base class for the finite volume discretization schemes.
Definition: fvbasediscretization.hh:87
const LocalLinearizer & localLinearizer(unsigned openMpThreadId) const
Returns the local jacobian which calculates the local stiffness matrix for an arbitrary element...
Definition: fvbasediscretization.hh:1264
This class stores an array of IntensiveQuantities objects, one intensive quantities object for each o...
void addAuxiliaryModule(BaseAuxiliaryModule< TypeTag > *auxMod)
Add a module for an auxiliary equation.
Definition: fvbasediscretization.hh:1835
The mapper to find the global index of an element.
Definition: fvbaseproperties.hh:228
This class calculates gradients of arbitrary quantities at flux integration points using the two-poin...
Definition: fvbasegradientcalculator.hh:51
void adaptGrid()
Called by the update() method when the grid should be refined.
Definition: fvbasediscretization.hh:1443
Scalar globalResidual(GlobalEqVector &dest, const SolutionVector &u) const
Compute the global residual for an arbitrary solution vector.
Definition: fvbasediscretization.hh:947
virtual void applyInitial()=0
Set the initial condition of the auxiliary module in the solution vector.
Base class for specifying auxiliary equations.
NewtonMethod & newtonMethod()
Returns the newton method object.
Definition: fvbasediscretization.hh:598
static void registerParameters()
Register all run-time parameters for the Vtk output module.
Definition: vtkprimaryvarsmodule.hpp:74
void start()
Start counting the time resources used by the simulation.
Definition: timer.cpp:46
Definition: fvbaseprimaryvariables.hh:161
void shiftStorageCache(unsigned numSlots=1) const
Shift storage cache by a given number of time step slots.
Definition: fvbasediscretization.hh:927
void invalidateIntensiveQuantitiesCache(unsigned timeIdx) const
Invalidate the whole intensive quantity cache for time index.
Definition: fvbasediscretization.hh:716
void updateBegin()
Called by the update() method before it tries to apply the newton method.
Definition: fvbasediscretization.hh:1430
The base class for writer modules.
Definition: baseoutputmodule.hh:67
const SolutionVector & solution(unsigned timeIdx) const
Reference to the solution at a given history index as a block vector.
Definition: fvbasediscretization.hh:1225
const GridView & gridView() const
Reference to the grid view of the spatial domain.
Definition: fvbasediscretization.hh:1821
The discretization specific part of the local residual.
Definition: fvbaseproperties.hh:97
This is a grid manager which does not create any border list.
Scalar primaryVarWeight(unsigned globalDofIdx, unsigned pvIdx) const
Returns the relative weight of a primary variable for calculating relative errors.
Definition: fvbasediscretization.hh:1292
bool enableStorageCache() const
Returns true iff the storage term is cached.
Definition: fvbasediscretization.hh:818
void invalidateStorageCacheEntry(unsigned globalIdx, unsigned timeIdx) const
Invalidate the storage cache for a given DOF and time index.
Definition: fvbasediscretization.hh:897
use locking to prevent race conditions when linearizing the global system of equations in multi-threa...
Definition: fvbaseproperties.hh:196
Specify whether the storage terms use extensive quantities or not.
Definition: fvbaseproperties.hh:248
Base class for the model specific class which provides access to all intensive (i.e., volume averaged) quantities.
Definition: fvbaseintensivequantities.hh:44
The mapper to find the global index of a vertex.
Definition: fvbaseproperties.hh:222
void serializeEntity(std::ostream &outstream, const DofEntity &dof)
Write the current solution for a degree of freedom to a restart file.
Definition: fvbasediscretization.hh:1536
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:883
Represents all quantities which available for calculating constraints.
a tag to mark properties as undefined
Definition: propertysystem.hh:38
The OpenMP threads manager.
Definition: fvbaseproperties.hh:189
bool storeIntensiveQuantities() const
Returns true if the cache for intensive quantities is enabled.
Definition: fvbasediscretization.hh:1887
std::string primaryVarName(unsigned pvIdx) const
Given an primary variable index, return a human readable name.
Definition: fvbasediscretization.hh:1638
A vector of holding a quantity for each equation (usually at a given spatial location) ...
Definition: fvbaseproperties.hh:115
Specify whether the some degrees of fredom can be constraint.
Definition: fvbaseproperties.hh:214
Simplifies writing multi-file VTK datasets.
Definition: vtkmultiwriter.hh:64
The base class for the finite volume discretization schemes without adaptation.
Definition: fvbasediscretization.hh:84
Structs needed for tpfalinearizer and its gpuparams struct extracted to be defined in one place that ...
Definition: blackoilbioeffectsmodules.hh:45
The base class for all output writers.
Definition: baseoutputwriter.hh:45
BaseAuxiliaryModule< TypeTag > * auxiliaryModule(unsigned auxEqModIdx)
Returns a given module for auxiliary equations.
Definition: fvbasediscretization.hh:1875
A Newton method for models using a finite volume discretization.
This class stores an array of IntensiveQuantities objects, one intensive quantities object for each o...
Definition: fvbaseelementcontext.hh:54
void clearAuxiliaryModules()
Causes the list of auxiliary equations to be cleared.
Definition: fvbasediscretization.hh:1859
SolutionVector & solution(unsigned timeIdx)
Definition: fvbasediscretization.hh:1231
const Linearizer & linearizer() const
Returns the operator linearizer for the global jacobian of the problem.
Definition: fvbasediscretization.hh:1246
void syncOverlap()
Syncronize the values of the primary variables on the degrees of freedom that overlap with the neighb...
Definition: fvbasediscretization.hh:1422
void addOutputModule(std::unique_ptr< BaseOutputModule< TypeTag >> newModule)
Add an module for writing visualization output after a timestep.
Definition: fvbasediscretization.hh:1669
The class which marks the border indices associated with the degrees of freedom on a process boundary...
Definition: basicproperties.hh:129
Vector containing volumetric or areal rates of quantities.
Definition: fvbaseproperties.hh:122
Type of object for specifying boundary conditions.
Definition: fvbaseproperties.hh:125
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:1681
Base class for the model specific class which provides access to all intensive (i.e., volume averaged) quantities.
Declare the properties used by the infrastructure code of the finite volume discretizations.
Provides data handles for parallel communication which operate on DOFs.
This class calculates gradients of arbitrary quantities at flux integration points using the two-poin...
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:1022
std::size_t numGridDof() const
Returns the number of degrees of freedom (DOFs) for the computational grid.
Definition: fvbasediscretization.hh:1578
void advanceTimeLevel()
Called by the problem if a time integration was successful, post processing of the solution is done a...
Definition: fvbasediscretization.hh:1481
Represents all quantities which available for calculating constraints.
Definition: fvbaseconstraintscontext.hh:43
const EqVector & cachedStorage(unsigned globalIdx, unsigned timeIdx) const
Retrieve an entry of the cache for the storage term.
Definition: fvbasediscretization.hh:843
const DofMapper & dofMapper() const
Mapper to convert the Dune entities of the discretization&#39;s degrees of freedoms are to indices...
Definition: fvbasediscretization.hh:1602
static unsigned threadId()
Return the index of the current OpenMP thread.
Definition: threadmanager.cpp:84
VTK output module for the fluid composition.
Definition: vtkprimaryvarsmodule.hpp:47
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:1561
Represents all quantities which available on boundary segments.
Scalar eqWeight(unsigned, unsigned) const
Returns the relative weight of an equation.
Definition: fvbasediscretization.hh:1304
bool verbose_() const
Returns whether messages should be printed.
Definition: fvbasediscretization.hh:1976
The secondary variables of all degrees of freedom in an element&#39;s stencil.
Definition: fvbaseproperties.hh:155
void serialize(Restarter &)
Serializes the current state of the model.
Definition: fvbasediscretization.hh:1507
SolutionVector & mutableSolution(unsigned timeIdx) const
Definition: fvbasediscretization.hh:1238
const ElementMapper & elementMapper() const
Returns the mapper for elements to indices.
Definition: fvbasediscretization.hh:1614
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
Definition: fvbaseproperties.hh:151
void invalidateStorageCache(unsigned timeIdx) const
Invalidate the whole storage cache for a given time index.
Definition: fvbasediscretization.hh:909
Provides an STL-iterator like interface to iterate over the enties of a GridView in OpenMP threaded a...
Definition: threadedentityiterator.hh:41
bool isLocalDof(unsigned globalIdx) const
Returns if the overlap of the volume ofa degree of freedom is non-zero.
Definition: fvbasediscretization.hh:1207
LocalResidual & localResidual_()
Reference to the local residal object.
Definition: fvbasediscretization.hh:1970
Calculates the Jacobian of the local residual for finite volume spatial discretizations using a finit...
The secondary variables of a constraint degree of freedom.
Definition: fvbaseproperties.hh:161
void resetLinearizer()
Resets the Jacobian matrix linearizer, so that the boundary types can be altered. ...
Definition: fvbasediscretization.hh:1621
Represents all quantities which available on boundary segments.
Definition: fvbaseboundarycontext.hh:45
The class which represents a constraint degree of freedom.
Definition: fvbaseproperties.hh:128
Calculates the local residual and its Jacobian for a single element of the grid.
A simple class which makes sure that a timer gets stopped if an exception is thrown.
Definition: timerguard.hh:41
void appendOutputFields(BaseOutputWriter &writer) const
Append the quantities relevant for the current solution to an output writer.
Definition: fvbasediscretization.hh:1812
void deserialize(Restarter &)
Deserializes the state of the model.
Definition: fvbasediscretization.hh:1521
The secondary variables within a sub-control volume.
Definition: fvbaseproperties.hh:139
The common code for the linearizers of non-linear systems of equations.
Provides an encapsulation to measure the system time.
Definition: timer.hpp:45
void updateSuccessful()
Called by the update() method if it was successful.
Definition: fvbasediscretization.hh:1437
LocalLinearizer & localLinearizer(unsigned openMpThreadId)
Definition: fvbasediscretization.hh:1270
unsigned cachedIntensiveQuantityHistorySize() const
Get the cached intensive quantity history size.
Definition: fvbasediscretization.hh:708
Class to specify constraints for a finite volume spatial discretization.
Definition: fvbaseconstraints.hh:47
Declares the parameters for the black oil model.
void checkConservativeness([[maybe_unused]] Scalar tolerance=-1, [[maybe_unused]] 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:1077
void applyInitialSolution()
Applies the initial solution for all degrees of freedom to which the model applies.
Definition: fvbasediscretization.hh:529
const VertexMapper & vertexMapper() const
Returns the mapper for vertices to indices.
Definition: fvbasediscretization.hh:1608
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
The part of the extensive quantities which is specific to the spatial discretization.
Definition: fvbaseproperties.hh:175
Specify if experimental features should be enabled or not.
Definition: fvbaseproperties.hh:256
Provides an encapsulation to measure the system time.
Class to specify constraints for a finite volume spatial discretization.
bool enableGridAdaptation() const
Returns whether the grid ought to be adapted to the solution during the simulation.
Definition: fvbasediscretization.hh:522
Scalar gridTotalVolume() const
Returns the volume of the whole grid which represents the spatial domain.
Definition: fvbasediscretization.hh:1217
Scalar globalResidual(GlobalEqVector &dest) const
Compute the global residual for the current solution vector.
Definition: fvbasediscretization.hh:962
bool update()
Try to progress the model to the next timestep.
Definition: fvbasediscretization.hh:1337
Vector containing a quantity of for equation for each DOF of the whole grid.
Definition: linalgproperties.hh:54
Simplifies multi-threaded capabilities.
This is a grid manager which does not create any border list.
Definition: nullborderlistmanager.hh:43
The class which linearizes the non-linear system of equations.
Definition: newtonmethodproperties.hh:36
Scalar dofTotalVolume(unsigned globalIdx) const
Returns the volume of a given control volume.
Definition: fvbasediscretization.hh:1199
Represents the primary variables used by the a model.
Element-wise caculation of the residual matrix for models based on a finite volume spatial discretiza...
Scalar relativeDofError(unsigned vertexIdx, const PrimaryVariables &pv1, const PrimaryVariables &pv2) const
Returns the relative error between two vectors of primary variables.
Definition: fvbasediscretization.hh:1316
A simple class which makes sure that a timer gets stopped if an exception is thrown.
Provide the properties at a face which make sense independently of the conserved quantities.
std::size_t numTotalDof() const
Returns the total number of degrees of freedom (i.e., grid plux auxiliary DOFs)
Definition: fvbasediscretization.hh:1595
A vector of holding a quantity for each equation for each DOF of an element.
Definition: fvbaseproperties.hh:118
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
void prepareOutputFields() const
Prepare the quantities relevant for the current solution to be appended to the output writers...
Definition: fvbasediscretization.hh:1770
Definition: fvbasediscretization.hh:272
Manages the simulation time.
Definition: basicproperties.hh:120
The history size required by the time discretization.
Definition: fvbaseproperties.hh:240
ScalarBuffer * allocateManagedScalarBuffer(std::size_t numEntities)
Allocate a managed buffer for a scalar field.
Definition: vtkmultiwriter.hh:192
std::size_t numAuxiliaryModules() const
Returns the number of modules for auxiliary equations.
Definition: fvbasediscretization.hh:1869
Specify the format the VTK output is written to disk.
Definition: fvbaseproperties.hh:210
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
Vector containing all primary variables of the grid.
Definition: fvbaseproperties.hh:132
void halt()
Stop the measurement reset all timing values.
Definition: timer.cpp:75
Base class for specifying auxiliary equations.
Definition: baseauxiliarymodule.hh:55
std::size_t numAuxiliaryDof() const
Returns the number of degrees of freedom (DOFs) of the auxiliary equations.
Definition: fvbasediscretization.hh:1584
static void registerParameters()
Register all run-time parameters for the model.
Definition: fvbasediscretization.hh:426
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:1663
Manages the initializing and running of time dependent problems.
Definition: simulator.hh:83
double stop()
Stop counting the time resources.
Definition: timer.cpp:52
Definition: blackoilmodel.hh:75
const LocalResidual & localResidual(unsigned openMpThreadId) const
Returns the object to calculate the local residual function.
Definition: fvbasediscretization.hh:1276
The secondary variables of a boundary segment.
Definition: fvbaseproperties.hh:158
void updateFailed()
Called by the update() method if it was unsuccessful.
Definition: fvbasediscretization.hh:1454
A vector of primary variables within a sub-control volume.
Definition: fvbaseproperties.hh:136
void updateCachedStorage(unsigned globalIdx, unsigned timeIdx, const EqVector &value) const
Set an entry of the cache for the storage term.
Definition: fvbasediscretization.hh:867
static std::string discretizationName()
Returns a string of discretization&#39;s human-readable name.
Definition: fvbasediscretization.hh:1630
The common code for the linearizers of non-linear systems of equations.
Definition: fvbaselinearizer.hh:77
VTK output module for the fluid composition.
Definition: fvbaseproperties.hh:83
LocalResidual & localResidual(unsigned openMpThreadId)
Definition: fvbasediscretization.hh:1282
Specify whether to use volumetric residuals or not.
Definition: fvbaseproperties.hh:252
Linearizer & linearizer()
Returns the object which linearizes the global system of equations at the current solution...
Definition: fvbasediscretization.hh:1253
const NewtonMethod & newtonMethod() const
Returns the newton method object.
Definition: fvbasediscretization.hh:604