Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
e5051fd
pack competences into one class
lenaploetzke Nov 10, 2025
1701534
rm assert committed in the test
lenaploetzke Nov 10, 2025
27fcc41
Not working: implement user data
lenaploetzke Nov 10, 2025
df0353c
fix error
lenaploetzke Nov 25, 2025
9b272a9
Merge branch 'handle-neighbor-and-ghost' into handle_element-data
lenaploetzke Nov 26, 2025
b3dc96e
added test
lenaploetzke Nov 26, 2025
58559f3
implement get_volume with cache
lenaploetzke Nov 28, 2025
8d94a95
add check for ghost test that we actually test smth
lenaploetzke Nov 28, 2025
e7934cc
add element data functionality
lenaploetzke Nov 28, 2025
a1cabed
rename test
lenaploetzke Nov 28, 2025
5119d03
adapt cmake
lenaploetzke Nov 28, 2025
7c57b3e
Merge branch 'main' into handle_element-data
lenaploetzke Dec 17, 2025
08f6e26
Merge branch 'handle-neighbor-and-ghost' into handle_element-data
lenaploetzke Dec 17, 2025
98a96da
Merge branch 'handle-neighbor-and-ghost' into handle_element-data
lenaploetzke Dec 18, 2025
c2a78f5
resolve doxygen warnings
lenaploetzke Dec 18, 2025
16c9687
Merge branch 'handle-neighbor-and-ghost' into handle_element-data
lenaploetzke Jan 7, 2026
277dc06
provide option to set element data via element instead of only via th…
lenaploetzke Jan 7, 2026
b493c5f
typo
lenaploetzke Jan 7, 2026
7d79e3f
doxygen
lenaploetzke Jan 8, 2026
efc900e
Merge branch 'handle-neighbor-and-ghost' into handle_element-data
lenaploetzke Jan 8, 2026
e8b023a
easier competence checks
lenaploetzke Jan 8, 2026
dc1fd8b
Merge branch 'handle-neighbor-and-ghost' into handle_element-data
lenaploetzke Jan 8, 2026
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
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 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 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 element with specified competences as template parameter.
Expand Down
116 changes: 83 additions & 33 deletions mesh_handle/element.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,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;

/**
* Definition of the mesh element class of the \ref mesh handle.
* An element without specified template parameters provides default implementations for basic functionality
Expand All @@ -62,11 +57,11 @@ class mesh;
*
* \tparam TCompetence The competences you want to add to the default functionality of the element.
*/
template <template <typename> class... TCompetence>
class element: public TCompetence<element<TCompetence...>>... {
template <typename mesh_class, template <typename> class... TCompetence>
class element: public TCompetence<element<mesh_class, TCompetence...>>... {
private:
using SelfType = element<TCompetence...>; /**< Type of the current class with all template parameters specified. */
using mesh_class = mesh<TCompetence...>; /**< Type of the mesh class used. */
using SelfType
= 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. */

/**
Expand All @@ -89,7 +84,7 @@ class element: public TCompetence<element<TCompetence...>>... {
m_element = t8_forest_get_leaf_element_in_tree (m_mesh->m_forest, m_tree_id, m_element_id);
}

if constexpr (neighbor_cache_exists) {
if constexpr (has_face_neighbor_cache ()) {
// Resize neighbor caches for clean access to the caches.
const int num_faces = this->get_num_faces ();
this->m_num_neighbors.resize (num_faces);
Expand All @@ -99,6 +94,16 @@ class element: public TCompetence<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 (); };
}
/** 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 All @@ -109,10 +114,6 @@ class element: public TCompetence<element<TCompetence...>>... {
{
return requires (T<SelfType>& competence) { competence.vertex_cache_filled (); };
}
/** This variable is true if any of the given competences \a TCompetence implements
a function vertex_cache_filled. */
static constexpr bool vertex_cache_exists = (false || ... || vertex_cache_defined<TCompetence> ());

/** Helper function to check if class T implements the function centroid_cache_filled.
* \tparam T The competence to be checked.
* \return true if T implements the function, false if not.
Expand All @@ -123,10 +124,6 @@ class element: public TCompetence<element<TCompetence...>>... {
{
return requires (T<SelfType>& competence) { competence.centroid_cache_filled (); };
}
/** This variable is true if any of the given competences \a TCompetence implements
a function centroid_cache_filled. */
static constexpr bool centroid_cache_exists = (false || ... || centroid_cache_defined<TCompetence> ());

/** Helper function to check if class T implements the function neighbor_cache_filled.
* \tparam T The competence to be checked.
* \return true if T implements the function, false if not.
Expand All @@ -137,20 +134,26 @@ class element: public TCompetence<element<TCompetence...>>... {
{
return requires (T<SelfType>& competence) { competence.neighbor_cache_filled (0); };
}
/** This variable is true if any of the given competences \a TCompetence implements
a function neighbor_cache_filled. */
static constexpr bool neighbor_cache_exists = (false || ... || neighbor_cache_defined<TCompetence> ());

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.
*/
static constexpr bool
has_volume_cache ()
{
return (false || ... || volume_cache_defined<TCompetence> ());
}
/**
* Function that checks if a cache for the vertex coordinates exists.
* \return true if a cache for the vertex coordinates exists, false otherwise.
*/
static constexpr bool
has_vertex_cache ()
{
return vertex_cache_exists;
return (false || ... || vertex_cache_defined<TCompetence> ());
}

/**
Expand All @@ -160,7 +163,7 @@ class element: public TCompetence<element<TCompetence...>>... {
static constexpr bool
has_centroid_cache ()
{
return centroid_cache_exists;
return (false || ... || centroid_cache_defined<TCompetence> ());
}

/**
Expand All @@ -170,7 +173,7 @@ class element: public TCompetence<element<TCompetence...>>... {
static constexpr bool
has_face_neighbor_cache ()
{
return neighbor_cache_exists;
return (false || ... || neighbor_cache_defined<TCompetence> ());
}

// --- Functionality of the element. In each function, it is checked if a cached version exists (and is used then). ---
Expand Down Expand Up @@ -209,6 +212,25 @@ class element: public TCompetence<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 (has_volume_cache ()) {
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 All @@ -218,7 +240,7 @@ class element: public TCompetence<element<TCompetence...>>... {
get_vertex_coordinates () const
{
// Check if we have a cached version and if the cache has already been filled.
if constexpr (vertex_cache_exists) {
if constexpr (has_vertex_cache ()) {
if (this->vertex_cache_filled ()) {
return this->m_vertex_coordinates;
}
Expand All @@ -232,7 +254,7 @@ class element: public TCompetence<element<TCompetence...>>... {
t8_forest_element_coordinate (m_mesh->m_forest, m_tree_id, element, icorner, vertex_coordinates[icorner].data ());
}
// Fill the cache in the cached version.
if constexpr (vertex_cache_exists) {
if constexpr (has_vertex_cache ()) {
this->m_vertex_coordinates = std::move (vertex_coordinates);
return this->m_vertex_coordinates;
}
Expand All @@ -248,15 +270,15 @@ class element: public TCompetence<element<TCompetence...>>... {
get_centroid () const
{
// Check if we have a cached version and if the cache has already been filled.
if constexpr (centroid_cache_exists) {
if constexpr (has_centroid_cache ()) {
if (this->centroid_cache_filled ()) {
return this->m_centroid.value ();
}
}
t8_3D_point coordinates;
t8_forest_element_centroid (m_mesh->m_forest, m_tree_id, get_element (), coordinates.data ());
// Fill the cache in the cached version.
if constexpr (centroid_cache_exists) {
if constexpr (has_centroid_cache ()) {
this->m_centroid = coordinates;
}
return coordinates;
Expand All @@ -272,7 +294,7 @@ class element: public TCompetence<element<TCompetence...>>... {
get_face_neighbors (int face, std::optional<std::reference_wrapper<std::vector<int>>> dual_faces = std::nullopt) const
{
SC_CHECK_ABORT (!m_is_ghost_element, "get_face_neighbors is not implemented for ghost elements.\n");
if constexpr (neighbor_cache_exists) {
if constexpr (has_face_neighbor_cache ()) {
if (this->neighbor_cache_filled (face)) {
if (dual_faces) {
dual_faces->get () = this->m_dual_faces[face];
Expand All @@ -296,7 +318,7 @@ class element: public TCompetence<element<TCompetence...>>... {
for (int ineighs = 0; ineighs < num_neighbors; ineighs++) {
neighbors_handle.push_back (&((*m_mesh)[neighids[ineighs]]));
}
if constexpr (neighbor_cache_exists) {
if constexpr (has_face_neighbor_cache ()) {
// Also store num_neighbors in cache to indicate that the cache is filled if a face does not have any neighbor.
this->m_num_neighbors[face] = num_neighbors;
this->m_dual_faces[face].assign (dual_faces_internal, dual_faces_internal + num_neighbors);
Expand All @@ -309,7 +331,7 @@ class element: public TCompetence<element<TCompetence...>>... {
T8_FREE (dual_faces_internal);
T8_FREE (neighids);
}
if constexpr (neighbor_cache_exists) {
if constexpr (has_face_neighbor_cache ()) {
return this->m_neighbors[face];
}
return neighbors_handle;
Expand All @@ -320,7 +342,7 @@ class element: public TCompetence<element<TCompetence...>>... {
*/
void
fill_face_neighbor_cache () const
requires (neighbor_cache_exists)
requires (has_face_neighbor_cache ())
{
for (int iface = 0; iface < get_num_faces (); iface++) {
get_face_neighbors (iface);
Expand Down Expand Up @@ -390,6 +412,34 @@ class element: public TCompetence<element<TCompetence...>>... {
return m_is_ghost_element;
}

// --- Getter and setter for element data. ---
/** Getter for the element data.
* For ghost elements ensure that \ref mesh::exchange_ghost_data is called on each process first.
* Element data for non-ghost elements can be accessed (if set) directly.
* \return Element data with data of Type mesh_class::ElementDataType.
*/
template <typename E = typename mesh_class::ElementDataType, typename = std::enable_if_t<!std::is_void<E>::value>>
const E&
get_element_data () const
{
return m_mesh->m_element_data[get_element_handle_id ()];
}

/**
* Set the element data for the element.
* \note You can only set element data for non-ghost elements.
* \param [in] element_data The element data to be set.
*/
template <typename E = typename mesh_class::ElementDataType, typename = std::enable_if_t<!std::is_void<E>::value>>
void
set_element_data (E element_data)
{
SC_CHECK_ABORT (!m_is_ghost_element, "Element data cannot be set for ghost elements.\n");
// Resize for the case that no data vector has been set previously.
m_mesh->m_element_data.resize (m_mesh->get_num_local_elements () + m_mesh->get_num_ghosts ());
m_mesh->m_element_data[get_element_handle_id ()] = element_data;
}

private:
//--- Private getter for internal use. ---
/**
Expand All @@ -412,7 +462,7 @@ class element: public TCompetence<element<TCompetence...>>... {
return t8_forest_get_tree_class (m_mesh->m_forest, m_tree_id);
}

const mesh_class* m_mesh; /**< Pointer to the mesh the element is defined for. */
mesh_class* m_mesh; /**< Pointer to the mesh the element is defined for. */
const t8_locidx_t m_tree_id; /**< The tree id of the element in the forest defined in the mesh. */
const t8_locidx_t m_element_id; /**< The element id of the element in the forest defined in the mesh. */
const bool m_is_ghost_element; /**< Flag to indicate if the element is a ghost element. */
Expand Down
Loading