TestMeshGenerator.cpp
/**
* \file
* \copyright
* Copyright (c) 2012-2023, OpenGeoSys Community (http://www.opengeosys.org)
* Distributed under a Modified BSD License.
* See accompanying file LICENSE.txt or
* http://www.opengeosys.org/project/license
*/
#include <gtest/gtest.h>
#include <cmath>
#include <memory>
#include <numeric>
#include "MathLib/MathTools.h"
#include "MeshLib/Elements/Element.h"
#include "MeshLib/Elements/Hex.h"
#include "MeshLib/Mesh.h"
#include "MeshLib/Node.h"
#include "MeshToolsLib/MeshGenerators/MeshGenerator.h"
using namespace MeshLib;
TEST(MeshLib, MeshGeneratorRegularHex)
{
const double L = 10.0;
const std::size_t n_subdivisions = 9;
const double dL = L / static_cast<double>(n_subdivisions);
std::unique_ptr<Mesh> msh(
MeshToolsLib::MeshGenerator::generateRegularHexMesh(L, n_subdivisions));
ASSERT_EQ(std::pow(n_subdivisions, 3), msh->getNumberOfElements());
ASSERT_EQ(std::pow(n_subdivisions + 1, 3), msh->getNumberOfNodes());
// check nodes
const Node& node0 = *msh->getNode(0);
const Node& node1 = *msh->getNode(1);
const Node& node_n = *msh->getNode(msh->getNumberOfNodes() - 2);
const Node& node_n1 = *msh->getNode(msh->getNumberOfNodes() - 1);
ASSERT_DOUBLE_EQ(.0, node0[0]);
ASSERT_DOUBLE_EQ(.0, node0[1]);
ASSERT_DOUBLE_EQ(.0, node0[2]);
ASSERT_DOUBLE_EQ(dL, node1[0]);
ASSERT_DOUBLE_EQ(.0, node1[1]);
ASSERT_DOUBLE_EQ(.0, node1[2]);
ASSERT_DOUBLE_EQ(L - dL, node_n[0]);
ASSERT_DOUBLE_EQ(L, node_n[1]);
ASSERT_DOUBLE_EQ(L, node_n[2]);
ASSERT_DOUBLE_EQ(L, node_n1[0]);
ASSERT_DOUBLE_EQ(L, node_n1[1]);
ASSERT_DOUBLE_EQ(L, node_n1[2]);
// check elements
const Element& ele0 = *msh->getElement(0);
const Element& ele_n = *msh->getElement(msh->getNumberOfElements() - 1);
const std::size_t offset_y0 = (n_subdivisions + 1);
const std::size_t offset_z0 = (n_subdivisions + 1) * (n_subdivisions + 1);
ASSERT_EQ(0u, getNodeIndex(ele0, 0));
ASSERT_EQ(1u, getNodeIndex(ele0, 1));
ASSERT_EQ(offset_y0 + 1, getNodeIndex(ele0, 2));
ASSERT_EQ(offset_y0, getNodeIndex(ele0, 3));
ASSERT_EQ(offset_z0, getNodeIndex(ele0, 4));
ASSERT_EQ(offset_z0 + 1, getNodeIndex(ele0, 5));
ASSERT_EQ(offset_z0 + offset_y0 + 1, getNodeIndex(ele0, 6));
ASSERT_EQ(offset_z0 + offset_y0, getNodeIndex(ele0, 7));
const std::size_t offset_yn0 = (n_subdivisions + 1) * (n_subdivisions - 1);
const std::size_t offset_yn1 = (n_subdivisions + 1) * n_subdivisions;
const std::size_t offset_zn0 =
(n_subdivisions + 1) * (n_subdivisions + 1) * (n_subdivisions - 1);
const std::size_t offset_zn1 =
(n_subdivisions + 1) * (n_subdivisions + 1) * n_subdivisions;
ASSERT_EQ(offset_zn0 + offset_yn0 + n_subdivisions - 1,
getNodeIndex(ele_n, 0));
ASSERT_EQ(offset_zn0 + offset_yn0 + n_subdivisions, getNodeIndex(ele_n, 1));
ASSERT_EQ(offset_zn0 + offset_yn1 + n_subdivisions, getNodeIndex(ele_n, 2));
ASSERT_EQ(offset_zn0 + offset_yn1 + n_subdivisions - 1,
getNodeIndex(ele_n, 3));
ASSERT_EQ(offset_zn1 + offset_yn0 + n_subdivisions - 1,
getNodeIndex(ele_n, 4));
ASSERT_EQ(offset_zn1 + offset_yn0 + n_subdivisions, getNodeIndex(ele_n, 5));
ASSERT_EQ(offset_zn1 + offset_yn1 + n_subdivisions, getNodeIndex(ele_n, 6));
ASSERT_EQ(offset_zn1 + offset_yn1 + n_subdivisions - 1,
getNodeIndex(ele_n, 7));
std::unique_ptr<Mesh> msh2(
MeshToolsLib::MeshGenerator::generateRegularHexMesh(
n_subdivisions, n_subdivisions, n_subdivisions,
L / n_subdivisions));
ASSERT_EQ(msh->getNumberOfNodes(), msh2->getNumberOfNodes());
ASSERT_DOUBLE_EQ(
0, MathLib::sqrDist(*(msh->getNode(msh->getNumberOfNodes() - 1)),
*(msh2->getNode(msh->getNumberOfNodes() - 1))));
unsigned n_x(10);
unsigned n_y(5);
unsigned n_z(2);
double delta(1.2);
std::unique_ptr<Mesh> hex_mesh(
MeshToolsLib::MeshGenerator::generateRegularHexMesh(n_x, n_y, n_z,
delta));
ASSERT_EQ(n_x * n_y * n_z, hex_mesh->getNumberOfElements());
ASSERT_EQ((n_x + 1) * (n_y + 1) * (n_z + 1), hex_mesh->getNumberOfNodes());
const MeshLib::Node* node(
hex_mesh->getNode(hex_mesh->getNumberOfNodes() - 1));
ASSERT_DOUBLE_EQ(n_x * delta, (*node)[0]);
ASSERT_DOUBLE_EQ(n_y * delta, (*node)[1]);
ASSERT_DOUBLE_EQ(n_z * delta, (*node)[2]);
}
TEST(MeshLib, MeshGeneratorRegularQuad)
{
unsigned n_x(10);
unsigned n_y(5);
double delta(1.2);
std::unique_ptr<Mesh> quad_mesh(
MeshToolsLib::MeshGenerator::generateRegularQuadMesh(n_x, n_y, delta));
ASSERT_EQ(n_x * n_y, quad_mesh->getNumberOfElements());
ASSERT_EQ((n_x + 1) * (n_y + 1), quad_mesh->getNumberOfNodes());
const MeshLib::Node* node(
quad_mesh->getNode(quad_mesh->getNumberOfNodes() - 1));
ASSERT_DOUBLE_EQ(n_x * delta, (*node)[0]);
ASSERT_DOUBLE_EQ(n_y * delta, (*node)[1]);
ASSERT_DOUBLE_EQ(0, (*node)[2]);
const double L = 10.0;
const std::size_t n_subdivisions = 9;
std::unique_ptr<Mesh> quad_mesh2(
MeshToolsLib::MeshGenerator::generateRegularQuadMesh(L,
n_subdivisions));
ASSERT_EQ(n_subdivisions * n_subdivisions,
quad_mesh2->getNumberOfElements());
node = quad_mesh2->getNode(quad_mesh2->getNumberOfNodes() - 1);
ASSERT_DOUBLE_EQ(L, (*node)[0]);
ASSERT_DOUBLE_EQ(L, (*node)[1]);
}
TEST(MeshLib, MeshGeneratorRegularPrism)
{
double const l_x(10);
double const l_y(10);
double const l_z(8);
unsigned n_x(10);
unsigned n_y(5);
unsigned n_z(4);
std::unique_ptr<Mesh> mesh(
MeshToolsLib::MeshGenerator::generateRegularPrismMesh(l_x, l_y, l_z,
n_x, n_y, n_z));
ASSERT_EQ(2 * n_x * n_y * n_z, mesh->getNumberOfElements());
ASSERT_EQ((n_x + 1) * (n_y + 1) * (n_z + 1), mesh->getNumberOfNodes());
std::size_t count(0);
for (std::size_t k = 0; k < (n_z + 1); ++k)
{
for (std::size_t j = 0; j < (n_y + 1); ++j)
{
for (std::size_t i = 0; i < (n_x + 1); ++i)
{
const MeshLib::Node* node(mesh->getNode(count++));
ASSERT_DOUBLE_EQ(static_cast<double>(i), (*node)[0]);
ASSERT_DOUBLE_EQ(static_cast<double>(j * 2), (*node)[1]);
ASSERT_DOUBLE_EQ(static_cast<double>(k * 2), (*node)[2]);
}
}
}
}
TEST(MeshLib, MeshGeneratorRegularPyramid)
{
const double L = 10.0;
const std::size_t n_subdivisions = 9;
const double dL = L / static_cast<double>(n_subdivisions);
std::vector<std::unique_ptr<BaseLib::ISubdivision>> vec_div;
vec_div.reserve(3);
for (unsigned i = 0; i < 3; i++)
{
vec_div.emplace_back(
new BaseLib::UniformSubdivision(L, n_subdivisions));
}
std::unique_ptr<Mesh> msh(
MeshToolsLib::MeshGenerator::generateRegularPyramidMesh(
*vec_div[0], *vec_div[1], *vec_div[2]));
// check number of generates nodes and elements
ASSERT_EQ(6 * std::pow(n_subdivisions, 3), msh->getNumberOfElements());
ASSERT_EQ(std::pow(n_subdivisions + 1, 3) + std::pow(n_subdivisions, 3),
msh->getNumberOfNodes());
// check the positions of the diagonal edge nodes (lower left front and
// upper right back)
const Node& node0 = *msh->getNode(0);
const Node& node1 = *msh->getNode(1);
const std::size_t L_index = static_cast<std::size_t>(L);
const Node& node_n = *msh->getNode(L_index * L_index * L_index - 2);
const Node& node_n1 = *msh->getNode(L_index * L_index * L_index - 1);
ASSERT_DOUBLE_EQ(.0, node0[0]);
ASSERT_DOUBLE_EQ(.0, node0[1]);
ASSERT_DOUBLE_EQ(.0, node0[2]);
ASSERT_DOUBLE_EQ(dL, node1[0]);
ASSERT_DOUBLE_EQ(.0, node1[1]);
ASSERT_DOUBLE_EQ(.0, node1[2]);
ASSERT_DOUBLE_EQ(L - dL, node_n[0]);
ASSERT_DOUBLE_EQ(L, node_n[1]);
ASSERT_DOUBLE_EQ(L, node_n[2]);
ASSERT_DOUBLE_EQ(L, node_n1[0]);
ASSERT_DOUBLE_EQ(L, node_n1[1]);
ASSERT_DOUBLE_EQ(L, node_n1[2]);
// check if the domain volume equals the volume of the elements
long double const element_volumes = std::accumulate(
cbegin(msh->getElements()), cend(msh->getElements()), 0.,
[](double const volume, auto* const element)
{ return volume + element->computeVolume(); });
EXPECT_NEAR(L * L * L, element_volumes, 1e-10);
// test node order of the elements
for (auto const element : msh->getElements())
{
ASSERT_TRUE(element->testElementNodeOrder());
}
// validate the elements
for (auto const element : msh->getElements())
{
ASSERT_TRUE(element->validate().none());
}
}