diff --git a/cmake/modules/AmdisCXXFeatures.cmake b/cmake/modules/AmdisCXXFeatures.cmake index a033c651e61f5bc8909b966f9e1641bb2b1ec021..58823c5e77bb3dbdab8f6a1292d13e27bdbee360 100644 --- a/cmake/modules/AmdisCXXFeatures.cmake +++ b/cmake/modules/AmdisCXXFeatures.cmake @@ -1,6 +1,4 @@ -#include(CheckIncludeFileCXX) include(CheckCXXSourceCompiles) -#include(CheckCXXSymbolExists) # fold expressions (a + ...) check_cxx_source_compiles(" @@ -30,4 +28,16 @@ check_cxx_source_compiles(" return f<1>(); } " AMDIS_HAS_CXX_CONSTEXPR_IF +) + +check_cxx_source_compiles(" + #include + #include + int main() + { + auto tup = std::make_tuple(0, 'a', 3.14); + for... (auto elem : tup) + std::cout << elem << std::endl; + } +" AMDIS_HAS_EXPANSION_STATEMENTS ) \ No newline at end of file diff --git a/config.h.cmake b/config.h.cmake index a9f4d0eded7ebff017e11faa2b7407baaaaade77..471450a344fc4ef112358b510cd92915209a614a 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -49,6 +49,7 @@ /* some detected compiler features may be used in AMDiS */ #cmakedefine AMDIS_HAS_CXX_FOLD_EXPRESSIONS 1 #cmakedefine AMDIS_HAS_CXX_CONSTEXPR_IF 1 +#cmakedefine AMDIS_HAS_EXPANSION_STATEMENTS 1 /* end amdis Everything below here will be overwritten diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index a22ffee36ba5ad297b32ac7bfb1cbd7107edff29..a2a8ee3fd558682f64ffb21d93194e1a7737cca2 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -24,4 +24,4 @@ add_dependencies(examples stokes1.2d stokes3.2d navier_stokes.2d - convection_diffusion.2d) \ No newline at end of file + convection_diffusion.2d) diff --git a/src/amdis/BoundaryManager.hpp b/src/amdis/BoundaryManager.hpp index 375c334ae1cba89044f78358ca6b04560573a856..a43e28d1f0c9fb11057512480fb4562e79ca0c49 100644 --- a/src/amdis/BoundaryManager.hpp +++ b/src/amdis/BoundaryManager.hpp @@ -146,9 +146,10 @@ namespace AMDiS if (!segment.boundary()) continue; - auto index = segment.boundarySegmentIndex(); - Dune::Hybrid::ifElse(Dune::Std::is_detected{}, - [&](auto id) { boundaryIds_[index] = id(segment).boundaryId(); }); + Dune::Hybrid::ifElse(Dune::Std::is_detected{}, [&](auto id) { + auto index = segment.boundarySegmentIndex(); + boundaryIds_[index] = id(segment).boundaryId(); + }); } } } diff --git a/src/amdis/DataTransfer.inc.hpp b/src/amdis/DataTransfer.inc.hpp index a181ffe1d722b2c146d2e128967c86aa0ed074bc..de25624a9ca08849dd4cbf9ccea0215ce4a844e9 100644 --- a/src/amdis/DataTransfer.inc.hpp +++ b/src/amdis/DataTransfer.inc.hpp @@ -22,8 +22,8 @@ #include #include +#include #include -#include namespace AMDiS { @@ -135,7 +135,7 @@ namespace AMDiS auto lv = basis_->localView(); auto const& idSet = gv.grid().localIdSet(); - forEachLeafNode_(lv.tree(), [&](auto const& node, auto const& tp) { + for_each_leaf_node(lv.tree(), [&](auto const& node, auto const& tp) { nodeDataTransfer_[tp].preAdaptInit(lv, coeff, node); }); @@ -148,7 +148,7 @@ namespace AMDiS lv.bind(e); auto& treeContainer = it.first->second; - forEachLeafNode_(lv.tree(), [&](auto const& node, auto const& tp) { + for_each_leaf_node(lv.tree(), [&](auto const& node, auto const& tp) { nodeDataTransfer_[tp].cacheLocal(treeContainer[tp]); }); } @@ -201,7 +201,7 @@ namespace AMDiS }; restrictLocalCompleted = true; - forEachLeafNode_(lv.tree(), [&](auto const& node, auto const& tp) { + for_each_leaf_node(lv.tree(), [&](auto const& node, auto const& tp) { restrictLocalCompleted &= nodeDataTransfer_[tp].restrictLocal(father, treeContainer[tp], xInChildCached, childContainer[tp], init); @@ -224,7 +224,7 @@ namespace AMDiS auto gv = basis_->gridView(); auto lv = basis_->localView(); auto const& idSet = gv.grid().localIdSet(); - forEachLeafNode_(lv.tree(), [&](auto const& node, auto const& tp) { + for_each_leaf_node(lv.tree(), [&](auto const& node, auto const& tp) { nodeDataTransfer_[tp].postAdaptInit(lv, coeff, node); }); @@ -243,7 +243,7 @@ namespace AMDiS if (it != persistentContainer_.end()) { lv.bind(e); auto const& treeContainer = it->second; - forEachLeafNode_(lv.tree(), [&](auto const& node, auto const& tp) { + for_each_leaf_node(lv.tree(), [&](auto const& node, auto const& tp) { nodeDataTransfer_[tp].copyLocal(treeContainer[tp]); }); finished_[index] = true; @@ -275,7 +275,7 @@ namespace AMDiS return fatherGeo.local(childGeo.global(x)); }; - forEachLeafNode_(lv.tree(), [&](auto const& node, auto const& tp) { + for_each_leaf_node(lv.tree(), [&](auto const& node, auto const& tp) { nodeDataTransfer_[tp].prolongLocal(father, treeContainer[tp], xInFather, init); }); diff --git a/src/amdis/DirichletBC.hpp b/src/amdis/DirichletBC.hpp index a74b0eabd797d0c4778822dd78757734fc89ba9c..df1947d1d6e057b90ea4401d1f8008755f924c9c 100644 --- a/src/amdis/DirichletBC.hpp +++ b/src/amdis/DirichletBC.hpp @@ -11,8 +11,8 @@ #include #include #include +#include #include -#include namespace AMDiS { diff --git a/src/amdis/PeriodicBC.inc.hpp b/src/amdis/PeriodicBC.inc.hpp index 2b449f3bd4a108ddbf91ce4f259624831802e891..7c5ebbf139a2ebf1a6b178a82a05edd62e416663 100644 --- a/src/amdis/PeriodicBC.inc.hpp +++ b/src/amdis/PeriodicBC.inc.hpp @@ -196,7 +196,7 @@ std::vector PeriodicBC:: coords(Node const& tree, std::vector const& localIndices) const { std::vector dofCoords(localIndices.size()); - AMDiS::forEachLeafNode_(tree, [&](auto const& node, auto const& tp) + for_each_leaf_node(tree, [&](auto const& node, auto const& tp) { std::size_t size = node.finiteElement().size(); auto geometry = node.element().geometry(); diff --git a/src/amdis/ProblemStat.inc.hpp b/src/amdis/ProblemStat.inc.hpp index 2e8021df7777c87867511b3045ed85665b30421a..7713a8aff4bf0e937abfe93e432df85dffbbf688 100644 --- a/src/amdis/ProblemStat.inc.hpp +++ b/src/amdis/ProblemStat.inc.hpp @@ -177,7 +177,7 @@ void ProblemStat::createMatricesAndVectors() rhs_ = std::make_shared(*globalBasis_, NO_OPERATION); auto localView = globalBasis_->localView(); - AMDiS::forEachNode_(localView.tree(), [&,this](auto const& node, auto treePath) + for_each_node(localView.tree(), [&,this](auto const& node, auto treePath) { std::string i = to_string(treePath); estimates_[i].resize(globalBasis_->gridView().indexSet().size(0)); @@ -205,7 +205,7 @@ void ProblemStat::createMarker() { marker_.clear(); auto localView = globalBasis_->localView(); - AMDiS::forEachNode_(localView.tree(), [&,this](auto const& node, auto treePath) + for_each_node(localView.tree(), [&,this](auto const& node, auto treePath) { std::string componentName = name_ + "->marker[" + to_string(treePath) + "]"; @@ -232,7 +232,7 @@ void ProblemStat::createFileWriter() { filewriter_.clear(); auto localView = globalBasis_->localView(); - forEachNode_(localView.tree(), [&,this](auto const& node, auto treePath) + for_each_node(localView.tree(), [&,this](auto const& node, auto treePath) { std::string componentName = name_ + "->output[" + to_string(treePath) + "]"; @@ -428,9 +428,9 @@ buildAfterAdapt(AdaptInfo& /*adaptInfo*/, Flag /*flag*/, bool asmMatrix, bool as rhs_->init(asmVector); auto localView = globalBasis_->localView(); - forEachNode_(localView.tree(), [&,this](auto const& rowNode, auto rowTp) { + for_each_node(localView.tree(), [&,this](auto const& rowNode, auto rowTp) { auto rowBasis = Dune::Functions::subspaceBasis(*globalBasis_, rowTp); - forEachNode_(localView.tree(), [&,this](auto const& colNode, auto colTp) { + for_each_node(localView.tree(), [&,this](auto const& colNode, auto colTp) { auto colBasis = Dune::Functions::subspaceBasis(*globalBasis_, colTp); for (auto bc : dirichletBCs_[rowNode][colNode]) bc->init(rowBasis, colBasis); @@ -456,8 +456,8 @@ buildAfterAdapt(AdaptInfo& /*adaptInfo*/, Flag /*flag*/, bool asmMatrix, bool as systemMatrix_->finish(asmMatrix); rhs_->finish(asmVector); - forEachNode_(localView.tree(), [&,this](auto const& rowNode, auto) { - forEachNode_(localView.tree(), [&,this](auto const& colNode, auto) { + for_each_node(localView.tree(), [&,this](auto const& rowNode, auto) { + for_each_node(localView.tree(), [&,this](auto const& colNode, auto) { // finish boundary condition for (auto bc : dirichletBCs_[rowNode][colNode]) bc->fillBoundaryCondition(*systemMatrix_, *solution_, *rhs_, rowNode, colNode); diff --git a/src/amdis/common/ForEach.hpp b/src/amdis/common/ForEach.hpp index dbe64d7d535132cd9833d2b81f42bc7d595885c2..7768a5610961eeba266f80355731758400193571 100644 --- a/src/amdis/common/ForEach.hpp +++ b/src/amdis/common/ForEach.hpp @@ -2,7 +2,6 @@ #include -#include #include #include @@ -16,34 +15,52 @@ namespace AMDiS void ignored_evaluation(std::initializer_list&&) { /* do nothing */ } } + template + constexpr void for_each(std::index_sequence, Tuple&& tuple, Functor&& f) + { + using std::get; +#if AMDIS_HAS_EXPANSION_STATEMENTS + for... (auto&& t : tuple) { f(FWD(t)); } +#elif AMDIS_HAS_CXX_FOLD_EXPRESSIONS + (f(get(tuple)),...); +#else + Impl_::ignored_evaluation({0, (f(get(tuple)), 0)...}); +#endif + } + template constexpr void for_each(Tuple&& tuple, Functor&& f) { - #if AMDIS_HAS_CXX_FOLD_EXPRESSIONS - Tools::apply([f=std::move(f)](auto&&... t) { (f(FWD(t)),...); }, tuple); - #else - Tools::apply([f=std::move(f)](auto&&... t) { - Impl_::ignored_evaluation({0, (f(FWD(t)), 0)...}); - }, tuple); - #endif + Tools::for_each(std::make_index_sequence>>{}, FWD(tuple), FWD(f)); + } + + + template + constexpr void for_range(std::index_sequence, Functor&& f) + { +#if AMDIS_HAS_CXX_FOLD_EXPRESSIONS + (f(index_t{}),...); +#else + Impl_::ignored_evaluation({0, (f(index_t{}), 0)...}); +#endif } template constexpr void for_range(index_t i0, index_t i1, Functor&& f) { - Tools::for_each(range_t{}, FWD(f)); + Tools::for_range(std::make_index_sequence{}, FWD(f)); } template constexpr void for_range(index_t, Functor&& f) { - Tools::for_each(range_t<0,N>{}, FWD(f)); + Tools::for_range(std::make_index_sequence{}, FWD(f)); } template constexpr void for_range(Functor&& f) { - Tools::for_each(range_t{}, FWD(f)); + Tools::for_range(std::make_index_sequence{}, FWD(f)); } } // end namespace Tools diff --git a/src/amdis/common/TypeTraits.hpp b/src/amdis/common/TypeTraits.hpp index 5d63c0775d8869ea38258351ac6e57bd3a88ed17..3270cb24cdab3f8eb14e329b4c1d2666166c9565 100644 --- a/src/amdis/common/TypeTraits.hpp +++ b/src/amdis/common/TypeTraits.hpp @@ -65,6 +65,12 @@ namespace AMDiS template using owner = T; + /// A functor with no operation + struct NoOp + { + template + constexpr void operator()(T&&...) const { /* no nothing */ } + }; /// Create a unique_ptr by copy/move construction template diff --git a/src/amdis/gridfunctions/DiscreteFunction.inc.hpp b/src/amdis/gridfunctions/DiscreteFunction.inc.hpp index 52c47b3ef8d7f88f3dc358b38dbae365066481f4..d9998b04bd47fff2cc1f4b62d1c05d7c504ad1d7 100644 --- a/src/amdis/gridfunctions/DiscreteFunction.inc.hpp +++ b/src/amdis/gridfunctions/DiscreteFunction.inc.hpp @@ -147,7 +147,7 @@ LocalFunction::operator()(Domain const& x) const auto&& coefficients = *globalFunction_.dofVector_; auto&& nodeToRangeEntry = globalFunction_.nodeToRangeEntry_; - forEachLeafNode_(*subTree_, [&,this](auto const& node, auto const& tp) + for_each_leaf_node(*subTree_, [&,this](auto const& node, auto const& tp) { auto&& fe = node.finiteElement(); auto&& localBasis = fe.localBasis(); @@ -193,7 +193,7 @@ GradientLocalFunction::operator()(Domain const& x) const auto&& coefficients = *globalFunction_.dofVector_; auto&& nodeToRangeEntry = globalFunction_.nodeToRangeEntry_; - forEachLeafNode_(*subTree_, [&,this](auto const& node, auto const& tp) + for_each_leaf_node(*subTree_, [&,this](auto const& node, auto const& tp) { // TODO: may DOFVectorView::Range to FieldVector type if necessary using LocalDerivativeTraits diff --git a/src/amdis/linearalgebra/DOFMatrixBase.inc.hpp b/src/amdis/linearalgebra/DOFMatrixBase.inc.hpp index 7088f001067996bb4ad8622267fa9f6e7eafe53c..f06bbde64f2d68fc52042ece6d62ebc0fe93e57e 100644 --- a/src/amdis/linearalgebra/DOFMatrixBase.inc.hpp +++ b/src/amdis/linearalgebra/DOFMatrixBase.inc.hpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include namespace AMDiS { @@ -75,8 +75,8 @@ assemble(RowLocalView const& rowLocalView, ColLocalView const& colLocalView) auto const& element = rowLocalView.element(); auto geometry = element.geometry(); - forEachNode_(rowLocalView.tree(), [&](auto const& rowNode, auto) { - forEachNode_(colLocalView.tree(), [&](auto const& colNode, auto) { + for_each_node(rowLocalView.tree(), [&](auto const& rowNode, auto) { + for_each_node(colLocalView.tree(), [&](auto const& colNode, auto) { auto& matOp = operators_[rowNode][colNode]; if (matOp) { matOp.bind(element, geometry); diff --git a/src/amdis/linearalgebra/DOFVectorBase.inc.hpp b/src/amdis/linearalgebra/DOFVectorBase.inc.hpp index 3be8021a685366a95376096fad69044fff64029b..4795c768f9f58a9579096d41a0dc40514dbcd3eb 100644 --- a/src/amdis/linearalgebra/DOFVectorBase.inc.hpp +++ b/src/amdis/linearalgebra/DOFVectorBase.inc.hpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include namespace AMDiS { @@ -66,7 +66,7 @@ assemble(LocalView const& localView) auto const& element = localView.element(); auto geometry = element.geometry(); - forEachNode_(localView.tree(), [&](auto const& node, auto) { + for_each_node(localView.tree(), [&](auto const& node, auto) { auto& rhsOp = operators_[node]; if (rhsOp) { rhsOp.bind(element, geometry); diff --git a/src/amdis/typetree/CMakeLists.txt b/src/amdis/typetree/CMakeLists.txt index 60c45aeb846993efd054f3a00ac46c55b693433a..e25449205cd9610e5b6d631fb946e325772b03b7 100644 --- a/src/amdis/typetree/CMakeLists.txt +++ b/src/amdis/typetree/CMakeLists.txt @@ -7,5 +7,4 @@ install(FILES TreeContainer.hpp TreeData.hpp TreePath.hpp - Visitor.hpp DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/amdis/typetree) diff --git a/src/amdis/typetree/Traversal.hpp b/src/amdis/typetree/Traversal.hpp index 45751bcdd23495dc9efcf53dcf4e8ba823e543ef..8dfd9cdffb669248e2b04d3672f23d623d7fc34c 100644 --- a/src/amdis/typetree/Traversal.hpp +++ b/src/amdis/typetree/Traversal.hpp @@ -3,139 +3,257 @@ #include #include +#include #include #include #include #include +#include +#include #include -namespace AMDiS -{ - // forward declaration of main engine struct - template - struct TraverseTree; - - - // Do not visit nodes the visitor is not interested in - template - struct TraverseTree - { - template - static void apply(const Node& node, const Visitor& visitor, TreePath const& tp) - {} - }; - -#ifndef DOXYGEN - - // some implementation details - - template - struct HybridChildType - : HybridChildType, std::remove_const_t> {}; - - template - struct HybridChildType - { - using type = typename Node::template Child<0>::Type; - }; - - template - struct HybridChildType> - { - using type = typename Node::template Child::Type; - }; - - template - constexpr std::size_t hybridDegree(NodeTag, Node const& node) - { - return Dune::TypeTree::degree(node); - } - - template - constexpr auto hybridDegree(Dune::TypeTree::CompositeNodeTag, Node const& node) - { - return Dune::index_constant{}; - } - - - template - constexpr bool notLastChild(Dune::index_constant const&, Dune::index_constant const&) - { - return k < n-1; - } - - constexpr bool notLastChild(std::size_t k, std::size_t n) - { - return k < n-1; - } - -#endif - - - template - struct TraverseTree - { - template - static void apply(N&& n, V&& v, TreePath const& tp) +// NOTE: backport of dune/typetree/traversal.hpp from Dune 2.7 + +namespace AMDiS { + + enum class TreePathType { - using Node = std::remove_reference_t; - using Visitor = std::remove_reference_t; + DYNAMIC, STATIC + }; + + namespace Impl { + + // This is a constexpr version of the ternery operator c?t1:t1. + // In contrast to the latter the type of t1 and t2 can be different. + // Notice that std::conditional would not do the trick, because + // it only selects between types. + template = 0> + constexpr auto conditionalValue(T1&& t1, T2&& t2) { + return std::forward(t1); + } + + template = 0> + constexpr auto conditionalValue(T1&& t1, T2&& t2) { + return std::forward(t2); + } + + + /* The signature is the same as for the public applyToTree + * function in Dune::Typetree, despite the additionally passed + * treePath argument. The path passed here is associated to + * the tree and the relative paths of the children (wrt. to tree) + * are appended to this. Hence the behavior of the public function + * is resembled by passing an empty treePath. + */ + + /* + * This is the overload for leaf traversal + */ + template::isLeaf, int> = 0> + void apply_to_tree(T&& tree, TP treePath, V&& visitor) + { + visitor.leaf(tree, treePath); + } + + /* + * This is the general overload doing child traversal. + */ + template::isLeaf, int> = 0> + void apply_to_tree(T&& tree, TP treePath, V&& visitor) + { + // Do we really want to take care for const-ness of the Tree + // when instantiating VisitChild below? I'd rather expect this: + // using Tree = remove_cvref_t; + // using Visitor = remove_cvref_t; + using Tree = std::remove_reference_t; + using Visitor = std::remove_reference_t; + visitor.pre(tree, treePath); + + // Use statically encoded degree unless tree + // is a power node and dynamic traversal is requested. + constexpr auto useDynamicTraversal = (Tree::isPower and Visitor::treePathType==TreePathType::DYNAMIC); + auto degree = conditionalValue(Tree::degree(), Dune::index_constant{}); + + auto indices = Dune::range(degree); + Dune::Hybrid::forEach(indices, [&](auto i) { + auto childTP = Dune::TypeTree::push_back(treePath, i); + auto&& child = tree.child(i); + using Child = TYPEOF(child); + + visitor.beforeChild(tree, child, treePath, i); + + // This requires that visiotor.in(...) can always be instantiated, + // even if there's a single child only. + if (i>0) + visitor.in(tree, treePath); + static constexpr auto visitChild = Visitor::template VisitChild::value; + #if AMDIS_HAS_CXX_CONSTEXPR_IF + if constexpr(visitChild) + applyToTree(child, childTP, visitor); + #else // AMDIS_HAS_CXX_CONSTEXPR_IF + Dune::Hybrid::ifElse(bool_t{}, [&] (auto /*id*/) { + applyToTree(child, childTP, visitor); + }); + #endif // AMDIS_HAS_CXX_CONSTEXPR_IF + visitor.afterChild(tree, child, treePath, i); + }); + visitor.post(tree, treePath); + } + + // Overload for leaf nodes + template::isLeaf, int> = 0> + void for_each_node(Tree&& tree, TP treePath, Pre&& /*preFunc*/, Leaf&& leafFunc, Post&& /*postFunc*/) + { + leafFunc(tree, treePath); + } + + // Overload for non-leaf nodes + // Forward declaration needed for recursion + template::isLeaf,int> = 0> + void for_each_node(Tree&& tree, TP treePath, Pre&& preFunc, Leaf&& leafFunc, Post&& postFunc); + + // Helper for power nodes + template::isPower, int> = 0> + void for_each_node_unfold(Tree&& tree, TP treePath, Pre&& preFunc, Leaf&& leafFunc, Post&& postFunc, std::index_sequence) + { + for (std::size_t i = 0; i < sizeof...(I); ++i) + Impl::for_each_node(tree.child(i), Dune::TypeTree::push_back(treePath, i), preFunc, leafFunc, postFunc); + } - v.pre(FWD(n),tp); + // Helper for composite nodes + template::isPower, int> = 0> + void for_each_node_unfold(Tree&& tree, TP treePath, Pre&& preFunc, Leaf&& leafFunc, Post&& postFunc, std::index_sequence) + { + (void)std::initializer_list{( + Impl::for_each_node(tree.child(Dune::index_constant{}), + Dune::TypeTree::push_back(treePath, Dune::index_constant{}), preFunc, leafFunc, postFunc),0)... + }; + } - auto const deg = hybridDegree(NodeTag{}, n); - Dune::Hybrid::forEach(Dune::range(deg), [&](auto const _k) + /* + * Traverse tree and visit each node. The signature is the same + * as for the public for_each_node function in Dune::Typtree, + * despite the additionally passed treePath argument. The path + * passed here is associated to the tree and the relative + * paths of the children (wrt. to tree) are appended to this. + * Hence the behavior of the public function is resembled + * by passing an empty treePath. + * + * See also the specialization for leaf-nodes. + */ + template::isLeaf,int>> + void for_each_node(Tree&& tree, TP treePath, Pre&& preFunc, Leaf&& leafFunc, Post&& postFunc) { - // always call beforeChild(), regardless of the value of visit - v.beforeChild(FWD(n),n.child(_k),tp,_k); + auto indices = std::make_index_sequence{}; + preFunc(tree, treePath); + Impl::for_each_node_unfold(tree, treePath, preFunc, leafFunc, postFunc, indices); + postFunc(tree, treePath); + } + + } // namespace Impl + + + // ******************************************************************************** + // Public Interface + // ******************************************************************************** - // descend to child - using C = typename HybridChildType::type; - const bool visit = Visitor::template VisitChild::value; - TraverseTree,visit>::apply(n.child(_k),FWD(v),push_back(tp, _k)); + //! Apply visitor to TypeTree. + /** + * \code + * #include + * \endcode + * This function applies the given visitor to the given tree. Both visitor and tree may be const + * or non-const (if the compiler supports rvalue references, they may even be a non-const temporary). + * + * \note The visitor must implement the interface laid out by DefaultVisitor (most easily achieved by + * inheriting from it) and specify the required type of tree traversal (static or dynamic) by + * inheriting from either StaticTraversal or DynamicTraversal. + * + * \param tree The tree the visitor will be applied to. + * \param visitor The visitor to apply to the tree. + */ + template + void apply_to_tree(Tree&& tree, Visitor&& visitor) + { + auto root = Dune::TypeTree::hybridTreePath(); + Impl::apply_to_tree(tree, root, visitor); + } - // always call afterChild(), regardless of the value of visit - v.afterChild(FWD(n),n.child(_k),tp,_k); + /** + * \brief Traverse tree and visit each node + * + * All passed callback functions are called with the + * node and corresponding treepath as arguments. + * + * \param tree The tree to traverse + * \param preFunc This function is called for each inner node before visiting its children + * \param leafFunc This function is called for each leaf node + * \param postFunc This function is called for each inner node after visiting its children + */ + template + void for_each_node(Tree&& tree, Pre&& preFunc, Leaf&& leafFunc, Post&& postFunc) + { + auto root = Dune::TypeTree::hybridTreePath(); + Impl::for_each_node(tree, root, preFunc, leafFunc, postFunc); + } - // if this is not the last child, call infix callback - if (notLastChild(_k, deg)) - v.in(FWD(n),tp); - }); + /** + * \brief Traverse tree and visit each node + * + * All passed callback functions are called with the + * node and corresponding treepath as arguments. + * + * \param tree The tree to traverse + * \param innerFunc This function is called for each inner node before visiting its children + * \param leafFunc This function is called for each leaf node + */ + template + void for_each_node(Tree&& tree, Inner&& innerFunc, Leaf&& leafFunc) + { + auto root = Dune::TypeTree::hybridTreePath(); + Impl::for_each_node(tree, root, innerFunc, leafFunc, NoOp{}); + } - v.post(FWD(n),tp); + /** + * \brief Traverse tree and visit each node + * + * The passed callback function is called with the + * node and corresponding treepath as arguments. + * + * \param tree The tree to traverse + * \param nodeFunc This function is called for each node + */ + template + void for_each_node(Tree&& tree, NodeFunc&& nodeFunc) + { + auto root = Dune::TypeTree::hybridTreePath(); + Impl::for_each_node(tree, root, nodeFunc, nodeFunc, NoOp{}); } - }; - - // LeafNode - just call the leaf() callback - template <> - struct TraverseTree - { - template - static void apply(N&& n, V&& v, TreePath const& tp) + + /** + * \brief Traverse tree and visit each leaf node + * + * The passed callback function is called with the + * node and corresponding treepath as arguments. + * + * \param tree The tree to traverse + * \param leafFunc This function is called for each leaf node + */ + template + void for_each_leaf_node(Tree&& tree, Leaf&& leafFunc) { - v.leaf(FWD(n),tp); + auto root = Dune::TypeTree::hybridTreePath(); + Impl::for_each_node(tree, root, NoOp{}, leafFunc, NoOp{}); } - }; - - //! Apply visitor to TypeTree. - /** - * This function applies the given visitor to the given tree. Both visitor and tree may be const - * or non-const (if the compiler supports rvalue references, they may even be a non-const temporary). - * - * \note The visitor must implement the interface laid out by DefaultVisitor (most easily achieved by - * inheriting from it). - * - * \param tree The tree the visitor will be applied to. - * \param visitor The visitor to apply to the tree. - */ - template - void traverseTree(Tree&& tree, Visitor&& visitor) - { - using Node = std::remove_reference_t; - using NodeTag = Dune::TypeTree::NodeTag; - using TreePath = Dune::TypeTree::HybridTreePath<>; - TraverseTree::apply(FWD(tree), FWD(visitor), TreePath{}); - } } // end namespace AMDiS diff --git a/src/amdis/typetree/TreeData.hpp b/src/amdis/typetree/TreeData.hpp index 2e558ace277c21b374b870fdf0187408ae5b0cb4..d6ecfe62e809838da685f6171072d1ce2c0da8a8 100644 --- a/src/amdis/typetree/TreeData.hpp +++ b/src/amdis/typetree/TreeData.hpp @@ -6,7 +6,7 @@ #include #include -#include +#include namespace AMDiS { @@ -195,10 +195,10 @@ namespace AMDiS } template - void applyImpl(Func&& func, std::true_type) { forEachLeafNode_(basis_->localView().tree(), func); } + void applyImpl(Func&& func, std::true_type) { for_each_leaf_node(basis_->localView().tree(), func); } template - void applyImpl(Func&& func, std::false_type) { forEachNode_(basis_->localView().tree(), func); } + void applyImpl(Func&& func, std::false_type) { for_each_node(basis_->localView().tree(), func); } protected: Basis const* basis_ = nullptr; @@ -238,7 +238,7 @@ namespace AMDiS void init(RowBasis const& rowBasis, ColBasis const& colBasis) { Super::init(rowBasis); - forEachNode_(rowBasis.localView().tree(), [&](auto const& node, auto&&) + for_each_node(rowBasis.localView().tree(), [&](auto const& node, auto&&) { (*this)[node].init(colBasis); }); diff --git a/src/amdis/typetree/Visitor.hpp b/src/amdis/typetree/Visitor.hpp deleted file mode 100644 index 153e0e1ea938ec51742e28d8901ccbf15c53c543..0000000000000000000000000000000000000000 --- a/src/amdis/typetree/Visitor.hpp +++ /dev/null @@ -1,120 +0,0 @@ -#pragma once - -#include -#include - -namespace AMDiS -{ - // from dune-typetree merge-request !2 - namespace Impl - { - template - class CallbackVisitor - : public Dune::TypeTree::TreeVisitor - { - public: - CallbackVisitor(PreFunc& preFunc, LeafFunc& leafFunc, PostFunc& postFunc) - : preFunc_(preFunc) - , leafFunc_(leafFunc) - , postFunc_(postFunc) - {} - - template - void pre(Node&& node, TreePath treePath) - { - preFunc_(node, treePath); - } - - template - void leaf(Node&& node, TreePath treePath) - { - leafFunc_(node, treePath); - } - - template - void post(Node&& node, TreePath treePath) - { - postFunc_(node, treePath); - } - - private: - PreFunc& preFunc_; - LeafFunc& leafFunc_; - PostFunc& postFunc_; - }; - - template - auto callbackVisitor(PreFunc& preFunc, LeafFunc& leafFunc, PostFunc& postFunc) - { - return CallbackVisitor(preFunc, leafFunc, postFunc); - } - - } // namespace Impl - - - /** - * \brief Traverse tree and visit each node - * - * All passed callback functions are called with the - * node and corresponding treepath as arguments. - * - * \param tree The tree to traverse - * \param preFunc This function is called for each inner node before visiting its children - * \param leafFunc This function is called for each leaf node - * \param postFunc This function is called for each inner node after visiting its children - */ - template - void forEachNode_(Tree&& tree, PreFunc&& preFunc, LeafFunc&& leafFunc, PostFunc&& postFunc) - { - traverseTree(tree, Impl::callbackVisitor(preFunc, leafFunc, postFunc)); - } - - /** - * \brief Traverse tree and visit each node - * - * All passed callback functions are called with the - * node and corresponding treepath as arguments. - * - * \param tree The tree to traverse - * \param innerFunc This function is called for each inner node before visiting its children - * \param leafFunc This function is called for each leaf node - */ - template - void forEachNode_(Tree&& tree, InnerFunc&& innerFunc, LeafFunc&& leafFunc) - { - auto nop = [](auto&&... args) {}; - forEachNode_(tree, innerFunc, leafFunc, nop); - } - - /** - * \brief Traverse tree and visit each node - * - * The passed callback function is called with the - * node and corresponding treepath as arguments. - * - * \param tree The tree to traverse - * \param nodeFunc This function is called for each node - */ - template - void forEachNode_(Tree&& tree, NodeFunc&& nodeFunc) - { - forEachNode_(tree, nodeFunc, nodeFunc); - } - - /** - * \brief Traverse tree and visit each leaf node - * - * The passed callback function is called with the - * node and corresponding treepath as arguments. - * - * \param tree The tree to traverse - * \param leafFunc This function is called for each leaf node - */ - template - void forEachLeafNode_(Tree&& tree, LeafFunc&& leafFunc) - { - auto nop = [](auto&&... args) {}; - forEachNode_(tree, nop, leafFunc, nop); - } - -} // end namespace AMDiS diff --git a/test/DataTransferTest.hpp b/test/DataTransferTest.hpp index 5502b105d153371d1704d0ede277229beacbab1e..11f0e3011bf5cf39712ecb513660bf1c32c825da 100644 --- a/test/DataTransferTest.hpp +++ b/test/DataTransferTest.hpp @@ -68,7 +68,7 @@ auto makeProblem(typename BasisCreator::GlobalBasis::GridView::Grid& grid, Fcts // interpolate given function to initial grid int k = 0; - AMDiS::forEachLeafNode_(localView.tree(), [&](auto const& node, auto tp) + for_each_leaf_node(localView.tree(), [&](auto const& node, auto tp) { interpolate(globalBasis, tp, prob.solution(tp).coefficients(), funcs[k]); k++; @@ -90,7 +90,7 @@ double calcError(Problem const& prob, Fcts const& funcs) int k = 0; // interpolate given function onto reference vector - AMDiS::forEachLeafNode_(localView.tree(), [&](auto const& node, auto tp) + for_each_leaf_node(localView.tree(), [&](auto const& node, auto tp) { interpolate(globalBasis, tp, ref, funcs[k]); k++; diff --git a/test/TreeDataTest.cpp b/test/TreeDataTest.cpp index d0320281dc436ff7a49d135a31a4c41d43466cc8..103b4d686ec5c23085d70061c588d44d5aa827c0 100644 --- a/test/TreeDataTest.cpp +++ b/test/TreeDataTest.cpp @@ -25,7 +25,7 @@ bool operator==(TreeData const& t1, TreeDatalocalView().tree(), [&](auto const& node, auto) { + for_each_node(t1.basis()->localView().tree(), [&](auto const& node, auto) { same = same && (t1[node] == t2[node]); }); @@ -38,7 +38,7 @@ bool operator==(TreeData const& t1, TreeDatalocalView().tree(), [&](auto const& node, auto) { + for_each_leaf_node(t1.basis()->localView().tree(), [&](auto const& node, auto) { same = same && (t1[node] == t2[node]); }); @@ -73,7 +73,7 @@ int main () TreeData treeData; treeData.init(basis); - AMDiS::forEachNode_(tree, [&](auto const& node, auto) { + for_each_node(tree, [&](auto const& node, auto) { treeData[node] = double(node.treeIndex()); }); @@ -109,7 +109,7 @@ int main () TreeData treeData; treeData.init(basis); - AMDiS::forEachLeafNode_(tree, [&](auto const& node, auto) { + for_each_leaf_node(tree, [&](auto const& node, auto) { treeData[node] = double(node.treeIndex()); });