#pragma once #include #include #include #include #include namespace AMDiS { /** * \addtogroup Adaption * @{ **/ enum class DataTransferOperation { NO_OPERATION = 0, INTERPOLATE = 1 }; /// \brief Interface for Containers allowing data transfer between grid changes. template class DataTransferInterface { public: /// Virtual destructor virtual ~DataTransferInterface() = default; /// Clone method virtual std::unique_ptr clone() const = 0; /// Collect data that is needed before grid adaption virtual void preAdapt(Container const& container, bool mightCoarsen) = 0; /// Interpolate data to new grid after grid adaption virtual void adapt(Container& container) = 0; /// Perform cleanup after grid adaption virtual void postAdapt(Container& container) = 0; }; /** * \brief Implementation of \ref DataTransferInterface that does not interpolate, but * just resizes the containers to the dimension of the basis **/ template class NoDataTransfer : public DataTransferInterface { using Interface = DataTransferInterface; public: std::unique_ptr clone() const override { return std::make_unique(); } void preAdapt(Container const&, bool) override {} void adapt(Container& container) override { container.resize(); } void postAdapt(Container&) override {} }; template class NodeDataTransfer; /** Data Transfer implementation for a single grid using interpolation * Handles computations related to the geometric information of the grid and passes that to the * underlying NodeDataTransfer classes */ template class DataTransfer : public DataTransferInterface { using LocalView = typename Basis::LocalView; using Tree = typename LocalView::Tree; using GridView = typename Basis::GridView; using Grid = typename GridView::Grid; using Element = typename GridView::template Codim<0>::Entity; using Geometry = typename Element::Geometry; using LocalCoordinate = typename Geometry::LocalCoordinate; using IdType = typename Grid::LocalIdSet::IdType; template using NodeElementData = typename NodeDataTransfer::NodeElementData; using ElementData = TypeTree::TreeContainer; using Interface = DataTransferInterface; public: DataTransfer(std::shared_ptr basis); std::unique_ptr clone() const override { return std::make_unique>(basis_); } /** Saves data contained in coeff in the PersistentContainer * To be called after grid.preAdapt() and before grid.adapt() */ void preAdapt(Container const& coeff, bool mightCoarsen) override; /** Unpacks data from the PersistentContainer * To be called after grid.adapt() and before grid.postAdapt() */ // [[expects: basis is updated in gridView]] // [[expects: comm is updated in basis]] void adapt(Container& coeff) override; /** Performs cleanup * To be called after grid.postAdapt() */ void postAdapt(Container& coeff) override; private: /// The global basis std::shared_ptr basis_; /// Container with data that persists during grid adaptation using PersistentContainer = std::map; PersistentContainer persistentContainer_; /// Map leaf entities to unique index using Mapper = Dune::LeafMultipleCodimMultipleGeomTypeMapper; Mapper mapper_; /// Data transfer on a single basis node template using NDT = NodeDataTransfer; using NodeDataTransferContainer = TypeTree::TreeContainer; NodeDataTransferContainer nodeDataTransfer_; }; /// Factory to create DataTransfer objects based on the \ref DataTransferOperation template class DataTransferFactory { using Interface = DataTransferInterface; public: template static std::unique_ptr create(DataTransferOperation op, std::shared_ptr basis) { switch (op) { case DataTransferOperation::NO_OPERATION: return std::make_unique>(); case DataTransferOperation::INTERPOLATE: return std::make_unique>(std::move(basis)); default: error_exit("Invalid data transfer\n"); return nullptr; // avoid warnings } } }; /** Wrapper class for (No)DataTransfer objects. * This wrapper class may be used instead of a pointer type to DataTransferInterface. It wraps * and redirects to the implementation, while providing deep copy and move functionality. * A virtual clone() method in the interface and implementation classes is required to perform * the deep copy of the implementation. */ template class DataTransferWrapper { using Interface = DataTransferInterface; using Factory = DataTransferFactory; using Self = DataTransferWrapper; public: template DataTransferWrapper(DataTransferOperation op, std::shared_ptr basis) : impl_(std::move(Factory::create(op, basis))) {} DataTransferWrapper(Self const& that) : impl_(std::move(that.impl_->clone())) {} DataTransferWrapper(Self&& that) = default; Self& operator=(Self const& that) { impl_ = std::move(that.impl_->clone()); return *this; } Self& operator=(Self&& that) = default; void preAdapt(Container const& c, bool b) { impl_->preAdapt(c, b); } void adapt(Container& c) { impl_->adapt(c); } void postAdapt(Container& c) { impl_->postAdapt(c); } private: std::unique_ptr impl_; }; /// @} } // end namespace AMDiS #include "DataTransfer.inc.hpp"