Program Listing for File element.hxx

Return to documentation for file (mesh_handle/element.hxx)

/*
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.
*/

#ifndef T8_ELEMENT_HXX
#define T8_ELEMENT_HXX

#include <t8.h>
#include <t8_element.h>
#include <t8_eclass.h>
#include <t8_forest/t8_forest_general.h>
#include <t8_forest/t8_forest_geometrical.h>
#include <t8_schemes/t8_scheme.hxx>
#include <t8_types/t8_vec.hxx>
#include <array>
#include <vector>

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

template <template <typename> class... TCompetence>
class element: public TCompetence<element<TCompetence...>>... {
  using SelfType = element<TCompetence...>;

 private:
  // --- Variables to check which functionality is defined in TCompetence. ---
  template <template <typename> class T>
  static constexpr bool
  vertex_cache_defined ()
  {
    return requires (T<SelfType>& competence) { competence.vertex_cache_filled (); };
  }
  /* This variable is true if any of the given competences \ref TCompetence implements
  a function vertex_cache_filled */
  static constexpr bool vertex_cache_exists = (false || ... || vertex_cache_defined<TCompetence> ());

  template <template <typename> class T>
  static constexpr bool
  centroid_cache_defined ()
  {
    return requires (T<SelfType>& competence) { competence.centroid_cache_filled (); };
  }
  /* This variable is true if any of the given competences \ref TCompetence implements
  a function centroid_cache_filled. */
  static constexpr bool centroid_cache_exists = (false || ... || centroid_cache_defined<TCompetence> ());

 public:
  element (mesh<SelfType>* mesh, t8_locidx_t tree_id, t8_locidx_t element_id)
    : m_mesh (mesh), m_tree_id (tree_id), m_element_id (element_id)
  {
  }

  // --- Functions to check if caches exist. ---
  static constexpr bool
  has_vertex_cache ()
  {
    return vertex_cache_exists;
  }

  static constexpr bool
  has_centroid_cache ()
  {
    return centroid_cache_exists;
  }

  // --- Functionality of the element. In each function, it is checked if a cached version exists (and is used then). ---
  t8_element_level
  get_level () const
  {
    const t8_eclass_t tree_class = get_tree_class ();
    const t8_element_t* element = get_element ();
    return t8_forest_get_scheme (m_mesh->m_forest)->element_get_level (tree_class, element);
  }

  t8_element_shape_t
  get_shape () const
  {
    return t8_forest_get_scheme (m_mesh->m_forest)->element_get_shape (get_tree_class (), get_element ());
  }

  std::vector<t8_3D_point>
  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 (this->vertex_cache_filled ()) {
        return this->m_vertex_coordinates;
      }
    }
    // Calculate the vertex coordinates.
    const t8_element_t* element = get_element ();
    const int num_corners
      = t8_forest_get_scheme (m_mesh->m_forest)->element_get_num_corners (get_tree_class (), element);
    std::vector<t8_3D_point> vertex_coordinates (num_corners);
    for (int icorner = 0; icorner < num_corners; ++icorner) {
      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) {
      this->m_vertex_coordinates = std::move (vertex_coordinates);
      return this->m_vertex_coordinates;
    }
    return vertex_coordinates;
  }

  t8_3D_point
  get_centroid () const
  {
    // Check if we have a cached version and if the cache has already been filled.
    if constexpr (centroid_cache_exists) {
      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) {
      this->m_centroid = coordinates;
    }
    return coordinates;
  }

  //--- Getter for the member variables. ---
  t8_locidx_t
  get_local_tree_id () const
  {
    return m_tree_id;
  }

  t8_locidx_t
  get_local_element_id () const
  {
    return m_element_id;
  }

  const mesh<SelfType>*
  get_mesh () const
  {
    return m_mesh;
  }

 private:
  //--- Private getter for internal use. ---
  const t8_element_t*
  get_element () const
  {
    return t8_forest_get_leaf_element_in_tree (m_mesh->m_forest, m_tree_id, m_element_id);
  }

  t8_eclass_t
  get_tree_class () const
  {
    return t8_forest_get_tree_class (m_mesh->m_forest, m_tree_id);
  }

  mesh<SelfType>* m_mesh;
  t8_locidx_t m_tree_id;
  t8_locidx_t m_element_id;
};

}  // namespace t8_mesh_handle
#endif /* !T8_ELEMENT_HXX */