diff --git a/mesh_handle/competence_pack.hxx b/mesh_handle/competence_pack.hxx index 258e93f66a..8c61c025ec 100644 --- a/mesh_handle/competence_pack.hxx +++ b/mesh_handle/competence_pack.hxx @@ -45,7 +45,12 @@ struct competence_pack }; /** Predefined competence pack combining all caching competences. */ -using cache_competences = competence_pack; +using all_cache_competences = competence_pack; + +/** Predefined competence pack combining all competences related to faces. */ +using cache_face_competences + = competence_pack; } // namespace t8_mesh_handle #endif /* !T8_COMPETENCE_PACK_HXX */ diff --git a/mesh_handle/competences.hxx b/mesh_handle/competences.hxx index c265c53035..a7a2616912 100644 --- a/mesh_handle/competences.hxx +++ b/mesh_handle/competences.hxx @@ -71,6 +71,29 @@ struct cache_volume: public t8_crtp_operator m_volume; /**< Cache for the volume. Use optional to allow no value if cache is not filled. */ }; +/** + * Competence to cache the diameter of an element at the first function call. + * \tparam TUnderlying Use the \ref element with specified competences as template parameter. + */ +template +struct cache_diameter: public t8_crtp_operator +{ + public: + /** + * Function that checks if the cache for the diameter has been filled. + * \return true if the cache has been filled, false otherwise. + */ + bool + diameter_cache_filled () const + { + return m_diameter.has_value (); + } + + protected: + mutable std::optional + m_diameter; /**< Cache for the diameter. Use optional to allow no value if cache is not filled. */ +}; + /** * Competence to cache the vertex coordinates of an element at the first function call. * \tparam TUnderlying Use the \ref element with specified competences as template parameter. @@ -117,12 +140,81 @@ struct cache_centroid: public t8_crtp_operator m_centroid; /**< Cache for the coordinates of the centroid. Use optional to allow no value if cache is not filled. */ }; +/** + * Competence to cache the area of a specific face at the first function call. + * \tparam TUnderlying Use the \ref element with specified competences as template parameter. + */ +template +struct cache_face_area: t8_crtp_operator +{ + public: + /** + * Function that checks if the cache for a face has been filled. + * \param [in] face The face for which the cache should be checked. + * \return true if the cache has been filled, false otherwise. + */ + bool + face_area_cache_filled (int face) const + { + return m_face_area[face].has_value (); + } + + protected: + mutable std::vector> m_face_area; /**< Vector with the face area each face. */ +}; + +/** + * Competence to cache the centroid of a specific face at the first function call. + * \tparam TUnderlying Use the \ref element with specified competences as template parameter. + */ +template +struct cache_face_centroid: t8_crtp_operator +{ + public: + /** + * Function that checks if the cache for a face has been filled. + * \param [in] face The face for which the cache should be checked. + * \return true if the cache has been filled, false otherwise. + */ + bool + face_centroid_cache_filled (int face) const + { + return m_face_centroid[face].has_value (); + } + + protected: + mutable std::vector> m_face_centroid; /**< Vector with the face centroid each face. */ +}; + +/** + * Competence to cache the normal of a specific face at the first function call. + * \tparam TUnderlying Use the \ref element with specified competences as template parameter. + */ +template +struct cache_face_normal: t8_crtp_operator +{ + public: + /** + * Function that checks if the cache for a face has been filled. + * \param [in] face The face for which the cache should be checked. + * \return true if the cache has been filled, false otherwise. + */ + bool + face_normal_cache_filled (int face) const + { + return m_face_normal[face].has_value (); + } + + protected: + mutable std::vector> m_face_normal; /**< Vector with the face normal each face. */ +}; + /** * Competence to cache the neighbors of an element at a specific face at the first function call. * \tparam TUnderlying Use the \ref element with specified competences as template parameter. */ template -struct cache_neighbors: t8_crtp_operator +struct cache_neighbors: t8_crtp_operator { public: /** diff --git a/mesh_handle/constructor_wrapper.hxx b/mesh_handle/constructor_wrapper.hxx new file mode 100644 index 0000000000..56d366a8f3 --- /dev/null +++ b/mesh_handle/constructor_wrapper.hxx @@ -0,0 +1,99 @@ +/* + This file is part of t8code. + t8code is a C library to manage a collection (a forest) of multiple + connected adaptive space-trees of general element classes in parallel. + + Copyright (C) 2025 the developers + + t8code is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + t8code is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with t8code; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +/** \file constructor_wrapper.hxx + * Construct a mesh handle instance from a cmesh and some default mesh handles. + */ + +#ifndef T8_CONSTRUCTOR_WRAPPER_HXX +#define T8_CONSTRUCTOR_WRAPPER_HXX + +#include +#include +#include +#include +#include +#include + +namespace t8_mesh_handle +{ + +/** Build a uniformly refined mesh handle on a coarse mesh using a default scheme. + * \param [in] cmesh A coarse mesh. + * \param [in] level An initial uniform refinement level. + * \param [in] comm MPI communicator to use. + * \param [in] do_face_ghost If true, a layer of ghost elements is created. + * \tparam TMesh The mesh handle class. + * \return Unique pointer to a uniformly refined mesh handle with coarse mesh \a cmesh and refinement level \a level. + */ +template +std::unique_ptr +handle_new_uniform_default (const t8_cmesh_t cmesh, const int level, const sc_MPI_Comm comm, + const bool do_face_ghost = false) +{ + const t8_scheme *scheme = t8_scheme_new_default (); + t8_forest_t forest = t8_forest_new_uniform (cmesh, scheme, level, do_face_ghost, sc_MPI_COMM_WORLD); + return std::make_unique (forest); +} + +/** Hybercube with 6 Tets, 6 Prism, 4 Hex. Refined uniformly to given level using the default scheme. + * \param [in] level An initial uniform refinement level. + * \param [in] comm MPI communicator to use. + * \param [in] do_partition If non-zero create a partitioned cmesh. + * \param [in] do_face_ghost If true, a layer of ghost elements is created. + * \param [in] periodic If non-zero create a periodic cmesh in each direction. + * \tparam TMesh The mesh handle class. + * \return Unique pointer to a uniformly refined mesh handle initially consisting of 6 Tets, 6 prism and 4 hex. + * Together, they form a cube. +*/ +template +std::unique_ptr +handle_hybrid_hypercube_uniform_default (const int level, const sc_MPI_Comm comm, const bool do_partition = false, + const bool do_face_ghost = false, const bool periodic = false) +{ + t8_cmesh_t cmesh = t8_cmesh_new_hypercube_hybrid (comm, do_partition, periodic); + return handle_new_uniform_default (cmesh, level, comm, do_face_ghost); +} + +/** Construct hybercube from one primitive tree class. Refined uniformly to given level using the default scheme. + * \param [in] eclass This element class determines the dimension and the number of trees needed to construct a cube. + * \param [in] level An initial uniform refinement level. + * \param [in] comm MPI communicator to use. + * \param [in] do_partition If non-zero create a partitioned cmesh. + * \param [in] do_face_ghost If true, a layer of ghost elements is created. + * \param [in] periodic If non-zero create a periodic cmesh in each direction. Not possible with \a eclass pyramid. + * \tparam TMesh The mesh handle class. + * \return Unique pointer to a uniformly refined mesh handle hypercube. +*/ +template +std::unique_ptr +handle_hypercube_uniform_default (t8_eclass_t eclass, const int level, const sc_MPI_Comm comm, + const bool do_partition = false, const bool do_face_ghost = false, + const bool periodic = false) +{ + // Broadcast option is hidden from the user. + t8_cmesh_t cmesh = t8_cmesh_new_hypercube (eclass, comm, 0, do_partition, periodic); + return handle_new_uniform_default (cmesh, level, comm, do_face_ghost); +} + +} // namespace t8_mesh_handle +#endif /* !T8_CONSTRUCTOR_WRAPPER_HXX */ diff --git a/mesh_handle/element.hxx b/mesh_handle/element.hxx index cb74480d3e..8f627457f3 100644 --- a/mesh_handle/element.hxx +++ b/mesh_handle/element.hxx @@ -21,7 +21,7 @@ along with t8code; if not, write to the Free Software Foundation, Inc., */ /** \file element.hxx - * Definition of the element class of the \ref t8_mesh_handle::mesh handle (can be ghost or mesh elements). + * Definition of the element class of the \ref t8_mesh_handle::mesh handle (can be ghost or mesh elements). */ #ifndef T8_ELEMENT_HXX @@ -64,9 +64,8 @@ class element: public TCompetence>... { = element; /**< Type of the current class with all template parameters specified. */ friend mesh_class; /**< Define mesh_class as friend to be able to access e.g. the constructor. */ - /** - * Private constructor for an element of a mesh. This could be a simple mesh element or a ghost element. - * This constructor should only be called by the mesh_class (and invisible for the user). + /** Private constructor for an element of a mesh. This could be a simple mesh element or a ghost element. + * This constructor should only be called by the mesh_class (and invisible for the user). * \param [in] mesh Pointer to the mesh the element should belong to. * \param [in] tree_id The tree id of the element in the forest defining the mesh. * \param [in] element_id The element id of the element in the forest defining the mesh. @@ -75,6 +74,7 @@ class element: public TCompetence>... { element (mesh_class* mesh, t8_locidx_t tree_id, t8_locidx_t element_id, bool is_ghost_element = false) : m_mesh (mesh), m_tree_id (tree_id), m_element_id (element_id), m_is_ghost_element (is_ghost_element) { + // Cache the t8_element_t from the forest as it is often used. if (m_is_ghost_element) { // The local ghost tree id is per definition the local tree id - number of local (non-ghost) trees. m_element = t8_forest_ghost_get_leaf_element ( @@ -84,136 +84,141 @@ class element: public TCompetence>... { m_element = t8_forest_get_leaf_element_in_tree (m_mesh->m_forest, m_tree_id, m_element_id); } + // Resize caches for clean access where the cache vector may not be filled completely at once. if constexpr (has_face_neighbor_cache ()) { - // Resize neighbor caches for clean access to the caches. - const int num_faces = this->get_num_faces (); + const int num_faces = get_num_faces (); this->m_num_neighbors.resize (num_faces); this->m_dual_faces.resize (num_faces); this->m_neighbors.resize (num_faces); } + if constexpr (has_face_area_cache ()) { + const int num_faces = get_num_faces (); + this->m_face_area.resize (num_faces); + } + if constexpr (has_face_centroid_cache ()) { + const int num_faces = get_num_faces (); + this->m_face_centroid.resize (num_faces); + } + if constexpr (has_face_normal_cache ()) { + const int num_faces = get_num_faces (); + this->m_face_normal.resize (num_faces); + } } - // --- Variables to check which functionality is defined in TCompetence. --- - /** Helper function to check if class T implements the function volume_cache_filled. - * \tparam T The competence to be checked. - * \return true if T implements the function, false if not. + public: + // --- Public functions to check if caches exist. --- + /** Function that checks if a cache for the element's volume exists. + * \return true if a cache exists, false otherwise. */ - template