Wildmeshing Toolkit
MultiMeshVisitor.hpp
Go to the documentation of this file.
1 #pragma once
2 #include <type_traits>
3 #include <variant> //to get monostage
4 #include <wmtk/Mesh.hpp>
5 #include <wmtk/Primitive.hpp>
14 #if !defined(NDEBUG)
15 #include <cassert>
16 #endif
17 
18 // TODO: extend this visitor to support const and non-const references
19 #define WMTK_MESH_VISITOR_ONLY_SUPPORTS_NONCONST_REFERENCE
20 
21 namespace wmtk::multimesh {
22 
23 // if NodeFunctor returns a value then
24 template <typename MMVisitor>
25 class MultiMeshVisitorExecutor;
26 
27 template <typename NodeFunctor_>
29 {
30 public:
32  using NodeFunctor = NodeFunctor_;
33 
34  using ReturnDataType = wmtk::utils::metaprogramming::
35  ReferenceWrappedFunctorReturnCache<NodeFunctor, MeshVariantTraits>;
37 
38  using TypeHelper = wmtk::utils::metaprogramming::detail::
39  ReferenceWrappedFunctorReturnType<NodeFunctor, MeshVariantTraits::AllReferenceTuple>;
40 
41 
42  /* @brief constructor that takes in the node and edge functors
43  *
44  * @param f The functor that will be run on each mesh in the tree
45  * */
47  : m_node_functor(f)
48  {}
49 
50 
51  template <typename MMVisitor_>
54 
55  /* @brief executes the node functor (and potentially edge functor) from the subtree of the input
56  * node
57  * @param mesh the mesh in the tree that the operation needs to run from
58  * @param simplex the simplex on the input mesh that we want to run the operation from
59  * @return a ReferenceWrappedFunctorReturnCache that lets one request (mesh,simplex) ->
60  * NodeFunctor Return type
61  * */
62  template <typename MeshType>
63  void execute_mesh(MeshType&& mesh)
64  {
65  static_assert(
66  !std::is_same_v<std::decay_t<MeshType>, Mesh>,
67  "Don't pass in a mesh, use variant/visitor to get its derived type");
68  Executor exec(*this);
69  exec.execute(std::forward<MeshType>(mesh));
70  }
71 
72  /* @brief executes the node functor (and potentially edge functor) from the entire graph
73  * @param mesh some mesh in the tree that the operation needs to run from
74  * @param simplex the simplex on the input mesh that we want to run the operation from
75  * @return a ReferenceWrappedFunctorReturnCache that lets one request (mesh,simplex) ->
76  * NodeFunctor Return type
77  * */
78  // even if you try to use an interior mesh node this always just uses the root
79  void execute_from_root(Mesh& mesh)
80  {
81  // if the user passed in a mesh class lets try re-invoking with a derived type
82  Mesh& root_base_mesh = mesh.get_multi_mesh_root();
83  auto mesh_root_variant = wmtk::utils::metaprogramming::as_mesh_variant(root_base_mesh);
84  Executor exec(*this);
85  std::visit([&](auto&& root) { execute_mesh(root.get()); }, mesh_root_variant);
86  }
87 
88 
89 protected:
91 };
92 
93 // if NodeFunctor returns a value then
94 template <typename MMVisitor>
96 {
97 public:
99  using NodeFunctor = typename MMVisitor::NodeFunctor;
100  // template <bool IsConst, typename MeshType>
101 
102  MultiMeshVisitorExecutor(const MMVisitor& v)
103  : visitor(v)
104  {}
105 
106  const MMVisitor& visitor;
107 
108 
109  /* @brief runs the node functor on every node in the subgraph and then runs hte edge functor if
110  * it exists
111  * @param mesh the mesh whose subgraph will be run
112  * @param simplex the simplex whose subgraph will be run
113  * */
114  template <typename MeshType>
115  void execute(MeshType&& mesh)
116  {
117  static_assert(std::is_base_of_v<Mesh, std::decay_t<MeshType>>);
118  run(std::forward<MeshType>(mesh));
119  }
120 
121 
122 private:
123  /* @brief runs the node functor on every node in the subgraph
124  * @param mesh the mesh whose subgraph will be run
125  * @param simplex the simplex whose subgraph will be run
126  * */
127  template <typename MeshType_>
128  void run(MeshType_&& current_mesh)
129  {
130  using MeshType = std::decay_t<MeshType_>;
131 
132 
133  // short circuit operations that happen below the desired dimension
134  constexpr static int64_t MeshDim = wmtk::utils::metaprogramming::cell_dimension_v<MeshType>;
135 
136 
137  // pre-compute all of the child tuples in case the node functor changes the mesh that
138  // breaks the traversal down
139  auto& child_datas = current_mesh.m_multi_mesh_manager.children();
140 
141  // go over each child mesh / child simplices and run the node functor on them
142  // then recurses this function onto the children
143  for (size_t child_index = 0; child_index < child_datas.size(); ++child_index) {
144  auto&& child_data = child_datas[child_index];
145  Mesh& child_mesh_base = *child_data.mesh;
146 
147 
148  auto child_mesh_variant =
150  std::visit(
151  [&](auto&& child_mesh_) noexcept {
152  auto&& child_mesh = child_mesh_.get();
153  using ChildType = std::decay_t<decltype(child_mesh)>;
154 
155  constexpr static int64_t ChildDim =
156  wmtk::utils::metaprogramming::cell_dimension_v<ChildType>;
157 
158  // std::visit compiles all combinations of meshes, and
159  // the behavior is undefined if MeshDim < ChildDim.
160  //
161  // we assert this to make sure the code is correct at
162  // runtime, we if constexpr after to make sure the
163  // compiler doesn't try to compile code in these cases
164  assert(MeshDim >= ChildDim);
165 
166  if constexpr (MeshDim >= ChildDim) {
167  run(child_mesh);
168  }
169  },
170  child_mesh_variant);
171  }
172 
173  visitor.m_node_functor(current_mesh);
174  }
175 };
176 
177 
178 template <typename NodeFunctor>
180 
181 
182 } // namespace wmtk::multimesh
Mesh & get_multi_mesh_root()
returns a reference to the root of a multimesh tree
typename MMVisitor::NodeFunctor NodeFunctor
wmtk::utils::metaprogramming::ReferenceWrappedFunctorReturnCache< NodeFunctor, MeshVariantTraits > ReturnDataType
MultiMeshVisitor(NodeFunctor &&) -> MultiMeshVisitor< NodeFunctor >
DerivedReferenceWrapperVariantTraits< Mesh, PointMesh, EdgeMesh, TriMesh, TetMesh > MeshVariantTraits
MeshVariantType as_mesh_variant(Mesh &mesh)