Skip to content
Draft
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
17 changes: 15 additions & 2 deletions mesh_handle/competence_pack.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
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
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
Expand All @@ -28,6 +28,7 @@
#pragma once

#include "competences.hxx"
#include "data_handler.hxx"
namespace t8_mesh_handle
{
// --- Element competence pack. ---
Expand All @@ -52,10 +53,15 @@ using all_cache_element_competences
= element_competence_pack<cache_volume, cache_diameter, cache_vertex_coordinates, cache_centroid, cache_face_areas,
cache_face_centroids, cache_face_normals, cache_neighbors>;

/** Predefined competence pack combining all competences related to faces. */
/** Predefined element competence pack combining all competences related to faces. */
using cache_face_element_competences
= element_competence_pack<cache_face_areas, cache_face_centroids, cache_face_normals, cache_neighbors>;

/** Predefined element competence pack combining all competences related to data.
* Please note that you must combine this with \ref t8_mesh_handle::data_mesh_competences. */
using data_element_competences
= element_competence_pack<element_data_element_competence, new_element_data_element_competence>;

// --- Mesh competence pack. ---
/** Class to pack different mesh competences into one template parameter for the \ref mesh class.
* \tparam TMeshCompetence The mesh competences to be packed.
Expand All @@ -75,4 +81,11 @@ struct mesh_competence_pack
using is_mesh_competence_pack = void; /**< Tag to identify this class. */
};

/** Predefined mesh competence pack combining all competences related to data.
* If you want to access the data also via the elements, combine this with \ref t8_mesh_handle::data_element_competences.
*/
template <T8MPISafeType TElementDataType>
using data_mesh_competences = mesh_competence_pack<element_data_mesh_competence<TElementDataType>::template type,
new_element_data_mesh_competence<TElementDataType>::template type>;

} // namespace t8_mesh_handle
194 changes: 167 additions & 27 deletions mesh_handle/data_handler.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,18 @@

/** \file data_handler.hxx
* Handler for the element data of a \ref t8_mesh_handle::mesh.
* The file defines a mesh and an element competence for element data handling.
* Use both competences together if you want to manage element data for the elements of the mesh and access it directly for each element.
* The file defines mesh and element competences for element data handling.
* The mesh competences make it possible to manage element data and exchange it for ghost elements between processes.
* The element competences makes it possible to access these element data directly for each element of the mesh.
* The competences with new element data additionally provide the possibility to set new element data that will
* be used to update the element data on commit (or on the related function call).
*/
#pragma once

#include <t8.h>
#include <t8_forest/t8_forest_general.h>
#include <t8_types/t8_crtp.hxx>
#include <t8_types/t8_operators.hxx>
#include <type_traits>
#include <vector>

Expand All @@ -43,19 +47,20 @@ concept T8MPISafeType

/** Handler for the element data of a \ref mesh.
* Use this competence if you want to manage element data for the elements of the mesh.
* Use the helper \ref element_data_competence to get this competence with the correct template parameters form for the mesh.
* Use the helper \ref element_data_mesh_competence to get this competence with the correct template parameters form.
* If you want to access the data not only in vector form but also directly for each element,
* you can combine this competence with the \ref access_element_data competence.
* you can combine this competence with \ref element_data_element_competence.
* In summary you can use the competences like this:
* mesh<element_competence_pack<access_element_data>,
* mesh_competence_pack<element_data_competence<YourElementDataType>::template type>>;
* mesh<element_competence_pack<element_data_element_competence>,
* mesh_competence_pack<element_data_mesh_competence<YourElementDataType>::template type>>;
* Some predefined competences are also defined in \ref competence_pack.hxx.
*
* \tparam TUnderlying Use the \ref mesh class here.
* \tparam TElementDataType The element data type you want to use for each element of the mesh.
* The data type has to be MPI safe as the data for ghost elements will be exchanged via MPI.
*/
template <typename TUnderlying, T8MPISafeType TElementDataType>
class handle_element_data: public t8_crtp_basic<TUnderlying> {
class element_data_mesh_competence_impl: public t8_crtp_basic<TUnderlying> {
public:
using ElementDataType = TElementDataType; /**< Make Type of the element data publicly accessible. */

Expand All @@ -69,9 +74,8 @@ class handle_element_data: public t8_crtp_basic<TUnderlying> {
const auto num_local_elements = this->underlying ().get_num_local_elements ();
const auto num_ghosts = this->underlying ().get_num_ghosts ();
T8_ASSERT (element_data.size () == static_cast<size_t> (num_local_elements));
m_element_data = std::move (element_data);
m_element_data.reserve (num_local_elements + num_ghosts);
m_element_data.resize (num_local_elements);
m_element_data = std::move (element_data);
}

/** Get the element data vector.
Expand Down Expand Up @@ -109,35 +113,52 @@ class handle_element_data: public t8_crtp_basic<TUnderlying> {
std::vector<TElementDataType> m_element_data; /**< Vector storing the (local) element data. */
};

/** Wrapper for \ref handle_element_data to hide TUnderlying and provide the form needed to pass it as a mesh competence.
* Use mesh_competence_pack<element_data_competence<YourElementDataType>::template type>
/** Wrapper for \ref element_data_mesh_competence_impl to hide TUnderlying and provide the form needed to pass it
* as a mesh competence.
* Use mesh_competence_pack<element_data_mesh_competence<YourElementDataType>::template type>
* to get this competence with the correct template parameter form for the mesh.
* \tparam TElementDataType The element data type you want to use for each element of the mesh.
* The data type has to be MPI safe as the data for ghost elements will be exchanged via MPI.
*/
template <T8MPISafeType TElementDataType>
struct element_data_competence
struct element_data_mesh_competence
{
/** Type to provide the form needed for the mesh competence pack.
* \tparam TUnderlying Use the \ref mesh class here.
*/
template <typename TUnderlying>
using type = handle_element_data<TUnderlying, TElementDataType>;
using type = element_data_mesh_competence_impl<TUnderlying, TElementDataType>;
};

// --- Element competence for element data management. ---
/** Element competence to enable that element data can be accessed directly for each element of the mesh.
* \note This competence requires that the mesh has the \ref handle_element_data competence to manage the
* element data vector and exchange ghost data.
* \note This competence requires that the mesh has \ref element_data_mesh_competence_impl
* (or \ref element_data_mesh_competence) competence that defines the element data vector and the element data type.
* \tparam TUnderlying Use the \ref element with specified competences as template parameter.
*/
template <typename TUnderlying>
struct access_element_data: public t8_crtp_basic<TUnderlying>
struct element_data_element_competence: public t8_crtp_operator<TUnderlying, element_data_element_competence>
{
public:
// --- Getter and setter for element data. ---
/** 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 of type TMeshClass::ElementDataType.
*/
void
set_element_data (auto element_data)
{
T8_ASSERT (this->underlying ().m_mesh->has_element_data_handler_competence ());
SC_CHECK_ABORT (!this->underlying ().is_ghost_element (), "Element data cannot be set for ghost elements.\n");
// Resize for the case that no data vector has been set previously.
this->underlying ().m_mesh->m_element_data.reserve (this->underlying ().m_mesh->get_num_local_elements ()
+ this->underlying ().m_mesh->get_num_ghosts ());
this->underlying ().m_mesh->m_element_data.resize (this->underlying ().m_mesh->get_num_local_elements ());
this->underlying ().m_mesh->m_element_data[this->underlying ().get_element_handle_id ()] = std::move (element_data);
}

/** Getter for the element data.
* For ghost elements ensure that \ref handle_element_data::exchange_ghost_data is called on each process first.
* For ghost elements ensure that \ref element_data_mesh_competence_impl::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 TMeshClass::ElementDataType.
*/
Expand All @@ -150,21 +171,140 @@ struct access_element_data: public t8_crtp_basic<TUnderlying>
"Element data not set.\n");
return this->underlying ().m_mesh->m_element_data[handle_id];
}
};

/** Set the element data for the element.
// --- Competences for new element data. ---
/* Using setter of \ref element_data_mesh_competence and \ref element_data_element_competence, the element data
* are updated in place such that we cannot access the old data afterwards. With the following competences,
* an additional data vector is defined for the mesh where new element data can be stored that will replace the element
* data vector on commit.
*/

/** Detail namespace should be uninteresting for users. */
namespace detail
{
/** Dummy for the inheritance of \ref new_element_data_mesh_competence_impl.
* The dummy class is used in the inheritance pattern to avoid diamond shaped inheritance
* if the competence is used together with \ref element_data_mesh_competence_impl.
* \tparam TUnderlying Use the \ref mesh class here.
*/
template <typename TUnderlying>
struct new_element_data_helper
{
};
} // namespace detail

/** Define new element data vector for the mesh.
* Using setter of \ref element_data_mesh_competence and \ref element_data_element_competence, the element data
* are updated in place such that we cannot access the old data afterwards.
* Use this competence if you want to manage new element data separately that will be used to update the element data
* on commit (or if \ref write_new_to_element_data is called).
* \note This competence only makes sense if the mesh also has \ref element_data_mesh_competence.
* You can use the predefined competence pack \ref data_mesh_competences to get both competences together.
* Use the helper \ref new_element_data_mesh_competence to get this competence with the correct template parameters form.
* If you want to access the data not only in vector form but also directly for each element,
* you can combine this competence with \ref new_element_data_element_competence.
*
* \tparam TUnderlying Use the \ref mesh class here.
* \tparam TElementDataType The element data type you want to use for each element of the mesh.
* The data type has to be MPI safe as the data for ghost elements will be exchanged via MPI.
* \note TElementDataType must be the same as the datatype in \ref element_data_mesh_competence_impl.
*/
template <typename TUnderlying, T8MPISafeType TElementDataType>
class new_element_data_mesh_competence_impl: public t8_crtp_operator<TUnderlying, detail::new_element_data_helper> {
public:
/** Set the new element data vector. The vector should have the length of num_local_elements.
* \param [in] new_element_data The element data vector to set with one entry of class TElementDataType
* for each local mesh element (excluding ghosts).
*/
void
set_new_element_data (std::vector<TElementDataType> new_element_data)
{
const auto num_local_elements = this->underlying ().get_num_local_elements ();
T8_ASSERT (new_element_data.size () == static_cast<size_t> (num_local_elements));
m_new_element_data = std::move (new_element_data);
m_new_element_data.resize (num_local_elements);
}

/** Get the new element data vector.
* The new element data of the local mesh elements can be set using \ref set_new_element_data.
* \return New element data vector with data of Type TElementDataType.
*/
const auto&
get_new_element_data () const
{
return m_new_element_data;
}

/** Overwrite the element data vector of the mesh with the new element data vector.
*/
void
write_new_to_element_data ()
{
T8_ASSERT (this->underlying ().has_element_data_handler_competence ());
this->underlying ().set_element_data (m_new_element_data);
m_new_element_data.clear ();
}

protected:
std::vector<TElementDataType> m_new_element_data; /**< Vector storing the (local) new element data. */
};

/** Wrapper for \ref new_element_data_mesh_competence_impl to hide TUnderlying and provide the form needed to pass
* it as a mesh competence.
* Use mesh_competence_pack<new_element_data_mesh_competence<YourElementDataType>::template type>
* to get this competence with the correct template parameter form for the mesh.
* \tparam TElementDataType The element data type you want to use for each element of the mesh.
* The data type has to be MPI safe as the data for ghost elements will be exchanged via MPI.
* \note TElementDataType must be the same as the datatype in \ref element_data_mesh_competence.
*/
template <T8MPISafeType TElementDataType>
struct new_element_data_mesh_competence
{
/** Type to provide the form needed for the mesh competence pack.
* \tparam TUnderlying Use the \ref mesh class here.
*/
template <typename TUnderlying>
using type = new_element_data_mesh_competence_impl<TUnderlying, TElementDataType>;
};

// --- Element competence for new element data. ---
/** Element competence to enable that element data can be accessed directly for each element of the mesh.
* \note This competence requires that the mesh has \ref new_element_data_mesh_competence_impl such that
* the new data vector is available and the element data type is defined.
* \tparam TUnderlying Use the \ref element with specified competences as template parameter.
*/
template <typename TUnderlying>
struct new_element_data_element_competence: public t8_crtp_operator<TUnderlying, new_element_data_element_competence>
{
public:
/** Set the new 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 of Type TMeshClass::ElementDataType.
* \param [in] new_element_data New element data to be set of Type TMeshClass::ElementDataType.
*/
void
set_element_data (auto element_data)
set_new_element_data (auto new_element_data)
{
T8_ASSERT (this->underlying ().m_mesh->has_element_data_handler_competence ());
SC_CHECK_ABORT (!this->underlying ().is_ghost_element (), "Element data cannot be set for ghost elements.\n");
T8_ASSERT (this->underlying ().m_mesh->has_new_element_data_handler_competence ());
SC_CHECK_ABORT (!this->underlying ().is_ghost_element (), "New element data cannot be set for ghost elements.\n");
// Resize for the case that no data vector has been set previously.
this->underlying ().m_mesh->m_element_data.reserve (this->underlying ().m_mesh->get_num_local_elements ()
+ this->underlying ().m_mesh->get_num_ghosts ());
this->underlying ().m_mesh->m_element_data.resize (this->underlying ().m_mesh->get_num_local_elements ());
this->underlying ().m_mesh->m_element_data[this->underlying ().get_element_handle_id ()] = std::move (element_data);
this->underlying ().m_mesh->m_new_element_data.resize (this->underlying ().m_mesh->get_num_local_elements ());
this->underlying ().m_mesh->m_new_element_data[this->underlying ().get_element_handle_id ()]
= std::move (new_element_data);
}

/** Getter for new element data.
* \return New element data with data of Type TMeshClass::ElementDataType.
*/
const auto&
get_new_element_data () const
{
T8_ASSERT (this->underlying ().m_mesh->has_new_element_data_handler_competence ());

const t8_locidx_t handle_id = this->underlying ().get_element_handle_id ();
T8_ASSERTF (static_cast<size_t> (handle_id) < this->underlying ().m_mesh->m_new_element_data.size (),
"Element data not set.\n");
return this->underlying ().m_mesh->m_new_element_data[handle_id];
}
};

Expand Down
6 changes: 4 additions & 2 deletions mesh_handle/element.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,10 @@ class element: public TCompetences<element<TMeshClass, TCompetences...>>... {
using SelfType
= element<TMeshClass, TCompetences...>; /**< Type of the current class with all template parameters specified. */
friend TMeshClass; /**< Define TMeshClass as friend to be able to access e.g. the constructor. */
friend struct access_element_data<
SelfType>; /**< Define the competence to access element data as friend to be able to access e.g. the mesh. */
friend struct element_data_element_competence<
SelfType>; /**< Define the competence as friend to be able to access e.g. the mesh from competence. */
friend struct new_element_data_element_competence<
SelfType>; /**< Define the competence as friend to be able to access e.g. the mesh from competence. */

/** 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 TMeshClass (and invisible for the user).
Expand Down
Loading