Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
DLR-AMR
GitHub Repository: DLR-AMR/t8code
Path: blob/main/test/t8_gtest_eclass.cxx
900 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) 2024 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.
*/

#include <gtest/gtest.h>
#include <t8_eclass.h>
#include <t8_cmesh/t8_cmesh.h>
#include <t8_cmesh/t8_cmesh_examples.h>
#include <t8_types/t8_vec.h>
#include <test/t8_gtest_macros.hxx>

struct gtest_eclass: public testing::TestWithParam<t8_eclass_t>
{
 protected:
  void
  SetUp () override
  {
    ieclass = GetParam ();
  }
  t8_eclass_t ieclass;
};

TEST (gtest_eclass, eclassCountIs8)
{
  EXPECT_EQ (T8_ECLASS_COUNT, 8);
}

TEST (gtest_eclass, invalid_class)
{
  EXPECT_FALSE (t8_eclass_is_valid ((t8_eclass_t) T8_ECLASS_INVALID));
}

TEST_P (gtest_eclass, dimension)
{
  const int eclass_dims[8] = { 0, 1, 2, 2, 3, 3, 3, 3 };
  EXPECT_EQ (t8_eclass_to_dimension[ieclass], eclass_dims[ieclass]);
}

TEST_P (gtest_eclass, valid_class)
{
  EXPECT_TRUE (t8_eclass_is_valid ((t8_eclass_t) ieclass));
}

TEST_P (gtest_eclass, compare)
{
  for (int jeclass = T8_ECLASS_ZERO; jeclass < T8_ECLASS_COUNT; ++jeclass) {
    if (ieclass == jeclass) {
      EXPECT_FALSE (t8_eclass_compare ((t8_eclass_t) ieclass, (t8_eclass_t) jeclass));
    }
    else if (t8_eclass_to_dimension[ieclass] == t8_eclass_to_dimension[jeclass]) {
      EXPECT_TRUE (t8_eclass_compare ((t8_eclass_t) ieclass, (t8_eclass_t) jeclass));
    }
  }
}

TEST_P (gtest_eclass, t8_to_vtk_corner_numbers)
{
  const int num_vertices = t8_eclass_num_vertices[ieclass];
  for (int ivertex = 0; ivertex < num_vertices; ivertex++) {
    const int vtk_corner_number = t8_eclass_t8_to_vtk_corner_number[ieclass][ivertex];
    const int t8_corner_number = t8_eclass_vtk_to_t8_corner_number[ieclass][vtk_corner_number];
    EXPECT_EQ (ivertex, t8_corner_number);
  }
}

TEST_P (gtest_eclass, eclass_face_orientation)
{
  const int num_faces = t8_eclass_num_faces[ieclass];
  /* For dim <= 2 all faces are 0 oriented. */
  if (t8_eclass_to_dimension[ieclass] <= 2) {
    for (int iface = 0; iface < num_faces; iface++) {
      EXPECT_EQ (0, t8_eclass_face_orientation[ieclass][iface]);
    }
  }
  else {
    /* Compute the normal of each face and the signed distance between the normal and the vector
     * from vertex 0 to the centroid. If the sign is positive the face is 0 oriented, 
     * ow it is 1 oriented. */
    t8_cmesh_t cmesh = t8_cmesh_new_from_class ((t8_eclass_t) ieclass, sc_MPI_COMM_WORLD);
    const double *vertices = t8_cmesh_get_tree_vertices (cmesh, 0);
    for (int iface = 0; iface < num_faces; iface++) {
      /* clang-format off */
      const int v[3] = {  t8_face_vertex_to_tree_vertex[ieclass][iface][0], 
                          t8_face_vertex_to_tree_vertex[ieclass][iface][1],
                          t8_face_vertex_to_tree_vertex[ieclass][iface][2] };
      /* clang-format on */
      double vec_0[3];
      double vec_1[3];
      t8_axpyz (vertices + 3 * v[1], vertices + 3 * v[0], vec_0, -1.0);
      t8_axpyz (vertices + 3 * v[2], vertices + 3 * v[0], vec_1, -1.0);
      double normal[3];
      t8_cross_3D (vec_0, vec_1, normal);
      double centroid[3] = { 0.0 };
      for (int ivertex = 0; ivertex < t8_eclass_num_vertices[ieclass]; ivertex++) {
        centroid[0] += vertices[3 * ivertex];
        centroid[1] += vertices[3 * ivertex + 1];
        centroid[2] += vertices[3 * ivertex + 2];
      }
      t8_ax (centroid, 1.0 / t8_eclass_num_vertices[ieclass]);
      t8_axpy (vertices + 3 * v[0], centroid, -1.0);
      const double c_n = t8_dot (centroid, normal);
      const int orientation = c_n > 0 ? 0 : 1;
      EXPECT_EQ (orientation, t8_eclass_face_orientation[ieclass][iface]);
    }
    t8_cmesh_destroy (&cmesh);
  }
}

TEST (gtest_eclass, eclass_order)
{
  /* 2D order of eclasses */
  EXPECT_EQ (t8_eclass_compare (T8_ECLASS_TRIANGLE, T8_ECLASS_QUAD), -1);
  EXPECT_EQ (t8_eclass_compare (T8_ECLASS_QUAD, T8_ECLASS_TRIANGLE), 1);

  /* 3d order of eclasses */
  /* TET < HEX < PRISM < PYRAMID */
  EXPECT_EQ (t8_eclass_compare (T8_ECLASS_TET, T8_ECLASS_HEX), -1);
  EXPECT_EQ (t8_eclass_compare (T8_ECLASS_TET, T8_ECLASS_PRISM), -1);
  EXPECT_EQ (t8_eclass_compare (T8_ECLASS_TET, T8_ECLASS_PYRAMID), -1);

  EXPECT_EQ (t8_eclass_compare (T8_ECLASS_HEX, T8_ECLASS_PRISM), -1);
  EXPECT_EQ (t8_eclass_compare (T8_ECLASS_HEX, T8_ECLASS_PYRAMID), -1);

  EXPECT_EQ (t8_eclass_compare (T8_ECLASS_PRISM, T8_ECLASS_PYRAMID), -1);

  /* PYRAMID > PRISM > HEX > TET */
  EXPECT_EQ (t8_eclass_compare (T8_ECLASS_PYRAMID, T8_ECLASS_PRISM), 1);
  EXPECT_EQ (t8_eclass_compare (T8_ECLASS_PYRAMID, T8_ECLASS_HEX), 1);
  EXPECT_EQ (t8_eclass_compare (T8_ECLASS_PYRAMID, T8_ECLASS_TET), 1);

  EXPECT_EQ (t8_eclass_compare (T8_ECLASS_PRISM, T8_ECLASS_HEX), 1);
  EXPECT_EQ (t8_eclass_compare (T8_ECLASS_PRISM, T8_ECLASS_TET), 1);

  EXPECT_EQ (t8_eclass_compare (T8_ECLASS_HEX, T8_ECLASS_TET), 1);
}

INSTANTIATE_TEST_SUITE_P (t8_gtest_eclass, gtest_eclass, AllEclasses, print_eclass);