From 2acff741b79c6218406c674f8865fa69729b8ecc Mon Sep 17 00:00:00 2001 From: Simon Praetorius Date: Sat, 10 Oct 2020 16:21:02 +0200 Subject: [PATCH 1/4] rename child() into discreteFunction() --- amdis/DOFVector.hpp | 35 ++++++++-------- amdis/ProblemInstat.hpp | 6 +-- amdis/ProblemStat.hpp | 12 +++--- amdis/gridfunctions/DiscreteFunction.hpp | 16 ++++---- amdis/io/FileWriterCreator.hpp | 8 ++-- amdis/typetree/TreeContainer.hpp | 2 +- docs/reference/DOFVector.md | 52 ++++++++++++------------ test/BackupRestoreTest.cpp | 8 ++-- test/DiscreteFunctionTest.cpp | 35 ++++++++-------- test/GradientTest.cpp | 12 +++--- 10 files changed, 93 insertions(+), 93 deletions(-) diff --git a/amdis/DOFVector.hpp b/amdis/DOFVector.hpp index 55524515..4ad69a0c 100644 --- a/amdis/DOFVector.hpp +++ b/amdis/DOFVector.hpp @@ -82,20 +82,21 @@ namespace AMDiS : DOFVector(std::make_shared(gridView, preBasisFactory), op) {} + /// Return the global basis std::shared_ptr const& basis() const { return basis_; } - template - auto child(TreePath const& path = {}) + /// Transform the DOFVector into a DiscreteFunction + template + auto discreteFunction(Indices... ii) { - auto&& tp = makeTreePath(path); - return makeDiscreteFunction(coefficients(), *basis_, tp); + return makeDiscreteFunction(coefficients(), *basis_, treepath(ii...)); } - template - auto child(TreePath const& path = {}) const + /// Transform the DOFVector into a DiscreteFunction + template + auto discreteFunction(Indices... ii) const { - auto&& tp = makeTreePath(path); - return makeDiscreteFunction(coefficients(), *basis_, tp); + return makeDiscreteFunction(coefficients(), *basis_, treepath(ii...)); } @@ -105,7 +106,7 @@ namespace AMDiS template void interpolate_noalias(Expr&& expr, Tag strategy = {}) { - child().interpolate_noalias(FWD(expr), strategy); + discreteFunction().interpolate_noalias(FWD(expr), strategy); } /// Interpolation of GridFunction to DOFVector. @@ -113,7 +114,7 @@ namespace AMDiS template void interpolate(Expr&& expr, Tag strategy = {}) { - child().interpolate(FWD(expr), strategy); + discreteFunction().interpolate(FWD(expr), strategy); } /// Interpolation of GridFunction to DOFVector. @@ -121,7 +122,7 @@ namespace AMDiS template DOFVector& operator<<(Expr&& expr) { - child().interpolate(FWD(expr)); + discreteFunction().interpolate(FWD(expr)); return *this; } @@ -247,17 +248,17 @@ namespace AMDiS } /// A Generator for a mutable \ref DiscreteFunction - template - auto makeDiscreteFunction(DOFVector& dofVec, Path const& path = {}) + template + auto discreteFunction(DOFVector& dofVec, Indices... ii) { - return dofVec.child(path); + return dofVec.discreteFunction(ii...); } /// A Generator for a mutable \ref DiscreteFunction - template - auto makeDiscreteFunction(DOFVector const& dofVec, Path const& path = {}) + template + auto discreteFunction(DOFVector const& dofVec, Indices... ii) { - return dofVec.child(path); + return dofVec.discreteFunction(ii...); } } // end namespace AMDiS diff --git a/amdis/ProblemInstat.hpp b/amdis/ProblemInstat.hpp index bf9bb847..55148dcd 100644 --- a/amdis/ProblemInstat.hpp +++ b/amdis/ProblemInstat.hpp @@ -62,12 +62,12 @@ namespace AMDiS } /// Return a const view to a oldSolution component - template - auto oldSolution(TreePath path = {}) const + template + auto oldSolution(Indices... ii) const { test_exit_dbg(bool(oldSolution_), "OldSolution need to be created. Call initialize with INIT_UH_OLD."); - return oldSolution_->child(path); + return oldSolution_->discreteFunction(ii...); } /// Implementation of \ref ProblemTimeInterface::transferInitialSolution(). diff --git a/amdis/ProblemStat.hpp b/amdis/ProblemStat.hpp index 0f154450..c86e85f1 100644 --- a/amdis/ProblemStat.hpp +++ b/amdis/ProblemStat.hpp @@ -368,19 +368,19 @@ namespace AMDiS /// Return a mutable view to a solution component - template - auto solution(TreePath path = {}) + template + auto solution(Indices... ii) { assert(bool(solution_) && "You have to call initialize() before."); - return solution_->child(path); + return solution_->discreteFunction(ii...); } /// Return a const view to a solution component - template - auto solution(TreePath path = {}) const + template + auto solution(Indices... ii) const { assert(bool(solution_) && "You have to call initialize() before."); - return solution_->child(path); + return solution_->discreteFunction(ii...); } diff --git a/amdis/gridfunctions/DiscreteFunction.hpp b/amdis/gridfunctions/DiscreteFunction.hpp index 99a27bb0..038e559d 100644 --- a/amdis/gridfunctions/DiscreteFunction.hpp +++ b/amdis/gridfunctions/DiscreteFunction.hpp @@ -73,7 +73,7 @@ namespace AMDiS /** * **Example:** * ``` - * auto v = makeDiscreteFunction(prob.solutionVector(),0); + * auto v = discreteFunction(prob.solutionVector(),0); * v.interpolate_noalias([](auto const& x) { return x[0]; }); * ``` **/ @@ -84,7 +84,7 @@ namespace AMDiS /** * **Example:** * ``` - * auto v = makeDiscreteFunction(prob.solutionVector(),0); + * auto v = discreteFunction(prob.solutionVector(),0); * v.interpolate(v + [](auto const& x) { return x[0]; }); * ``` * Allows to have a reference to the DOFVector in the expression, e.g. as @@ -126,10 +126,10 @@ namespace AMDiS /// Return the const DOFVector using Super::coefficients; - template - auto child(Path const& path = {}) + template + auto child(Indices... ii) { - auto tp = cat(this->treePath_, makeTreePath(path)); + auto tp = cat(this->treePath_, treepath(ii...)); return makeDiscreteFunction(*mutableCoeff_, this->basis(), tp); } @@ -223,10 +223,10 @@ namespace AMDiS return *coefficients_; } - template - auto child(Path const& path = {}) const + template + auto child(Indices... ii) const { - auto tp = cat(this->treePath_, makeTreePath(path)); + auto tp = cat(this->treePath_, treepath(ii...)); return makeDiscreteFunction(*coefficients_, *basis_, tp); } diff --git a/amdis/io/FileWriterCreator.hpp b/amdis/io/FileWriterCreator.hpp index c25e816b..65c1b7f3 100644 --- a/amdis/io/FileWriterCreator.hpp +++ b/amdis/io/FileWriterCreator.hpp @@ -40,13 +40,13 @@ namespace AMDiS /** * \param type String representing the type of the writer. One of {vtk, dune-vtk, gmsh, backup} * \param prefix The initfile prefix tp configure the filewriter - * \param treePath Treepath to the component of the systemVector to be handled by the fileWriter. + * \param ii... Indices of the treepath to the component of the systemVector to be handled by the fileWriter. **/ - template + template std::unique_ptr - create(std::string type, std::string prefix, TreePath treePath = {}) const + create(std::string type, std::string prefix, Indices... ii) const { - auto data = makeDiscreteFunction(*systemVector_, treePath); + auto data = discreteFunction(*systemVector_, ii...); return create_impl(std::move(type), std::move(prefix), data, Dune::PriorityTag<42>{}); } diff --git a/amdis/typetree/TreeContainer.hpp b/amdis/typetree/TreeContainer.hpp index 652ad87d..159cb14c 100644 --- a/amdis/typetree/TreeContainer.hpp +++ b/amdis/typetree/TreeContainer.hpp @@ -260,7 +260,7 @@ namespace AMDiS return ValueAndContainer{ value(node), Tools::apply_indices( - [&](auto... i) { return Dune::makeTupleVector((*this)(node.child(i))...); })}; + [&](auto... ii) { return Dune::makeTupleVector((*this)(node.child(ii))...); })}; } else { static_assert(Node::isLeaf || Node::isPower || Node::isComposite, diff --git a/docs/reference/DOFVector.md b/docs/reference/DOFVector.md index 23a40917..8b0938b2 100644 --- a/docs/reference/DOFVector.md +++ b/docs/reference/DOFVector.md @@ -126,33 +126,33 @@ DOFVector> vec2(std::move(basis2)); - Generator function to construct a DOFVector: [`makeDOFVector()`](#function-makedofvector) -## function `DOFVector::child` +## function `DOFVector::discreteFunction` ```c++ -template -auto child(TreePath const& path = {}) // (1) +template +auto discreteFunction(Indices... ii) // (1) -template -auto child(TreePath const& path = {}) const // (2) +template +auto discreteFunction(Indices... ii) const // (2) ``` -(1) Creates a mutable `DiscreteFunction` representing the sub-space w.r.t. the passed tree-path. The `path` thereby +(1) Creates a mutable `DiscreteFunction` representing the sub-space w.r.t. the passed tree-path. The path `{ii...}` thereby refers to the hierarchic global basis. -(2) Creates a constant `DiscreteFunction` representing the sub-space w.r.t. the passed tree-path. The `path` thereby +(2) Creates a constant `DiscreteFunction` representing the sub-space w.r.t. the passed tree-path. The path `{ii...}` thereby refers to the hierarchic global basis. #### Arguments -`TreePath path` -: A Treepath identifying a node in the basis tree. +`Indices... ii` +: Components of the tree-path identifying the basis node #### Example ```c++ DOFVector vec(basis); -auto vec_ = vec.child(); -auto vec_0 = vec.child(_0); -auto vec_10 = vec.child(treepath(_1,0)); +auto vec_ = vec.discreteFunction(); +auto vec_0 = vec.discreteFunction(_0); +auto vec_10 = vec.discreteFunction(_1,0); ``` @@ -343,7 +343,7 @@ only available for the const or mutable `is_const` template parameter specializa defined on. The type of the treePath also defines the `Range` type of the DiscreteFunction. #### See Also -- Generator function to construct a DiscreteFunction: [`makeDiscreteFunction()`](#function-makediscretefunction) +- Generator function to construct a DiscreteFunction: [`discreteFunction()`](#function-discretefunction) ## function `DiscreteFunction::entitySet` @@ -382,25 +382,25 @@ Returns the const (1) or mutable (2) coefficient vector. ## function `DiscreteFunction::child` ```c++ // (1) -template -auto child(TreePath const& path = {}) const +template +auto child(Indices... ii) const // (2) -template -auto child(TreePath const& path = {}) +template +auto child(Indices... ii) ``` Returns the const (1) or mutable (2) sub-range view of the stored DOFVector. #### Arguments -`TreePath path` -: A Treepath identifying a node in the basis tree. +`Indices... ii` +: Components of the tree-path identifying a node in the basis tree. #### Example ```c++ ParallelGlobalBasis basis(gridView, power<3>(lagrange<1>())); auto vec = makeDOFVector(basis); -auto df = makeDiscreteFunction(vec); +auto df = discreteFunction(vec); auto df1 = df.child(); auto df2 = df.child(0); @@ -462,8 +462,8 @@ Note, the range type of the expression must be compatible with the `Range` type ParallelGlobalBasis basis(gridView, power<3>(lagrange<1>())); auto vec = makeDOFVector(basis); -auto df1 = vec.child(); -auto df2 = vec.child(0); +auto df1 = vec.discreteFunction(); +auto df2 = vec.discreteFunction(0); // Range type is FieldVector df1 << [](FieldVector const& x) -> FieldVector { return x; }; @@ -519,8 +519,8 @@ using namespace Dune::Functions::BasisFactory; ParallelGlobalBasis basis(gridView, power<2>(lagrange<2>())); auto vec = makeDOFVector(basis1); -auto df1 = makeDiscreteFunction(vec); -auto df2 = makeDiscreteFunction(vec, 1); -auto df3 = makeDiscreteFunction(vec, _1); -auto df4 = makeDiscreteFunction(vec, Dune::TypeTree::hybridTreePath(0)); +auto df1 = discreteFunction(vec); +auto df2 = discreteFunction(vec, 1); +auto df3 = discreteFunction(vec, _1); +auto df4 = discreteFunction(vec, Dune::TypeTree::hybridTreePath(0)); ``` diff --git a/test/BackupRestoreTest.cpp b/test/BackupRestoreTest.cpp index 4749405f..e5c97eb8 100644 --- a/test/BackupRestoreTest.cpp +++ b/test/BackupRestoreTest.cpp @@ -59,15 +59,15 @@ void test(Factory factory) AMDIS_TEST_EQ(num_vertices, prob.grid()->size(Grid::dimension)); DOFVector vec(prob.globalBasis()); - vec.child(Dune::Indices::_0) << [](auto const& x) { return x; }; - vec.child(Dune::Indices::_1) << [](auto const& x) { return two_norm(x); }; + vec.discreteFunction(Dune::Indices::_0) << [](auto const& x) { return x; }; + vec.discreteFunction(Dune::Indices::_1) << [](auto const& x) { return two_norm(x); }; double error0 = std::sqrt(integrate( - unary_dot(prob.solution(Dune::Indices::_0) - vec.child(Dune::Indices::_0)), prob.gridView())); + unary_dot(prob.solution(Dune::Indices::_0) - vec.discreteFunction(Dune::Indices::_0)), prob.gridView())); AMDIS_TEST(error0 < 1.e-10); double error1 = std::sqrt(integrate( - pow<2>(prob.solution(Dune::Indices::_1) - vec.child(Dune::Indices::_1)), prob.gridView())); + pow<2>(prob.solution(Dune::Indices::_1) - vec.discreteFunction(Dune::Indices::_1)), prob.gridView())); AMDIS_TEST(error1 < 1.e-10); } } diff --git a/test/DiscreteFunctionTest.cpp b/test/DiscreteFunctionTest.cpp index a1f60471..607c5d79 100644 --- a/test/DiscreteFunctionTest.cpp +++ b/test/DiscreteFunctionTest.cpp @@ -54,9 +54,9 @@ int main(int argc, char** argv) auto U1 = *prob.solutionVector(); auto U2 = *prob.solutionVector(); - auto u0 = makeDiscreteFunction(U0); - auto u1 = makeDiscreteFunction(U1); - auto u2 = makeDiscreteFunction(U2); + auto u0 = discreteFunction(U0); + auto u1 = discreteFunction(U1); + auto u2 = discreteFunction(U2); // Test const and mutable construction auto const& U_c = *prob.solutionVector(); @@ -65,8 +65,8 @@ int main(int argc, char** argv) DiscreteFunction u0_c(U_c.coefficients(), *U_c.basis()); DiscreteFunction u0_m(U_m.coefficients(), *U_m.basis()); - auto u1_c = makeDiscreteFunction(U_c); - auto u1_m = makeDiscreteFunction(U_m); + auto u1_c = discreteFunction(U_c); + auto u1_m = discreteFunction(U_m); // sub-range view on DiscreteFunction auto su1_c = u1_c.child(); @@ -139,19 +139,18 @@ int main(int argc, char** argv) } auto V0 = makeDOFVector(prob.globalBasis()); - auto v0 = makeDiscreteFunction(V0); + auto v0 = discreteFunction(V0); v0 << expr1; // test discreteFunction - int preTP1 = 0; - std::integral_constant preTP2; - auto tp = treepath(preTP1); + std::integral_constant _0; + auto tp = treepath(0); auto W0 = *prob.solutionVector(); auto W1 = *prob.solutionVector(); auto W2 = *prob.solutionVector(); - auto w0 = makeDiscreteFunction(W0, preTP1); - auto w1 = makeDiscreteFunction(W1, preTP2); - auto w2 = makeDiscreteFunction(W2, tp); + auto w0 = discreteFunction(W0, 0); + auto w1 = discreteFunction(W1, _0); + auto w2 = discreteFunction(W2, tp); // test discreteFunction with (pre)treepath argument auto expr = [](auto const& x) { return 1 + x[0] + x[1]; }; @@ -160,9 +159,9 @@ int main(int argc, char** argv) auto W5 = *prob.solutionVector(); auto W7 = *prob.solutionVector(); auto W8 = *prob.solutionVector(); - auto w3 = makeDiscreteFunction(W3, preTP1); - auto w4 = makeDiscreteFunction(W4, preTP2); - auto w5 = makeDiscreteFunction(W5, tp); + auto w3 = discreteFunction(W3, 0); + auto w4 = discreteFunction(W4, _0); + auto w5 = discreteFunction(W5, tp); auto w6 = prob.solution(tp); auto& W6 = *prob.solutionVector(); w3 << expr; @@ -174,9 +173,9 @@ int main(int argc, char** argv) AMDIS_TEST( comp(W3, W6) ); // test interpolation on subbasis - auto w7 = makeDiscreteFunction(W7); - auto w8_0 = makeDiscreteFunction(W8, 0); - auto w8_1 = makeDiscreteFunction(W8, 1); + auto w7 = discreteFunction(W7); + auto w8_0 = discreteFunction(W8, 0); + auto w8_1 = discreteFunction(W8, 1); w7 << expr; w8_0 << expr; w8_1 << expr; diff --git a/test/GradientTest.cpp b/test/GradientTest.cpp index 23a7005f..f5e566d5 100644 --- a/test/GradientTest.cpp +++ b/test/GradientTest.cpp @@ -29,9 +29,9 @@ void test() auto uVector = makeDOFVector(basis); - auto u = makeDiscreteFunction(uVector); - auto u_0 = makeDiscreteFunction(uVector, 0); - auto u_1 = makeDiscreteFunction(uVector, 1); + auto u = discreteFunction(uVector); + auto u_0 = discreteFunction(uVector, 0); + auto u_1 = discreteFunction(uVector, 1); // eval a functor at global coordinates (at quadrature points) u_0 << evalAtQP([](auto const& x) { return x[0] + x[1]; }); @@ -66,9 +66,9 @@ void test() (integrate(partialAtQP(u_0,0) + partialAtQP(u_1,1), gridView))); auto vVector(uVector); - auto v = makeDiscreteFunction(vVector); - auto v_0 = makeDiscreteFunction(vVector, 0); - auto v_1 = makeDiscreteFunction(vVector, 1); + auto v = discreteFunction(vVector); + auto v_0 = discreteFunction(vVector, 0); + auto v_1 = discreteFunction(vVector, 1); // test gradient v << evalAtQP([](auto const& x) { -- GitLab From 02dcede3e1175ec17435161577429ca894783bb1 Mon Sep 17 00:00:00 2001 From: Simon Praetorius Date: Sat, 10 Oct 2020 20:20:44 +0200 Subject: [PATCH 2/4] Cleanup TreePath generation --- amdis/DOFVector.hpp | 4 +- amdis/DirichletBC.hpp | 2 +- amdis/LinearForm.inc.hpp | 1 + amdis/PeriodicBC.hpp | 2 +- amdis/ProblemStat.hpp | 16 ++-- amdis/ProblemStat.inc.hpp | 4 +- amdis/gridfunctions/DiscreteFunction.hpp | 33 +++---- amdis/typetree/TreePath.hpp | 105 ++++++++++------------- docs/reference/DOFVector.md | 57 +----------- docs/reference/GlobalBasis.md | 10 +-- docs/reference/Operators.md | 2 +- docs/reference/Problem.md | 14 +-- examples/navier_stokes.cc | 4 +- examples/stokes0.cc | 6 +- examples/stokes1.cc | 2 +- test/AdaptInfoTest.cpp | 4 +- test/CMakeLists.txt | 3 + test/DiscreteFunctionTest.cpp | 6 +- test/TreePathTest.cpp | 39 +++++++++ 19 files changed, 140 insertions(+), 174 deletions(-) create mode 100644 test/TreePathTest.cpp diff --git a/amdis/DOFVector.hpp b/amdis/DOFVector.hpp index 4ad69a0c..c2bed839 100644 --- a/amdis/DOFVector.hpp +++ b/amdis/DOFVector.hpp @@ -89,14 +89,14 @@ namespace AMDiS template auto discreteFunction(Indices... ii) { - return makeDiscreteFunction(coefficients(), *basis_, treepath(ii...)); + return DiscreteFunction{coefficients(), *basis_, makeTreePath(ii...)}; } /// Transform the DOFVector into a DiscreteFunction template auto discreteFunction(Indices... ii) const { - return makeDiscreteFunction(coefficients(), *basis_, treepath(ii...)); + return DiscreteFunction{coefficients(), *basis_, makeTreePath(ii...)}; } diff --git a/amdis/DirichletBC.hpp b/amdis/DirichletBC.hpp index 45910098..413fbe33 100644 --- a/amdis/DirichletBC.hpp +++ b/amdis/DirichletBC.hpp @@ -130,7 +130,7 @@ namespace AMDiS BoundarySubset boundarySubset, Values&& values) { - return makeDirichletBC(rowBasis, treepath(), colBasis, treepath(), + return makeDirichletBC(rowBasis, makeTreePath(), colBasis, makeTreePath(), std::move(boundarySubset), FWD(values)); } diff --git a/amdis/LinearForm.inc.hpp b/amdis/LinearForm.inc.hpp index fcaba36b..42f224fb 100644 --- a/amdis/LinearForm.inc.hpp +++ b/amdis/LinearForm.inc.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include namespace AMDiS { diff --git a/amdis/PeriodicBC.hpp b/amdis/PeriodicBC.hpp index 3ddef043..35255465 100644 --- a/amdis/PeriodicBC.hpp +++ b/amdis/PeriodicBC.hpp @@ -161,7 +161,7 @@ namespace AMDiS BoundarySubset boundarySubset, Impl::FaceTrafo trafo) { - return makePeriodicBC(basis, treepath(), std::move(boundarySubset), + return makePeriodicBC(basis, makeTreePath(), std::move(boundarySubset), std::move(trafo)); } diff --git a/amdis/ProblemStat.hpp b/amdis/ProblemStat.hpp index c86e85f1..8d806cd9 100644 --- a/amdis/ProblemStat.hpp +++ b/amdis/ProblemStat.hpp @@ -148,9 +148,9 @@ namespace AMDiS * * \param op A (pre-) local operator, \see LocalOperator, \see GridFunctionOperator * \param row TreePath identifying the sub-basis in the global basis tree - * corresponding to the row basis. \see treepath() + * corresponding to the row basis. \see makeTreePath() * \param col TreePath identifying the sub-basis in the global basis tree - * corresponding to the column basis. \see treepath() + * corresponding to the column basis. \see makeTreePath() * * Example: * ``` @@ -173,9 +173,9 @@ namespace AMDiS * constructed from an integer. \see BoundaryType * \param op A (pre-) local operator, \see LocalOperator, \see GridFunctionOperator * \param row TreePath identifying the sub-basis in the global basis tree - * corresponding to the row basis. \see treepath() + * corresponding to the row basis. \see makeTreePath() * \param col TreePath identifying the sub-basis in the global basis tree - * corresponding to the column basis. \see treepath() + * corresponding to the column basis. \see makeTreePath() * * Example: * ``` @@ -201,7 +201,7 @@ namespace AMDiS * * \param op A (pre-) local operator, \see LocalOperator, \see GridFunctionOperator * \param path TreePath identifying the sub-basis in the global basis tree - * corresponding to the row basis. \see treepath() + * corresponding to the row basis. \see makeTreePath() * * Example: * ``` @@ -224,7 +224,7 @@ namespace AMDiS * constructed from an integer. \see BoundaryType * \param op A (pre-) local operator, \see LocalOperator, \see GridFunctionOperator * \param path TreePath identifying the sub-basis in the global basis tree - * corresponding to the row basis. \see treepath() + * corresponding to the row basis. \see makeTreePath() * * Example: * ``` @@ -251,9 +251,9 @@ namespace AMDiS * \param predicate Functor `bool(WorldVector)` returning true for all * DOFs on the boundary that should be assigned a value. * \param row TreePath identifying the sub-basis in the global basis tree - * corresponding to the row basis. \see treepath() + * corresponding to the row basis. \see makeTreePath() * \param col TreePath identifying the sub-basis in the global basis tree - * corresponding to the column basis. \see treepath() + * corresponding to the column basis. \see makeTreePath() * \param values Functor `Range(WorldVector)` or any \ref GridFunction * that is evaluated in the DOFs identified by the predicate. * diff --git a/amdis/ProblemStat.inc.hpp b/amdis/ProblemStat.inc.hpp index 975e8cf4..af4d67ca 100644 --- a/amdis/ProblemStat.inc.hpp +++ b/amdis/ProblemStat.inc.hpp @@ -335,10 +335,10 @@ void ProblemStat:: addPeriodicBC(BoundaryType id, WorldMatrix const& matrix, WorldVector const& vector) { auto localView = globalBasis_->localView(); - auto basis = Dune::Functions::subspaceBasis(*globalBasis_, treepath()); + auto basis = Dune::Functions::subspaceBasis(*globalBasis_, makeTreePath()); auto bc = makePeriodicBC( std::move(basis), {*boundaryManager_, id}, {matrix, vector}); - boundaryConditions_[treepath()][treepath()].push_back(makeUniquePtr(std::move(bc))); + boundaryConditions_[makeTreePath()][makeTreePath()].push_back(makeUniquePtr(std::move(bc))); } diff --git a/amdis/gridfunctions/DiscreteFunction.hpp b/amdis/gridfunctions/DiscreteFunction.hpp index 038e559d..ada77d7c 100644 --- a/amdis/gridfunctions/DiscreteFunction.hpp +++ b/amdis/gridfunctions/DiscreteFunction.hpp @@ -28,23 +28,14 @@ namespace AMDiS * **Requirements:** * - GB models \ref Concepts::GlobalBasis **/ - template > + template class DiscreteFunction; // deduction guide - template - DiscreteFunction(Coeff&, GB const&, TreePath = {}) - -> DiscreteFunction>; - - - /// A Generator for a mutable \ref DiscreteFunction - template ().localView())> > - auto makeDiscreteFunction(Coeff& coefficients, GB const& basis, Path const& path = {}) - { - return DiscreteFunction>{coefficients, basis, path}; - } + template + DiscreteFunction(Coeff&, GB const&, Path const& path) + -> DiscreteFunction; /// A mutable view on the subspace of a DOFVector, \relates DiscreteFunction @@ -61,8 +52,8 @@ namespace AMDiS public: /// Constructor. Stores a pointer to the mutable `dofvector`. - template - DiscreteFunction(Coefficients& dofVector, GlobalBasis const& basis, Path const& path = {}) + template + DiscreteFunction(Coefficients& dofVector, GlobalBasis const& basis, Path const& path) : Super(dofVector, basis, path) , mutableCoeff_(&dofVector) {} @@ -129,8 +120,8 @@ namespace AMDiS template auto child(Indices... ii) { - auto tp = cat(this->treePath_, treepath(ii...)); - return makeDiscreteFunction(*mutableCoeff_, this->basis(), tp); + auto tp = cat(this->treePath_, makeTreePath(ii...)); + return DiscreteFunction{*mutableCoeff_, this->basis(), tp}; } using Super::child; @@ -181,8 +172,8 @@ namespace AMDiS public: /// Constructor. Stores a pointer to the dofVector and a copy of the treePath. - template - DiscreteFunction(Coefficients const& coefficients, GlobalBasis const& basis, Path const& path = {}) + template + DiscreteFunction(Coefficients const& coefficients, GlobalBasis const& basis, Path const& path) : coefficients_(&coefficients) , basis_(&basis) , treePath_(makeTreePath(path)) @@ -226,8 +217,8 @@ namespace AMDiS template auto child(Indices... ii) const { - auto tp = cat(this->treePath_, treepath(ii...)); - return makeDiscreteFunction(*coefficients_, *basis_, tp); + auto tp = cat(this->treePath_, makeTreePath(ii...)); + return DiscreteFunction{*coefficients_, *basis_, tp}; } protected: diff --git a/amdis/typetree/TreePath.hpp b/amdis/typetree/TreePath.hpp index d6d6dfda..8ad846c9 100644 --- a/amdis/typetree/TreePath.hpp +++ b/amdis/typetree/TreePath.hpp @@ -23,29 +23,24 @@ namespace AMDiS namespace Definition { - template + template struct IsPreTreePath - : std::is_integral + : std::is_integral {}; - template - struct IsPreTreePath> - : std::true_type + template + struct IsPreTreePath> + : std::is_integral {}; - template - struct IsPreTreePath> - : std::true_type + template + struct IsPreTreePath> + : std::is_integral {}; - template - struct IsPreTreePath> - : std::true_type - {}; - - template - struct IsPreTreePath> - : std::true_type + template + struct IsPreTreePath> + : std::conjunction...> {}; template <> @@ -65,6 +60,24 @@ namespace AMDiS } // end namespace Concepts + namespace Impl + { + template , int> = 0> + std::size_t treePathIndex(Index i) + { + return std::size_t(i); + } + + template , int> = 0> + auto treePathIndex(std::integral_constant) + { + return std::integral_constant{}; + } + + } // end namespace Impl + #ifdef DOXYGEN /// \brief Converts a (pre)TreePath into a HybridTreePath @@ -82,7 +95,7 @@ namespace AMDiS * ``` * makeTreePath(1), * makeTreePath(int_<2>), - * makeTreePath(treepath(1, int_<2>)) + * makeTreePath(1, index_<2>) * ``` **/ template @@ -90,35 +103,34 @@ namespace AMDiS #else // DOXYGEN - inline auto makeTreePath(int i) { return Dune::TypeTree::hybridTreePath(std::size_t(i)); } - inline auto makeTreePath(std::size_t i) { return Dune::TypeTree::hybridTreePath(i); } - inline auto makeTreePath(RootTreePath) { return Dune::TypeTree::hybridTreePath(); } - - - template - auto makeTreePath(std::integral_constant) + template + auto makeTreePath(Indices... ii) + -> decltype( Dune::TypeTree::hybridTreePath(Impl::treePathIndex(ii)...) ) { - return Dune::TypeTree::hybridTreePath(std::integral_constant{}); + return Dune::TypeTree::hybridTreePath(Impl::treePathIndex(ii)...); } - template - auto makeTreePath(std::integer_sequence) + inline auto makeTreePath() { - return Dune::TypeTree::hybridTreePath(std::integral_constant{}...); + return Dune::TypeTree::hybridTreePath(); } - template - auto makeTreePath(std::integral_constant _i) + inline auto makeTreePath(RootTreePath) { - return Dune::TypeTree::hybridTreePath(_i); + return makeTreePath(); } - template - auto makeTreePath(std::index_sequence) + template + auto makeTreePath(std::integer_sequence) { - return Dune::TypeTree::hybridTreePath(std::integral_constant{}...); + return makeTreePath(std::integral_constant{}...); } + template + auto makeTreePath(std::tuple const& tp) + { + return std::apply([](auto... ii) { return makeTreePath(ii...); }, tp); + } template auto const& makeTreePath(Dune::TypeTree::HybridTreePath const& tp) @@ -140,18 +152,6 @@ namespace AMDiS } #endif - template - auto makeTreePath(TP const&) - { - static_assert( Concepts::PreTreePath, - "Argument must be a valid treepath, or an integer/index-constant"); - return Dune::TypeTree::hybridTreePath(); - } - - /// Type of the generated treepath - template - using TreePath_t = TYPEOF(makeTreePath(std::declval())); - #endif // DOXYGEN @@ -200,19 +200,6 @@ namespace AMDiS return {{0u}}; } - /// \brief Generate a TreePath from a sequence of integers and integral-constants - /** - * Converts a sequence of arguments to a \ref Dune::TypeTree::HybridTreePath. - * The arguments can be one of - * - integer type (`int, std::size_t`) - * - integral constant (`std::integral_constant, index_t`) - **/ - template - constexpr Dune::TypeTree::HybridTreePath treepath(T const&... t) - { - return Dune::TypeTree::HybridTreePath(t...); - } - namespace Impl { diff --git a/docs/reference/DOFVector.md b/docs/reference/DOFVector.md index 8b0938b2..eee492dc 100644 --- a/docs/reference/DOFVector.md +++ b/docs/reference/DOFVector.md @@ -153,6 +153,7 @@ DOFVector vec(basis); auto vec_ = vec.discreteFunction(); auto vec_0 = vec.discreteFunction(_0); auto vec_10 = vec.discreteFunction(_1,0); +auto vec_10_b ? discreteFunction(vec,_1,0); ``` @@ -342,9 +343,6 @@ only available for the const or mutable `is_const` template parameter specializa : A `Dune::TypeTree::HybridTreePath<...>` representing the coordinates of a node in the basis tree this DiscreteFunction is defined on. The type of the treePath also defines the `Range` type of the DiscreteFunction. -#### See Also -- Generator function to construct a DiscreteFunction: [`discreteFunction()`](#function-discretefunction) - ## function `DiscreteFunction::entitySet` ```c++ @@ -471,56 +469,3 @@ df1 << [](FieldVector const& x) -> FieldVector { return x; } // Range type is double df2 += 42.0; ``` - - -## function `makeDiscreteFunction` -Defined in header [``](https://gitlab.mn.tu-dresden.de/amdis/amdis-core/blob/master/amdis/gridfunctions/DiscreteFunction.hpp) - -```c++ -// (1) -template > -auto makeDiscreteFunction(DOFVector const& dofVector, - GlobalBasis const& basis, - PreTreePath const& preTreePath = {}) -// (2) -template > -auto makeDiscreteFunction(DOFVector& dofVector, - GlobalBasis const& basis, - PreTreePath const& preTreePath = {}) -``` - -Constructs a const (1) or mutable (2) DiscreteFunction from a `DOFVector` and a tree path. The TreePath can therby -by given by a pree-tree path, i.e. a sequence of integers or integral constants a `Dune::TypeTree::HybridTreePath` -can be constructed from. - -#### Arguments -`DOFVector<...> dofVector` -: The container storing the global coefficients. Is stored as pointer in the DiscreteFunction and thus must have a longer lifetime - than the DiscreteFunction. - -`GlobalBasis const& basis` -: The global basis associated to dofVector. - -`PreTreePath preTreePath` -: A pree-tree path, a `Dune::TypeTree::HybridTreePath<...>` can be created from. - -#### Return value -Returns a `DiscreteFunction` if the `DOFVector` is const, or a -`DiscreteFunction` if the `DOFVector` is mutable. The `TREE_PATH` is -thereby given by the type of `makeTreePath(preTreePath)`. - -#### Example -```c++ -using namespace Dune::Functions::BasisFactory; - -// pass a reference to the basis -ParallelGlobalBasis basis(gridView, power<2>(lagrange<2>())); -auto vec = makeDOFVector(basis1); - -auto df1 = discreteFunction(vec); -auto df2 = discreteFunction(vec, 1); -auto df3 = discreteFunction(vec, _1); -auto df4 = discreteFunction(vec, Dune::TypeTree::hybridTreePath(0)); -``` diff --git a/docs/reference/GlobalBasis.md b/docs/reference/GlobalBasis.md index 2df96016..a8f00071 100644 --- a/docs/reference/GlobalBasis.md +++ b/docs/reference/GlobalBasis.md @@ -122,13 +122,13 @@ for_each_leaf_node(root, [&](auto const& node, auto const& tp) { #### Working on specific nodes using a TreePath {: #globalbasis-using-treepath } There are cases when we want to address a certain tree node. To come back to our Taylor-Hood example we might want to add an operator that only acts on the velocity vector or the pressure, or even just a single component of the velocity vector. For this end a type of node index exists, called `TreePath`. This defines a list of indices specifying which path to take from the root at each node on the way. For technical reasons the index type is either an `int` (for power nodes) or `std::integral_constant` for composite nodes. For convenience we can use `Dune::Indices::_0` instead of writing `std::integral_constant`. Note how indices always start at 0 and follow the order we specify when creating the `PreBasis`. -Using once again the Taylor-Hood basis we can use the `treepath(Args...)` function to convert indices into a `TreePath` for certain nodes. +Using once again the Taylor-Hood basis we can use the `makeTreePath(Args...)` function to convert indices into a `TreePath` for certain nodes. ```c++ -auto tp_v = treepath(Dune::Indices::_0); // velocity vector -auto tp_p = treepath(Dune::Indices::_1); // pressure -auto tp_v2 = treepath(Dune::Indices::_0, 1); // second component of the velocity vector -auto tp_root = treepath(); // root +auto tp_v = makeTreePath(Dune::Indices::_0); // velocity vector +auto tp_p = makeTreePath(Dune::Indices::_1); // pressure +auto tp_v2 = makeTreePath(Dune::Indices::_0, 1); // second component of the velocity vector +auto tp_root = makeTreePath(); // root ``` Recall that `localView.tree()` returns the root of the basis tree. Using a `TreePath` we can access a specific node using the free funtion `Dune::TypeTree::child(Node, TreePath)`. diff --git a/docs/reference/Operators.md b/docs/reference/Operators.md index 37f56392..5ba17127 100644 --- a/docs/reference/Operators.md +++ b/docs/reference/Operators.md @@ -130,7 +130,7 @@ prob.addVectorOperator(op2, 0_c); // define an operator added to all velocity components auto op3 = makeOperator(tag::gradtest_gradtrial{}, viscosity); for (std::size_t i = 0; i < Grid::dimensionworld; ++i) - prob.addMatrixOperator(op3, treepath(0_c,i), treepath(0_c,i)); + prob.addMatrixOperator(op3, makeTreePath(0_c,i), makeTreePath(0_c,i)); ``` #### Quadrature arguments diff --git a/docs/reference/Problem.md b/docs/reference/Problem.md index ab11f6ff..11591822 100644 --- a/docs/reference/Problem.md +++ b/docs/reference/Problem.md @@ -228,11 +228,11 @@ void addMatrixOperator(BoundaryType b, Operator const& op, RowTreePath row = {}, `RowTreePath row` : TreePath identifying the sub-basis in the global basis tree corresponding - to the row basis, see [`treepath()`](TypeTree#function-treepath) + to the row basis, see [`makeTreePath()`](TypeTree#function-makeTreePath) `ColTreePath col` : TreePath identifying the sub-basis in the global basis tree corresponding - to the column basis, see [`treepath()`](TypeTree#function-treepath) + to the column basis, see [`makeTreePath()`](TypeTree#function-makeTreePath) `BoundaryType b` : Boundary indentifier/number to set on which part of the boundary to assemble @@ -243,7 +243,7 @@ void addMatrixOperator(BoundaryType b, Operator const& op, RowTreePath row = {}, the root node in the basis tree. The tree-paths can be constructed from integers or integral-constants, or by using - the [`treepath()`](TypeTree#function-treepath) function. It is then transformed into + the [`makeTreePath()`](TypeTree#function-makeTreePath) function. It is then transformed into a `Dune::TypeTree::HybridTreePath<...>` type. #### Examples @@ -285,7 +285,7 @@ side vector of the linear system `TreePath path` : TreePath identifying the sub-basis in the global basis tree - corresponding to the row basis, see [`treepath()`](TypeTree#function-treepath) + corresponding to the row basis, see [`makeTreePath()`](TypeTree#function-makeTreePath) `BoundaryType b` : Boundary indentifier/number to set on which part of the boundary to assemble @@ -296,7 +296,7 @@ side vector of the linear system the root node in the basis tree. The tree-path can be constructed from integers or integral-constants, or by using - the [`treepath()`](TypeTree#function-treepath) function. It is then transformed into + the [`makeTreePath()`](TypeTree#function-makeTreePath) function. It is then transformed into a `Dune::TypeTree::HybridTreePath<...>` type. #### Examples @@ -341,11 +341,11 @@ set in the `BoundaryManager` before. `RowTreePath row` : TreePath identifying the sub-basis in the global basis tree corresponding - to the row basis, see [`treepath()`](TypeTree#function-treepath) + to the row basis, see [`makeTreePath()`](TypeTree#function-makeTreePath) `ColTreePath col` : TreePath identifying the sub-basis in the global basis tree corresponding - to the column basis, see [`treepath()`](TypeTree#function-treepath) + to the column basis, see [`makeTreePath()`](TypeTree#function-makeTreePath) `Values values` : A [`GridFunction`](GridFunctions) evaluating to the Dirichlet values that diff --git a/examples/navier_stokes.cc b/examples/navier_stokes.cc index 0e4c9ff2..da6ec48b 100644 --- a/examples/navier_stokes.cc +++ b/examples/navier_stokes.cc @@ -53,7 +53,7 @@ int main(int argc, char** argv) // sum_i + + auto opStokes = makeOperator(tag::stokes{}, viscosity); - prob.addMatrixOperator(opStokes, treepath(), treepath()); + prob.addMatrixOperator(opStokes, makeTreePath(), makeTreePath()); // <(u * nabla)u_i^old, v_i> auto opNonlin1 = makeOperator(tag::testvec_trialvec{}, @@ -64,7 +64,7 @@ int main(int argc, char** argv) // <(u^old * nabla)u_i, v_i> auto opNonlin2 = makeOperator(tag::test_gradtrial{}, density * prob.solution(_v)); - prob.addMatrixOperator(opNonlin2, treepath(_v,i), treepath(_v,i)); + prob.addMatrixOperator(opNonlin2, makeTreePath(_v,i), makeTreePath(_v,i)); } // <(u^old * grad(u_i^old)), v_i> diff --git a/examples/stokes0.cc b/examples/stokes0.cc index 979182b5..acbf4c0f 100644 --- a/examples/stokes0.cc +++ b/examples/stokes0.cc @@ -25,15 +25,15 @@ int main(int argc, char** argv) for (std::size_t i = 0; i < WORLDDIM; ++i) { // auto opL = makeOperator(tag::gradtest_gradtrial{}, viscosity); - prob.addMatrixOperator(opL, treepath(_v,i), treepath(_v,i)); + prob.addMatrixOperator(opL, makeTreePath(_v,i), makeTreePath(_v,i)); // auto opP = makeOperator(tag::partialtest_trial{i}, 1.0); - prob.addMatrixOperator(opP, treepath(_v,i), _p); + prob.addMatrixOperator(opP, makeTreePath(_v,i), _p); // auto opDiv = makeOperator(tag::test_partialtrial{i}, 1.0); - prob.addMatrixOperator(opDiv, _p, treepath(_v,i)); + prob.addMatrixOperator(opDiv, _p, makeTreePath(_v,i)); } // define boundary values diff --git a/examples/stokes1.cc b/examples/stokes1.cc index 50581ed6..6027ef01 100644 --- a/examples/stokes1.cc +++ b/examples/stokes1.cc @@ -25,7 +25,7 @@ int main(int argc, char** argv) for (std::size_t i = 0; i < WORLDDIM; ++i) { // auto opL = makeOperator(tag::gradtest_gradtrial{}, viscosity); - prob.addMatrixOperator(opL, treepath(_v,i), treepath(_v,i)); + prob.addMatrixOperator(opL, makeTreePath(_v,i), makeTreePath(_v,i)); } // diff --git a/test/AdaptInfoTest.cpp b/test/AdaptInfoTest.cpp index 7264e307..ad267b1d 100644 --- a/test/AdaptInfoTest.cpp +++ b/test/AdaptInfoTest.cpp @@ -13,8 +13,8 @@ int main() { AdaptInfo adaptInfo("adapt"); - auto root_tp = treepath(); - auto tp = treepath(0_c); + auto root_tp = makeTreePath(); + auto tp = makeTreePath(0_c); std::string str = "0"; adaptInfo.setEstSum(0.1, tp); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index ded27d37..67df8fd1 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -149,6 +149,9 @@ dune_add_test(SOURCES SwitchCasesTest.cpp dune_add_test(SOURCES TreeContainerTest.cpp LINK_LIBRARIES amdis) +dune_add_test(SOURCES TreePathTest.cpp + LINK_LIBRARIES amdis) + dune_add_test(SOURCES UniqueBorderPartitionTest.cpp LINK_LIBRARIES amdis MPI_RANKS 2 diff --git a/test/DiscreteFunctionTest.cpp b/test/DiscreteFunctionTest.cpp index 607c5d79..55ee59f9 100644 --- a/test/DiscreteFunctionTest.cpp +++ b/test/DiscreteFunctionTest.cpp @@ -62,8 +62,8 @@ int main(int argc, char** argv) auto const& U_c = *prob.solutionVector(); auto& U_m = *prob.solutionVector(); - DiscreteFunction u0_c(U_c.coefficients(), *U_c.basis()); - DiscreteFunction u0_m(U_m.coefficients(), *U_m.basis()); + DiscreteFunction u0_c(U_c.coefficients(), *U_c.basis(), makeTreePath()); + DiscreteFunction u0_m(U_m.coefficients(), *U_m.basis(), makeTreePath()); auto u1_c = discreteFunction(U_c); auto u1_m = discreteFunction(U_m); @@ -144,7 +144,7 @@ int main(int argc, char** argv) // test discreteFunction std::integral_constant _0; - auto tp = treepath(0); + auto tp = makeTreePath(0); auto W0 = *prob.solutionVector(); auto W1 = *prob.solutionVector(); auto W2 = *prob.solutionVector(); diff --git a/test/TreePathTest.cpp b/test/TreePathTest.cpp new file mode 100644 index 00000000..d2649972 --- /dev/null +++ b/test/TreePathTest.cpp @@ -0,0 +1,39 @@ +#include + +#include +#include +#include +#include + +#include "Tests.hpp" + +using namespace AMDiS; +using namespace Dune::Indices; + +int main (int argc, char** argv) +{ + Environment env(argc, argv); + + static_assert( std::is_same_v< + Dune::TypeTree::HybridTreePath<>, + TYPEOF(makeTreePath())> ); + + static_assert( std::is_same_v< + Dune::TypeTree::HybridTreePath<>, + TYPEOF(makeTreePath(std::declval()))> ); + + static_assert( std::is_same_v< + Dune::TypeTree::HybridTreePath, + TYPEOF(makeTreePath(0))> ); + + static_assert( std::is_same_v< + Dune::TypeTree::HybridTreePath>, + TYPEOF(makeTreePath(0,_1))> ); + + static_assert( std::is_same_v< + Dune::TypeTree::HybridTreePath>, + TYPEOF(makeTreePath(std::tuple{0,_1}))> ); + + auto tp = Dune::TypeTree::hybridTreePath(1u, _2); + static_assert( std::is_same_v ); +} -- GitLab From aaf4cc91258916454e582539cbc58a1214fad43e Mon Sep 17 00:00:00 2001 From: "Praetorius, Simon" Date: Tue, 13 Oct 2020 22:29:02 +0200 Subject: [PATCH 3/4] Apply 1 suggestion(s) to 1 file(s) --- docs/reference/DOFVector.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/DOFVector.md b/docs/reference/DOFVector.md index eee492dc..f49842d6 100644 --- a/docs/reference/DOFVector.md +++ b/docs/reference/DOFVector.md @@ -153,7 +153,7 @@ DOFVector vec(basis); auto vec_ = vec.discreteFunction(); auto vec_0 = vec.discreteFunction(_0); auto vec_10 = vec.discreteFunction(_1,0); -auto vec_10_b ? discreteFunction(vec,_1,0); +auto vec_10_b = discreteFunction(vec,_1,0); ``` -- GitLab From 8dd06e223a256875a72684904179b89947223347 Mon Sep 17 00:00:00 2001 From: Simon Praetorius Date: Tue, 13 Oct 2020 22:38:57 +0200 Subject: [PATCH 4/4] update documentation of makeTreePath --- amdis/typetree/TreePath.hpp | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/amdis/typetree/TreePath.hpp b/amdis/typetree/TreePath.hpp index 8ad846c9..efd66a03 100644 --- a/amdis/typetree/TreePath.hpp +++ b/amdis/typetree/TreePath.hpp @@ -80,22 +80,26 @@ namespace AMDiS #ifdef DOXYGEN - /// \brief Converts a (pre)TreePath into a HybridTreePath + /// \brief Converts a sequence of indices into a HybridTreePath /** - * Converts an integer, an integralconstant or a Dune TreePath into an - * \ref Dune::TypeTree::HybridTreePath that is used in GlobalBasis traversal. + * Converts an integer, an integralconstant, a sequence of those, or a TreePath + * into an \ref Dune::TypeTree::HybridTreePath that is used in GlobalBasis traversal. * * **Requirements:** - * - `PreTreePath` one of - * + integer type (`int, std::size_t`), - * + integral constant (`std::integral_constant<[int|std::size_t], i>`) - * + any Dune TreePath (`TreePath, DynamicTreePath, HybridTreePath`) + * The arguments can be one or more of + * - integer type (`int, std::size_t`) + * - integral constant (`std::integral_constant<[int|std::size_t],i>, index_t`) + * or one of dune treepath types, e.g. + * - any Dune TreePath (`TreePath, HybridTreePath`) + * - a `std::tuple` type * * **Example:** * ``` - * makeTreePath(1), - * makeTreePath(int_<2>), - * makeTreePath(1, index_<2>) + * makeTreePath(0,1,2), + * makeTreePath(int_<2>, 0), + * makeTreePath(1, index_<2>), + * makeTreePath(hybridTreePath(0,1,2)), + * makeTreePath(std::tuple{0,index_<2>,2}) * ``` **/ template -- GitLab