.. _program_listing_file_mesh_handle_mesh.hxx: Program Listing for File mesh.hxx ================================= |exhale_lsh| :ref:`Return to documentation for file ` (``mesh_handle/mesh.hxx``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp /* 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) 2026 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. */ #pragma once #include #include "element.hxx" #include "competence_pack.hxx" #include "internal/adapt.hxx" #include "concepts.hxx" #include "data_handler.hxx" #include #include #include #include #include #include #include #include namespace t8_mesh_handle { template concept ElementCompetencePack = requires { typename TType::is_element_competence_pack; }; template concept MeshCompetencePack = requires { typename TType::is_mesh_competence_pack; }; template , MeshCompetencePack TMeshCompetencePack = mesh_competence_pack<>> class mesh: public TMeshCompetencePack::template apply> { public: using SelfType = mesh; using element_class = typename TElementCompetencePack::template apply< SelfType, element>; friend element_class; using mesh_tag = void; using mesh_const_iterator = typename std::vector::const_iterator; using mesh_iterator = typename std::vector::iterator; friend struct element_data_element_competence; using adapt_callback_type = std::function elements)>; template using adapt_callback_type_with_userdata = std::function elements, TUserDataType user_data)>; mesh (t8_forest_t forest): m_forest (forest) { T8_ASSERT (t8_forest_is_committed (m_forest)); update_elements (); } ~mesh () { t8_forest_unref (&m_forest); } // --- Getter for mesh related information. --- t8_locidx_t get_num_local_elements () const { return t8_forest_get_local_num_leaf_elements (m_forest); } t8_locidx_t get_num_ghosts () const { return t8_forest_get_num_ghosts (m_forest); } int get_dimension () const { return t8_forest_get_dimension (m_forest); } t8_forest_t get_forest () const { return m_forest; } bool is_balanced () { return t8_forest_is_balanced (m_forest); } // --- Methods to access elements. --- mesh_const_iterator cbegin () const { return m_elements.cbegin (); } mesh_const_iterator cend () const { return m_elements.cend (); } mesh_iterator begin () { return m_elements.begin (); } mesh_iterator end () { return m_elements.end (); } mesh_const_iterator begin () const { return this->cbegin (); } mesh_const_iterator end () const { return this->cend (); } const element_class& operator[] (t8_locidx_t local_index) const { T8_ASSERT (0 <= local_index && local_index < get_num_local_elements () + get_num_ghosts ()); if (local_index < get_num_local_elements ()) { return m_elements[local_index]; } else { return m_ghosts[local_index - get_num_local_elements ()]; } } element_class& operator[] (t8_locidx_t local_index) { return const_cast (static_cast (this)->operator[] (local_index)); } // --- Methods to change the mesh, e.g. adapt, partition, balance, ... --- template static adapt_callback_type mesh_adapt_callback_wrapper (adapt_callback_type_with_userdata adapt_callback_with_userdata, const TUserDataType& user_data) { return [=] (const SelfType& mesh, std::span elements) { return adapt_callback_with_userdata (mesh, elements, user_data); }; } void set_adapt (adapt_callback_type adapt_callback) { if (!m_uncommitted_forest.has_value ()) { m_uncommitted_forest.emplace (); t8_forest_init (&*m_uncommitted_forest); } // Create and register adaptation context holding the mesh handle and the user defined callback. detail::adapt_registry::register_context ( m_forest, std::make_unique> (*this, std::move (adapt_callback))); // Set up the forest for adaptation using the wrapper callback. // Recursive adaptation is currently not supported. t8_forest_set_adapt (m_uncommitted_forest.value (), m_forest, detail::mesh_adapt_callback_wrapper, false); } void set_partition (bool set_for_coarsening = false) { if (!m_uncommitted_forest.has_value ()) { t8_forest_t new_forest; t8_forest_init (&new_forest); m_uncommitted_forest = new_forest; } t8_forest_set_partition (m_uncommitted_forest.value (), m_forest, set_for_coarsening); } void set_balance (bool no_repartition = false) { if (!m_uncommitted_forest.has_value ()) { t8_forest_t new_forest; t8_forest_init (&new_forest); m_uncommitted_forest = new_forest; } t8_forest_set_balance (m_uncommitted_forest.value (), m_forest, no_repartition); } void set_ghost (bool do_ghost = true, t8_ghost_type_t ghost_type = T8_GHOST_FACES) { if (!m_uncommitted_forest.has_value ()) { m_uncommitted_forest.emplace (); t8_forest_init (&*m_uncommitted_forest); } t8_forest_set_ghost (m_uncommitted_forest.value (), do_ghost, ghost_type); } void commit () { if (!m_uncommitted_forest.has_value ()) { m_uncommitted_forest.emplace (); t8_forest_init (&*m_uncommitted_forest); } /* It can happen that the user only calls set_ghost before commit. This does not set the set_from member of the forest and we copy the current forest in this case. */ if (m_uncommitted_forest.value ()->set_from == NULL) { t8_forest_set_copy (m_uncommitted_forest.value (), m_forest); } t8_forest_ref (m_forest); t8_forest_commit (m_uncommitted_forest.value ()); // Check if we adapted and unregister the adapt context if so. if (detail::adapt_registry::get (m_forest) != nullptr) { detail::adapt_registry::unregister_context (m_forest); if constexpr (has_element_data_handler_competence ()) { t8_global_infof ( "Please note that the element data is not interpolated automatically during adaptation. Use the " "function set_element_data() to provide new adapted element data.\n"); } } t8_forest_unref (&m_forest); // Update underlying forest of the mesh. m_forest = m_uncommitted_forest.value (); m_uncommitted_forest.reset (); update_elements (); } // --- Methods to check for mesh competences. --- static constexpr bool has_element_data_handler_competence () { return requires (SelfType& mesh) { mesh.get_element_data (); }; } private: void update_elements () { m_elements.clear (); m_elements.reserve (get_num_local_elements ()); // Iterate through forest elements and fill the element vector with newly created mesh elements. for (t8_locidx_t itree = 0; itree < t8_forest_get_num_local_trees (m_forest); ++itree) { const t8_locidx_t num_elems = t8_forest_get_tree_num_leaf_elements (m_forest, itree); for (t8_locidx_t ielem = 0; ielem < num_elems; ++ielem) { m_elements.push_back (element_class (this, itree, ielem)); } } update_ghost_elements (); } void update_ghost_elements () { if (get_num_ghosts () == 0) { m_ghosts.clear (); return; } m_ghosts.clear (); m_ghosts.reserve (get_num_ghosts ()); t8_locidx_t num_loc_trees = t8_forest_get_num_local_trees (m_forest); for (t8_locidx_t itree = 0; itree < t8_forest_get_num_ghost_trees (m_forest); ++itree) { const t8_locidx_t num_elems = t8_forest_ghost_tree_num_leaf_elements (m_forest, itree); for (t8_locidx_t ielem = 0; ielem < num_elems; ++ielem) { m_ghosts.push_back (element_class (this, num_loc_trees + itree, ielem, true)); } } } t8_forest_t m_forest; std::vector m_elements; std::vector m_ghosts; std::optional m_uncommitted_forest; }; } // namespace t8_mesh_handle