Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
DLR-AMR
GitHub Repository: DLR-AMR/t8code
Path: blob/main/test/mesh_handle/t8_gtest_mesh_handle.cxx
916 views
/*
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 t8_gtest_mesh_handle.cxx
 * Tests if the \ref t8_mesh_handle::mesh class of the handle works as intended for different types of template parameter classes. 
 */

#include <gtest/gtest.h>
#include <test/t8_gtest_macros.hxx>
#include <t8.h>

#include <mesh_handle/mesh.hxx>
#include <mesh_handle/competences.hxx>
#include <mesh_handle/competence_pack.hxx>
#include <mesh_handle/constructor_wrappers.hxx>

/** Parametrized test fixture for the mesh handle tests. */
struct t8_mesh_handle_test: public testing::TestWithParam<std::tuple<t8_eclass_t, int>>
{
 protected:
  void
  SetUp () override
  {
    eclass = std::get<0> (GetParam ());
    level = std::get<1> (GetParam ());
  }

  t8_eclass_t eclass; /**< Element class used for testing.*/
  int level;          /**< Refinement level used for testing.*/
};

/** Test default \ref t8_mesh_handle::mesh handle, the iterator and some exemplary functionality. */
TEST_P (t8_mesh_handle_test, test_default_mesh_handle)
{
  using mesh_class = t8_mesh_handle::mesh<>;
  using element_class = typename mesh_class::element_class;
  auto mesh = t8_mesh_handle::handle_hypercube_uniform_default<mesh_class> (eclass, level, sc_MPI_COMM_WORLD, true,
                                                                            true, false);
  EXPECT_FALSE (element_class::has_vertex_cache ());
  EXPECT_FALSE (element_class::has_centroid_cache ());

  // Iterate with the constant iterator over all mesh elements and check some functionality.
  for (auto it = mesh->cbegin (); it != mesh->cend (); ++it) {
    EXPECT_FALSE (it->has_vertex_cache ());
    EXPECT_FALSE (it->has_centroid_cache ());
    auto centroid = it->get_centroid ();
    for (const auto& coordinate : centroid) {
      EXPECT_TRUE (coordinate >= 0.0 && coordinate <= 1.0);
    }
    auto vertex_coordinates = (*it).get_vertex_coordinates ();
    for (int ivertex = 0; ivertex < (int) vertex_coordinates.size (); ++ivertex) {
      for (const auto& coordinate : vertex_coordinates[ivertex]) {
        EXPECT_TRUE (coordinate >= 0.0 && coordinate <= 1.0);
      }
    }
  }

  // Check loop with indices.
  for (int ielement = 0; ielement < mesh->get_num_local_elements (); ielement++) {
    EXPECT_EQ (level, (*mesh)[ielement].get_level ());
    EXPECT_EQ (ielement, (*mesh)[ielement].get_element_handle_id ());
  }
}

/** Test mesh class with all competence available using some exemplary functionality. */
TEST_P (t8_mesh_handle_test, test_all_cache_competence)
{
  // --- Use predefined competences to use all available caching competences. ---
  using mesh_class = t8_mesh_handle::mesh<t8_mesh_handle::all_cache_competences>;
  using element_class = typename mesh_class::element_class;
  auto mesh = t8_mesh_handle::handle_hypercube_uniform_default<mesh_class> (eclass, level, sc_MPI_COMM_WORLD, true,
                                                                            true, false);
  EXPECT_TRUE (element_class::has_volume_cache ());
  EXPECT_TRUE (element_class::has_diameter_cache ());
  EXPECT_TRUE (element_class::has_vertex_cache ());
  EXPECT_TRUE (element_class::has_centroid_cache ());
  EXPECT_TRUE (element_class::has_face_areas_cache ());
  EXPECT_TRUE (element_class::has_face_centroids_cache ());
  EXPECT_TRUE (element_class::has_face_normals_cache ());
  EXPECT_TRUE (element_class::has_face_neighbor_cache ());

  // Iterate over all mesh elements and access some exemplary functionality which sets the caches.
  for (auto it = mesh->cbegin (); it != mesh->cend (); ++it) {
    EXPECT_FALSE (it->volume_cache_filled ());
    EXPECT_FALSE (it->centroid_cache_filled ());
    EXPECT_FALSE (it->vertex_cache_filled ());
    EXPECT_EQ (level, it->get_level ());
    EXPECT_GE (it->get_volume (), 0);
    for (const auto& coordinate : it->get_centroid ()) {
      EXPECT_TRUE (coordinate >= 0.0 && coordinate <= 1.0);
    }
    for (int ivertex = 0; ivertex < it->get_num_vertices (); ++ivertex) {
      for (const auto& coordinate : it->get_vertex_coordinates (ivertex)) {
        EXPECT_TRUE (coordinate >= 0.0 && coordinate <= 1.0);
      }
    }
  }
  // Check if caches are set. If caches are accessed correctly is checked in another test.
  for (auto it = mesh->cbegin (); it != mesh->cend (); ++it) {
    EXPECT_TRUE (it->volume_cache_filled ());
    EXPECT_TRUE (it->centroid_cache_filled ());
    EXPECT_TRUE (it->vertex_cache_filled ());
    EXPECT_FALSE (it->diameter_cache_filled ());
    if (it->get_num_faces () > 0) {
      EXPECT_FALSE (it->face_area_cache_filled (0));
      EXPECT_FALSE (it->face_centroid_cache_filled (0));
      EXPECT_FALSE (it->face_normal_cache_filled (0));
    }
    EXPECT_FALSE (it->neighbor_cache_filled_any ());
  }
}

/** Test mesh class with all predefined face competences using some exemplary functionality. */
TEST_P (t8_mesh_handle_test, test_cache_face_competences)
{
  // --- Use all predefined competences. ---
  using mesh_class = t8_mesh_handle::mesh<t8_mesh_handle::cache_face_competences>;
  using element_class = typename mesh_class::element_class;
  auto mesh = t8_mesh_handle::handle_hypercube_uniform_default<mesh_class> (eclass, level, sc_MPI_COMM_WORLD, true,
                                                                            true, false);
  EXPECT_FALSE (element_class::has_volume_cache ());
  EXPECT_FALSE (element_class::has_diameter_cache ());
  EXPECT_FALSE (element_class::has_vertex_cache ());
  EXPECT_FALSE (element_class::has_centroid_cache ());
  EXPECT_TRUE (element_class::has_face_areas_cache ());
  EXPECT_TRUE (element_class::has_face_centroids_cache ());
  EXPECT_TRUE (element_class::has_face_normals_cache ());
  EXPECT_TRUE (element_class::has_face_neighbor_cache ());

  // Iterate over all mesh elements and access some exemplary functionality which sets the caches.
  for (auto it = mesh->cbegin (); it != mesh->cend (); ++it) {
    if (it->get_num_faces () == 0) {
      GTEST_SKIP () << "Skipping test as there are no faces to be tested.";
    }
    for (int iface = 0; iface < it->get_num_faces (); ++iface) {
      EXPECT_FALSE (it->face_area_cache_filled (iface));
      EXPECT_FALSE (it->face_normal_cache_filled (iface));
      EXPECT_GE (it->get_face_area (iface), 0);
      for (const auto& coordinate : it->get_face_normal (iface)) {
        EXPECT_TRUE (coordinate >= -1 && coordinate <= 1);
      }
    }
  }
  // Check if caches are set. If caches are accessed correctly is checked in another test.
  for (auto it = mesh->cbegin (); it != mesh->cend (); ++it) {
    for (int iface = 0; iface < it->get_num_faces (); ++iface) {
      EXPECT_TRUE (it->face_area_cache_filled (iface));
      EXPECT_FALSE (it->face_centroid_cache_filled (iface));
      EXPECT_TRUE (it->face_normal_cache_filled (iface));
    }
    EXPECT_FALSE (it->neighbor_cache_filled_any ());
  }
}

INSTANTIATE_TEST_SUITE_P (t8_gtest_mesh, t8_mesh_handle_test, testing::Combine (AllEclasses, testing::Range (2, 3)));