move the dynamic refinement part related to dune fem to separate class

introduced base discretization in tagsystem to be able to change between dunefem adaptation or not
This commit is contained in:
hnil 2023-08-03 14:06:08 +02:00 committed by Arne Morten Kvarving
parent 7e1a1b27a2
commit 37b87aedb1
6 changed files with 292 additions and 129 deletions

View File

@ -39,7 +39,6 @@
#include "fvbaseboundarycontext.hh"
#include "fvbaseconstraintscontext.hh"
#include "fvbaseconstraints.hh"
#include "fvbasediscretization.hh"
#include "fvbasegradientcalculator.hh"
#include "fvbasenewtonmethod.hh"
#include "fvbaseprimaryvariables.hh"
@ -64,12 +63,6 @@
#include <dune/common/fmatrix.hh>
#include <dune/istl/bvector.hh>
#if HAVE_DUNE_FEM
#include <dune/fem/space/common/adaptationmanager.hh>
#include <dune/fem/space/common/restrictprolongtuple.hh>
#include <dune/fem/function/blockvectorfunction.hh>
#include <dune/fem/misc/capabilities.hh>
#endif
#include <algorithm>
#include <cstddef>
@ -78,10 +71,13 @@
#include <stdexcept>
#include <sstream>
#include <string>
#include <type_traits>
#include <vector>
namespace Opm {
template<class TypeTag>
class FvBaseDiscretizationNoAdapt;
template<class TypeTag>
class FvBaseDiscretization;
} // namespace Opm
@ -322,6 +318,23 @@ struct UseVolumetricResidual<TypeTag, TTag::FvBaseDiscretization> { static const
template<class TypeTag>
struct EnableExperiments<TypeTag, TTag::FvBaseDiscretization> { static constexpr bool value = true; };
template <class TypeTag, class MyTypeTag>
struct BaseDiscretizationType {
using type = UndefinedProperty;
};
#if !HAVE_DUNE_FEM
template<class TypeTag>
struct BaseDiscretizationType<TypeTag,TTag::FvBaseDiscretization> {
using type = FvBaseDiscretizationNoAdapt<TypeTag>;
};
template<class TypeTag>
struct DiscreteFunction<TypeTag, TTag::FvBaseDiscretization> {
using BaseDiscretization = FvBaseDiscretization<TypeTag>;
using type = typename BaseDiscretization::BlockVectorWrapper;
};
#endif
} // namespace Opm::Properties
namespace Opm {
@ -422,25 +435,8 @@ public:
};
private:
#if HAVE_DUNE_FEM
using DiscreteFunctionSpace = GetPropType<TypeTag, Properties::DiscreteFunctionSpace> ;
// discrete function storing solution data
using DiscreteFunction = Dune::Fem::ISTLBlockVectorDiscreteFunction<DiscreteFunctionSpace, PrimaryVariables>;
// problem restriction and prolongation operator for adaptation
using Problem = GetPropType<TypeTag, Properties::Problem> ;
using ProblemRestrictProlongOperator = typename Problem :: RestrictProlongOperator ;
// discrete function restriction and prolongation operator for adaptation
using DiscreteFunctionRestrictProlong = Dune::Fem::RestrictProlongDefault< DiscreteFunction >;
using RestrictProlong = Dune::Fem::RestrictProlongTuple< DiscreteFunctionRestrictProlong, ProblemRestrictProlongOperator >;
// adaptation classes
using AdaptationManager = Dune::Fem::AdaptationManager<Grid, RestrictProlong >;
#else
using DiscreteFunction = BlockVectorWrapper ;
using DiscreteFunctionSpace = size_t ;
#endif
using DiscreteFunctionSpace = GetPropType<TypeTag, Properties::DiscreteFunctionSpace>;
using DiscreteFunction = GetPropType<TypeTag, Properties::DiscreteFunction>;
// copying a discretization object is not a good idea
FvBaseDiscretization(const FvBaseDiscretization& );
@ -457,25 +453,11 @@ public:
, newtonMethod_(simulator)
, localLinearizer_(ThreadManager::maxThreads())
, linearizer_(new Linearizer())
#if HAVE_DUNE_FEM
, space_( simulator.vanguard().gridPart() )
#else
, space_( asImp_().numGridDof() )
#endif
, enableGridAdaptation_( EWOMS_GET_PARAM(TypeTag, bool, EnableGridAdaptation) )
, enableIntensiveQuantityCache_(EWOMS_GET_PARAM(TypeTag, bool, EnableIntensiveQuantityCache))
, enableStorageCache_(EWOMS_GET_PARAM(TypeTag, bool, EnableStorageCache))
, enableThermodynamicHints_(EWOMS_GET_PARAM(TypeTag, bool, EnableThermodynamicHints))
{
#if HAVE_DUNE_FEM
if (enableGridAdaptation_ && !Dune::Fem::Capabilities::isLocallyAdaptive<Grid>::v)
throw std::invalid_argument("Grid adaptation enabled, but chosen Grid is not capable"
" of adaptivity");
#else
if (enableGridAdaptation_)
throw std::invalid_argument("Grid adaptation currently requires the presence of the "
"dune-fem module");
#endif
bool isEcfv = std::is_same<Discretization, EcfvDiscretization<TypeTag> >::value;
if (enableGridAdaptation_ && !isEcfv)
throw std::invalid_argument("Grid adaptation currently only works for the "
@ -486,8 +468,6 @@ public:
size_t numDof = asImp_().numGridDof();
for (unsigned timeIdx = 0; timeIdx < historySize; ++timeIdx) {
solution_[timeIdx].reset(new DiscreteFunction("solution", space_));
if (storeIntensiveQuantities()) {
intensiveQuantityCache_[timeIdx].resize(numDof);
intensiveQuantityCacheUpToDate_[timeIdx].resize(numDof, /*value=*/false);
@ -1420,48 +1400,8 @@ public:
*/
void adaptGrid()
{
#if HAVE_DUNE_FEM
// adapt the grid if enabled and if all dependencies are available
// adaptation is only done if markForGridAdaptation returns true
if (enableGridAdaptation_)
{
// check if problem allows for adaptation and cells were marked
if( simulator_.problem().markForGridAdaptation() )
{
// adapt the grid and load balance if necessary
adaptationManager().adapt();
// if the grid has potentially changed, we need to re-create the
// supporting data structures.
#if DUNE_VERSION_NEWER(DUNE_GRID, 2, 8)
elementMapper_.update(gridView_);
vertexMapper_.update(gridView_);
#else
elementMapper_.update();
vertexMapper_.update();
#endif
resetLinearizer();
// this is a bit hacky because it supposes that Problem::finishInit()
// works fine multiple times in a row.
//
// TODO: move this to Problem::gridChanged()
finishInit();
// notify the problem that the grid has changed
//
// TODO: come up with a mechanism to access the unadapted data structures
// outside of the problem (i.e., grid, mappers, solutions)
simulator_.problem().gridChanged();
// notify the modules for visualization output
auto outIt = outputModules_.begin();
auto outEndIt = outputModules_.end();
for (; outIt != outEndIt; ++outIt)
(*outIt)->allocBuffers();
}
}
#endif
throw std::invalid_argument("Grid adaptation need to be implemented for "
"specific settings of grid and function spaces");
}
/*!
@ -1498,7 +1438,9 @@ public:
void advanceTimeLevel()
{
// at this point we can adapt the grid
asImp_().adaptGrid();
if (this->enableGridAdaptation_) {
asImp_().adaptGrid();
}
// make the current solution the previous one.
solution(/*timeIdx=*/1) = solution(/*timeIdx=*/0);
@ -1907,22 +1849,6 @@ public:
bool storeIntensiveQuantities() const
{ return enableIntensiveQuantityCache_ || enableThermodynamicHints_; }
#if HAVE_DUNE_FEM
AdaptationManager& adaptationManager()
{
if( ! adaptationManager_ )
{
// create adaptation objects here, because when doing so in constructor
// problem is not yet intialized, aka seg fault
restrictProlong_.reset(
new RestrictProlong( DiscreteFunctionRestrictProlong(*(solution_[/*timeIdx=*/ 0] )),
simulator_.problem().restrictProlongOperator() ) );
adaptationManager_.reset( new AdaptationManager( simulator_.vanguard().grid(), *restrictProlong_ ) );
}
return *adaptationManager_;
}
#endif
const Timer& prePostProcessTimer() const
{ return prePostProcessTimer_; }
@ -1938,13 +1864,9 @@ public:
template<class Serializer>
void serializeOp(Serializer& serializer)
{
for (auto& sol : solution_) {
#if HAVE_DUNE_FEM
serializer(sol->blockVector());
#else
serializer(*sol);
#endif
}
using BaseDiscretization = GetPropType<TypeTag, Properties::BaseDiscretizationType>;
using Helper = typename BaseDiscretization::template SerializeHelper<Serializer>;
Helper::serializeOp(serializer, solution_);
}
bool operator==(const FvBaseDiscretization& rhs) const
@ -2049,15 +1971,8 @@ protected:
// while these are logically bools, concurrent writes to vector<bool> are not thread safe.
mutable std::vector<unsigned char> intensiveQuantityCacheUpToDate_[historySize];
DiscreteFunctionSpace space_;
mutable std::array< std::unique_ptr< DiscreteFunction >, historySize > solution_;
#if HAVE_DUNE_FEM
std::unique_ptr<RestrictProlong> restrictProlong_;
std::unique_ptr<AdaptationManager> adaptationManager_;
#endif
std::list<BaseOutputModule<TypeTag>*> outputModules_;
Scalar gridTotalVolume_;
@ -2071,6 +1986,50 @@ protected:
bool enableStorageCache_;
bool enableThermodynamicHints_;
};
/*!
* \ingroup FiniteVolumeDiscretizations
*
* \brief The base class for the finite volume discretization schemes without adaptation.
*/
template<class TypeTag>
class FvBaseDiscretizationNoAdapt : public FvBaseDiscretization<TypeTag>
{
using ParentType = FvBaseDiscretization<TypeTag>;
using Simulator = GetPropType<TypeTag, Properties::Simulator>;
using DiscreteFunction = GetPropType<TypeTag, Properties::DiscreteFunction>;
static constexpr unsigned historySize = getPropValue<TypeTag, Properties::TimeDiscHistorySize>();
public:
template<class Serializer>
struct SerializeHelper {
template<class SolutionType>
static void serializeOp(Serializer& serializer,
SolutionType& solution)
{
for (auto& sol : solution) {
serializer(*sol);
}
}
};
FvBaseDiscretizationNoAdapt(Simulator& simulator)
: ParentType(simulator)
{
if (this->enableGridAdaptation_) {
throw std::invalid_argument("Grid adaptation need to use"
" BaseDiscretization = FvBaseDiscretizationFemAdapt"
" which currently requires the presence of the"
" dune-fem module");
}
size_t numDof = this->asImp_().numGridDof();
for (unsigned timeIdx = 0; timeIdx < historySize; ++timeIdx) {
this->solution_[timeIdx] = std::make_unique<DiscreteFunction>("solution", numDof);
}
}
};
} // namespace Opm
#endif
#endif // EWOMS_FV_BASE_DISCRETIZATION_HH

View File

@ -0,0 +1,174 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \copydoc Opm::FvBaseDiscretization
*/
#ifndef EWOMS_FV_BASE_DISCRETIZATION_FEMADAPT_HH
#define EWOMS_FV_BASE_DISCRETIZATION_FEMADAPT_HH
#include <opm/models/discretization/common/fvbasediscretization.hh>
#include <dune/fem/space/common/adaptationmanager.hh>
#include <dune/fem/space/common/restrictprolongtuple.hh>
#include <dune/fem/function/blockvectorfunction.hh>
#include <dune/fem/misc/capabilities.hh>
namespace Opm {
template<class TypeTag>
class FvBaseDiscretizationFemAdapt;
namespace Properties {
template<class TypeTag>
struct BaseDiscretizationType<TypeTag,TTag::FvBaseDiscretization> {
using type = FvBaseDiscretizationFemAdapt<TypeTag>;
};
template<class TypeTag>
struct DiscreteFunction<TypeTag, TTag::FvBaseDiscretization> {
using DiscreteFunctionSpace = GetPropType<TypeTag, Properties::DiscreteFunctionSpace>;
using PrimaryVariables = GetPropType<TypeTag, Properties::PrimaryVariables>;
using type = Dune::Fem::ISTLBlockVectorDiscreteFunction<DiscreteFunctionSpace, PrimaryVariables>;
};
} // namespace Properties
/*!
* \ingroup FiniteVolumeDiscretizations
*
* \brief The base class for the finite volume discretization schemes.
*/
template <class TypeTag>
class FvBaseDiscretizationFemAdapt : public FvBaseDiscretization<TypeTag>
{
using Grid = GetPropType<TypeTag, Properties::Grid>;
using ParentType = FvBaseDiscretization<TypeTag>;
using PrimaryVariables = GetPropType<TypeTag, Properties::PrimaryVariables>;
using Problem = GetPropType<TypeTag, Properties::Problem>;
using Simulator = GetPropType<TypeTag, Properties::Simulator>;
static constexpr unsigned historySize = getPropValue<TypeTag, Properties::TimeDiscHistorySize>();
using DiscreteFunctionSpace = GetPropType<TypeTag, Properties::DiscreteFunctionSpace>;
// discrete function storing solution data
using DiscreteFunction = Dune::Fem::ISTLBlockVectorDiscreteFunction<DiscreteFunctionSpace, PrimaryVariables>;
// problem restriction and prolongation operator for adaptation
using ProblemRestrictProlongOperator = typename Problem::RestrictProlongOperator;
// discrete function restriction and prolongation operator for adaptation
using DiscreteFunctionRestrictProlong = Dune::Fem::RestrictProlongDefault<DiscreteFunction>;
using RestrictProlong
= Dune::Fem::RestrictProlongTuple<DiscreteFunctionRestrictProlong, ProblemRestrictProlongOperator>;
// adaptation classes
using AdaptationManager = Dune::Fem::AdaptationManager<Grid, RestrictProlong>;
public:
template<class Serializer>
struct SerializeHelper {
template<class SolutionType>
static void serializeOp(Serializer& serializer,
SolutionType& solution)
{
for (auto& sol : solution) {
serializer(sol->blockVector());
}
}
};
FvBaseDiscretizationFemAdapt(Simulator& simulator)
: ParentType(simulator)
, space_(simulator.vanguard().gridPart())
{
if (this->enableGridAdaptation_ && !Dune::Fem::Capabilities::isLocallyAdaptive<Grid>::v) {
throw std::invalid_argument("Grid adaptation enabled, but chosen Grid is not capable"
" of adaptivity");
}
for (unsigned timeIdx = 0; timeIdx < historySize; ++timeIdx) {
this->solution_[timeIdx] = std::make_unique<DiscreteFunction>("solution", space_);
}
}
void adaptGrid()
{
// adapt the grid if enabled and if all dependencies are available
// adaptation is only done if markForGridAdaptation returns true
if (this->enableGridAdaptation_) {
// check if problem allows for adaptation and cells were marked
if (this->simulator_.problem().markForGridAdaptation()) {
// adapt the grid and load balance if necessary
adaptationManager().adapt();
// if the grid has potentially changed, we need to re-create the
// supporting data structures.
this->elementMapper_.update(this->gridView_);
this->vertexMapper_.update(this->gridView_);
this->resetLinearizer();
// this is a bit hacky because it supposes that Problem::finishInit()
// works fine multiple times in a row.
//
// TODO: move this to Problem::gridChanged()
this->finishInit();
// notify the problem that the grid has changed
//
// TODO: come up with a mechanism to access the unadapted data structures
// outside of the problem (i.e., grid, mappers, solutions)
this->simulator_.problem().gridChanged();
// notify the modules for visualization output
auto outIt = this->outputModules_.begin();
auto outEndIt = this->outputModules_.end();
for (; outIt != outEndIt; ++outIt)
(*outIt)->allocBuffers();
}
}
}
AdaptationManager& adaptationManager()
{
if (!adaptationManager_) {
// create adaptation objects here, because when doing so in constructor
// problem is not yet intialized, aka seg fault
restrictProlong_ = std::make_unique<RestrictProlong>(DiscreteFunctionRestrictProlong(*(this->solution_[/*timeIdx=*/0])),
this->simulator_.problem().restrictProlongOperator());
adaptationManager_ = std::make_unique<AdaptationManager>(this->simulator_.vanguard().grid(), *restrictProlong_);
}
return *adaptationManager_;
}
private:
DiscreteFunctionSpace space_;
std::unique_ptr<RestrictProlong> restrictProlong_;
std::unique_ptr<AdaptationManager> adaptationManager_;
};
} // namespace Opm
#endif

View File

@ -90,6 +90,9 @@ struct Stencil { using type = UndefinedProperty; };
template<class TypeTag, class MyTypeTag>
struct DiscreteFunctionSpace { using type = UndefinedProperty; };
template<class TypeTag, class MyTypeTag>
struct DiscreteFunction { using type = UndefinedProperty; };
//! The type of the problem
template<class TypeTag, class MyTypeTag>
struct Problem { using type = UndefinedProperty; };

View File

@ -39,6 +39,7 @@
#include <opm/models/discretization/common/fvbasediscretization.hh>
#if HAVE_DUNE_FEM
#include <opm/models/discretization/common/fvbasediscretizationfemadapt.hh>
#include <dune/fem/space/common/functionspace.hh>
#include <dune/fem/space/finitevolume.hh>
#endif
@ -97,6 +98,18 @@ private:
public:
using type = Dune::Fem::FiniteVolumeSpace< FunctionSpace, GridPart, 0 >;
};
#else
template <class TypeTag>
struct DummySpaceEcfv {
using DiscreteFunctionSpace = GetPropType<TypeTag, Properties::DiscreteFunctionSpace>;
DummySpaceEcfv(const DiscreteFunctionSpace&) {};
DummySpaceEcfv(const int&) {};
};
template <class TypeTag>
struct DiscreteFunctionSpace<TypeTag, TTag::EcfvDiscretization> {
using type = DummySpaceEcfv<TypeTag>;
};
#endif
//! Set the border list creator for to the one of an element based
@ -130,10 +143,9 @@ namespace Opm {
* \brief The base class for the element-centered finite-volume discretization scheme.
*/
template<class TypeTag>
class EcfvDiscretization : public FvBaseDiscretization<TypeTag>
class EcfvDiscretization : public GetPropType<TypeTag, Properties::BaseDiscretizationType>
{
using ParentType = FvBaseDiscretization<TypeTag>;
using ParentType = GetPropType<TypeTag, Properties::BaseDiscretizationType>;
using Implementation = GetPropType<TypeTag, Properties::Model>;
using DofMapper = GetPropType<TypeTag, Properties::DofMapper>;
using PrimaryVariables = GetPropType<TypeTag, Properties::PrimaryVariables>;

View File

@ -40,6 +40,7 @@
#include <opm/models/discretization/common/fvbasediscretization.hh>
#if HAVE_DUNE_FEM
#include <opm/models/discretization/common/fvbasediscretizationfemadapt.hh>
#include <dune/fem/space/common/functionspace.hh>
#include <dune/fem/space/lagrange.hh>
#endif
@ -109,6 +110,18 @@ public:
// Lagrange discrete function space with unknowns at the cell vertices
using type = Dune::Fem::LagrangeDiscreteFunctionSpace< FunctionSpace, GridPart, 1 >;
};
#else
template <class TypeTag>
struct DummySpaceVcfv {
using DiscreteFunctionSpace = GetPropType<TypeTag, Properties::DiscreteFunctionSpace>;
DummySpaceVcfv(const DiscreteFunctionSpace&) {};
DummySpaceVcfv(const int&) {};
};
template <class TypeTag>
struct DiscreteFunctionSpace<TypeTag, TTag::VcfvDiscretization> {
using type = DummySpaceVcfv<TypeTag>;
};
#endif
//! Set the border list creator for vertices
@ -138,9 +151,9 @@ namespace Opm {
* \brief The base class for the vertex centered finite volume discretization scheme.
*/
template<class TypeTag>
class VcfvDiscretization : public FvBaseDiscretization<TypeTag>
class VcfvDiscretization : public GetPropType<TypeTag, Properties::BaseDiscretizationType>
{
using ParentType = FvBaseDiscretization<TypeTag>;
using ParentType = GetPropType<TypeTag, Properties::BaseDiscretizationType>;
using Implementation = GetPropType<TypeTag, Properties::Model>;
using DofMapper = GetPropType<TypeTag, Properties::DofMapper>;
using GridView = GetPropType<TypeTag, Properties::GridView>;

View File

@ -120,15 +120,17 @@ protected:
void updateGridView_()
{
#if HAVE_DUNE_FEM
// first delete old grid part
// this is due to a bug in dune-fem (dangling reference)
gridPart_.reset();
gridPart_.reset(new GridPart(asImp_().grid()));
gridView_.reset(new GridView(static_cast<GridView>(*gridPart_)));
assert(gridView_->size(0) == asImp_().grid().leafGridView().size(0));
#else
gridView_.reset(new GridView(asImp_().grid().leafGridView()));
if constexpr (std::is_same_v<GridView,
typename GetPropType<TypeTag,
Properties::GridPart>::GridViewType>) {
gridPart_ = std::make_unique<GridPart>(asImp_().grid());
gridView_ = std::make_unique<GridView>(static_cast<GridView>(*gridPart_));
assert(gridView_->size(0) == asImp_().grid().leafGridView().size(0));
} else
#endif
{
gridView_ = std::make_unique<GridView>(asImp_().grid().leafGridView());
}
}
private: