Wildmeshing Toolkit
Loading...
Searching...
No Matches
MultiMeshSimplexVisitor.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>
15#if !defined(NDEBUG)
16#include <cassert>
17#endif
18
19// TODO: extend this visitor to support const and non-const references
20#define WMTK_MESH_VISITOR_ONLY_SUPPORTS_NONCONST_REFERENCE
21
22namespace wmtk::multimesh {
23
24// if NodeFunctor returns a value then
25template <typename MMVisitor>
26class MultiMeshSimplexVisitorExecutor;
27
28template <int64_t cell_dimension_, typename NodeFunctor_>
30{
31public:
33 using NodeFunctor = NodeFunctor_;
34 constexpr static int64_t cell_dimension = cell_dimension_;
35
36 constexpr static bool HasReturnCache =
37 !wmtk::utils::metaprogramming::
38 all_return_void_v<NodeFunctor, MeshVariantTraits, simplex::Simplex>;
46
51#if defined(WMTK_MESH_VISITOR_ONLY_SUPPORTS_NONCONST_REFERENCE)
52 template <typename MeshType>
53 using GetReturnType_t = typename TypeHelper::template ReturnType<MeshType>;
54 template <typename MeshType>
55 constexpr static bool HasReturnValue_v = !std::is_void_v<GetReturnType_t<MeshType>>;
56#else
57 template <bool IsConst, typename MeshType>
58 using GetReturnType_t = typename TypeHelper::template ReturnType<IsConst, MeshType>;
59 template <bool IsConst, typename MeshType>
60 constexpr static bool HasReturnValue_v = !std::is_void_v<GetReturnType_t<IsConst, MeshType>>;
61#endif
62
63
64 /* @brief constructor that takes in the node and edge functors
65 *
66 * @param f The functor that will be run on each mesh in the tree
67 * */
71
72 /* @brief utility constructor that delegates a constant for class template arugment deduction
73 * @param _ deduction hint that helps pick cell_dimension
74 * @param f The functor that will be run on each mesh in the tree
75 * */
76 MultiMeshSimplexVisitor(std::integral_constant<int64_t, cell_dimension>, NodeFunctor&& f)
78 {}
79
80
81 template <typename MMVisitor_>
83 using Executor =
85
86 /* @brief executes the node functor (and potentially edge functor) from the subtree of the input
87 * node
88 * @param mesh the mesh in the tree that the operation needs to run from
89 * @param simplex the simplex on the input mesh that we want to run the operation from
90 * @return a ReferenceWrappedFunctorReturnCache that lets one request (mesh,simplex) ->
91 * NodeFunctor Return type
92 * */
93 template <typename MeshType>
94 void execute_mesh(MeshType&& mesh, const simplex::NavigatableSimplex& simplex)
95 {
96 static_assert(
97 !std::is_same_v<std::decay_t<MeshType>, Mesh>,
98 "Don't pass in a mesh, use variant/visitor to get its derived type");
99 Executor exec(*this);
100 exec.execute(std::forward<MeshType>(mesh), simplex);
101 if constexpr (HasReturnCache) {
102 m_cache = std::move(exec.m_return_data);
103 m_edge_events = std::move(exec.edge_events);
104 }
105 }
106
107 /* @brief executes the node functor (and potentially edge functor) from the entire graph
108 * @param mesh some mesh in the tree that the operation needs to run from
109 * @param simplex the simplex on the input mesh that we want to run the operation from
110 * @return a ReferenceWrappedFunctorReturnCache that lets one request (mesh,simplex) ->
111 * NodeFunctor Return type
112 * */
113 // even if you try to use an interior mesh node this always just uses the root
115 {
116 // if the user passed in a mesh class lets try re-invoking with a derived type
117 Mesh& root_base_mesh = mesh.get_multi_mesh_root();
118 auto mesh_root_variant = wmtk::utils::metaprogramming::as_mesh_variant(root_base_mesh);
119
120 const simplex::Simplex root_simplex_nonav = mesh.map_to_root(simplex);
121 assert(root_base_mesh.is_valid(root_simplex_nonav.tuple()));
122 const simplex::NavigatableSimplex root_simplex(root_base_mesh, root_simplex_nonav);
123 assert(root_base_mesh.is_valid(root_simplex.tuple()));
124 Executor exec(*this);
125 std::visit([&](auto&& root) { execute_mesh(root.get(), root_simplex); }, mesh_root_variant);
126 }
127
128 const CacheType& cache() const { return m_cache; }
129 CacheType take_cache() { return std::move(m_cache); }
130 auto node_events() const { return m_cache.keys(); }
131 const auto& edge_events() const { return m_edge_events; }
132
133protected:
136
137 using KeyType = std::
138 conditional_t<HasReturnCache, typename ReturnDataType::KeyType, std::tuple<const Mesh*>>;
139
140
141 // cache of edge events that happened
142 std::vector<std::tuple<KeyType, KeyType>> m_edge_events;
143};
144
145// if NodeFunctor returns a value then
146template <typename MMVisitor>
148{
149public:
150 constexpr static int64_t cell_dimension = MMVisitor::cell_dimension;
152 using NodeFunctor = typename MMVisitor::NodeFunctor;
153 template <typename T>
154 using GetReturnType_t = typename MMVisitor::template GetReturnType_t<T>;
155 // template <bool IsConst, typename MeshType>
156
163 constexpr static bool HasReturnCache =
164 !wmtk::utils::metaprogramming::
165 all_return_void_v<NodeFunctor, MeshVariantTraits, simplex::Simplex>;
166
168 : visitor(v)
169 {}
170
172 const MMVisitor& visitor;
173 using KeyType = std::
174 conditional_t<HasReturnCache, typename ReturnDataType::KeyType, std::tuple<const Mesh*>>;
175
176
177 // cache of edge events that happened
178 std::vector<std::tuple<KeyType, KeyType>> edge_events;
179
180
181 /* @brief runs the node functor on every node in the subgraph and then runs hte edge functor if
182 * it exists
183 * @param mesh the mesh whose subgraph will be run
184 * @param simplex the simplex whose subgraph will be run
185 * */
186 template <typename MeshType>
187 void execute(MeshType&& mesh, const simplex::NavigatableSimplex& simplex)
188 {
189 static_assert(std::is_base_of_v<Mesh, std::decay_t<MeshType>>);
190 run(std::forward<MeshType>(mesh), simplex);
191 }
192
193
194private:
195 /* @brief runs the node functor on every node in the subgraph
196 * @param mesh the mesh whose subgraph will be run
197 * @param simplex the simplex whose subgraph will be run
198 * */
199 template <typename MeshType_>
200 void run(MeshType_&& current_mesh, const simplex::NavigatableSimplex& simplex)
201 {
202 assert(current_mesh.is_valid(simplex.tuple()));
203 using MeshType = std::decay_t<MeshType_>;
204
205
206 // short circuit operations that happen below the desired dimension
207 constexpr static int64_t MeshDim = wmtk::utils::metaprogramming::cell_dimension_v<MeshType>;
208 if constexpr (cell_dimension > MeshDim) {
209 return;
210 }
211#if defined(WMTK_MESH_VISITOR_ONLY_SUPPORTS_NONCONST_REFERENCE)
212 using CurReturnType = GetReturnType_t<MeshType>;
213#else
214 constexpr static bool CurIsConst = std::is_const_v<MeshType>;
215 using CurReturnType = GetReturnType_t<CurIsConst, MeshType>;
216#endif
217
218 constexpr static bool CurHasReturn = !std::is_void_v<CurReturnType>;
219
220 // pre-compute all of the child tuples in case the node functor changes the mesh that
221 // breaks the traversal down
222 auto& child_datas = current_mesh.m_multi_mesh_manager.children();
223 std::vector<std::vector<simplex::NavigatableSimplex>> mapped_child_simplices;
224 mapped_child_simplices.reserve(child_datas.size());
225
226
227 // in-place convert this tuple into all of the child simplices
228 // TODO: this repeatedly extracts every version of hte input smiplex,
229 // we could cache this in the future
230 std::transform(
231 child_datas.begin(),
232 child_datas.end(),
233 std::back_inserter(mapped_child_simplices),
234 [&](const auto& child_data) {
235 Mesh& child_mesh = *child_data.mesh;
236
237 const std::vector<simplex::Simplex> _r =
238 current_mesh.map_to_child(child_mesh, simplex);
239 std::vector<simplex::NavigatableSimplex> r;
240 std::transform(
241 _r.begin(),
242 _r.end(),
243 std::back_inserter(r),
244 [&](const simplex::Simplex& s) {
245 return simplex::NavigatableSimplex(child_mesh, s);
246 });
247#if !defined(NDEBUG)
248 for (const auto& s : r) {
249 assert(child_mesh.is_valid(s.tuple()));
250 }
251#endif
252
253 return r;
254 });
255
256
257 // go over each child mesh / child simplices and run the node functor on them
258 // then recurses this function onto the children
259 for (size_t child_index = 0; child_index < child_datas.size(); ++child_index) {
260 auto&& child_data = child_datas[child_index];
261 auto&& simplices = mapped_child_simplices[child_index];
262 Mesh& child_mesh_base = *child_data.mesh;
263
264#if !defined(NDEBUG)
265 for (const auto& s : simplices) {
266 assert(child_mesh_base.is_valid(s.tuple()));
267 }
268#endif
269
270 auto child_mesh_variant =
272 std::visit(
273 [&](auto&& child_mesh_) noexcept {
274 auto&& child_mesh = child_mesh_.get();
275 using ChildType = std::decay_t<decltype(child_mesh)>;
276#if defined(WMTK_MESH_VISITOR_ONLY_SUPPORTS_NONCONST_REFERENCE)
277 using ChildReturnType = GetReturnType_t<ChildType>;
278#else
279 constexpr static bool ChildIsConst = std::is_const_v<ChildType>;
280 using ChildReturnType = GetReturnType_t<ChildIsConst, ChildType>;
281#endif
282
283 constexpr static bool ChildHasReturn = !std::is_void_v<ChildReturnType>;
284 constexpr static int64_t ChildDim =
285 wmtk::utils::metaprogramming::cell_dimension_v<ChildType>;
286
287 // std::visit compiles all combinations of meshes, and
288 // the behavior is undefined if MeshDim < ChildDim.
289 //
290 // we assert this to make sure the code is correct at
291 // runtime, we if constexpr after to make sure the
292 // compiler doesn't try to compile code in these cases
293 assert(MeshDim >= ChildDim);
294
295 if constexpr (MeshDim >= ChildDim) {
296 for (const simplex::NavigatableSimplex& child_simplex : simplices) {
297 assert(child_mesh.is_valid(child_simplex.tuple()));
298
299 run(child_mesh, child_simplex);
300
301 if constexpr (HasReturnCache && ChildHasReturn && CurHasReturn) {
302 auto parent_id = m_return_data.get_id(current_mesh, simplex);
303 auto child_id = m_return_data.get_id(child_mesh, child_simplex);
304 edge_events.emplace_back(parent_id, child_id);
305 }
306 }
307 }
308 },
309 child_mesh_variant);
310 }
311
312 // after running on the chlidren, we finally run the operator and record the return data
313 if constexpr (CurHasReturn) {
314 auto current_return = visitor.m_node_functor(current_mesh, simplex);
315
316 m_return_data.add(std::move(current_return), current_mesh, simplex);
317 } else {
318 visitor.m_node_functor(current_mesh, simplex);
319 }
320 }
321};
322
323
324template <int64_t cell_dimension, typename NodeFunctor>
325MultiMeshSimplexVisitor(std::integral_constant<int64_t, cell_dimension>, NodeFunctor&&)
327
328template <typename NodeFunctor>
330
331
332} // namespace wmtk::multimesh
virtual bool is_valid(const Tuple &tuple) const
check validity of tuple including its hash
Definition Mesh.cpp:113
simplex::Simplex map_to_root(const simplex::Simplex &my_simplex) const
maps a simplex from this mesh to the root mesh
Mesh & get_multi_mesh_root()
returns a reference to the root of a multimesh tree
std::conditional_t< HasReturnCache, typename ReturnDataType::KeyType, std::tuple< const Mesh * > > KeyType
void run(MeshType_ &&current_mesh, const simplex::NavigatableSimplex &simplex)
void execute(MeshType &&mesh, const simplex::NavigatableSimplex &simplex)
wmtk::utils::metaprogramming::MeshVariantTraits MeshVariantTraits
typename MMVisitor::template GetReturnType_t< T > GetReturnType_t
wmtk::utils::metaprogramming::ReferenceWrappedFunctorReturnCacheCustomComparator< NodeFunctor, MeshVariantTraits, wmtk::simplex::utils::MeshSimplexComparator, simplex::NavigatableSimplex > ReturnDataType
std::vector< std::tuple< KeyType, KeyType > > edge_events
void execute_from_root(Mesh &mesh, const simplex::NavigatableSimplex &simplex)
std::vector< std::tuple< KeyType, KeyType > > m_edge_events
void execute_mesh(MeshType &&mesh, const simplex::NavigatableSimplex &simplex)
typename TypeHelper::template ReturnType< MeshType > GetReturnType_t
MultiMeshSimplexVisitor(std::integral_constant< int64_t, cell_dimension >, NodeFunctor &&f)
wmtk::utils::metaprogramming::ReferenceWrappedFunctorReturnCacheCustomComparator< NodeFunctor, MeshVariantTraits, wmtk::simplex::utils::MeshSimplexComparator, simplex::NavigatableSimplex > ReturnDataType
wmtk::utils::metaprogramming::MeshVariantTraits MeshVariantTraits
std::conditional_t< HasReturnCache, typename ReturnDataType::KeyType, std::tuple< const Mesh * > > KeyType
const Tuple & tuple() const
Definition Simplex.hpp:53
DerivedReferenceWrapperVariantTraits< Mesh, PointMesh, EdgeMesh, TriMesh, TetMesh > MeshVariantTraits
MeshVariantType as_mesh_variant(Mesh &mesh)
std::conditional_t< all_return_void_v< Functor, BaseVariantTraitsType, OtherArgumentTypes... >, std::monostate, detail::ReferenceWrappedFunctorReturnCache< Functor, BaseVariantTraitsType, ComparatorType, OtherArgumentTypes... > > ReferenceWrappedFunctorReturnCacheCustomComparator
tuple::concatenate_types_t< ReferenceTuple, ConstReferenceTuple > AllReferenceTuple