From 79502b5ba9e59d54a33c68d8f3668bb73517b82d Mon Sep 17 00:00:00 2001
From: Wenqing Wang <wenqing.wang@ufz.de>
Date: Wed, 6 Jul 2016 18:05:00 +0200
Subject: [PATCH] [PMesh] Split two functions into three functions,
 respectively, and corrected some typos

---
 Applications/Utils/CMakeLists.txt             |   4 +
 .../PartitionMesh/NodeWiseMeshPartitioner.cpp | 170 ++++++++++++------
 .../PartitionMesh/NodeWiseMeshPartitioner.h   |  70 ++++++--
 .../PartitionMesh/PartitionMesh.cpp           |  26 +--
 MeshLib/Node.h                                |  12 +-
 5 files changed, 200 insertions(+), 82 deletions(-)

diff --git a/Applications/Utils/CMakeLists.txt b/Applications/Utils/CMakeLists.txt
index 64d1ce31540..b48aa979192 100644
--- a/Applications/Utils/CMakeLists.txt
+++ b/Applications/Utils/CMakeLists.txt
@@ -8,5 +8,9 @@ add_subdirectory(SimpleMeshCreation)
 if(OGS_BUILD_GUI)
     add_subdirectory(OGSFileConverter)
 else()
+    # When OGS_BUILD_GUI=ON, vtk libraries are linked to every object in
+    # building, which lets the compilation of mpmetis (in the project
+    # of PartitionMesh) fail. Therefore, the following subdirectory is
+    # excluded when OGS_BUILD_GUI=ON.
     add_subdirectory(ModelPreparation/PartitionMesh)
 endif() # OGS_BUILD_GUI
diff --git a/Applications/Utils/ModelPreparation/PartitionMesh/NodeWiseMeshPartitioner.cpp b/Applications/Utils/ModelPreparation/PartitionMesh/NodeWiseMeshPartitioner.cpp
index 50faf96d682..b4220e3a920 100644
--- a/Applications/Utils/ModelPreparation/PartitionMesh/NodeWiseMeshPartitioner.cpp
+++ b/Applications/Utils/ModelPreparation/PartitionMesh/NodeWiseMeshPartitioner.cpp
@@ -42,14 +42,14 @@ void NodeWiseMeshPartitioner::readMetisData(const std::string& file_name_base)
     const std::string npartitions_str = std::to_string(_npartitions);
 
     // Read partitioned mesh data from METIS
-    std::string fname_parts = file_name_base + ".mesh.npart." + npartitions_str;
+    const std::string fname_parts = file_name_base + ".mesh.npart." + npartitions_str;
 
-    std::ifstream npart_in(fname_parts.data());
+    std::ifstream npart_in(fname_parts);
     if (!npart_in.is_open())
     {
         OGS_FATAL(
-            "Error: cannot open file %s. It may not exist! \
-                   \n Run mpmetis beforehand or use option -m",
+            "Error: cannot open file %s. It may not exist!\n"
+            "Run mpmetis beforehand or use option -m",
             fname_parts.data());
     }
 
@@ -63,6 +63,12 @@ void NodeWiseMeshPartitioner::readMetisData(const std::string& file_name_base)
           break;
     }
 
+    if (npart_in.bad())
+    {
+        OGS_FATAL(
+            "Error while reading file %s.", fname_parts.data());
+    }
+
     npart_in.close();
 
     if( counter != nnodes)
@@ -71,10 +77,15 @@ void NodeWiseMeshPartitioner::readMetisData(const std::string& file_name_base)
             "Error: data in %s are less than expected.", fname_parts.data());
     }
 
-    // TEST  std::remove(fname_parts.c_str());
+    // remove metis files.
+    std::remove(fname_parts.c_str());
+    const std::string fname_eparts = file_name_base + ".mesh.epart."
+                                     + npartitions_str;
+    std::remove(fname_eparts.c_str());
 }
 
-void NodeWiseMeshPartitioner::partitionByMETIS(const bool is_mixed_hl_elem)
+void NodeWiseMeshPartitioner
+         ::partitionByMETIS(const bool is_mixed_high_order_linear_elems)
 {
     std::vector<MeshLib::Node*> const& nodes = _mesh->getNodes();
     for (std::size_t part_id = 0; part_id < _partitions.size(); part_id++)
@@ -90,13 +101,14 @@ void NodeWiseMeshPartitioner::partitionByMETIS(const bool is_mixed_hl_elem)
         {
             if (_nodes_partition_ids[i] == part_id)
             {
-                if (is_mixed_hl_elem)
-                {
+                if (is_mixed_high_order_linear_elems)
+                { // TODO: Test it once there is a case
                     if (i < _mesh->getNumberOfBaseNodes())
                         partition.nodes.push_back(nodes[i]);
                     else
                         extra_nodes.push_back(nodes[i]);
                 }
+                else
                 {
                     partition.nodes.push_back(nodes[i]);
                 }
@@ -106,7 +118,7 @@ void NodeWiseMeshPartitioner::partitionByMETIS(const bool is_mixed_hl_elem)
         partition.number_of_non_ghost_nodes =
             partition.number_of_non_ghost_base_nodes + extra_nodes.size();
 
-        // Find elements that are bellowed to this partition
+        // Find elements that belong to this partition
         std::vector<MeshLib::Element*> const& elements = _mesh->getElements();
         for (std::size_t elem_id = 0; elem_id < elements.size(); elem_id++)
         {
@@ -149,7 +161,7 @@ void NodeWiseMeshPartitioner::partitionByMETIS(const bool is_mixed_hl_elem)
 
                 if (_nodes_partition_ids[node_id] != part_id)
                 {
-                    if (is_mixed_hl_elem)
+                    if (is_mixed_high_order_linear_elems)
                     {
                         if (node_id < _mesh->getNumberOfBaseNodes())
                             partition.nodes.push_back(nodes[node_id]);
@@ -166,21 +178,22 @@ void NodeWiseMeshPartitioner::partitionByMETIS(const bool is_mixed_hl_elem)
         }
         partition.number_of_base_nodes = partition.nodes.size();
 
-        if (is_mixed_hl_elem)
+        if (is_mixed_high_order_linear_elems)
             partition.nodes.insert(partition.nodes.end(), extra_nodes.begin(),
                                    extra_nodes.end());
     }
 
-    renumberNodeIndices();
+    renumberNodeIndices(is_mixed_high_order_linear_elems);
 }
 
-void NodeWiseMeshPartitioner::renumberNodeIndices()
+void NodeWiseMeshPartitioner::renumberNodeIndices
+                           (const bool is_mixed_high_order_linear_elems)
 {
     std::size_t node_global_id_offset = 0;
+    // Renumber the global indices.
+    // -- Base nodes
     for (auto& partition : _partitions)
     {
-        // Renumber the global indecies.
-        // -- Base nodes
         for (std::size_t i = 0; i < partition.number_of_non_ghost_base_nodes;
              i++)
         {
@@ -188,7 +201,14 @@ void NodeWiseMeshPartitioner::renumberNodeIndices()
                 node_global_id_offset;
             node_global_id_offset++;
         }
-        // -- Nodes for high order elements.
+    }
+
+    if (!is_mixed_high_order_linear_elems)
+        return;
+
+    // -- Nodes for high order elements.
+    for (auto& partition : _partitions)
+    {
         const std::size_t end_id = partition.number_of_base_nodes +
                                    partition.number_of_non_ghost_nodes -
                                    partition.number_of_non_ghost_base_nodes;
@@ -203,12 +223,18 @@ void NodeWiseMeshPartitioner::renumberNodeIndices()
 
 void NodeWiseMeshPartitioner::writeMETIS(const std::string& file_name)
 {
-    std::ofstream os(file_name.data(), std::ios::trunc);
+    std::ofstream os(file_name, std::ios::trunc);
     if (!os.is_open())
     {
-        OGS_FATAL("Error: cannot open file %s. It may not exist! ",
+        OGS_FATAL("Error: cannot open file %s.",
                   file_name.data());
     }
+
+    if (!os.good())
+    {
+        OGS_FATAL("Error: Cannot write in file %s.", file_name.data());
+    }
+
     std::vector<MeshLib::Element*> const& elements = _mesh->getElements();
     os << elements.size() << " \n";
     for (const auto* elem : elements)
@@ -220,13 +246,14 @@ void NodeWiseMeshPartitioner::writeMETIS(const std::string& file_name)
         }
         os << "\n";
     }
-    os.flush();
 }
 
 NodeWiseMeshPartitioner::IntegerType
 NodeWiseMeshPartitioner::getNumberOfIntegerVariablesOfElements(
     const std::vector<const MeshLib::Element*>& elements) const
 {
+    // Number of material ID, element type, and number of the nodes of
+    // an element of all elements in the current partition.
     IntegerType nmb_element_idxs = 3 * elements.size();
     for (const auto* elem : elements)
     {
@@ -235,13 +262,12 @@ NodeWiseMeshPartitioner::getNumberOfIntegerVariablesOfElements(
     return nmb_element_idxs;
 }
 
-void NodeWiseMeshPartitioner::writeBinary(const std::string& file_name_base)
+std::tuple< std::vector<NodeWiseMeshPartitioner::IntegerType>,
+            std::vector<NodeWiseMeshPartitioner::IntegerType>>
+NodeWiseMeshPartitioner::writeConfigDataBinary(const std::string& file_name_base)
 {
-    const std::string npartitions_str = std::to_string(_npartitions);
-
-    // Output configuration data
-    std::string fname =
-        file_name_base + "_partitioned_msh_cfg" + npartitions_str + ".bin";
+    const std::string fname = file_name_base + "_partitioned_msh_cfg"
+                              + std::to_string(_npartitions) + ".bin";
     FILE* of_bin_cfg = fopen(fname.c_str(), "wb");
 
     const IntegerType num_config_data = 14;
@@ -290,10 +316,20 @@ void NodeWiseMeshPartitioner::writeBinary(const std::string& file_name_base)
 
         loop_id++;
     }
+
     fclose(of_bin_cfg);
 
-    // Output elements
-    fname = file_name_base + "_partitioned_msh_ele" + npartitions_str + ".bin";
+    return  std::make_tuple(num_elem_integers, num_g_elem_integers);
+}
+
+void NodeWiseMeshPartitioner::writeElementsBinary
+                     (const std::string& file_name_base,
+                      const std::vector<IntegerType>& num_elem_integers,
+                      const std::vector<IntegerType>& num_g_elem_integers)
+{
+    const std::string npartitions_str = std::to_string(_npartitions);
+    std::string fname = file_name_base + "_partitioned_msh_ele"
+                              + npartitions_str + ".bin";
     FILE* of_bin_ele = fopen(fname.c_str(), "wb");
     fname =
         file_name_base + "_partitioned_msh_ele_g" + npartitions_str + ".bin";
@@ -302,7 +338,7 @@ void NodeWiseMeshPartitioner::writeBinary(const std::string& file_name_base)
     {
         const auto& partition = _partitions[i];
 
-        // Set the local node indecies of the current partition.
+        // Set the local node indices of the current partition.
         IntegerType node_local_id_offset = 0;
         std::vector<IntegerType> nodes_local_ids(_mesh->getNumberOfNodes(), -1);
         for (const auto* node : partition.nodes)
@@ -311,7 +347,7 @@ void NodeWiseMeshPartitioner::writeBinary(const std::string& file_name_base)
             node_local_id_offset++;
         }
 
-        // An vector contians all element integer variales of
+        // A vector contians all element integer variales of
         // the non-ghost elements of this partition
         std::vector<IntegerType> ele_info(num_elem_integers[i]);
 
@@ -326,7 +362,7 @@ void NodeWiseMeshPartitioner::writeBinary(const std::string& file_name_base)
                                        counter);
         }
         // Write vector data of non-ghost elements
-        fwrite(&ele_info[0], 1, (num_elem_integers[i]) * sizeof(IntegerType),
+        fwrite(ele_info.data(), 1, (num_elem_integers[i]) * sizeof(IntegerType),
                of_bin_ele);
 
         // Ghost elements
@@ -342,14 +378,18 @@ void NodeWiseMeshPartitioner::writeBinary(const std::string& file_name_base)
                                        counter);
         }
         // Write vector data of ghost elements
-        fwrite(&ele_info[0], 1, (num_g_elem_integers[i]) * sizeof(IntegerType),
+        fwrite(ele_info.data(), 1, (num_g_elem_integers[i]) * sizeof(IntegerType),
                of_bin_ele_g);
     }
+
     fclose(of_bin_ele);
     fclose(of_bin_ele_g);
+}
 
-    // Output an array of all nodes
-    fname = file_name_base + "_partitioned_msh_nod" + npartitions_str + ".bin";
+void NodeWiseMeshPartitioner::writeNodesBinary(const std::string& file_name_base)
+{
+    const std::string fname = file_name_base + "_partitioned_msh_nod"
+                              + std::to_string(_npartitions) + ".bin";
     FILE* of_bin_nod = fopen(fname.c_str(), "wb");
     for (const auto& partition : _partitions)
     {
@@ -366,20 +406,33 @@ void NodeWiseMeshPartitioner::writeBinary(const std::string& file_name_base)
             node_struct.z = coords[2];
             nodes_buffer.emplace_back(node_struct);
         }
-        fwrite(&nodes_buffer[0], sizeof(NodeStruct), partition.nodes.size(),
+        fwrite(nodes_buffer.data(), sizeof(NodeStruct), partition.nodes.size(),
                of_bin_nod);
     }
     fclose(of_bin_nod);
 }
 
-void NodeWiseMeshPartitioner::writeASCII(const std::string& file_name_base)
+void NodeWiseMeshPartitioner::writeBinary(const std::string& file_name_base)
 {
-    const std::string npartitions_str = std::to_string(_npartitions);
+    const auto elem_integers = writeConfigDataBinary(file_name_base);
+
+    const std::vector<IntegerType>& num_elem_integers
+                                         = std::get<0>(elem_integers);
+    const std::vector<IntegerType>& num_g_elem_integers
+                                         = std::get<1>(elem_integers);
+    writeElementsBinary(file_name_base, num_elem_integers,
+                        num_g_elem_integers);
+
+    writeNodesBinary(file_name_base);
+}
 
-    // Write the configuration data
-    std::string fname =
-        file_name_base + "_partitioned_cfg" + npartitions_str + ".msh";
-    std::fstream os_subd_head(fname.c_str(), std::ios::out | std::ios::trunc);
+void NodeWiseMeshPartitioner::writeConfigDataASCII
+                                    (const std::string& file_name_base)
+{
+    const std::string fname =
+                              file_name_base + "_partitioned_cfg"
+                              + std::to_string(_npartitions) + ".msh";
+    std::fstream os_subd_head(fname, std::ios::out | std::ios::trunc);
     const std::string mesh_info =
         "Subdomain mesh ("
         "Number of nodes; Number of base nodes;"
@@ -406,16 +459,18 @@ void NodeWiseMeshPartitioner::writeASCII(const std::string& file_name_base)
                                    partition.regular_elements);
         os_subd_head << " " << getNumberOfIntegerVariablesOfElements(
                                    partition.ghost_elements)
-                     << " 0 \n";
+                     << " 0\n";
     }
-    os_subd_head.close();
+}
 
-    // Write the elements of each partitions
-    fname = file_name_base + "_partitioned_elems_" + npartitions_str + ".msh";
-    std::fstream os_subd(fname.c_str(), std::ios::out | std::ios::trunc);
+void NodeWiseMeshPartitioner::writeElementsASCII(const std::string& file_name_base)
+{
+    const std::string fname = file_name_base + "_partitioned_elems_"
+                              + std::to_string(_npartitions) + ".msh";
+    std::fstream os_subd(fname, std::ios::out | std::ios::trunc);
     for (const auto& partition : _partitions)
     {
-        // Set the local node indecies of the current partition.
+        // Set the local node indices of the current partition.
         IntegerType node_local_id_offset = 0;
         std::vector<IntegerType> nodes_local_ids(_mesh->getNumberOfNodes(), -1);
         for (const auto* node : partition.nodes)
@@ -434,11 +489,13 @@ void NodeWiseMeshPartitioner::writeASCII(const std::string& file_name_base)
         }
         os_subd << std::endl;
     }
-    os_subd.close();
+}
 
-    // Write the nodes of each partitions
-    fname = file_name_base + "_partitioned_nodes_" + npartitions_str + ".msh";
-    std::fstream os_subd_node(fname.c_str(), std::ios::out | std::ios::trunc);
+void NodeWiseMeshPartitioner::writeNodesASCII(const std::string& file_name_base)
+{
+    const std::string fname = file_name_base + "_partitioned_nodes_"
+                              + std::to_string(_npartitions) + ".msh";
+    std::fstream os_subd_node(fname, std::ios::out | std::ios::trunc);
     os_subd_node.precision(std::numeric_limits<double>::digits10);
     os_subd_node.setf(std::ios::scientific);
 
@@ -452,7 +509,13 @@ void NodeWiseMeshPartitioner::writeASCII(const std::string& file_name_base)
         }
         os_subd_node << std::endl;
     }
-    os_subd_node.close();
+}
+
+void NodeWiseMeshPartitioner::writeASCII(const std::string& file_name_base)
+{
+    writeConfigDataASCII(file_name_base);
+    writeElementsASCII(file_name_base);
+    writeNodesASCII(file_name_base);
 }
 
 void NodeWiseMeshPartitioner::resetGlobalNodeIndices()
@@ -484,9 +547,8 @@ void NodeWiseMeshPartitioner::getElementIntegerVariables(
     std::vector<IntegerType>& elem_info,
     IntegerType& counter)
 {
-    unsigned mat_id = 0;  // TODO: Materical ID to be set from the mesh data
+    unsigned mat_id = 0;  // TODO: Material ID to be set from the mesh data
     const IntegerType nn = elem.getNumberOfNodes();
-    ;
     elem_info[counter++] = mat_id;
     elem_info[counter++] = static_cast<unsigned>(elem.getCellType());
     elem_info[counter++] = nn;
@@ -502,7 +564,7 @@ void NodeWiseMeshPartitioner::writeLocalElementNodeIndices(
     const MeshLib::Element& elem,
     const std::vector<IntegerType>& local_node_ids)
 {
-    unsigned mat_id = 0;  // TODO: Materical ID to be set from the mesh data
+    unsigned mat_id = 0;  // TODO: Material ID to be set from the mesh data
     os << mat_id << " " << static_cast<unsigned>(elem.getCellType())
        << " " << elem.getNumberOfNodes() << " ";
     for (unsigned i = 0; i < elem.getNumberOfNodes(); i++)
diff --git a/Applications/Utils/ModelPreparation/PartitionMesh/NodeWiseMeshPartitioner.h b/Applications/Utils/ModelPreparation/PartitionMesh/NodeWiseMeshPartitioner.h
index feda8c1a135..2aa2f000401 100644
--- a/Applications/Utils/ModelPreparation/PartitionMesh/NodeWiseMeshPartitioner.h
+++ b/Applications/Utils/ModelPreparation/PartitionMesh/NodeWiseMeshPartitioner.h
@@ -16,6 +16,7 @@
 #define NODE_WISE_MESH_PARTITIONER_H_
 
 #include <memory>
+#include <tuple>
 #include <vector>
 #include <string>
 #include <fstream>
@@ -49,7 +50,7 @@ public:
      * \param mesh           Pointer to a mesh object.
      */
     NodeWiseMeshPartitioner(const IntegerType num_partitions,
-                            std::unique_ptr<MeshLib::Mesh>& mesh)
+                            std::unique_ptr<MeshLib::Mesh>&& mesh)
         : _npartitions(num_partitions),
           _partitions(num_partitions),
           _mesh(std::move(mesh)),
@@ -58,12 +59,11 @@ public:
           _elements_status(_mesh->getNumberOfElements(), false)
     {
     }
-    ~NodeWiseMeshPartitioner() = default;
 
     /// Partition by node.
     /// \param is_mixed_hl_elem Flag to indicate whether the elements of
     /// a mesh can be used for both linear and high order interpolation
-    void partitionByMETIS(const bool is_mixed_hl_elem);
+    void partitionByMETIS(const bool is_mixed_high_order_linear_elems);
 
     void resetGlobalNodeIndices();
 
@@ -103,13 +103,16 @@ private:
     /// Partition IDs of each nodes.
     std::vector<std::size_t> _nodes_partition_ids;
 
-    /// Flags to indicate the status of all elements.
+    /// Flags to indicate that whether elements are processed or not.
     std::vector<bool> _elements_status;
 
-    void renumberNodeIndices();
+    // Renumber the global indices of nodes,
+    /// \param is_mixed_hl_elem Flag to indicate whether the elements of
+    /// a mesh can be used for both linear and high order interpolation
+    void renumberNodeIndices(const bool is_mixed_high_order_linear_elems);
 
     /*!
-       Calculate the totoal number of integer variables of an element
+       Calculate the total number of integer variables of an element
        vector.
            Each element has three integer variables for material ID,
        element type, number of nodes of the element. Therefore
@@ -121,11 +124,11 @@ private:
         const std::vector<const MeshLib::Element*>& elements) const;
 
     /*!
-         \brief get integer variables, which are used to define an element
+         \brief Get integer variables, which are used to define an element
          \param elem            Element
-         \param local_node_ids  Local node indicies of a partition
-         \param elem_info       An vector holds all integer variables of element
-       definitions
+         \param local_node_ids  Local node indices of a partition
+         \param elem_info       A vector holds all integer variables of
+                                element definitions
          \param counter         Recorder of the number of integer variables.
     */
     void getElementIntegerVariables(const MeshLib::Element& elem,
@@ -134,10 +137,53 @@ private:
                                     IntegerType& counter);
 
     /*!
-        \brief Write local indicies of element nodes to a ASCII file
+         \brief Write the configuration data of the partition data in
+                binary files.
+         \param file_name_base The prefix of the file name.
+         \return element 1: The numbers of all non-ghost element integer
+                            variables of each partitions.
+                 element 2: The numbers of all ghost element integer
+                            variables of each partitions.
+    */
+    std::tuple< std::vector<IntegerType>, std::vector<IntegerType>>
+         writeConfigDataBinary(const std::string& file_name_base);
+
+    /*!
+         \brief Write the element integer variables of all partitions
+                into binary files.
+         \param file_name_base      The prefix of the file name.
+         \param num_elem_integers   The numbers of all non-ghost element
+                                    integer variables of each partitions.
+         \param num_g_elem_integers The numbers of all ghost element
+                                    integer variables of each partitions.
+    */
+    void writeElementsBinary(const std::string& file_name_base,
+                      const std::vector<IntegerType>& num_elem_integers,
+                      const std::vector<IntegerType>& num_g_elem_integers);
+
+    ///  Write the nodes of all partitions into a binary file.
+    ///  \param file_name_base The prefix of the file name.
+    void writeNodesBinary(const std::string& file_name_base);
+
+
+    /// Write the configuration data of the partition data in ASCII files.
+    /// \param file_name_base The prefix of the file name.
+    void writeConfigDataASCII(const std::string& file_name_base);
+
+    ///  Write the element integer variables of all partitions into
+    ///  ASCII files.
+    /// \param file_name_base The prefix of the file name.
+    void writeElementsASCII(const std::string& file_name_base);
+
+    ///  Write the nodes of all partitions into a ASCII file.
+    /// \param file_name_base The prefix of the file name.
+    void writeNodesASCII(const std::string& file_name_base);
+
+    /*!
+        \brief Write local indices of element nodes to a ASCII file
         \param os              Output stream
         \param elem            Element
-        \param local_node_ids  Local node indicies of a partition
+        \param local_node_ids  Local node indices of a partition
     */
     void writeLocalElementNodeIndices(
         std::ostream& os,
diff --git a/Applications/Utils/ModelPreparation/PartitionMesh/PartitionMesh.cpp b/Applications/Utils/ModelPreparation/PartitionMesh/PartitionMesh.cpp
index dd6b9f8e2fa..92dd52597d6 100644
--- a/Applications/Utils/ModelPreparation/PartitionMesh/PartitionMesh.cpp
+++ b/Applications/Utils/ModelPreparation/PartitionMesh/PartitionMesh.cpp
@@ -17,7 +17,6 @@
 #ifdef _MSC_VER
 #include <windows.h>
 #else
-#include <sys/time.h>
 #include <climits>
 #endif
 
@@ -34,14 +33,16 @@ int main(int argc, char* argv[])
 {
     ApplicationsLib::LogogSetup logog_setup;
 
-    std::string m_str =
+    const std::string m_str =
         "Partition a mesh for parallel computing."
         "The tasks of this tool are in twofold:\n"
         "1. Convert mesh file to the input file of the partitioning tool,\n"
         "2. Partition a mesh using the partitioning tool,\n"
         "\tcreate the mesh data of each partition,\n"
-        "\trenumber the node indicies of each partition,\n"
-        "\tand output the results for parallel computing.";
+        "\trenumber the node indices of each partition,\n"
+        "\tand output the results for parallel computing.\n"
+        "Note: If this tool is installed as a system command,\n"
+        "\tthe command must be run with its full path.";
 
     TCLAP::CmdLine cmd(m_str, ' ', "0.1");
     TCLAP::ValueArg<std::string> mesh_input(
@@ -86,7 +87,7 @@ int main(int argc, char* argv[])
          mesh_ptr->getNumberOfElements());
 
     ApplicationUtils::NodeWiseMeshPartitioner mesh_partitioner(
-        nparts.getValue(), mesh_ptr);
+        nparts.getValue(), std::move(mesh_ptr));
 
     if (ogs2metis_flag.getValue())
     {
@@ -103,19 +104,18 @@ int main(int argc, char* argv[])
         {
             INFO("METIS is running ...");
             const std::string exe_name = argv[0];
-            std::string exe_path =
-                exe_name.substr(0, exe_name.find_last_of("/\\"));
-            INFO("Path to mtmetis is: \n\t%s", exe_path.c_str());
+            const std::string exe_path = BaseLib::extractPath(exe_name);
+            INFO("Path to mpmetis is: \n\t%s", exe_path.c_str());
 
-            std::string mpmetis_com =
+            const std::string mpmetis_com =
                 exe_path + "/mpmetis " + " -gtype=nodal " + file_name_base +
                 ".mesh " + std::to_string(nparts.getValue());
 
-            int status = system(mpmetis_com.c_str());
+            const int status = system(mpmetis_com.c_str());
             if (status != 0)
             {
                 INFO("Failed in system calling.");
-                INFO("Return value of system calling %d ", status);
+                INFO("Return value of system call %d ", status);
                 return EXIT_FAILURE;
             }
         }
@@ -135,12 +135,12 @@ int main(int argc, char* argv[])
             mesh_partitioner.writeBinary(file_name_base);
         }
 
-        INFO("Write the mesh with renumbered node indicies into VTU ...");
+        INFO("Write the mesh with renumbered node indices into VTU ...");
         mesh_partitioner.writeGlobalMeshVTU(file_name_base);
     }
 
     INFO("Total runtime: %g s.", run_timer.elapsed());
-    INFO("Total CPU time: %g s.\n", CPU_timer.elapsed());
+    INFO("Total CPU time: %g s.", CPU_timer.elapsed());
 
     return EXIT_SUCCESS;
 }
diff --git a/MeshLib/Node.h b/MeshLib/Node.h
index de493e4f2d4..410f25614f9 100644
--- a/MeshLib/Node.h
+++ b/MeshLib/Node.h
@@ -22,6 +22,11 @@
 #include "MathLib/Point3dWithID.h"
 #include "MathLib/Vector3.h"
 
+namespace ApplicationUtils
+{
+    class NodeWiseMeshPartitioner;
+}
+
 namespace MeshLib {
 
 class Element;
@@ -35,6 +40,7 @@ class Node final : public MathLib::Point3dWithID
     friend class Mesh;
     friend class MeshRevision;
     friend class MeshLayerMapper;
+    friend class ApplicationUtils::NodeWiseMeshPartitioner;
 
 public:
     /// Constructor using a coordinate array
@@ -67,9 +73,6 @@ public:
         return Node(_x[0]-v[0], _x[1]-v[1], _x[2]-v[2]);
     }
 
-    /// Sets the ID of a node to the given value.
-    void setID(std::size_t id) { _id = id; }
-
 protected:
     /// Update coordinates of a node.
     /// This method automatically also updates the areas/volumes of all connected elements.
@@ -92,6 +95,9 @@ protected:
         _connected_nodes = connected_nodes;
     }
 
+    /// Sets the ID of a node to the given value.
+    void setID(std::size_t id) { _id = id; }
+
     std::vector<Node*> _connected_nodes;
     std::vector<Element*> _elements;
 }; /* class */
-- 
GitLab