diff --git a/src/amdis/CMakeLists.txt b/src/amdis/CMakeLists.txt index 9c277b265831f10b8e4ebe497caff0a9de9985ef..e99d8316c9ea9717a93512c200873adfb43ae94f 100644 --- a/src/amdis/CMakeLists.txt +++ b/src/amdis/CMakeLists.txt @@ -31,6 +31,7 @@ install(FILES GridFunctionOperator.hpp GridFunctions.hpp GridTransfer.hpp + GridTransferManager.hpp Initfile.hpp InitfileParser.hpp LinearAlgebra.hpp diff --git a/src/amdis/GridTransfer.hpp b/src/amdis/GridTransfer.hpp index 1b930ad191ec02a76c2d139cfc32131a31293a29..98b9af7971f0e23758365f31ae58d62a921ed010 100644 --- a/src/amdis/GridTransfer.hpp +++ b/src/amdis/GridTransfer.hpp @@ -1,56 +1,91 @@ #pragma once -#include <vector> +#include <list> #include <amdis/linear_algebra/DOFVectorInterface.hpp> +#include <amdis/Output.hpp> + namespace AMDiS { + class GridTransferInterface + { + public: + virtual ~GridTransferInterface() = default; + + virtual void attach(DOFVectorInterface*) = 0; + virtual void detach(DOFVectorInterface*) = 0; + virtual bool preAdapt() = 0; + virtual bool adapt() = 0; + virtual void postAdapt() = 0; + + }; + + template <class Grid> class GridTransfer + : public GridTransferInterface { using Self = GridTransfer; public: - GridTransfer(Grid& grid) - : grid_(&grid) - {} + void bind(Grid& grid) + { + grid_ = &grid; + } + + void unbind() + { + grid_ = nullptr; + } /// Attach a data container to the grid transfer, that gets interpolated during grid change - void attach(DOFVectorInterface* vec) + virtual void attach(DOFVectorInterface* vec) override { data_.push_back(vec); } + virtual void detach(DOFVectorInterface* vec) override + { + auto it = std::find(data_.begin(), data_.end(), vec); + if (it != data_.end()) + data_.erase(it); + else + warning("DOFVector to detach not found"); + } + /// Prepare the grid and the data for the adaption - bool preAdapt() + virtual bool preAdapt() override { + assert(grid_ != nullptr); mightCoarsen_ = grid_->preAdapt(); // any element might be coarsened in adapt() - for (auto* vec : data_) + for (auto* vec : this->data_) vec->preAdapt(mightCoarsen_); return mightCoarsen_; } /// do the grid adaption - bool adapt() + virtual bool adapt() override { + assert(grid_ != nullptr); refined_ = grid_->adapt(); // returns true if a least one entity was refined return refined_; } // Perform data adaption to the new grid - void postAdapt() + virtual void postAdapt() override { + assert(grid_ != nullptr); if (mightCoarsen_ || refined_) { - for (auto* vec : data_) + for (auto* vec : this->data_) vec->postAdapt(refined_); } grid_->postAdapt(); } - protected: - Grid* grid_; - std::vector<DOFVectorInterface*> data_; + private: + Grid* grid_ = nullptr; + std::list<DOFVectorInterface*> data_; bool mightCoarsen_ = false; bool refined_ = false; }; diff --git a/src/amdis/GridTransferManager.hpp b/src/amdis/GridTransferManager.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f9e31fd0314d20216ff38c671bcd628857bdcd88 --- /dev/null +++ b/src/amdis/GridTransferManager.hpp @@ -0,0 +1,93 @@ +#pragma once + +#include <cstdint> +#include <map> +#include <memory> + +#include <amdis/GridTransfer.hpp> +#include <amdis/utility/ConcurrentCache.hpp> + +namespace AMDiS +{ + /// Static administration class for automatic handling of DOFVectors during grid adaption + class GridTransferManager + { + template <class T1, class T2> + friend class DOFVectorBase; + + using Self = GridTransferManager; + using Key = std::uintptr_t; + using Data = std::unique_ptr<GridTransferInterface>; + + private: + // Constructors. Since this is a static class you cannot call any constructor. + GridTransferManager() = delete; + + public: + /** + * \brief Adapts the grid according to previously set marks and performs data transfer on + * all DOFVectors associated to the given grid. + * + * This function retrieves the grid's stored GridTransfer and calls its adaptation methods. + * During this process the grid will change according to previously set grid element markings. + * All DOFVectors associated to the given grid will be interpolated to the new grid according to + * their DataTransfer member object. + * + * 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> + static bool adapt(Grid& grid) + { + auto gridTransfer = GridTransferManager::gridTransfer(grid); + bool adapted = gridTransfer.preAdapt(); + adapted |= gridTransfer.adapt(); + gridTransfer.postAdapt(); + return adapted; + } + + /// Returns the GridTransfer corresponding to a Grid, to be used during the adaptation cycle + template <class Grid> + static GridTransfer<Grid>& gridTransfer(Grid& grid) + { + GridTransfer<Grid>* gridTransfer + = dynamic_cast<GridTransfer<Grid>*>(Self::gridTransferInterface(grid)); + gridTransfer->bind(grid); + return *gridTransfer; + } + + private: + // DOFVector registration methods. They are called automaticly by the DOFVectors. + template <class Vec> + static void attach(Vec& vec) + { + auto const& grid = vec.basis().gridView().grid(); + Self::gridTransferInterface(grid)->attach(&vec); + } + + template <class Vec> + static void detach(Vec& vec) + { + auto const& grid = vec.basis().gridView().grid(); + Self::gridTransferInterface(grid)->detach(&vec); + } + + // Returns the GridTransferInterface class, + // used for attaching and detaching DOFVectors to a GridTransfer + template <class Grid> + static GridTransferInterface* gridTransferInterface(Grid const &grid) + { + Key key = Key(&grid); + auto& gridTransferInterfaceUniquePtr = GridTransferCache::get(key, [&](Key const&) + { + return std::make_unique<GridTransfer<Grid>>(); + }); + return gridTransferInterfaceUniquePtr.get(); + } + + private: + // Associate to each Grid (represented as address) a GridTransfer + using GridTransferCache = ConcurrentCache< Key, Data, StaticLockedPolicy, std::map<Key, Data> >; + }; + +} // end namespace AMDiS diff --git a/src/amdis/ProblemStat.hpp b/src/amdis/ProblemStat.hpp index d0804eeba1b92c13feb407b6ab82bea754be666f..2ae9e342ba9a079c929229506a60845ba0fb9482 100644 --- a/src/amdis/ProblemStat.hpp +++ b/src/amdis/ProblemStat.hpp @@ -18,7 +18,6 @@ #include <amdis/DirichletBC.hpp> //#include <amdis/Estimator.hpp> #include <amdis/Flag.hpp> -#include <amdis/GridTransfer.hpp> #include <amdis/Initfile.hpp> #include <amdis/LinearAlgebra.hpp> #include <amdis/LinearSolvers.hpp> @@ -347,12 +346,6 @@ namespace AMDiS setGrid(Dune::stackobject_to_shared_ptr(grid)); } - void addAdaptionData(DOFVectorInterface* vec) - { - assert(bool(gridTransfer_)); - gridTransfer_->attach(vec); - } - void addMarker(std::shared_ptr<Marker<Grid>> const& marker) { marker_.push_back(marker); @@ -384,7 +377,6 @@ namespace AMDiS void adoptGrid(std::shared_ptr<Grid> const& grid) { grid_ = grid; - gridTransfer_ = std::make_shared<GridTransfer<Grid>>(*grid_); Parameters::get(name_ + "->mesh", gridName_); } @@ -421,9 +413,6 @@ namespace AMDiS /// Grid of this problem. std::shared_ptr<Grid> grid_; - /// Handling the adaption of the grid - std::shared_ptr<GridTransfer<Grid>> gridTransfer_; - /// Name of the grid std::string gridName_ = "mesh"; diff --git a/src/amdis/ProblemStat.inc.hpp b/src/amdis/ProblemStat.inc.hpp index 38eec52543d7a10ad04662f4b79cbc21c52be657..f7d4cb1129ad53b5234babeb03293d15980b3ace 100644 --- a/src/amdis/ProblemStat.inc.hpp +++ b/src/amdis/ProblemStat.inc.hpp @@ -10,6 +10,7 @@ #include <amdis/AdaptInfo.hpp> #include <amdis/FileWriter.hpp> #include <amdis/GridFunctionOperator.hpp> +#include <amdis/GridTransferManager.hpp> #include <amdis/LocalAssembler.hpp> #include <amdis/common/Loops.hpp> @@ -37,7 +38,6 @@ void ProblemStat<Traits>::initialize( adoptFlag.isSet(INIT_SYSTEM) || adoptFlag.isSet(INIT_FE_SPACE))) { grid_ = adoptProblem->grid_; - gridTransfer_ = adoptProblem->gridTransfer_; } } @@ -123,7 +123,6 @@ void ProblemStat<Traits>::createGrid() { Parameters::get(name_ + "->mesh", gridName_); grid_ = MeshCreator<Grid>::create(gridName_); - gridTransfer_ = std::make_shared<GridTransfer<Grid>>(*grid_); msg("Create grid:"); msg("#elements = {}" , grid_->size(0)); @@ -175,10 +174,6 @@ void ProblemStat<Traits>::createMatricesAndVectors() solution_ = std::make_shared<SystemVector>(*globalBasis_, INTERPOLATE); rhs_ = std::make_shared<SystemVector>(*globalBasis_, NO_OPERATION); - assert(bool(gridTransfer_)); - gridTransfer_->attach(solution_.get()); - gridTransfer_->attach(rhs_.get()); - auto localView = globalBasis_->localView(); AMDiS::forEachNode_(localView.tree(), [&,this](auto const& node, auto treePath) { @@ -333,11 +328,8 @@ adaptGrid(AdaptInfo& adaptInfo) { Dune::Timer t; - bool adapted = gridTransfer_->preAdapt(); - adapted |= gridTransfer_->adapt(); // NOTE: |= does not short-circuit and works with bools as ||= - if (adapted) - globalBasis_->update(gridView()); - gridTransfer_->postAdapt(); + bool adapted = GridTransferManager::adapt(*grid_); + globalBasis_->update(gridView()); msg("adaptGrid needed {} seconds", t.elapsed()); return adapted ? MESH_ADAPTED : Flag(0); diff --git a/src/amdis/linear_algebra/DOFVectorBase.hpp b/src/amdis/linear_algebra/DOFVectorBase.hpp index 89cf6cb98f5bf6391b5058c144f47b2092754994..7f8049957bd21e0bdd4374d2e45cd2e2daae56be 100644 --- a/src/amdis/linear_algebra/DOFVectorBase.hpp +++ b/src/amdis/linear_algebra/DOFVectorBase.hpp @@ -1,10 +1,12 @@ #pragma once #include <cmath> +#include <utility> #include <dune/functions/functionspacebases/sizeinfo.hh> #include <amdis/DataTransfer.hpp> +#include <amdis/GridTransferManager.hpp> #include <amdis/LocalAssemblerList.hpp> #include <amdis/common/Math.hpp> #include <amdis/common/ScalarTypes.hpp> @@ -52,18 +54,47 @@ namespace AMDiS , dataTransfer_(DataTransferFactory::create(op, basis)) { compress(); + GridTransferManager::attach(*this); operators_.init(basis); } - DOFVectorBase(Self const&) = default; - DOFVectorBase(Self&&) = default; + /// Copy constructor + DOFVectorBase(Self const& that) + : basis_(that.basis_) + , backend_(that.backend_) + , elementVector_(that.elementVector_) + , operators_(that.operators_) + , dataTransfer_(that.dataTransfer_) + { + GridTransferManager::attach(*this); + } + + /// Move constructor + DOFVectorBase(Self&& that) + : basis_(std::move(that.basis_)) + , backend_(std::move(that.backend_)) + , elementVector_(std::move(that.elementVector_)) + , operators_(std::move(that.operators_)) + , dataTransfer_(std::move(that.dataTransfer_)) + { + GridTransferManager::attach(*this); + } + + /// Destructor + virtual ~DOFVectorBase() override + { + GridTransferManager::detach(*this); + } /// Copy assignment operator Self& operator=(Self const& that) { + GridTransferManager::detach(*this); basis_ = that.basis_; backend_.resize(that.size()); backend_ = that.backend_; + dataTransfer_ = that.dataTransfer_; + GridTransferManager::attach(*this); return *this; } diff --git a/test/DOFVectorTest.cpp b/test/DOFVectorTest.cpp index a626f888d2a52cdb20503eb1dc3c88d8e90e9ac6..288981fcb3b66658c686a8893bd532e8710b4050 100644 --- a/test/DOFVectorTest.cpp +++ b/test/DOFVectorTest.cpp @@ -7,6 +7,7 @@ #include <dune/functions/functionspacebases/powerbasis.hh> #include <dune/functions/functionspacebases/lagrangebasis.hh> +#include <amdis/GridTransferManager.hpp> #include <amdis/LinearAlgebra.hpp> #include "Tests.hpp" @@ -41,26 +42,41 @@ int main(int argc, char** argv) Dune::FieldVector<double, 2> L; L = 1.0; auto s = Dune::filledArray<2>(1); Dune::YaspGrid<2> grid(L, s); + auto const& gridView = grid.leafGridView(); // create basis - auto basis = makeBasis(grid.leafGridView(), + auto basis = makeBasis(gridView, composite(power<2>(lagrange<2>(), flatInterleaved()), lagrange<1>(), flatLexicographic())); - using Basis = decltype(basis); - DOFVector<Basis> vec1(basis); - test_dofvector(basis, vec1); - DOFVector<Basis, float> vec2(basis); - test_dofvector(basis, vec2); + { + DOFVector<Basis> vec1(basis); + test_dofvector(basis, vec1); + + DOFVector<Basis, float> vec2(basis); + test_dofvector(basis, vec2); - auto vec3 = makeDOFVector(basis); - test_dofvector(basis, vec3); + auto vec3 = makeDOFVector(basis); + test_dofvector(basis, vec3); - auto vec4 = makeDOFVector<float>(basis); - test_dofvector(basis, vec4); + auto vec4 = makeDOFVector<float>(basis); + test_dofvector(basis, vec4); #if DUNE_HAVE_CXX_CLASS_TEMPLATE_ARGUMENT_DEDUCTION - DOFVector vec5(basis); - test_dofvector(basis, vec5); + DOFVector vec5(basis); + test_dofvector(basis, vec5); #endif -} \ No newline at end of file + } + + // test GridTransferManager registration + { + DOFVector<Basis> vec1(basis); + test_dofvector(basis, vec1); + for (auto const& e : elements(gridView)) + grid.mark(1, e); + GridTransferManager::adapt(grid); + AMDIS_TEST_EQ(vec1.size(), basis.dimension()); + } + + report_errors(); +}