diff --git a/src/amdis/DataTransfer.hpp b/src/amdis/DataTransfer.hpp index 362bca0d4e11051c33e7e8dfe2e5bdd8aa80e45d..e7da6447add188f909540e06968739658ab99fcf 100644 --- a/src/amdis/DataTransfer.hpp +++ b/src/amdis/DataTransfer.hpp @@ -1,8 +1,12 @@ #pragma once +#include <map> #include <memory> +#include <dune/grid/common/mcmgmapper.hh> + #include <amdis/Output.hpp> +#include <amdis/typetree/TreeContainer.hpp> namespace AMDiS { @@ -51,8 +55,64 @@ namespace AMDiS }; + template <class Node, class Container, class Basis> + 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 Container, class Basis> - class DataTransfer; + class DataTransfer + : public DataTransferInterface<Container> + { + 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 <class Node> + using NodeElementData = typename NodeDataTransfer<Node, Container, Basis>::NodeElementData; + using ElementData = TYPEOF(makeTreeContainer<NodeElementData>(std::declval<const Tree&>())); + + public: + DataTransfer(std::shared_ptr<Basis> 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() + */ + void postAdapt(Container& coeff, bool refined) override; + + private: + /// The global basis + std::shared_ptr<Basis const> basis_; + + /// Container with data that persists during grid adaptation + using PersistentContainer = std::map<IdType, ElementData>; + PersistentContainer persistentContainer_; + + /// Map leaf entities to unique index + using Mapper = Dune::LeafMultipleCodimMultipleGeomTypeMapper<Grid>; + Mapper mapper_; + + /// Data transfer on a single basis node + template <class Node> + using NDT = NodeDataTransfer<Node, Container, Basis>; + using NodeDataTransferContainer = TYPEOF(makeTreeContainer<NDT>(std::declval<const Tree&>())); + NodeDataTransferContainer nodeDataTransfer_; + }; + /// Factory to create DataTransfer objects based on the \ref DataTransferOperation template <class Container> @@ -62,14 +122,14 @@ namespace AMDiS public: template <class Basis> - static std::unique_ptr<Interface> create(DataTransferOperation op, Basis const& basis) + static std::unique_ptr<Interface> create(DataTransferOperation op, std::shared_ptr<Basis> basis) { switch (op) { case DataTransferOperation::NO_OPERATION: return std::make_unique<NoDataTransfer<Container>>(); case DataTransferOperation::INTERPOLATE: - return std::make_unique<DataTransfer<Container, Basis>>(basis); + return std::make_unique<DataTransfer<Container, Basis>>(std::move(basis)); default: error_exit("Invalid data transfer\n"); return nullptr; // avoid warnings diff --git a/src/amdis/DataTransfer.inc.hpp b/src/amdis/DataTransfer.inc.hpp index ca5d200fe20737810cb41e2150720bac3b7d4c19..c5a8a1775c46e14346555bb470cd609d5fff72d3 100644 --- a/src/amdis/DataTransfer.inc.hpp +++ b/src/amdis/DataTransfer.inc.hpp @@ -15,454 +15,410 @@ #include <dune/common/hash.hh> #include <dune/grid/common/geometry.hh> -#include <dune/grid/common/mcmgmapper.hh> #include <dune/grid/common/rangegenerators.hh> #include <dune/functions/common/functionfromcallable.hh> -#include <dune/functions/functionspacebases/lagrangebasis.hh> #include <amdis/Output.hpp> #include <amdis/common/ConcurrentCache.hpp> #include <amdis/typetree/Traversal.hpp> -#include <amdis/typetree/TreeContainer.hpp> - -namespace AMDiS -{ - template <class Node, class Container, class Basis> - class NodeDataTransfer; +namespace AMDiS { - /** Data Transfer implementation for a single grid - * Handles computations related to the geometric information of the grid and passes that to the - * underlying NodeDataTransfer classes - */ - template <class Container, class Basis> - class DataTransfer - : public DataTransferInterface<Container> +namespace Impl +{ + // Hash function for cache container + struct CoordHasher { - using LocalView = typename Basis::LocalView; - using Tree = typename LocalView::Tree; - using GridView = typename Basis::GridView; - using Grid = typename GridView::Grid; - using Mapper = Dune::LeafMultipleCodimMultipleGeomTypeMapper<Grid>; - - using IdSet = typename Grid::LocalIdSet; - using IdType = typename IdSet::IdType; - - using Element = typename GridView::template Codim<0>::Entity; - using Geometry = typename Element::Geometry; - using LocalCoordinate = typename Geometry::LocalCoordinate; - using BoolCoordPair = std::pair<bool, LocalCoordinate>; - - // Hash function for cache container - struct Hasher + template <class LocalCoord> + std::size_t operator()(LocalCoord const& coord) const { - std::size_t operator()(LocalCoordinate const& coord) const - { - std::size_t seed = 0; - for (std::size_t i = 0; i < coord.size(); ++i) - Dune::hash_combine(seed, coord[i]); - return seed; - } - }; + std::size_t seed = 0; + for (std::size_t i = 0; i < coord.size(); ++i) + Dune::hash_combine(seed, coord[i]); + return seed; + } + }; - using CacheImp = std::unordered_map<LocalCoordinate, BoolCoordPair, Hasher>; - using ChildCache = ConcurrentCache<LocalCoordinate, BoolCoordPair, ConsecutivePolicy, CacheImp>; +} // end namespace Impl - constexpr static int d = Geometry::coorddimension; - using ctype = typename Geometry::ctype; - // Returns the Node's NodeDataTransfer - struct NDT - { - template<class Node> - auto operator()(const Node& node) - { - using NDT = NodeDataTransfer<Node, Container, Basis>; - return NDT{}; - } - }; +template <class C, class B> +DataTransfer<C,B>::DataTransfer(std::shared_ptr<B> basis) + : basis_(std::move(basis)) + , mapper_(basis_->gridView().grid(), Dune::mcmgElementLayout()) + , nodeDataTransfer_(makeTreeContainer<NDT>(basis_->localView().tree())) +{} - using NodeDataTransferContainer = TYPEOF(makeTreeContainer<Tree, NDT>(std::declval<const Tree&>(), NDT())); - // Returns the Node's NodeElementData - struct NodeElementData - { - template<class Node> - auto operator()(const Node& node) - { - using NED = typename NodeDataTransfer<Node, Container, Basis> - ::NodeElementData; - return NED{}; - } - }; - - using ElementData = TYPEOF(makeTreeContainer<Tree, NodeElementData>(std::declval<const Tree&>(), NodeElementData())); - - public: - // Container with data that persists during grid adaptation - using PersistentContainer = std::map<IdType, ElementData>; - - public: - DataTransfer(Basis const& basis) - : basis_(&basis) - , mapper_(basis.gridView().grid(), Dune::mcmgElementLayout()) - , finished_(mapper_.size(), false) - , nodeDataTransfer_(makeTreeContainer<Tree, NDT>(basis_->localView().tree(), NDT())) - {} - - /** 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() - */ - void postAdapt(Container& coeff, bool refined) override; - - private: - Basis const* basis_; - PersistentContainer persistentContainer_; - Mapper mapper_; - std::vector<bool> finished_; - NodeDataTransferContainer nodeDataTransfer_; - }; +template <class C, class B> +void DataTransfer<C,B>::preAdapt(C const& coeff, bool mightCoarsen) +{ + GridView gv = basis_->gridView(); + LocalView lv = basis_->localView(); + auto const& idSet = gv.grid().localIdSet(); - template <class C, class B> - void DataTransfer<C,B>::preAdapt(C const& coeff, bool mightCoarsen) + for_each_leaf_node(lv.tree(), [&](auto const& node, auto const& tp) { + nodeDataTransfer_[tp].preAdaptInit(lv, coeff, node); + }); + + // Make persistent DoF container + persistentContainer_.clear(); + for (const auto& e : elements(gv)) { - auto gv = basis_->gridView(); - auto lv = basis_->localView(); - auto const& idSet = gv.grid().localIdSet(); + auto it = persistentContainer_.emplace(idSet.id(e), makeTreeContainer<NodeElementData>(lv.tree())); + lv.bind(e); + auto& treeContainer = it.first->second; for_each_leaf_node(lv.tree(), [&](auto const& node, auto const& tp) { - nodeDataTransfer_[tp].preAdaptInit(lv, coeff, node); + nodeDataTransfer_[tp].cacheLocal(treeContainer[tp]); }); + } + + if (!mightCoarsen) + return; - // Make persistent DoF container - persistentContainer_.clear(); - for (const auto& e : elements(gv)) + // Interpolate from possibly vanishing elements + auto maxLevel = gv.grid().maxLevel(); + using std::sqrt; + typename Grid::ctype const checkInsideTolerance = sqrt(std::numeric_limits<typename Grid::ctype>::epsilon()); + for (auto const& e : elements(gv)) + { + auto father = e; + while (father.mightVanish() && father.hasFather()) { - auto it = persistentContainer_.emplace(idSet.id(e), - makeTreeContainer<Tree, NodeElementData>(lv.tree(), NodeElementData())); + father = father.father(); + auto it = persistentContainer_.emplace(idSet.id(father), makeTreeContainer<NodeElementData>(lv.tree())); + if (!it.second) + continue; - lv.bind(e); auto& treeContainer = it.first->second; + auto geo = father.geometry(); + bool init = true; // init flag for first call on new father element + bool restrictLocalCompleted = false; + auto hItEnd = father.hend(maxLevel); + for (auto hIt = father.hbegin(maxLevel); hIt != hItEnd; ++hIt) { + if (!hIt->isLeaf()) + continue; + + auto const& child = *hIt; + auto search = persistentContainer_.find(idSet.id(child)); + assert(search != persistentContainer_.end()); + auto const& childContainer = search->second; + lv.bind(child); + + auto const& childGeo = child.geometry(); + auto refTypeId = Dune::referenceElement(childGeo).type().id(); + + using BoolCoordPair = std::pair<bool, LocalCoordinate>; + using CacheImp = std::unordered_map<LocalCoordinate, BoolCoordPair, Impl::CoordHasher>; + using ChildCache = ConcurrentCache<LocalCoordinate, BoolCoordPair, ConsecutivePolicy, CacheImp>; + + // Transfers input father-local point x into child-local point y + // Returns false if x is not inside the child + auto xInChild = [&](LocalCoordinate const& x) -> BoolCoordPair { + LocalCoordinate local = childGeo.local(geo.global(x)); + // TODO(FM): Using an implementation detail as workaround for insufficient + // tolerance, see https://gitlab.dune-project.org/core/dune-grid/issues/84 + bool isInside = Dune::Geo::Impl::checkInside(refTypeId, Geometry::coorddimension, local, checkInsideTolerance); + return BoolCoordPair(isInside, std::move(local)); + }; + // TODO(FM): Disable for single-node basis + ChildCache childCache; + auto xInChildCached = [&](LocalCoordinate const& x) -> BoolCoordPair { + return childCache.get(x, [&](LocalCoordinate const& x) { return xInChild(x); }); + }; + + restrictLocalCompleted = true; + for_each_leaf_node(lv.tree(), [&](auto const& node, auto const& tp) { + restrictLocalCompleted &= + nodeDataTransfer_[tp].restrictLocal(father, treeContainer[tp], xInChildCached, + childContainer[tp], init); + }); + init = false; + } + // test if restrictLocal was completed on all nodes + assert(restrictLocalCompleted); + + } // end while (father.mightVanish) + } // end for (elements) +} + + +template <class C, class B> +void DataTransfer<C,B>::postAdapt(C& coeff, bool refined) +{ + coeff.resize(*basis_); + GridView gv = basis_->gridView(); + LocalView lv = basis_->localView(); + auto const& idSet = gv.grid().localIdSet(); + for_each_leaf_node(lv.tree(), [&](auto const& node, auto const& tp) { + nodeDataTransfer_[tp].postAdaptInit(lv, coeff, node); + }); + + mapper_.update(); + std::vector<bool> finished(mapper_.size(), false); + for (const auto& e : elements(gv)) + { + auto index = mapper_.index(e); + if (finished[index]) + continue; + + auto it = persistentContainer_.find(idSet.id(e)); + + // Data already exists and no interpolation is required + if (it != persistentContainer_.end()) { + lv.bind(e); + auto const& treeContainer = it->second; for_each_leaf_node(lv.tree(), [&](auto const& node, auto const& tp) { - nodeDataTransfer_[tp].cacheLocal(treeContainer[tp]); + nodeDataTransfer_[tp].copyLocal(treeContainer[tp]); }); + finished[index] = true; + continue; } - // Interpolate from possibly vanishing elements - if (mightCoarsen) { - auto maxLevel = gv.grid().maxLevel(); - using std::sqrt; - ctype const checkInsideTolerance = sqrt(std::numeric_limits<ctype>::epsilon()); - for (auto const& e : elements(gv)) - { - auto father = e; - while (father.mightVanish() && father.hasFather()) - { - father = father.father(); - auto it = persistentContainer_.emplace(idSet.id(father), - makeTreeContainer<Tree, NodeElementData>(lv.tree(), NodeElementData())); - if (it.second) { - auto& treeContainer = it.first->second; - auto geo = father.geometry(); - bool init = true; // init flag for first call on new father element - bool restrictLocalCompleted = false; - auto hItEnd = father.hend(maxLevel); - for (auto hIt = father.hbegin(maxLevel); hIt != hItEnd; ++hIt) { - if (hIt->isLeaf()) { - auto const& child = *hIt; - auto search = persistentContainer_.find(idSet.id(child)); - assert(search != persistentContainer_.end()); - auto const& childContainer = search->second; - lv.bind(child); - - auto const& childGeo = child.geometry(); - auto const& ref = Dune::referenceElement(childGeo); - auto const& refTypeId = ref.type().id(); - - // Transfers input father-local point x into child-local point y - // Returns false if x is not inside the child - auto xInChild = [&](LocalCoordinate const& x) -> BoolCoordPair { - LocalCoordinate local = childGeo.local(geo.global(x)); - // TODO(FM): Using an implementation detail as workaround for insufficient - // tolerance, see https://gitlab.dune-project.org/core/dune-grid/issues/84 - bool isInside = Dune::Geo::Impl::checkInside(refTypeId, d, local, checkInsideTolerance); - return BoolCoordPair(isInside, std::move(local)); - }; - - // TODO(FM): Disable for single-node basis - ChildCache childCache; - auto xInChildCached = [&](LocalCoordinate const& x) -> BoolCoordPair { - return childCache.get(x, [&](LocalCoordinate const& x) { return xInChild(x); }); - }; - - restrictLocalCompleted = true; - for_each_leaf_node(lv.tree(), [&](auto const& node, auto const& tp) { - restrictLocalCompleted &= - nodeDataTransfer_[tp].restrictLocal(father, treeContainer[tp], xInChildCached, - childContainer[tp], init); - }); - init = false; - } - } - // test if restrictLocal was completed on all nodes - assert(restrictLocalCompleted); - } - } - } - } - } + // Data needs to be interpolated + auto father = e; + while (father.hasFather() && father.isNew()) + father = father.father(); - template <class C, class B> - void DataTransfer<C,B>::postAdapt(C& coeff, bool refined) - { - coeff.resize(*basis_); - auto gv = basis_->gridView(); - auto lv = basis_->localView(); - auto const& idSet = gv.grid().localIdSet(); - for_each_leaf_node(lv.tree(), [&](auto const& node, auto const& tp) { - nodeDataTransfer_[tp].postAdaptInit(lv, coeff, node); - }); + auto maxLevel = gv.grid().maxLevel(); + auto fatherGeo = father.geometry(); + bool init = true; // init flag for first call on new father element - mapper_.update(); - finished_.clear(); - finished_.resize(mapper_.size(), false); - for (const auto& e : elements(gv)) - { - auto index = mapper_.index(e); - if (finished_[index]) + auto father_it = persistentContainer_.find(idSet.id(father)); + assert(father_it != persistentContainer_.end()); + auto const& treeContainer = father_it->second; + + auto hItEnd = father.hend(maxLevel); + for (auto hIt = father.hbegin(maxLevel); hIt != hItEnd; ++hIt) { + if (!hIt->isLeaf()) continue; - auto it = persistentContainer_.find(idSet.id(e)); + auto const& child = *hIt; + lv.bind(child); - // Data already exists and no interpolation is required - if (it != persistentContainer_.end()) { - lv.bind(e); - auto const& treeContainer = it->second; - for_each_leaf_node(lv.tree(), [&](auto const& node, auto const& tp) { - nodeDataTransfer_[tp].copyLocal(treeContainer[tp]); - }); - finished_[index] = true; - } - // Data needs to be interpolated - else { - auto father = e; - while (father.hasFather() && father.isNew()) - father = father.father(); - - auto maxLevel = gv.grid().maxLevel(); - auto fatherGeo = father.geometry(); - bool init = true; // init flag for first call on new father element - - auto it = persistentContainer_.find(idSet.id(father)); - assert(it != persistentContainer_.end()); - auto const& treeContainer = it->second; - - auto hItEnd = father.hend(maxLevel); - for (auto hIt = father.hbegin(maxLevel); hIt != hItEnd; ++hIt) { - if (hIt->isLeaf()) { - auto const& child = *hIt; - lv.bind(child); - - // coordinate transform from child to father element - auto xInFather = [&fatherGeo, childGeo = child.geometry()] - (LocalCoordinate const& x) -> LocalCoordinate - { - return fatherGeo.local(childGeo.global(x)); - }; - - for_each_leaf_node(lv.tree(), [&](auto const& node, auto const& tp) { - nodeDataTransfer_[tp].prolongLocal(father, treeContainer[tp], xInFather, init); - }); - - finished_[mapper_.index(child)] = true; - init = false; - } - } - } + // coordinate transform from child to father element + auto xInFather = [&fatherGeo, childGeo = child.geometry()] + (LocalCoordinate const& x) -> LocalCoordinate + { + return fatherGeo.local(childGeo.global(x)); + }; + + for_each_leaf_node(lv.tree(), [&](auto const& node, auto const& tp) { + nodeDataTransfer_[tp].prolongLocal(father, treeContainer[tp], xInFather, init); + }); + + finished[mapper_.index(child)] = true; + init = false; } + } // end for (elements) +} + + +/** Element-local data transfer on a single leaf node of the basis tree + * Handles computations related to the finite element basis node + */ +template <class Node, class Container, class Basis> +class NodeDataTransfer +{ + using T = typename Container::value_type; + using LocalView = typename Basis::LocalView; + using Element = typename Node::Element; + + using LocalBasis = typename Node::FiniteElement::Traits::LocalBasisType; + using LBRangeType = typename LocalBasis::Traits::RangeType; + using LocalInterpolation = typename Node::FiniteElement::Traits::LocalBasisType; + using LIDomainType = typename LocalInterpolation::Traits::DomainType; + using LIRangeType = typename LocalInterpolation::Traits::RangeType; + +public: + using NodeElementData = std::vector<T>; + +public: + NodeDataTransfer() = default; + + /// To be called once before cacheLocal/restrictLocal are called within the preAdapt step + void preAdaptInit(LocalView const& lv, Container const& coeff, Node const& node) + { + lv_ = &lv; + node_ = &node; + fatherNode_ = std::make_unique<Node>(node); + constCoeff_ = &coeff; } - /** Element-local data transfer on a single leaf node of the basis tree - * Handles computations related to the finite element basis node - */ - template <class Node, class Container, class Basis> - class NodeDataTransfer + /// \brief Cache data on the element bound to node_ + /** + * This functions is used whenever the element does not vanish and thus the + * data can trivially be transferred to the new element + **/ + // [[expects: preAdaptInit to be called before]] + void cacheLocal(NodeElementData& dofs) const { - using T = typename Container::value_type; - using LocalView = typename Basis::LocalView; - using Element = typename Node::Element; + auto const& fe = node_->finiteElement(); + auto feSize = fe.size(); + dofs.resize(feSize); + for (std::size_t i = 0; i < feSize; ++i) + dofs[i] = (*constCoeff_)[lv_->index(node_->localIndex(i))]; + } - using LocalBasis = typename Node::FiniteElement::Traits::LocalBasisType; - using LBRangeType = typename LocalBasis::Traits::RangeType; - using LocalInterpolation = typename Node::FiniteElement::Traits::LocalBasisType; - using LIDomainType = typename LocalInterpolation::Traits::DomainType; - using LIRangeType = typename LocalInterpolation::Traits::RangeType; + /** \brief Evaluate data on the child element bound to node_ and interpolate onto + * father entity using the coordinate transformation trafo from father to child. + * + * Stores cached data in the NodeElementData argument. After grid adaption the + * data is copied by \ref copyLocal or \ref prolongLocal to the target element + * in the new grid. + * + * \param father The father element to interpolate to + * \param fatherDOFs Container to store the interpolated DOFs + * \param trafo Coordinate transform from local coordinates in father to local + * coordinates in child element + * \param childDOFs DOF values from the child element + * \param init The father element is visited for the first time + **/ + // [[expects: preAdaptInit to be called before]] + template <class Trafo> + bool restrictLocal(Element const& father, NodeElementData& fatherDOFs, Trafo const& trafo, + NodeElementData const& childDOFs, bool init); + + + /// To be called once before copyLocal/prolongLocal are called within the postAdapt step + void postAdaptInit(LocalView const& lv, Container& coeff, Node const& node) + { + lv_ = &lv; + node_ = &node; + fatherNode_ = std::make_unique<Node>(node); + coeff_ = &coeff; + } - public: - using NodeElementData = std::vector<T>; + /// \brief Copy already existing data to element bound to node_ + // [[expects: postAdaptInit to be called before]] + void copyLocal(NodeElementData const& dofs) const + { + for (std::size_t i = 0; i < dofs.size(); ++i) + (*coeff_)[lv_->index(node_->localIndex(i))] = dofs[i]; + } - public: - NodeDataTransfer() = default; + /** \brief Interpolate data from father onto the child element bound to node_ using + * the transformation trafo from child to father + * + * Stores the interpolated data from father to child in the container \ref coeff_. + * + * \param father The father element + * \param fatherDOFs DOF values cached on the father element before adapt + * \param trafo Coordinate transform from local coordinates in child to local + * coordinates in father element + * \param init Father element is visited for the first time + **/ + // [[expects: postAdaptInit to be called before]] + template <class Trafo> + void prolongLocal(Element const& father, NodeElementData const& fatherDOFs, + Trafo const& trafo, bool init); + +private: + LocalView const* lv_ = nullptr; + Node const* node_ = nullptr; + std::unique_ptr<Node> fatherNode_; + Container const* constCoeff_ = nullptr; + Container* coeff_ = nullptr; + std::vector<bool> finishedDOFs_; + NodeElementData fatherDOFsTemp_; +}; + + +template <class N, class C, class B> + template <class Trafo> +bool NodeDataTransfer<N,C,B>:: + restrictLocal(Element const& father, NodeElementData& fatherDOFs, Trafo const& trafo, + NodeElementData const& childDOFs, bool init) +{ + auto& fatherNode = *fatherNode_; + std::size_t currentDOF = 0; + if (init) + { + // TODO(FM): This is UB, replace with FE cache for father + bindTree(fatherNode, father); + } + auto const& childNode = *node_; + auto const& childFE = childNode.finiteElement(); + auto const& fatherFE = fatherNode.finiteElement(); - /// To be called once before cacheLocal/restrictLocal are called within the preAdapt step - void preAdaptInit(LocalView const& lv, Container const& coeff, Node const& node) - { - lv_ = &lv; - node_ = &node; - auto nodeCopy = node; - fatherNode_ = std::make_unique<Node>(std::move(nodeCopy)); - constCoeff_ = &coeff; - } + if (init) { + finishedDOFs_.assign(fatherFE.size(), false); + fatherDOFsTemp_.assign(fatherFE.size(), 0); + } - /// To be called once before copyLocal/prolongLocal are called within the postAdapt step - void postAdaptInit(LocalView const& lv, Container& coeff, Node const& node) + auto evalLeaf = [&](LIDomainType const& x) -> LIRangeType { + if (!finishedDOFs_[currentDOF]) { - lv_ = &lv; - node_ = &node; - auto nodeCopy = node; - fatherNode_ = std::make_unique<Node>(std::move(nodeCopy)); - coeff_ = &coeff; - } + auto const& insideLocal = trafo(x); + bool isInside = insideLocal.first; + if (isInside) + { + auto const& local = insideLocal.second; + thread_local std::vector<LBRangeType> shapeValues; + childFE.localBasis().evaluateFunction(local, shapeValues); - /// Cache data on the element bound to node_ - void cacheLocal(NodeElementData& dofs) const - { - auto const& fe = node_->finiteElement(); - auto feSize = fe.size(); - dofs.resize(feSize); - for (std::size_t i = 0; i < feSize; ++i) - dofs[i] = (*constCoeff_)[lv_->index(node_->localIndex(i))]; - } + assert(childDOFs.size() == shapeValues.size()); - /** Evaluate data on the child element bound to node_ and interpolate onto father entity - * using the coordinate transformation trafo from father to child - */ - template <class Trafo> - bool restrictLocal(Element const& father, NodeElementData& fatherDOFs, Trafo const& trafo, - NodeElementData const& childDOFs, bool init); + LIRangeType y(0); + for (std::size_t i = 0; i < shapeValues.size(); ++i) + y += shapeValues[i] * childDOFs[i]; - /// Copy already existing data to element bound to node_ - void copyLocal(NodeElementData const& dofs) const - { - for (std::size_t i = 0; i < dofs.size(); ++i) - (*coeff_)[lv_->index(node_->localIndex(i))] = dofs[i]; + fatherDOFsTemp_[currentDOF] = y; + finishedDOFs_[currentDOF++] = true; + return y; + } } - - /** Interpolate data from father onto the child element bound to node_ using the transformation - * trafo from child to father - */ - template <class Trafo> - void prolongLocal(Element const& father, NodeElementData const& fatherDOFs, - Trafo const& trafo, bool init); - - private: - LocalView const* lv_; - Node const* node_; - std::unique_ptr<Node> fatherNode_; - Container const* constCoeff_; - Container* coeff_; - std::vector<bool> finishedDOFs_; - NodeElementData fatherDOFsTemp_; + return fatherDOFsTemp_[currentDOF++]; }; - template <class Node, class C, class B> - template <class Trafo> - bool NodeDataTransfer<Node,C,B>:: - restrictLocal(Element const& father, NodeElementData& fatherDOFs, Trafo const& trafo, - NodeElementData const& childDOFs, bool init) - { - auto& fatherNode = *fatherNode_; - std::size_t currentDOF = 0; - if (init) - { - // TODO(FM): This is UB, replace with FE cache for father - bindTree(fatherNode, father); - } - auto const& childNode = *node_; - auto const& childFE = childNode.finiteElement(); - auto const& fatherFE = fatherNode.finiteElement(); - if (init) - { - finishedDOFs_.assign(fatherFE.size(), false); - fatherDOFsTemp_.assign(fatherFE.size(), 0); - } + using FFC + = Dune::Functions::FunctionFromCallable<LIRangeType(LIDomainType), decltype(evalLeaf)>; + fatherFE.localInterpolation().interpolate(FFC(evalLeaf), fatherDOFs); - auto evalLeaf = [&](LIDomainType const& x) -> LIRangeType { - if (!finishedDOFs_[currentDOF]) - { - auto const& insideLocal = trafo(x); - bool isInside = insideLocal.first; - if (isInside) - { - auto const& local = insideLocal.second; - thread_local std::vector<LBRangeType> shapeValues; - childFE.localBasis().evaluateFunction(local, shapeValues); - - assert(childDOFs.size() == shapeValues.size()); - - LIRangeType y(0); - for (std::size_t i = 0; i < shapeValues.size(); ++i) - y += shapeValues[i] * childDOFs[i]; - - fatherDOFsTemp_[currentDOF] = y; - finishedDOFs_[currentDOF++] = true; - return y; - } - } - return fatherDOFsTemp_[currentDOF++]; - }; + // Return true if all father DOFs have been evaluated + return std::accumulate(finishedDOFs_.begin(), finishedDOFs_.end(), true, + std::logical_and<bool>()); +} - using FFC - = Dune::Functions::FunctionFromCallable<LIRangeType(LIDomainType), decltype(evalLeaf)>; - fatherFE.localInterpolation().interpolate(FFC(evalLeaf), fatherDOFs); - // Return true if all father DOFs have been evaluated - return std::accumulate(finishedDOFs_.begin(), finishedDOFs_.end(), true, - std::logical_and<bool>()); +template <class N, class C, class B> + template <class Trafo> +void NodeDataTransfer<N,C,B>:: + prolongLocal(Element const& father, NodeElementData const& fatherDOFs, + Trafo const& trafo, bool init) +{ + auto& fatherNode = *fatherNode_; + if (init) + { + // TODO(FM): This is UB, replace with FE cache for father + bindTree(fatherNode, father); } + auto const& childNode = *node_; - template <class Node, class C, class B> - template <class Trafo> - void NodeDataTransfer<Node,C,B>:: - prolongLocal(Element const& father, NodeElementData const& fatherDOFs, - Trafo const& trafo, bool init) + // evaluate father in child coordinate x + auto evalFather = [&](LIDomainType const& x) -> LIRangeType { - auto& fatherNode = *fatherNode_; - if (init) - { - // TODO(FM): This is UB, replace with FE cache for father - bindTree(fatherNode, father); - } - auto const& childNode = *node_; - - // evaluate father in child coordinate x - auto evalFather = [&](LIDomainType const& x) -> LIRangeType - { - thread_local std::vector<LBRangeType> shapeValues; - fatherNode.finiteElement().localBasis().evaluateFunction(trafo(x), shapeValues); - assert(shapeValues.size() == fatherDOFs.size()); + thread_local std::vector<LBRangeType> shapeValues; + fatherNode.finiteElement().localBasis().evaluateFunction(trafo(x), shapeValues); + assert(shapeValues.size() == fatherDOFs.size()); - LIRangeType y(0); - for (std::size_t i = 0; i < shapeValues.size(); ++i) - y += shapeValues[i] * fatherDOFs[i]; + LIRangeType y(0); + for (std::size_t i = 0; i < shapeValues.size(); ++i) + y += shapeValues[i] * fatherDOFs[i]; - return y; - }; + return y; + }; - auto const& childFE = childNode.finiteElement(); - thread_local std::vector<T> childDOFs; - using FFC = Dune::Functions - ::FunctionFromCallable<LIRangeType(LIDomainType), decltype(evalFather)>; - childFE.localInterpolation().interpolate(FFC(evalFather), childDOFs); + auto const& childFE = childNode.finiteElement(); + thread_local std::vector<T> childDOFs; + using FFC = Dune::Functions + ::FunctionFromCallable<LIRangeType(LIDomainType), decltype(evalFather)>; + childFE.localInterpolation().interpolate(FFC(evalFather), childDOFs); - for (std::size_t i = 0; i < childDOFs.size(); ++i) - (*coeff_)[lv_->index(childNode.localIndex(i))] = childDOFs[i]; - } + for (std::size_t i = 0; i < childDOFs.size(); ++i) + (*coeff_)[lv_->index(childNode.localIndex(i))] = childDOFs[i]; +} } // end namespace AMDiS diff --git a/src/amdis/linearalgebra/DOFVectorBase.hpp b/src/amdis/linearalgebra/DOFVectorBase.hpp index c505124d17842927b239ee8e351e7dcb64d2b0e1..50f6d6a71ebb9f4f55fbe9e378fffabea0c33528 100644 --- a/src/amdis/linearalgebra/DOFVectorBase.hpp +++ b/src/amdis/linearalgebra/DOFVectorBase.hpp @@ -84,8 +84,8 @@ namespace AMDiS public: /// Constructor. Stores the shared_ptr of the basis and creates a new DataTransfer. DOFVectorBase(std::shared_ptr<GlobalBasis> basis, DataTransferOperation op) - : basis_(basis) - , dataTransfer_(DataTransferFactory::create(op, *basis_)) + : basis_(std::move(basis)) + , dataTransfer_(DataTransferFactory::create(op, basis_)) { compress(); attachToGridTransfer(); diff --git a/src/amdis/typetree/TreeContainer.hpp b/src/amdis/typetree/TreeContainer.hpp index 4ecc70865e73012b5e9d36b36679bc83863e32d9..62be88589848d7c595f39408ec7182c53a906f8b 100644 --- a/src/amdis/typetree/TreeContainer.hpp +++ b/src/amdis/typetree/TreeContainer.hpp @@ -202,6 +202,13 @@ namespace AMDiS return makeTreeContainer(tree, [](const auto&) {return Value{};}); } + template<template<class> class NodeData, class Tree> + auto makeTreeContainer(const Tree& tree) + { + return makeTreeContainer(tree, [](const auto& node) {return NodeData<TYPEOF(node)>{};}); + } + + /** * \brief Alias to container type generated by makeTreeContainer for given value and tree type */