From 237d7ea2a27a9fbe2205a29dbcf72d71d4aee31d Mon Sep 17 00:00:00 2001
From: Thomas Fischer <thomas.fischer@ufz.de>
Date: Thu, 16 Apr 2020 13:58:05 +0200
Subject: [PATCH] [MeL/MG] Fct. to create mesh of pyramid elements.

---
 MeshLib/MeshGenerators/MeshGenerator.cpp | 134 ++++++++++++++++++++++-
 MeshLib/MeshGenerators/MeshGenerator.h   |  20 ++++
 2 files changed, 152 insertions(+), 2 deletions(-)

diff --git a/MeshLib/MeshGenerators/MeshGenerator.cpp b/MeshLib/MeshGenerators/MeshGenerator.cpp
index f6ef78bf463..f80fcc02b36 100644
--- a/MeshLib/MeshGenerators/MeshGenerator.cpp
+++ b/MeshLib/MeshGenerators/MeshGenerator.cpp
@@ -13,14 +13,15 @@
 #include <memory>
 #include <numeric>
 
-#include "MeshLib/Node.h"
+#include "MeshLib/Elements/Hex.h"
 #include "MeshLib/Elements/Line.h"
+#include "MeshLib/Elements/Pyramid.h"
 #include "MeshLib/Elements/Quad.h"
-#include "MeshLib/Elements/Hex.h"
 #include "MeshLib/Elements/Tet.h"
 #include "MeshLib/Elements/Tri.h"
 #include "MeshLib/MeshEditing/AddLayerToMesh.h"
 #include "MeshLib/MeshEditing/RemoveMeshComponents.h"
+#include "MeshLib/Node.h"
 
 namespace MeshLib
 {
@@ -113,6 +114,39 @@ std::vector<MeshLib::Node*> MeshGenerator::generateRegularNodes(
     return nodes;
 }
 
+namespace MeshGenerator
+{
+std::vector<MeshLib::Node*> generateRegularPyramidTopNodes(
+    std::vector<double> const& x_coords,
+    std::vector<double> const& y_coords,
+    std::vector<double> const& z_coords,
+    const MathLib::Point3d& origin)
+{
+    std::vector<Node*> nodes;
+    nodes.reserve((x_coords.size() - 1) * (y_coords.size() - 1) *
+                  (z_coords.size() - 1));
+
+    auto const n_x_coords = x_coords.size() - 1;
+    auto const n_y_coords = y_coords.size() - 1;
+    auto const n_z_coords = z_coords.size() - 1;
+
+    for (std::size_t i = 0; i < n_z_coords; i++)
+    {
+        const double z((z_coords[i] + z_coords[i + 1]) / 2 + origin[2]);
+        for (std::size_t j = 0; j < n_y_coords; j++)
+        {
+            const double y((y_coords[j] + y_coords[j + 1]) / 2 + origin[1]);
+            for (std::size_t k = 0; k < n_x_coords; k++)
+            {
+                const double x((x_coords[k] + x_coords[k + 1]) / 2 + origin[0]);
+                nodes.push_back(new Node(x, y, z));
+            }
+        }
+    }
+    return nodes;
+}
+}  // end namespace MeshGenerator
+
 Mesh* MeshGenerator::generateLineMesh(
     const double length,
     const std::size_t subdivision,
@@ -331,6 +365,102 @@ Mesh* MeshGenerator::generateRegularHexMesh(
     return new Mesh(mesh_name, nodes, elements);
 }
 
+Mesh* MeshGenerator::generateRegularPyramidMesh(
+    const BaseLib::ISubdivision& div_x,
+    const BaseLib::ISubdivision& div_y,
+    const BaseLib::ISubdivision& div_z,
+    MathLib::Point3d const& origin,
+    std::string const& mesh_name)
+{
+    std::vector<double> vec_x(div_x());
+    std::vector<double> vec_y(div_y());
+    std::vector<double> vec_z(div_z());
+    std::vector<Node*> nodes(generateRegularNodes(vec_x, vec_y, vec_z, origin));
+    std::vector<Node*> const top_nodes(
+        generateRegularPyramidTopNodes(vec_x, vec_y, vec_z, origin));
+
+    nodes.insert(nodes.end(), top_nodes.begin(), top_nodes.end());
+
+    const unsigned n_x_nodes(vec_x.size());
+    const unsigned n_y_nodes(vec_y.size());
+    const unsigned n_z_nodes(vec_z.size());
+    const unsigned n_x_cells(vec_x.size() - 1);
+    const unsigned n_y_cells(vec_y.size() - 1);
+    const unsigned n_z_cells(vec_z.size() - 1);
+
+    // elements
+    std::vector<Element*> elements;
+    auto const top_node_offset(n_x_nodes * n_y_nodes * n_z_nodes);
+    elements.reserve(n_x_cells * n_y_cells * n_z_cells);
+
+    for (std::size_t i = 0; i < n_z_cells; i++)
+    {
+        const std::size_t offset_z1 = i * n_x_nodes * n_y_nodes;  // bottom
+        const std::size_t offset_z2 = (i + 1) * n_x_nodes * n_y_nodes;  // top
+        for (std::size_t j = 0; j < n_y_cells; j++)
+        {
+            const std::size_t offset_y1 = j * n_x_nodes;
+            const std::size_t offset_y2 = (j + 1) * n_x_nodes;
+            for (std::size_t k = 0; k < n_x_cells; k++)
+            {
+                // generate 6 pyramids within the virtual hexahedron cell
+                int const pyramid_top_index(i * n_x_cells * n_y_cells +
+                                            j * n_x_cells + k +
+                                            top_node_offset);
+                elements.push_back(
+                    new Pyramid{{// bottom 'hexahedron' face
+                                 nodes[offset_z1 + offset_y1 + k],
+                                 nodes[offset_z1 + offset_y1 + k + 1],
+                                 nodes[offset_z1 + offset_y2 + k + 1],
+                                 nodes[offset_z1 + offset_y2 + k],
+                                 // top
+                                 nodes[pyramid_top_index]}});
+                elements.push_back(
+                    new Pyramid{{// top 'hexahedron' face
+                                 nodes[offset_z2 + offset_y1 + k + 1],
+                                 nodes[offset_z2 + offset_y1 + k],
+                                 nodes[offset_z2 + offset_y2 + k],
+                                 nodes[offset_z2 + offset_y2 + k + 1],
+                                 // top of pyramid directed towards the bottom
+                                 nodes[pyramid_top_index]}});
+                elements.push_back(
+                    new Pyramid{{// right 'hexahedron' face
+                                 nodes[offset_z1 + offset_y1 + k + 1],
+                                 nodes[offset_z2 + offset_y1 + k + 1],
+                                 nodes[offset_z2 + offset_y2 + k + 1],
+                                 nodes[offset_z1 + offset_y2 + k + 1],
+                                 // top of pyramid directed towards the bottom
+                                 nodes[pyramid_top_index]}});
+                elements.push_back(
+                    new Pyramid{{// left 'hexahedron' face
+                                 nodes[offset_z2 + offset_y1 + k],
+                                 nodes[offset_z1 + offset_y1 + k],
+                                 nodes[offset_z1 + offset_y2 + k],
+                                 nodes[offset_z2 + offset_y2 + k],
+                                 // top of pyramid directed towards the bottom
+                                 nodes[pyramid_top_index]}});
+                elements.push_back(
+                    new Pyramid{{// front 'hexahedron' face
+                                 nodes[offset_z2 + offset_y1 + k],
+                                 nodes[offset_z2 + offset_y1 + k + 1],
+                                 nodes[offset_z1 + offset_y1 + k + 1],
+                                 nodes[offset_z1 + offset_y1 + k],
+                                 // top of pyramid directed towards the bottom
+                                 nodes[pyramid_top_index]}});
+                elements.push_back(
+                    new Pyramid{{// back 'hexahedron' face
+                                 nodes[offset_z1 + offset_y2 + k],
+                                 nodes[offset_z1 + offset_y2 + k + 1],
+                                 nodes[offset_z2 + offset_y2 + k + 1],
+                                 nodes[offset_z2 + offset_y2 + k],
+                                 // top of pyramid directed towards the bottom
+                                 nodes[pyramid_top_index]}});
+            }
+        }
+    }
+    return new Mesh(mesh_name, nodes, elements);
+}
+
 Mesh* MeshGenerator::generateRegularTriMesh(
     const double length,
     const std::size_t subdivision,
diff --git a/MeshLib/MeshGenerators/MeshGenerator.h b/MeshLib/MeshGenerators/MeshGenerator.h
index 5fbba4385e0..7e50c392342 100644
--- a/MeshLib/MeshGenerators/MeshGenerator.h
+++ b/MeshLib/MeshGenerators/MeshGenerator.h
@@ -290,6 +290,26 @@ Mesh* generateRegularHexMesh(const unsigned n_x_cells,
                              MathLib::Point3d const& origin = MathLib::ORIGIN,
                              std::string   const& mesh_name = "mesh");
 
+/**
+ * Generate a regular 3D mesh that consists of pyramid elements.
+ *
+ * This algorithm generates regular grid points as well as middle points of the
+ * virtual hexahedra cells and split each hex grid cell into six pyramids.
+ *
+ * \param div_x Subdivision operator in x direction
+ * \param div_y Subdivision operator in y direction
+ * \param div_z Subdivision operator in z direction
+ * \param origin Optional mesh's origin (the bottom lower left corner) with
+ * MathLib::ORIGIN default.
+ * \param mesh_name Name of the new mesh.
+ */
+Mesh* generateRegularPyramidMesh(
+    const BaseLib::ISubdivision& div_x,
+    const BaseLib::ISubdivision& div_y,
+    const BaseLib::ISubdivision& div_z,
+    MathLib::Point3d const& origin = MathLib::ORIGIN,
+    std::string const& mesh_name = "mesh");
+
 /**
  * Generate a regular 2D Triangle-Element mesh. The mesh is generated in the
  * x-y-plane.
-- 
GitLab