From 00d8ad684d57573675e2a1363aae613eaefb9e64 Mon Sep 17 00:00:00 2001
From: Thomas Fischer <thomas.fischer@ufz.de>
Date: Thu, 16 Jan 2020 14:58:34 +0100
Subject: [PATCH] [MeL/SurfaceExtraction] Refactor getBoundaryElementsAsMesh.

---
 MeshLib/MeshSurfaceExtraction.cpp | 190 +++++++++++++++++++-----------
 MeshLib/MeshSurfaceExtraction.h   |  27 ++++-
 2 files changed, 145 insertions(+), 72 deletions(-)

diff --git a/MeshLib/MeshSurfaceExtraction.cpp b/MeshLib/MeshSurfaceExtraction.cpp
index 4fca3dd9733..be2fb1caeb9 100644
--- a/MeshLib/MeshSurfaceExtraction.cpp
+++ b/MeshLib/MeshSurfaceExtraction.cpp
@@ -437,22 +437,95 @@ bool MeshSurfaceExtraction::createSfcMeshProperties(
     return true;
 }
 
-std::unique_ptr<MeshLib::Mesh> getBoundaryElementsAsMesh(
-    MeshLib::Mesh const& bulk_mesh,
-    std::string const& subsfc_node_id_prop_name,
-    std::string const& subsfc_element_id_prop_name,
-    std::string const& face_id_prop_name)
+std::tuple<std::vector<MeshLib::Node*>, std::vector<std::size_t>>
+MeshSurfaceExtraction::createNodesFromElements(
+    std::vector<MeshLib::Element*> const& elements,
+    std::size_t const n_all_nodes)
 {
-    auto const mesh_dimension = bulk_mesh.getDimension();
-    if (mesh_dimension < 2 || mesh_dimension > 3)
+    std::vector<const MeshLib::Node*> tmp_nodes(n_all_nodes, nullptr);
+    for (auto const* elem : elements)
     {
-        ERR("Cannot handle meshes of dimension %i", mesh_dimension);
+        for (unsigned j = 0; j < elem->getNumberOfBaseNodes(); ++j)
+        {
+            const MeshLib::Node* node(elem->getNode(j));
+            tmp_nodes[node->getID()] = node;
+        }
     }
 
+    std::vector<MeshLib::Node*> nodes;
+    std::vector<std::size_t> node_id_map(n_all_nodes);
+    for (unsigned i = 0; i < n_all_nodes; ++i)
+    {
+        if (tmp_nodes[i])
+        {
+            node_id_map[i] = nodes.size();
+            nodes.push_back(new MeshLib::Node(*tmp_nodes[i]));
+        }
+    }
+    return {nodes, node_id_map};
+}
+
+void MeshSurfaceExtraction::createSurfaceElementsFromElement(
+    MeshLib::Element const& surface_element,
+    std::vector<MeshLib::Element*>& surface_elements,
+    std::vector<std::size_t>& element_to_bulk_element_id_map,
+    std::vector<std::size_t>& element_to_bulk_face_id_map)
+{
+    const unsigned n_faces(surface_element.getNumberOfBoundaries());
+    for (unsigned j = 0; j < n_faces; ++j)
+    {
+        if (surface_element.getNeighbor(j) != nullptr)
+        {
+            continue;
+        }
+
+        auto const face = std::unique_ptr<MeshLib::Element const>{
+            surface_element.getBoundary(j)};
+        switch (face->getGeomType())
+        {
+            case MeshElemType::TRIANGLE:
+            {
+                surface_elements.push_back(new MeshLib::Tri(
+                    *static_cast<const MeshLib::Tri*>(face.get())));
+                break;
+            }
+            case MeshElemType::QUAD:
+            {
+                surface_elements.push_back(new MeshLib::Quad(
+                    *static_cast<const MeshLib::Quad*>(face.get())));
+                break;
+            }
+            case MeshElemType::LINE:
+            {
+                surface_elements.push_back(new MeshLib::Line(
+                    *static_cast<const MeshLib::Line*>(face.get())));
+                break;
+            }
+            case MeshElemType::POINT:
+            {
+                surface_elements.push_back(new MeshLib::Point(
+                    *static_cast<const MeshLib::Point*>(face.get())));
+                break;
+            }
+            default:
+                ERR("Unknown face element extracted.");
+        }
+        element_to_bulk_face_id_map.push_back(j);
+        element_to_bulk_element_id_map.push_back(surface_element.getID());
+    }
+}
+
+std::tuple<std::vector<MeshLib::Element*>, std::vector<std::size_t>,
+           std::vector<std::size_t>>
+MeshSurfaceExtraction::createSurfaceElements(MeshLib::Mesh const& bulk_mesh)
+{
     std::vector<std::size_t> element_to_bulk_element_id_map;
     std::vector<std::size_t> element_to_bulk_face_id_map;
-    std::vector<MeshLib::Element*> sfc_elements;
+    std::vector<MeshLib::Element*> surface_elements;
+
     auto const& bulk_elements = bulk_mesh.getElements();
+    auto const mesh_dimension = bulk_mesh.getDimension();
+
     for (auto const* elem : bulk_elements)
     {
         const unsigned element_dimension(elem->getDimension());
@@ -465,83 +538,68 @@ std::unique_ptr<MeshLib::Mesh> getBoundaryElementsAsMesh(
         {
             continue;
         }
-
-        const unsigned nFaces(elem->getNumberOfFaces());
-        for (unsigned j = 0; j < nFaces; ++j)
-        {
-            if (elem->getNeighbor(j) != nullptr)
-            {
-                continue;
-            }
-
-            auto const face =
-                std::unique_ptr<MeshLib::Element const>{elem->getFace(j)};
-            switch (face->getGeomType())
-            {
-                case MeshElemType::TRIANGLE:
-                {
-                    sfc_elements.push_back(new MeshLib::Tri(
-                        *static_cast<const MeshLib::Tri*>(face.get())));
-                    break;
-                }
-                case MeshElemType::QUAD:
-                {
-                    sfc_elements.push_back(new MeshLib::Quad(
-                        *static_cast<const MeshLib::Quad*>(face.get())));
-                    break;
-                }
-                case MeshElemType::LINE:
-                {
-                    sfc_elements.push_back(new MeshLib::Line(
-                        *static_cast<const MeshLib::Line*>(face.get())));
-                    break;
-                }
-                case MeshElemType::POINT:
-                {
-                    sfc_elements.push_back(new MeshLib::Point(
-                        *static_cast<const MeshLib::Point*>(face.get())));
-                    break;
-                }
-                default:
-                    ERR("Unknown face element extracted.");
-            }
-            element_to_bulk_element_id_map.push_back(elem->getID());
-            element_to_bulk_face_id_map.push_back(j);
-        }
+        createSurfaceElementsFromElement(*elem, surface_elements,
+                                         element_to_bulk_element_id_map,
+                                         element_to_bulk_face_id_map);
     }
+    return {surface_elements, element_to_bulk_element_id_map,
+            element_to_bulk_face_id_map};
+}
 
-    std::vector<MeshLib::Node*> sfc_nodes;
-    std::vector<std::size_t> node_id_map(bulk_mesh.getNumberOfNodes());
-    MeshSurfaceExtraction::get2DSurfaceNodes(
-        sfc_nodes, bulk_mesh.getNumberOfNodes(), sfc_elements, node_id_map);
+std::unique_ptr<MeshLib::Mesh> MeshSurfaceExtraction::getBoundaryElementsAsMesh(
+    MeshLib::Mesh const& bulk_mesh,
+    std::string const& subsfc_node_id_prop_name,
+    std::string const& subsfc_element_id_prop_name,
+    std::string const& face_id_prop_name)
+{
+    auto const mesh_dimension = bulk_mesh.getDimension();
+    if (mesh_dimension < 2 || mesh_dimension > 3)
+    {
+        ERR("Cannot handle meshes of dimension %i", mesh_dimension);
+    }
 
-    // create new elements vector with newly created nodes (and delete
-    // temp-elements)
+    // create surface elements based on the subsurface nodes
+    std::vector<std::size_t> element_to_bulk_element_id_map;
+    std::vector<std::size_t> element_to_bulk_face_id_map;
+    std::vector<MeshLib::Element*> surface_elements;
+    std::tie(surface_elements, element_to_bulk_element_id_map,
+             element_to_bulk_face_id_map) = createSurfaceElements(bulk_mesh);
+
+    // create new nodes needed for the new surface elements
+    std::vector<MeshLib::Node*> surface_nodes;
+    std::vector<std::size_t> node_id_map;
+    std::tie(surface_nodes, node_id_map) =
+        MeshSurfaceExtraction::createNodesFromElements(
+            surface_elements, bulk_mesh.getNumberOfNodes());
+
+    // create new elements using newly created nodes and delete temp-elements
     std::vector<MeshLib::Element*> new_elements;
     try
     {
         new_elements = MeshSurfaceExtraction::createSfcElementVector(
-            sfc_elements, sfc_nodes, node_id_map);
+            surface_elements, surface_nodes, node_id_map);
     }
     catch (std::runtime_error const& err)
     {
         ERR("BoundaryExtraction; could not create new surface elements:\n%s.",
             err.what());
-        std::for_each(sfc_elements.begin(), sfc_elements.end(),
+        std::for_each(surface_elements.begin(), surface_elements.end(),
                       [](MeshLib::Element* e) { delete e; });
-        std::for_each(sfc_nodes.begin(), sfc_nodes.end(),
+        std::for_each(surface_nodes.begin(), surface_nodes.end(),
                       [](MeshLib::Node* n) { delete n; });
         return nullptr;
     }
-    std::for_each(sfc_elements.begin(), sfc_elements.end(),
+    std::for_each(surface_elements.begin(), surface_elements.end(),
                   [](MeshLib::Element* e) { delete e; });
 
     std::vector<std::size_t> id_map;
-    id_map.reserve(sfc_nodes.size());
-    std::transform(begin(sfc_nodes), end(sfc_nodes), std::back_inserter(id_map),
+    id_map.reserve(surface_nodes.size());
+    std::transform(begin(surface_nodes), end(surface_nodes),
+                   std::back_inserter(id_map),
                    [](MeshLib::Node* const n) { return n->getID(); });
-    std::unique_ptr<MeshLib::Mesh> surface_mesh(
-        new Mesh(bulk_mesh.getName() + "-Surface", sfc_nodes, new_elements));
+
+    std::unique_ptr<MeshLib::Mesh> surface_mesh(new Mesh(
+        bulk_mesh.getName() + "-Surface", surface_nodes, new_elements));
 
     // transmit the original node ids of the bulk mesh as a property
     if (!subsfc_node_id_prop_name.empty())
diff --git a/MeshLib/MeshSurfaceExtraction.h b/MeshLib/MeshSurfaceExtraction.h
index 00e0f74080e..2173a0fe4e3 100644
--- a/MeshLib/MeshSurfaceExtraction.h
+++ b/MeshLib/MeshSurfaceExtraction.h
@@ -80,6 +80,13 @@ public:
      */
     static MeshLib::Mesh* getMeshBoundary(const MeshLib::Mesh& mesh);
 
+    static std::unique_ptr<MeshLib::Mesh> getBoundaryElementsAsMesh(
+        MeshLib::Mesh const& bulk_mesh,
+        std::string const& subsfc_node_id_prop_name,
+        std::string const& subsfc_element_id_prop_name,
+        std::string const& face_id_prop_name);
+
+private:
     /// Functionality needed for getSurfaceNodes() and getMeshSurface()
     static void get2DSurfaceElements(
         const std::vector<MeshLib::Element*>& all_elements,
@@ -90,6 +97,20 @@ public:
         double angle,
         unsigned mesh_dimension);
 
+    static std::tuple<std::vector<MeshLib::Node*>, std::vector<std::size_t>>
+    createNodesFromElements(std::vector<MeshLib::Element*> const& elements,
+                            std::size_t const n_all_nodes);
+
+    static void createSurfaceElementsFromElement(
+        MeshLib::Element const& surface_element,
+        std::vector<MeshLib::Element*>& surface_elements,
+        std::vector<std::size_t>& element_to_bulk_element_id_map,
+        std::vector<std::size_t>& element_to_bulk_face_id_map);
+
+    static std::tuple<std::vector<MeshLib::Element*>, std::vector<std::size_t>,
+                      std::vector<std::size_t>>
+    createSurfaceElements(MeshLib::Mesh const& bulk_mesh);
+
     /// Functionality needed for getSurfaceNodes() and getMeshSurface()
     static void get2DSurfaceNodes(
         std::vector<MeshLib::Node*>& sfc_nodes,
@@ -135,10 +156,4 @@ public:
         std::vector<std::size_t> const& element_ids_map);
 };
 
-std::unique_ptr<MeshLib::Mesh> getBoundaryElementsAsMesh(
-    MeshLib::Mesh const& bulk_mesh,
-    std::string const& subsfc_node_id_prop_name,
-    std::string const& subsfc_element_id_prop_name,
-    std::string const& face_id_prop_name);
-
 }  // namespace MeshLib
-- 
GitLab