Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
DLR-AMR
GitHub Repository: DLR-AMR/t8code
Path: blob/main/test/t8_geometry/t8_gtest_geometry_negative_volume.cxx
915 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_geometry_negative_volume.cxx
* Provide tests to check the functionality of the negative volume check function
* of the geometries.
*/

#include <gtest/gtest.h>
#include <t8_eclass.h>
#include <t8_cmesh/t8_cmesh.hxx>
#include <t8_geometry/t8_geometry_implementations/t8_geometry_linear.hxx>
#include <test/t8_gtest_memory_macros.hxx>
#include <test/t8_gtest_macros.hxx>

struct check_negative_volume: public testing::TestWithParam<t8_eclass_t>
{
 protected:
  void
  SetUp () override
  {
    tree_class = GetParam ();
    num_vertices = t8_eclass_num_vertices[tree_class];
  }
  void
  TearDown () override
  {
  }
  t8_eclass_t tree_class;
  int num_vertices;
};

/**
 * Given an eclass fill \a vertices_ids with the corner_ids of a cube [0,1]^3, such that
 * the volume is positive
 * \param [in] eclass The eclass to use
 * \param [in, out] vertices_ids 8 ints on input, filled with the corner ids to use for i-th vertex of the element on output
 */
static void
get_vertices_ids (const t8_eclass_t eclass, int vertices_ids[T8_ECLASS_MAX_CORNERS])
{
  switch (eclass) {
  case T8_ECLASS_HEX:
    vertices_ids[4] = 4;
    vertices_ids[5] = 5;
    vertices_ids[6] = 6;
    vertices_ids[7] = 7;
    vertices_ids[3] = 3;
    vertices_ids[2] = 2;
    vertices_ids[1] = 1;
    vertices_ids[0] = 0;
    break;
  case T8_ECLASS_PRISM:
    vertices_ids[3] = 4;
    vertices_ids[4] = 5;
    vertices_ids[5] = 7;
    vertices_ids[0] = 0;
    vertices_ids[1] = 1;
    vertices_ids[2] = 3;
    break;
  case T8_ECLASS_TET:
    vertices_ids[0] = 0;
    vertices_ids[1] = 1;
    vertices_ids[2] = 5;
    vertices_ids[3] = 7;
    break;
  case T8_ECLASS_PYRAMID:
    vertices_ids[0] = 1;
    vertices_ids[1] = 3;
    vertices_ids[2] = 0;
    vertices_ids[3] = 2;
    vertices_ids[4] = 7;
    break;
  default:
    break;
  }
}

/* Test if positive volume of 3D cells is detected correctly */
TEST_P (check_negative_volume, linear_geometry_positive_volume)
{
  int vertices_ids[T8_ECLASS_MAX_CORNERS];
  get_vertices_ids (tree_class, vertices_ids);
  /* clang-format off */
  const double vertices_coords[24] = {
    0, 0, 0,
    1, 0, 0,
    0, 1, 0,
    1, 1, 0,
    0, 0, 1,
    1, 0, 1,
    0, 1, 1,
    1, 1, 1
  };
  /* clang-format on */
  double *elem_vertices = T8_TESTSUITE_ALLOC (double, 3 * num_vertices);
  t8_cmesh_new_translate_vertices_to_attributes (vertices_ids, vertices_coords, elem_vertices, num_vertices);
  t8_cmesh_t cmesh = t8_cmesh_new ();
  t8_cmesh_register_geometry<t8_geometry_linear> (cmesh);
  t8_cmesh_set_tree_class (cmesh, 0, tree_class);
  t8_cmesh_set_tree_vertices (cmesh, 0, elem_vertices, num_vertices);
  /* Disable negative volume check so that we can check the results in the test. */
  t8_cmesh_disable_negative_volume_check (cmesh);
  t8_cmesh_commit (cmesh, sc_MPI_COMM_WORLD);

  EXPECT_TRUE (t8_cmesh_validate_geometry (cmesh, true));
  T8_TESTSUITE_FREE (elem_vertices);
  t8_cmesh_destroy (&cmesh);
}

/* Test if negative volume of 3D cells is detected correctly */
TEST_P (check_negative_volume, linear_geometry_negative_volume)
{
  int vertices_ids[T8_ECLASS_MAX_CORNERS];
  get_vertices_ids (tree_class, vertices_ids);
  /* Same nodes as above, but inverted. All 3D elements will have negative volume*/
  /* clang-format off */
  const double vertices_coords[24] = {
    0, 0, 1,
    1, 0, 1,
    0, 1, 1,
    1, 1, 1,
    0, 0, 0,
    1, 0, 0,
    0, 1, 0,
    1, 1, 0
  };
  /* clang-format on */
  double *elem_vertices = T8_TESTSUITE_ALLOC (double, 3 * num_vertices);
  t8_cmesh_new_translate_vertices_to_attributes (vertices_ids, vertices_coords, elem_vertices, num_vertices);
  t8_cmesh_t cmesh = t8_cmesh_new ();
  t8_cmesh_register_geometry<t8_geometry_linear> (cmesh);
  t8_cmesh_set_tree_class (cmesh, 0, tree_class);
  t8_cmesh_set_tree_vertices (cmesh, 0, elem_vertices, num_vertices);
  /* Disable negative volume check so that we can check the results in the test. */
  t8_cmesh_disable_negative_volume_check (cmesh);
  t8_cmesh_commit (cmesh, sc_MPI_COMM_WORLD);

  if (t8_eclass_to_dimension[tree_class] <= 2) {
    EXPECT_TRUE (t8_cmesh_validate_geometry (cmesh, true));
  }
  else {
    EXPECT_FALSE (t8_cmesh_validate_geometry (cmesh, true));
  }
  T8_TESTSUITE_FREE (elem_vertices);
  t8_cmesh_destroy (&cmesh);
}

INSTANTIATE_TEST_SUITE_P (t8_gtest_geometry_negative_volume, check_negative_volume,
                          testing::Range (T8_ECLASS_HEX, T8_ECLASS_COUNT), print_eclass);