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
25 changes: 19 additions & 6 deletions mesh_handle/competence_pack.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,14 @@ using all_cache_element_competences
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>;
/** Predefined element data competence pack.
* Please note that you must combine this with \ref t8_mesh_handle::data_mesh_competences_basic. */
using data_element_competences_basic = element_competence_pack<element_data_element_competence>;

/** Predefined element competence pack combining the element data competence and competence to set new element data.
* Please note that you must combine this with \ref t8_mesh_handle::new_data_mesh_competences. */
using new_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.
Expand All @@ -90,11 +95,19 @@ struct mesh_competence_pack
/** Empty competence pack. */
using empty_mesh_competences = mesh_competence_pack<>;

/** 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.
/** Predefined mesh competence pack to handle element data.
* If you want to access the data also via the elements, combine this with \ref t8_mesh_handle::data_element_competences_basic.
*/
template <T8MPISafeType TElementDataType>
using data_mesh_competences_basic = mesh_competence_pack<element_data_mesh_competence<TElementDataType>::template type>;

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

// --- Compute union of competence packs. ---
/** Compute the unique union of the competences of several competence_pack. This could be
Expand Down
152 changes: 145 additions & 7 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,9 +47,9 @@ 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_mesh_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 element_data_element_competence 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<element_data_element_competence>,
* mesh_competence_pack<element_data_mesh_competence<YourElementDataType>::template type>>;
Expand Down Expand Up @@ -133,13 +137,12 @@ struct element_data_mesh_competence
* \tparam TUnderlying Use the \ref element with specified competences as template parameter.
*/
template <typename TUnderlying>
struct element_data_element_competence: 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.
* \param [in] element_data The element data to be set of type TMeshClass::ElementDataType.
*/
void
set_element_data (auto element_data)
Expand Down Expand Up @@ -170,4 +173,139 @@ struct element_data_element_competence: public t8_crtp_basic<TUnderlying>
}
};

// --- 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 new_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] new_element_data New element data to be set of Type TMeshClass::ElementDataType.
*/
void
set_new_element_data (auto new_element_data)
{
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_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];
}
};

} // namespace t8_mesh_handle
6 changes: 4 additions & 2 deletions mesh_handle/element.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ namespace t8_mesh_handle
* 2.) for the cached options to keep the number of member variables of the default element to a minimum to save memory.
* The choice between calculate and cache is a tradeoff between runtime and memory usage.
*
* \tparam TMeshClass The class of the mesh the element belongs to.
* \tparam TCompetences The competences you want to add to the default functionality of the element.
*/

Expand All @@ -65,8 +66,9 @@ class element: public TCompetences<element<TMeshClass, TCompetences...>>... {
parameters specified. */
friend TMeshClass; /**< Define TMeshClass as friend to be able to access e.g. the constructor. */
friend struct element_data_element_competence<
SelfType>; /**< Define the competence to access element data as friend to
be able to access e.g. the mesh. */
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
37 changes: 26 additions & 11 deletions mesh_handle/mesh.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ class mesh: public TMeshCompetencePack::template apply<mesh<TElementCompetencePa
using mesh_iterator =
typename std::vector<element_class>::iterator; /**< Non-const iterator type for the mesh elements. */
friend struct element_data_element_competence<element_class>; /**< Friend struct to access its element data vector. */
friend struct new_element_data_element_competence<
element_class>; /**< Friend struct to access its element data vector. */

/** Callback function prototype to decide for refining and coarsening of a family of elements
* or one element in a mesh handle.
Expand Down Expand Up @@ -250,6 +252,25 @@ class mesh: public TMeshCompetencePack::template apply<mesh<TElementCompetencePa
return const_cast<element_class&> (static_cast<const mesh*> (this)->operator[] (local_index));
}

// --- Methods to check for mesh competences. ---
/** Function that checks if a competence for element data handling is given.
* \return true if mesh has a data handler, false otherwise.
*/
static constexpr bool
has_element_data_handler_competence ()
{
return requires (SelfType& mesh) { mesh.get_element_data (); };
}

/** Function that checks if a competence for element data handling is given.
* \return true if mesh has a data handler, false otherwise.
*/
static constexpr bool
has_new_element_data_handler_competence ()
{
return requires (SelfType& mesh) { mesh.get_new_element_data (); };
}

// --- Methods to change the mesh, e.g. adapt, partition, balance, ... ---
/** Wrapper to convert an adapt callback with user data of type \ref adapt_callback_type_with_userdata
* into a callback without user data of type \ref adapt_callback_type using the defined user data \a user_data.
Expand Down Expand Up @@ -358,6 +379,7 @@ class mesh: public TMeshCompetencePack::template apply<mesh<TElementCompetencePa
* The forest used to define the mesh handle is replaced in this function.
* The previous forest is unreferenced. Call \ref t8_forest_ref before if you want to keep it alive.
* Specialize the update with calls like \ref set_adapt first.
* If the competence \ref new_element_data_mesh_competence is used, the element data will be updated.
*/
void
commit ()
Expand All @@ -377,7 +399,7 @@ class mesh: public TMeshCompetencePack::template apply<mesh<TElementCompetencePa
// Check if we adapted and unregister the adapt context if so.
if (detail::adapt_registry::get (m_uncommitted_forest.value ()) != nullptr) {
detail::adapt_registry::unregister_context (m_forest);
if (has_element_data_handler_competence ()) {
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");
Expand All @@ -388,16 +410,9 @@ class mesh: public TMeshCompetencePack::template apply<mesh<TElementCompetencePa
m_forest = m_uncommitted_forest.value ();
m_uncommitted_forest = std::nullopt;
update_elements ();
}

// --- Methods to check for mesh competences. ---
/** Function that checks if a competence for element data handling is given.
* \return true if mesh has a data handler, false otherwise.
*/
static constexpr bool
has_element_data_handler_competence ()
{
return requires (SelfType& mesh) { mesh.get_element_data (); };
if constexpr (has_new_element_data_handler_competence ()) {
this->write_new_to_element_data ();
}
}

private:
Expand Down
Loading
Loading