Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 47 additions & 10 deletions mesh_handle/abstract_element.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,6 @@ along with t8code; if not, write to the Free Software Foundation, Inc.,

namespace t8_mesh_handle
{
/* Forward declaration of the \ref mesh class of the handle.
*/
template <template <typename> class... TCompetence>
class mesh;

/**
* Common interface of the mesh elements and the ghost elements of the \ref mesh handle.
* An element without specified template parameters provides default implementations for basic functionality
Expand All @@ -61,13 +56,13 @@ class mesh;
*
* \tparam TCompetence The competences you want to add to the default functionality of the element.
*/
template <template <typename> class... TCompetence>
class abstract_element: public TCompetence<abstract_element<TCompetence...>>... {
template <typename mesh_class, template <typename> class... TCompetence>
class abstract_element: public TCompetence<abstract_element<mesh_class, TCompetence...>>... {
protected:
using SelfType
= abstract_element<TCompetence...>; /**< Type of the current class with all template parameters specified. */
using mesh_class = mesh<TCompetence...>; /**< Type of the mesh class the used. */
friend mesh_class; /**< Define mesh_class as friend to be able to access e.g. the constructor. */
= abstract_element<mesh_class,
TCompetence...>; /**< 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. */

/**
* Protected constructor for an element of a mesh.
Expand All @@ -82,6 +77,20 @@ class abstract_element: public TCompetence<abstract_element<TCompetence...>>...
}

// --- 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.
*/
template <template <typename> class T>
static constexpr bool
volume_cache_defined ()
{
return requires (T<SelfType>& competence) { competence.volume_cache_filled (); };
}
/** This variable is true if any of the given competences \a TCompetence implements
a function volume_cache_filled. */
static constexpr bool volume_cache_exists = (false || ... || volume_cache_defined<TCompetence> ());

/** Helper function to check if class T implements the function vertex_cache_filled.
* \tparam T The competence to be checked.
* \return true if T implements the function, false if not.
Expand Down Expand Up @@ -112,6 +121,15 @@ class abstract_element: public TCompetence<abstract_element<TCompetence...>>...

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.
*/
static constexpr bool
has_volume_cache ()
{
return volume_cache_exists;
}
/**
* Function that checks if a cache for the vertex coordinates exists.
* \return true if a cache for the vertex coordinates exists, false otherwise.
Expand Down Expand Up @@ -168,6 +186,25 @@ class abstract_element: public TCompetence<abstract_element<TCompetence...>>...
return t8_forest_get_scheme (m_mesh->m_forest)->element_get_shape (get_tree_class (), get_element ());
}

/**
* Getter for the element's volume.
* This function uses or sets the cached version defined in TCompetence if available and calculates if not.
* \return The volume of the element.
*/
double
get_volume () const
{
if constexpr (volume_cache_exists) {
if (this->volume_cache_filled ()) {
return this->m_volume.value ();
}
// Fill cache.
this->m_volume = t8_forest_element_volume (m_mesh->m_forest, m_tree_id, get_element ());
return this->m_volume.value ();
}
return t8_forest_element_volume (m_mesh->m_forest, m_tree_id, get_element ());
}

/**
* Getter for the vertex coordinates of the element.
* This function uses or sets the cached version defined in TCompetence if available and calculates if not.
Expand Down
51 changes: 51 additions & 0 deletions mesh_handle/competence_pack.hxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
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 competence_pack.hxx
* Define to pack different competences into one template parameter for the \ref t8_mesh_handle::mesh class.
*/
#ifndef T8_COMPETENCE_PACK_HXX
#define T8_COMPETENCE_PACK_HXX

#include "competences.hxx"
namespace t8_mesh_handle
{
/** Class to pack different competences into one template parameter for the \ref mesh class.
* \tparam TCompetence The competences to be packed.
*/
template <template <typename> class... TCompetence>
struct competence_pack
{
/** Apply the competence pack to a template class, e.g. the \ref abstract_element class.
* \tparam Target The target template class to apply the \a TCompetence pack to.
*/
template <typename mesh_class, template <typename, template <typename> class...> class Target>
using apply = Target<mesh_class, TCompetence...>;

using is_competence_pack = void; /**< Tag to identify this class. */
};

/** Predefined competence pack combining all caching competences. */
using cache_competences = competence_pack<cache_volume, cache_vertex_coordinates, cache_centroid, cache_neighbors>;

} // namespace t8_mesh_handle
#endif /* !T8_COMPETENCE_PACK_HXX */
23 changes: 23 additions & 0 deletions mesh_handle/competences.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,29 @@ along with t8code; if not, write to the Free Software Foundation, Inc.,
namespace t8_mesh_handle
{

/**
* Competence to cache the volume of an element at the first function call.
* \tparam TUnderlying Use the \ref abstract_element with specified competences as template parameter.
*/
template <typename TUnderlying>
struct cache_volume: public t8_crtp_operator<TUnderlying, cache_volume>
{
public:
/**
* Function that checks if the cache for the volume has been filled.
* \return true if the cache has been filled, false otherwise.
*/
bool
volume_cache_filled () const
{
return m_volume.has_value ();
}

protected:
mutable std::optional<double>
m_volume; /**< Cache for the volume. 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 abstract_element with specified competences as template parameter.
Expand Down
12 changes: 3 additions & 9 deletions mesh_handle/ghost_element.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -33,22 +33,16 @@

namespace t8_mesh_handle
{
/* Forward declaration of the \ref mesh class of the handle.
*/
template <template <typename> class... TCompetence>
class mesh;

/**
* Class for the ghost elements of the \ref mesh handle.
* This class is a child class of the abstract element class and implements the functionality specific to ghost elements.
* See \ref abstract_element for more information, especially on the template parameter.
*
* \tparam TCompetence The competences you want to add to the default functionality of the element.
*/
template <template <typename> class... TCompetence>
class ghost_element: public abstract_element<TCompetence...> {
using Base = abstract_element<TCompetence...>;
using mesh_class = mesh<TCompetence...>;
template <typename mesh_class, template <typename> class... TCompetence>
class ghost_element: public abstract_element<mesh_class, TCompetence...> {
using Base = abstract_element<mesh_class, TCompetence...>;
friend mesh_class;

/**
Expand Down
109 changes: 96 additions & 13 deletions mesh_handle/mesh.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -32,25 +32,36 @@
#include "abstract_element.hxx"
#include "mesh_element.hxx"
#include "ghost_element.hxx"
#include "competence_pack.hxx"
#include <t8_forest/t8_forest_ghost.h>
#include <vector>
#include <type_traits>

namespace t8_mesh_handle
{

/**
* Wrapper for a forest that enables it to be handled as a simple mesh object.
* \tparam TCompetence The competences you want to add to the default functionality of the mesh.
* \tparam TCompetencePack The competences you want to add to the default functionality of the mesh.
* \see abstract_element for more details on the choice of the template parameter.
* \note Please pack your competences using the \ref competence_pack class.
* \tparam TUserData The user data type you want to associate with the mesh. Use void (this is also the default) if you do not want to set user data.
* \tparam TElementData The element data type you want to use for each element of the mesh.
* Use void (this is also the default) if you do not want to set element data.
*/
template <template <typename> class... TCompetence>
template <typename TCompetencePack = competence_pack<>, typename TUserData = void, typename TElementData = void>
class mesh {
public:
using SelfType = mesh<TCompetencePack, TUserData,
TElementData>; /**< Type of the current class with all template parameters specified. */
/** Type definitions of the element classes with given competences. */
using abstract_element_class = abstract_element<
TCompetence...>; /**< The abstract element class of the mesh (could be a mesh element of ghost). */
using mesh_element_class = mesh_element<TCompetence...>; /**< The mesh element class of the mesh. */
using ghost_element_class = ghost_element<TCompetence...>; /**< The ghost element class of the mesh. */
using abstract_element_class = TCompetencePack::template apply<
SelfType, abstract_element>; /**< The abstract element class of the mesh (could be a mesh element of ghost). */
using mesh_element_class
= TCompetencePack::template apply<SelfType, mesh_element>; /**< The mesh element class of the mesh. */
using ghost_element_class
= TCompetencePack::template apply<SelfType, ghost_element>; /**< The ghost element class of the mesh. */

// Declare all element classes as friend such that private members (e.g. the forest) can be accessed.
friend abstract_element_class; /**< Abstract element class as friend. */
friend mesh_element_class; /**< Mesh element class as friend. */
Expand All @@ -61,10 +72,11 @@ class mesh {

/**
* Constructor for a mesh of the handle.
* \param [in] input_forest The forest from which the mesh should be created.
* \param [in] forest The forest from which the mesh should be created.
*/
mesh (t8_forest_t input_forest): m_forest (input_forest)
mesh (t8_forest_t forest): m_forest (forest)
{
T8_ASSERT ((std::is_same<typename TCompetencePack::is_competence_pack, void>::value));
T8_ASSERT (t8_forest_is_committed (m_forest));
update_elements ();
}
Expand All @@ -89,6 +101,16 @@ class mesh {
return t8_forest_get_num_ghosts (m_forest);
}

/**
* Getter for the dimension the mesh handle lives in.
* \return The dimension.
*/
int
get_dimension () const
{
return t8_forest_get_dimension (m_forest);
}

/**
* Returns a constant iterator to the first (local) mesh element.
* \return Constant iterator to the first (local) mesh element.
Expand Down Expand Up @@ -171,9 +193,9 @@ class mesh {
}

/**
* Setter for the forest.
* \param [in] input_forest The forest from which the mesh should be a wrapper.
*/
* Setter for the forest.
* \param [in] input_forest The forest from which the mesh should be a wrapper.
*/
void
set_forest (t8_forest_t input_forest)
{
Expand All @@ -182,14 +204,74 @@ class mesh {
update_elements ();
}

/**
* Set the user data of the mesh. This can i.e. be used to pass user defined arguments to the adapt routine.
* \param [in] data The user data of class TUserData. Data will never be touched by mesh handling routines.
*/
template <typename U = TUserData, typename = std::enable_if_t<!std::is_void<U>::value>>
void
set_user_data (const U& data)
{
t8_forest_set_user_data (m_forest, data);
}

/**
* Get the user data of the mesh.
* \return The user data previously set using \ref set_user_data.
*/
template <typename U = TUserData, typename = std::enable_if_t<!std::is_void<U>::value>>
const U&
get_user_data () const
{
return *static_cast<const U*> (t8_forest_get_user_data (m_forest));
}

/**
* Set the element data vector. The vector should have the length of num_local_elements.
* \param [in] element_data The element data vector to set with one entry of class TElementData
* for each local mesh element (excluding ghosts).
*/
template <typename E = TElementData, typename = std::enable_if_t<!std::is_void<E>::value>>
void
set_element_data (const std::vector<E>& element_data)
{
T8_ASSERT (element_data.size () == get_num_local_elements ());
m_element_data.clear ();
m_element_data.resize (get_num_local_elements () + get_num_local_ghosts ());
std::copy (element_data.begin (), element_data.end (), m_element_data.begin ());
}

/**
* Get the element data vector including ghost entries.
* The element data of the local mesh elements is the one set using \ref set_element_data.
* In this function, additionally the ghost entries are filled exchanging the correct entries of the
* element vector between processes.
* \return Element data vector of size num_local_elements + num_local_ghosts with data of Type TElementData.
*/
template <typename E = TElementData, typename = std::enable_if_t<!std::is_void<E>::value>>
const std::vector<E>&
get_element_data ()
{
// t8_forest_ghost_exchange_data expects an sc_array, so we need to wrap our data array to one.
sc_array* sc_array_wrapper;
T8_ASSERT (m_element_data.size () == get_num_local_elements () + get_num_local_ghosts ());
sc_array_wrapper = sc_array_new_data (m_element_data.data (), sizeof (TElementData),
get_num_local_elements () + get_num_local_ghosts ());

// Data exchange: entries with indices > num_local_elements will get overwritten.
t8_forest_ghost_exchange_data (m_forest, sc_array_wrapper);

sc_array_destroy (sc_array_wrapper);
return m_element_data;
}

private:
/**
* Update the storage of the mesh elements according to the current forest.
*/
void
update_elements ()
{
// Clear the element vector if already created.
m_elements.clear ();
m_elements.reserve (get_num_local_elements ());
// Iterate through forest elements and fill the element vector with newly created mesh elements.
Expand All @@ -208,7 +290,6 @@ class mesh {
void
update_ghost_elements ()
{
// Clear the ghost vector if already created.
m_ghosts.clear ();
m_ghosts.reserve (get_num_local_ghosts ());
t8_locidx_t num_loc_trees = t8_forest_get_num_local_trees (m_forest);
Expand All @@ -224,6 +305,8 @@ class mesh {
t8_forest_t m_forest; /**< The forest the mesh should be defined for. */
std::vector<mesh_element_class> m_elements; /**< Vector storing the (local) mesh elements. */
std::vector<ghost_element_class> m_ghosts; /**< Vector storing the (local) ghost elements. */
std::conditional_t<!std::is_void_v<TElementData>, std::vector<TElementData>, std::nullptr_t>
m_element_data; /**< Vector storing the (local) element data. */
};

} // namespace t8_mesh_handle
Expand Down
Loading
Loading