Commit 22b3c720 authored by Praetorius, Simon's avatar Praetorius, Simon
Browse files

Rewrite adaption interface to allow to attach bases to the grid-transfer

parent b0713779
#pragma once
#include <amdis/common/ConceptsBase.hpp>
namespace AMDiS
{
/**
* \addtogroup Concepts
* @{
**/
namespace Concepts
{
namespace Definition
{
struct InterpolateData
{
template <class Data>
auto requires_(Data const& data) -> decltype(
const_cast<Data&>(data).preAdapt(true),
const_cast<Data&>(data).postAdapt(true)
);
};
struct UpdateData
{
template <class Basis>
auto requires_(Basis const& basis) -> decltype(
const_cast<Basis&>(basis).update(basis.gridView())
);
};
} // end namespace Definition
template <class Data>
constexpr bool InterpolateData = models<Definition::InterpolateData(Data)>;
template <class Basis>
constexpr bool UpdateData = models<Definition::UpdateData(Basis)>;
} // end namespace Concepts
/// @}
/**
* \addtogroup Adaption
* @{
**/
/// \brief Interface for transfer between grid changes
class AdaptionInterface
{
public:
virtual ~AdaptionInterface() = default;
/// Prepare the grid and the data for the adaption
virtual bool preAdapt() = 0;
/// Do the grid adaption
virtual bool adapt() = 0;
// Perform data adaption to the new grid
virtual void postAdapt() = 0;
};
/// @}
} // end namespace AMDiS
......@@ -17,6 +17,8 @@ install(FILES
AdaptBase.hpp
AdaptInfo.hpp
AdaptInstationary.hpp
AdaptionInterface.hpp
AdaptiveGlobalBasis.hpp
AdaptStationary.hpp
AMDiS.hpp
Assembler.hpp
......
#pragma once
#include <functional>
#include <list>
#include <amdis/AdaptionInterface.hpp>
#include <amdis/Output.hpp>
#include <amdis/linearalgebra/DOFVectorInterface.hpp>
namespace AMDiS
{
......@@ -12,35 +13,26 @@ namespace AMDiS
* @{
**/
/// \brief Interface for transfer between grid changes to be registered in a \ref GridTransferManager
class GridTransferInterface
{
public:
virtual ~GridTransferInterface() = default;
/// Attach a data container to the grid transfer, that gets interpolated during grid change
virtual void attach(DOFVectorInterface*) = 0;
/// Remove a data constainer from the grid transfer. Throws a warning if container not found.
virtual void detach(DOFVectorInterface*) = 0;
/// Prepare the grid and the data for the adaption
virtual bool preAdapt() = 0;
/// Do the grid adaption
virtual bool adapt() = 0;
// Perform data adaption to the new grid
virtual void postAdapt() = 0;
};
/// \brief Implementation of \ref GridTransferInterface for concrete Grid type.
/// \brief Implementation of \ref AdaptionInterface for concrete Grid type.
template <class Grid>
class GridTransfer
: public GridTransferInterface
: public AdaptionInterface
{
using Self = GridTransfer;
using Key = std::uintptr_t;
struct InterpolateCallback
{
std::function<void(bool)> preAdapt;
std::function<void(bool)> postAdapt;
int count = 0;
};
struct UpdateCallback
{
std::function<void(void)> update;
int count = 0;
};
public:
/// Bind a (mutable) grid to this GridTransfer. Must be called before any xxxAdapt() method.
......@@ -63,20 +55,57 @@ namespace AMDiS
return grid_ != nullptr;
}
/// Implements \ref GridTransferInterface::attach
void attach(DOFVectorInterface* vec) override
/// Register data to GridTransfer.
/**
* This inserts a callback that is called in \ref preAdapt() and another that is
* called in \ref postAdapt() step.
*
* *Requirement:*
* - Data must be a model of \ref Concepts::InterpolateData
**/
template <class Data,
REQUIRES(Concepts::InterpolateData<Data>)>
void attach(Data& data)
{
data_.push_back(vec);
auto it = interpolateCallbacks_.emplace(Key(&data), InterpolateCallback{
[&data](bool mightCoarsen) -> void { data.preAdapt(mightCoarsen); },
[&data](bool refined) -> void { data.postAdapt(refined); }});
it.first->second.count++;
}
/// Implements \ref GridTransferInterface::detach
void detach(DOFVectorInterface* vec) override
/// Register data to GridTransfer.
/**
* This inserts a callback that is called after the \ref adapt() step.
* The callback calls `data.update(data.gridView())`.
*
* *Requirement:*
* - Data must be a model of \ref Concepts::UpdateData
**/
template <class Data,
REQUIRES(Concepts::UpdateData<Data>)>
void attach(Data& data)
{
auto it = std::find(data_.begin(), data_.end(), vec);
if (it != data_.end())
data_.erase(it);
else
warning("DOFVector to detach not found");
auto it = updateCallbacks_.emplace(Key(&data), UpdateCallback{
[&data]() -> void { data.update(data.gridView()); }});
it.first->second.count++;
}
/// Unregister data from GridTransfer. Data is identified by its address.
template <class Data,
REQUIRES(Concepts::InterpolateData<Data>)>
void detach(Data& data)
{
eraseCallback(interpolateCallbacks_, Key(&data));
}
/// Unregister data from GridTransfer. Data is identified by its address.
template <class Data,
REQUIRES(Concepts::UpdateData<Data>)>
void detach(Data& data)
{
eraseCallback(updateCallbacks_, Key(&data));
}
/// Implements \ref GridTransferInterface::preAdapt
......@@ -85,8 +114,8 @@ namespace AMDiS
{
assert(bound());
mightCoarsen_ = grid_->preAdapt();
for (auto* vec : this->data_)
vec->preAdapt(mightCoarsen_);
for (auto&& data : interpolateCallbacks_)
data.second.preAdapt(mightCoarsen_);
return mightCoarsen_;
}
......@@ -105,9 +134,12 @@ namespace AMDiS
{
assert(bound());
if (mightCoarsen_ || refined_) {
for (auto* vec : this->data_)
vec->postAdapt(refined_);
for (auto&& data : updateCallbacks_)
data.second.update();
for (auto&& data : interpolateCallbacks_)
data.second.postAdapt(refined_);
}
grid_->postAdapt();
changeIndex_++;
}
......@@ -118,12 +150,27 @@ namespace AMDiS
return changeIndex_;
}
private:
// remove entry from map if count <= 1, otherwise reduce count by 1
template <class Map>
void eraseCallback(Map& map, Key key)
{
auto it = map.find(key);
if (it == map.end())
warning("Data to detach not found");
else if (it->second.count > 1)
it->second.count--;
else
map.erase(it);
}
private:
/// A grid this GridTransfer is bound to in \ref bind()
Grid* grid_ = nullptr;
/// A list of data containers handled during grid adaption
std::list<DOFVectorInterface*> data_;
std::map<Key,InterpolateCallback> interpolateCallbacks_;
std::map<Key,UpdateCallback> updateCallbacks_;
/// Flag set during \ref preAdapt(), indicating whether any element might be coarsened in \ref adapt()
bool mightCoarsen_ = false;
......
......@@ -4,6 +4,7 @@
#include <map>
#include <memory>
#include <amdis/AdaptionInterface.hpp>
#include <amdis/GridTransfer.hpp>
#include <amdis/common/ConcurrentCache.hpp>
......@@ -17,12 +18,9 @@ namespace AMDiS
/// Static administration class for automatic handling of DOFVectors during grid adaption
class GridTransferManager
{
template <class, class>
friend class DOFVectorBase;
using Self = GridTransferManager;
using Key = std::uintptr_t;
using Data = std::unique_ptr<GridTransferInterface>;
using Data = std::shared_ptr<AdaptionInterface>;
private:
// Constructors. Since this is a static class you cannot call any constructor.
......@@ -41,56 +39,56 @@ namespace AMDiS
* Takes a grid as argument. Marking of the grid needs to be performed prior to calling this.
* Returns true if the grid changed during adaptation.
**/
template <class Grid, class ...Bases>
static bool adapt(Grid& grid, Bases&... bases)
template <class Grid>
static bool adapt(Grid& grid)
{
auto gridTransfer = GridTransferManager::gridTransfer(grid);
bool adapted = gridTransfer.preAdapt();
adapted |= gridTransfer.adapt();
// call basis.update(basis.gridView()) on all bases
(void)std::initializer_list<int>({0, (bases.update(bases.gridView()),0)...});
gridTransfer.postAdapt();
auto transfer = gridTransfer(grid);
bool adapted = transfer->preAdapt();
adapted |= transfer->adapt();
transfer->postAdapt();
return adapted;
}
/// Returns the GridTransfer corresponding to a Grid, to be used during the adaptation cycle
/// Returns the GridTransfer bound to a Grid, to be used during the adaptation cycle
template <class Grid>
static GridTransfer<Grid>& gridTransfer(Grid& grid)
static std::shared_ptr<GridTransfer<Grid>> gridTransfer(Grid& grid)
{
GridTransfer<Grid>* gridTransfer
= dynamic_cast<GridTransfer<Grid>*>(Self::gridTransferInterface(grid));
gridTransfer->bind(grid);
return *gridTransfer;
auto transfer = get(grid);
transfer->bind(grid);
return transfer;
}
private:
// DOFVector registration methods. They are called automaticly by the DOFVectors.
template <class Vec>
static void attach(Vec& vec)
public:
template <class Grid, class Data>
static void attach(Grid const& grid, Data& data)
{
auto const& grid = vec.basis().gridView().grid();
Self::gridTransferInterface(grid)->attach(&vec);
get(grid)->attach(data);
}
template <class Vec>
static void detach(Vec& vec)
template <class Grid, class Data>
static void detach(Grid const& grid, Data& data)
{
auto const& grid = vec.basis().gridView().grid();
Self::gridTransferInterface(grid)->detach(&vec);
get(grid)->detach(data);
}
// Returns the GridTransferInterface class,
// used for attaching and detaching DOFVectors to a GridTransfer
private:
/// \brief Returns the GridTransfer class, used for attaching and detaching Data
/**
* NOTE: The returned GridTransfer is not yet bound to a grid, since a
* mutable reference `Grid&` is needed for the binding.
**/
template <class Grid>
static GridTransferInterface* gridTransferInterface(Grid const &grid)
static std::shared_ptr<GridTransfer<Grid>> get(Grid const& grid)
{
Key key = Key(&grid);
GridTransferCache cache;
auto& gridTransferInterfaceUniquePtr = cache.get(key, [&](Key const&)
auto& gridTransferInterface = cache.get(key, [&](Key const&)
{
return std::make_unique<GridTransfer<Grid>>();
});
return gridTransferInterfaceUniquePtr.get();
return std::dynamic_pointer_cast<GridTransfer<Grid>>(gridTransferInterface);
}
private:
......
......@@ -387,7 +387,7 @@ namespace AMDiS
void adoptGlobalBasis(std::shared_ptr<GlobalBasis> const& globalBasis)
{
globalBasis_ = globalBasis;
initGlobalBasis(*globalBasis_);
initGlobalBasis();
}
void adoptGrid(std::shared_ptr<Grid> const& grid)
......@@ -408,7 +408,7 @@ namespace AMDiS
void createGlobalBasisImpl(std::true_type);
void createGlobalBasisImpl(std::false_type);
void initGlobalBasis(GlobalBasis const& globalBasis);
void initGlobalBasis();
public: // implementation of iteration interface methods
......
......@@ -50,7 +50,7 @@ void ProblemStat<Traits>::initialize(
if (globalRefinements > 0) {
grid_->globalRefine(globalRefinements);
if (globalBasis_)
globalBasis_->update(gridView());
globalBasis_->update(globalBasis_->gridView());
}
}
......@@ -143,7 +143,7 @@ template <class Traits>
void ProblemStat<Traits>::createGlobalBasis()
{
createGlobalBasisImpl(Dune::Std::is_detected<HasCreate,Traits,GridView>{});
initGlobalBasis(*globalBasis_);
initGlobalBasis();
}
......@@ -164,7 +164,7 @@ void ProblemStat<Traits>::createGlobalBasisImpl(std::false_type)
template <class Traits>
void ProblemStat<Traits>::initGlobalBasis(GlobalBasis const& globalBasis)
void ProblemStat<Traits>::initGlobalBasis()
{
dirichletBCs_.init(*globalBasis_, *globalBasis_);
periodicBCs_.init(*globalBasis_, *globalBasis_);
......@@ -367,7 +367,7 @@ globalCoarsen(int n)
for (const auto& element : elements(grid_->leafGridView()))
grid_->mark(-1, element);
adapted |= GridTransferManager::adapt(*grid_, *globalBasis_);
adapted |= GridTransferManager::adapt(*grid_);
}
msg("globalCoarsen needed {} seconds", t.elapsed());
......@@ -389,7 +389,6 @@ globalRefine(int refCount)
/*then*/ [&](auto id) {
// TODO(FM): Add a way to pass a GridTransfer as ADH with *globalBasis_ argument
id(grid_)->globalRefine(refCount, GridTransferManager::gridTransfer(*grid_));
globalBasis_->update(this->gridView());
},
/*else*/ [&](auto id) {
for (int i = 0; i < refCount; ++i) {
......@@ -397,7 +396,7 @@ globalRefine(int refCount)
for (const auto& element : elements(grid_->leafGridView()))
grid_->mark(1, element);
adapted |= GridTransferManager::adapt(*id(grid_), *id(globalBasis_));
adapted |= GridTransferManager::adapt(*id(grid_));
}
});
......@@ -412,7 +411,7 @@ adaptGrid(AdaptInfo& adaptInfo)
{
Dune::Timer t;
bool adapted = GridTransferManager::adapt(*grid_, *globalBasis_);
bool adapted = GridTransferManager::adapt(*grid_);
msg("adaptGrid needed {} seconds", t.elapsed());
return adapted ? MESH_ADAPTED : Flag(0);
......
......@@ -8,8 +8,8 @@
#define REQUIRES_(...)
#define CONCEPT constexpr
#else
#define REQUIRES(...) std::enable_if_t<__VA_ARGS__ , int>* = nullptr
#define REQUIRES_(...) std::enable_if_t<__VA_ARGS__ , int>*
#define REQUIRES(...) std::enable_if_t<__VA_ARGS__ , int> = 0
#define REQUIRES_(...) std::enable_if_t<__VA_ARGS__ , int>
#define CONCEPT constexpr
#endif
......
......@@ -57,12 +57,12 @@ namespace AMDiS
public:
/// Constructor. Constructs new BaseVector.
DOFVectorBase(GlobalBasis const& basis, DataTransferOperation op = DataTransferOperation::INTERPOLATE)
DOFVectorBase(GlobalBasis& basis, DataTransferOperation op = DataTransferOperation::INTERPOLATE)
: basis_(&basis)
, dataTransfer_(DataTransferFactory::create(op, basis))
{
compress();
GridTransferManager::attach(*this);
attachToGridTransfer();
operators_.init(basis);
}
......@@ -74,7 +74,7 @@ namespace AMDiS
, operators_(that.operators_)
, dataTransfer_(that.dataTransfer_)
{
GridTransferManager::attach(*this);
attachToGridTransfer();
}
/// Move constructor
......@@ -85,24 +85,24 @@ namespace AMDiS
, operators_(std::move(that.operators_))
, dataTransfer_(std::move(that.dataTransfer_))
{
GridTransferManager::attach(*this);
attachToGridTransfer();
}
/// Destructor
~DOFVectorBase() override
{
GridTransferManager::detach(*this);
detachFromGridTransfer();
}
/// Copy assignment operator
Self& operator=(Self const& that)
{
GridTransferManager::detach(*this);
detachFromGridTransfer();
basis_ = that.basis_;
backend_.resize(that.size());
backend_ = that.backend_;
dataTransfer_ = that.dataTransfer_;
GridTransferManager::attach(*this);
attachToGridTransfer();
return *this;
}
......@@ -225,9 +225,22 @@ namespace AMDiS
dataTransfer_->postAdapt(*this, refined);
}
private:
void attachToGridTransfer()
{
GridTransferManager::attach(basis_->gridView().grid(), *this);
GridTransferManager::attach(basis_->gridView().grid(), *basis_);
}
void detachFromGridTransfer()
{
GridTransferManager::detach(basis_->gridView().grid(), *basis_);
GridTransferManager::detach(basis_->gridView().grid(), *this);
}
private:
/// The finite element space / basis associated with the data vector
GlobalBasis const* basis_;
GlobalBasis* basis_;
/// Data backend
Backend backend_;
......
......@@ -91,7 +91,7 @@ namespace AMDiS
using Super = DOFVectorBase<BasisType, EigenVector<ValueType>>;
public:
DOFVector(BasisType const& basis, DataTransferOperation op = DataTransferOperation::INTERPOLATE)
DOFVector(BasisType& basis, DataTransferOperation op = DataTransferOperation::INTERPOLATE)
: Super(basis, op)
{}
......@@ -102,7 +102,7 @@ namespace AMDiS
/// Constructor a dofvector from given basis and name
template <class ValueType = double, class Basis>
DOFVector<Basis, ValueType>
makeDOFVector(Basis const& basis, DataTransferOperation op = DataTransferOperation::INTERPOLATE)
makeDOFVector(Basis& basis, DataTransferOperation op = DataTransferOperation::INTERPOLATE)
{
return {basis, op};
}
......
......@@ -100,7 +100,7 @@ namespace AMDiS
using Super = DOFVectorBase<BasisType, IstlVector<ValueType>>;
public:
DOFVector(BasisType const& basis, DataTransferOperation op = DataTransferOperation::INTERPOLATE)
DOFVector(BasisType& basis, DataTransferOperation op = DataTransferOperation::INTERPOLATE)
: Super(basis, op)
{}
......@@ -111,7 +111,7 @@ namespace AMDiS
/// Constructor a dofvector from given basis and name
template <class ValueType = double, class Basis>
DOFVector<Basis, ValueType>
makeDOFVector(Basis const& basis, DataTransferOperation op = DataTransferOperation::INTERPOLATE)
makeDOFVector(Basis& basis, DataTransferOperation op = DataTransferOperation::INTERPOLATE)
{
return {basis, op};
}
......
......@@ -91,7 +91,7 @@ namespace AMDiS
using Super = DOFVectorBase<BasisType, MtlVector<ValueType>>;
public:
DOFVector(BasisType const& basis, DataTransferOperation op = DataTransferOperation::INTERPOLATE)
DOFVector(BasisType& basis, DataTransferOperation op = DataTransferOperation::INTERPOLATE)
: Super(basis, op)
{}
......@@ -102,7 +102,7 @@ namespace AMDiS
/// Constructor a dofvector from given basis and name
template <class ValueType = double, class Basis>
DOFVector<Basis, ValueType>
makeDOFVector(Basis const& basis, DataTransferOperation op = DataTransferOperation::INTERPOLATE)
makeDOFVector(Basis& basis, DataTransferOperation op = DataTransferOperation::INTERPOLATE)
{
return {basis, op};
}
......
......@@ -74,7 +74,7 @@ int main(int argc, char** argv)
test_dofvector(basis, vec1);
for (auto const& e : elements(gridView))
grid.mark(1, e);
GridTransferManager::adapt(grid, basis);
GridTransferManager::adapt(grid);
AMDIS_TEST_EQ(vec1.size(), basis.dimension());
}
......
......@@ -60,29 +60,29 @@ auto makeProblem(typename BasisCreator::GlobalBasis::GridView::Grid& grid, Fcts
using Problem = ProblemStat<BasisCreator>;
// make problem
Problem prob("test", grid);
prob.initialize(INIT_ALL);
auto prob = std::make_unique<Problem>("test", grid);
prob->initialize(INIT_ALL);