diff --git a/src/wmtk/invariants/Invariant.cpp b/src/wmtk/invariants/Invariant.cpp index a14059d84d..dfd951e38b 100644 --- a/src/wmtk/invariants/Invariant.cpp +++ b/src/wmtk/invariants/Invariant.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include namespace wmtk::invariants { @@ -57,7 +58,10 @@ bool Invariant::directly_modified_after( return true; } - +bool Invariant::is_collection() const +{ + return false; +} bool Invariant::use_old_state_in_after() const { return m_use_old_state_in_after; diff --git a/src/wmtk/invariants/Invariant.hpp b/src/wmtk/invariants/Invariant.hpp index 12bbdc9746..cabbbf9c31 100644 --- a/src/wmtk/invariants/Invariant.hpp +++ b/src/wmtk/invariants/Invariant.hpp @@ -1,4 +1,5 @@ #pragma once +#include #include #include namespace wmtk { @@ -30,6 +31,7 @@ class Invariant const Mesh& mesh() const; + // A compact pipeline for evaluating after without computing any cofaces // TODO change name virtual bool directly_modified_after( const std::vector& simplices_before, @@ -41,12 +43,15 @@ class Invariant bool use_old_state_in_after() const; bool use_new_state_in_after() const; + virtual bool is_collection() const; + private: const Mesh& m_mesh; const bool m_use_before = true; const bool m_use_old_state_in_after = true; const bool m_use_new_state_in_after = true; +protected: const std::vector get_top_dimension_cofaces( const std::vector& simplices) const; }; diff --git a/src/wmtk/invariants/InvariantCollection.cpp b/src/wmtk/invariants/InvariantCollection.cpp index cb1d804a8b..94d66c140c 100644 --- a/src/wmtk/invariants/InvariantCollection.cpp +++ b/src/wmtk/invariants/InvariantCollection.cpp @@ -2,12 +2,15 @@ #include #include #include +#include namespace wmtk::invariants { InvariantCollection::InvariantCollection(const Mesh& m) : Invariant(m, true, true, true) -{} +{ + m_use_same_mesh_caching = true; +} InvariantCollection::~InvariantCollection() = default; InvariantCollection::InvariantCollection(const InvariantCollection&) = default; InvariantCollection::InvariantCollection(InvariantCollection&&) = default; @@ -26,7 +29,10 @@ InvariantCollection& InvariantCollection::operator=(InvariantCollection&& o) void InvariantCollection::add(std::shared_ptr invariant) { - m_invariants.emplace_back(std::move(invariant)); + const auto& invar = m_invariants.emplace_back(std::move(invariant)); + if (m_use_same_mesh_caching && &mesh() == &invar->mesh()) { + m_same_mesh_invariants.emplace_back(invar); + } } bool InvariantCollection::before(const simplex::Simplex& t) const { @@ -113,12 +119,62 @@ bool InvariantCollection::directly_modified_after( mapped_simplices_after)) { return false; } - } else { + } else if (!m_use_same_mesh_caching) { if (!invariant->directly_modified_after(simplices_before, simplices_after)) { return false; } } } + if (m_use_same_mesh_caching) { + std::vector tuples_before, tuples_after; + return directly_modified_after_cached( + simplices_before, + simplices_after, + tuples_before, + tuples_after); + } + return true; +} +bool InvariantCollection::is_collection() const +{ + return true; +} + +bool InvariantCollection::directly_modified_after_cached( + const std::vector& simplices_before, + const std::vector& simplices_after, + std::vector& cofaces_before, + std::vector& cofaces_after) const +{ + for (const auto& invariant_ptr : m_same_mesh_invariants) { + const auto& invariant = *invariant_ptr; + assert(&mesh() == &invariant.mesh()); + if (invariant.is_collection()) { + if (!static_cast(invariant).directly_modified_after_cached( + simplices_before, + simplices_after, + cofaces_before, + cofaces_after)) { + return false; + } + } else if (invariant.use_after()) { + if (invariant.use_new_state_in_after()) { + if (cofaces_after.empty()) { + cofaces_after = get_top_dimension_cofaces(simplices_after); + } + } + if (invariant.use_old_state_in_after()) { + if (cofaces_before.empty()) { + cofaces_before = mesh().parent_scope( + [&]() { return get_top_dimension_cofaces(simplices_before); }); + } + } + + if (!after(cofaces_before, cofaces_after)) { + return false; + } + } + } return true; } @@ -164,4 +220,5 @@ InvariantCollection::get_map_mesh_to_invariants() // } + } // namespace wmtk::invariants diff --git a/src/wmtk/invariants/InvariantCollection.hpp b/src/wmtk/invariants/InvariantCollection.hpp index ab257c0428..a4fdbcd0fa 100644 --- a/src/wmtk/invariants/InvariantCollection.hpp +++ b/src/wmtk/invariants/InvariantCollection.hpp @@ -29,8 +29,17 @@ class InvariantCollection : public Invariant bool directly_modified_after( const std::vector& simplices_before, - const std::vector& simplices_after) const override; + const std::vector& simplices_after) const final override; + // optimization for evaluating connected subgraphs of invariants that share the same mesh + // In this case we can cache the cofaces computed once rather than re-evaluate them + bool directly_modified_after_cached( + const std::vector& simplices_before, + const std::vector& simplices_after, + std::vector& cofaces_before, + std::vector& cofaces_after) const; + + bool is_collection() const final override; // pass by value so this can be internally moved void add(std::shared_ptr invariant); @@ -44,6 +53,8 @@ class InvariantCollection : public Invariant private: std::vector> m_invariants; + std::vector> m_same_mesh_invariants; + bool m_use_same_mesh_caching = false; }; } // namespace invariants diff --git a/src/wmtk/multimesh/MultiMeshManager.cpp b/src/wmtk/multimesh/MultiMeshManager.cpp index 5b824734a8..24a1e3543f 100644 --- a/src/wmtk/multimesh/MultiMeshManager.cpp +++ b/src/wmtk/multimesh/MultiMeshManager.cpp @@ -504,10 +504,14 @@ std::vector MultiMeshManager::map_tuples( int64_t depth = my_id.size(); - auto [root_ref, tuple] = map_up_to_tuples(my_mesh, my_simplex, depth); - const simplex::Simplex simplex(root_ref, my_simplex.primitive_type(), tuple); + if (is_root()) { + return my_mesh.m_multi_mesh_manager.map_down_relative_tuples(my_mesh, my_simplex, other_id); + } else { + auto [root_ref, tuple] = map_up_to_tuples(my_mesh, my_simplex, depth); + const simplex::Simplex simplex(root_ref, my_simplex.primitive_type(), tuple); - return root_ref.m_multi_mesh_manager.map_down_relative_tuples(root_ref, simplex, other_id); + return root_ref.m_multi_mesh_manager.map_down_relative_tuples(root_ref, simplex, other_id); + } } std::vector MultiMeshManager::lub_map_tuples( @@ -524,16 +528,23 @@ std::vector MultiMeshManager::lub_map_tuples( int64_t depth = my_id.size() - lub_id.size(); - auto [local_root_ref, tuple] = map_up_to_tuples(my_mesh, my_simplex, depth); - assert(other_mesh.m_multi_mesh_manager.is_child(other_mesh, local_root_ref)); + auto other_relative_id = relative_id(lub_id, other_id); + if (depth == 0) { + return my_mesh.m_multi_mesh_manager.map_down_relative_tuples( + my_mesh, + my_simplex, + other_relative_id); + } else { + auto [local_root_ref, tuple] = map_up_to_tuples(my_mesh, my_simplex, depth); + assert(other_mesh.m_multi_mesh_manager.is_child(other_mesh, local_root_ref)); - const simplex::Simplex simplex(local_root_ref, my_simplex.primitive_type(), tuple); + const simplex::Simplex simplex(local_root_ref, my_simplex.primitive_type(), tuple); - auto other_relative_id = relative_id(lub_id, other_id); - return local_root_ref.m_multi_mesh_manager.map_down_relative_tuples( - local_root_ref, - simplex, - other_relative_id); + return local_root_ref.m_multi_mesh_manager.map_down_relative_tuples( + local_root_ref, + simplex, + other_relative_id); + } } simplex::Simplex MultiMeshManager::map_to_root( diff --git a/src/wmtk/operations/attribute_update/AttributeTransferStrategyBase.cpp b/src/wmtk/operations/attribute_update/AttributeTransferStrategyBase.cpp index de3629d6b8..c2f788ba0c 100644 --- a/src/wmtk/operations/attribute_update/AttributeTransferStrategyBase.cpp +++ b/src/wmtk/operations/attribute_update/AttributeTransferStrategyBase.cpp @@ -48,25 +48,25 @@ std::vector AttributeTransferStrategyBase::get_parent_simplices( if (my_primitive_type != parent_primitive_type) { // lambda for running either of the cases - std::vector r; if (parent_tuples.size() == 1) { - r = simplex::neighbors_single_dimension_tuples( + parent_tuples = simplex::neighbors_single_dimension_tuples( m, - simplex::Simplex(m, my_primitive_type, parent_tuples[0]), + simplex::Simplex(my_primitive_type, parent_tuples[0]), parent_primitive_type); } else { + std::vector r; for (const auto& parent_tup : parent_tuples) { std::vector c = simplex::neighbors_single_dimension_tuples( m, - simplex::Simplex(m, my_primitive_type, parent_tup), + simplex::Simplex(my_primitive_type, parent_tup), parent_primitive_type); std::copy(c.begin(), c.end(), std::back_inserter(r)); } if (parent_tuples.size() > 1) { simplex::utils::unique_homogeneous_simplices_inline(m, parent_primitive_type, r); } + parent_tuples = std::move(r); } - parent_tuples = std::move(r); } return parent_tuples; } diff --git a/src/wmtk/simplex/Simplex.hpp b/src/wmtk/simplex/Simplex.hpp index 75d1055cc4..16098cf41c 100644 --- a/src/wmtk/simplex/Simplex.hpp +++ b/src/wmtk/simplex/Simplex.hpp @@ -32,7 +32,6 @@ class Simplex Tuple m_tuple; public: - // the mesh class can use this index value to cache/accelerate operations Simplex(const PrimitiveType& ptype, const Tuple& t) : m_primitive_type{ptype} , m_tuple{t}