From f359e53e46e0f1d437632b98154ae3b46bc31fac Mon Sep 17 00:00:00 2001
From: Dmitri Naumov <dmitri.naumov@ufz.de>
Date: Fri, 9 Jan 2015 15:55:48 +0100
Subject: [PATCH] Squashed code review changes.

[IO] Replace pointer types with std::vector.

[T] Use Logog formatter pointers. Reduce indent.

[MeL] Remove default NodePartitionedMesh dtor definition.

[MeL] Const correctness of NodePartitionedMesh::isGhostNode().

[IO] Remove default NodePartitionedMeshRead definiton.

[IO] Split long lines.

[IO] Correct doxygen comments.

[IO] Correct private _mpi_comm variable name.

[IO] Correct typo in buildNodeStructTypeMPI() fct name.

[IO] Use NodeData reference instead of pointer.

[IO] Add std namespace identifier for std::getline.

[IO] Remove printMessage().

[IO] Remove unused MPI_status, make message_tag const.

[IO] Add private NodePartitionedMeshReader::readDataFromFile().

This encapsulates MPI IO code.

[MeL] NodePartMesh: Change global node id type to std::size_t.

[IO] Fix some of implicit int type conversions: sign/width.

[IO] Correct doxygen comments.

[IO] Move MPI communicator init to NodePartMeshReader ctor.

[MeL] Use size_t from std namespace.

[IO] Use postfix increment for counters.

[IO] Pass a vector to buildNodeStructType().

[IO] Use std::vector's data() instead of &v[0] in MPI calls.

[IO] Rewrite openASCIIFiles. Scopes and var names.

[IO] Improve const correctness.

[IO] Remove almost unused MeshLib namespace include.

[IO] Improve some comments.

[IO] Add missing includes and remove unused one.

[MeL] Remove unused forward declaration.

[IO] Replace _size_str with on-the-fly conversion.

[IO] Spelling

[IO] Remove duplicate information.

[IO] Improve const-correctness of member fcts.

[IO] Use std::vector in readElementASCII().

[IO] Move up MPI_node deallocation.

[IO] Rename variables.

anode -> node.
s_nodes -> nodes.

_size -> _mpi_comm_size
_rank -> _mpi_rank

[IO] Replace mesh_controls type with std::array.

In the readASCII().

[IO] Variable declaration at definition/use point.

[IO] Rewrite buildNodesStructTypeMPI().

Shorten the code, use MPI blocks for array (of three coordinates).

[IO] Make _mpi_node_type a class variable.

Move initialization to ctor and freeing to dtor.
Function renames.

The reader must exit scope before MPI_FINILIZE
is called.

[IO] Change variable's type long->int; MPI_Send().

[IO] Comment on element types.

[IO] Rename readBinaryDataFromFile(). Change container type.
---
 FileIO/MPI_IO/NodePartitionedMeshReader.cpp   | 460 ++++++++----------
 FileIO/MPI_IO/NodePartitionedMeshReader.h     | 121 +++--
 MeshLib/NodePartitionedMesh.h                 |  45 +-
 .../MPI/NodePartitionedMeshTester.cpp         |  97 ++--
 4 files changed, 347 insertions(+), 376 deletions(-)

diff --git a/FileIO/MPI_IO/NodePartitionedMeshReader.cpp b/FileIO/MPI_IO/NodePartitionedMeshReader.cpp
index 35b115bdc46..e79d29eafef 100644
--- a/FileIO/MPI_IO/NodePartitionedMeshReader.cpp
+++ b/FileIO/MPI_IO/NodePartitionedMeshReader.cpp
@@ -14,6 +14,8 @@
 
 #include "NodePartitionedMeshReader.h"
 
+#include <array>
+
 #include "logog/include/logog.hpp"
 
 #include "BaseLib/RunTime.h"
@@ -28,24 +30,34 @@
 #include "MeshLib/Elements/Tet.h"
 #include "MeshLib/Elements/Tri.h"
 
-using namespace MeshLib;
-
 namespace FileIO
 {
-MeshLib::NodePartitionedMesh* NodePartitionedMeshReader::read(MPI_Comm comm, const std::string &file_name_base)
+
+NodePartitionedMeshReader::NodePartitionedMeshReader(MPI_Comm comm)
+    : _mpi_comm(comm)
+{
+    MPI_Comm_size(_mpi_comm, &_mpi_comm_size);
+    MPI_Comm_rank(_mpi_comm, &_mpi_rank);
+
+    registerNodeDataMpiType();
+}
+
+NodePartitionedMeshReader::~NodePartitionedMeshReader()
+{
+    MPI_Type_free(&_mpi_node_type);
+}
+
+MeshLib::NodePartitionedMesh* NodePartitionedMeshReader::read(
+    const std::string &file_name_base)
 {
     BaseLib::RunTime timer;
     timer.start();
 
-    mpi_comm_ = comm;
-    MPI_Comm_size(mpi_comm_, &_size);
-    _size_str = std::to_string(_size);
-    MPI_Comm_rank(mpi_comm_, &_rank);
-
-    NodePartitionedMesh *mesh = nullptr;
+    MeshLib::NodePartitionedMesh *mesh = nullptr;
 
     // Always try binary file first
-    std::string fname_new = file_name_base + "_partitioned_msh_cfg" + _size_str + ".bin";
+    std::string const fname_new = file_name_base + "_partitioned_msh_cfg" +
+        std::to_string(_mpi_comm_size) + ".bin";
 
     if(!BaseLib::IsFileExisting(fname_new)) // doesn't exist binary file.
     {
@@ -62,124 +74,96 @@ MeshLib::NodePartitionedMesh* NodePartitionedMeshReader::read(MPI_Comm comm, con
 
     INFO("\t\n>>Total elapsed time in reading mesh:%f s\n", timer.elapsed());
 
-    MPI_Barrier(comm);
+    MPI_Barrier(_mpi_comm);
 
     return mesh;
 }
 
-MeshLib::NodePartitionedMesh* NodePartitionedMeshReader
-::readBinary(const std::string &file_name_base)
+template <typename DATA>
+bool
+NodePartitionedMeshReader::readBinaryDataFromFile(std::string const& filename,
+        MPI_Offset offset, MPI_Datatype type, DATA& data) const
+{
+    // Open file
+    MPI_File file;
+
+    char* filename_char = const_cast<char*>(filename.data());
+    int const file_status = MPI_File_open(_mpi_comm, filename_char,
+            MPI_MODE_RDONLY, MPI_INFO_NULL, &file);
+
+    if(file_status != 0)
+    {
+        ERR("Error opening file %s. MPI error code %d", filename.c_str(), file_status);
+        return false;
+    }
+
+    // Read data
+    char file_mode[] = "native";
+    MPI_File_set_view(file, offset, type, type, file_mode, MPI_INFO_NULL);
+    MPI_File_read(file, data.data(), data.size(), type, MPI_STATUS_IGNORE);
+    MPI_File_close(&file);
+
+    return true;
+}
+
+MeshLib::NodePartitionedMesh* NodePartitionedMeshReader::readBinary(
+        const std::string &file_name_base)
 {
     //----------------------------------------------------------------------------------
     // Read headers
-    MPI_File fh;
-    char ftype[] = "native";
-    int file_status = 0;
+
     const std::string fname_header = file_name_base +  "_partitioned_msh_";
-    const std::string fname_num_p_ext = _size_str + ".bin";
+    const std::string fname_num_p_ext = std::to_string(_mpi_comm_size) + ".bin";
 
-    std::string fname_new_base = fname_header + "cfg" + fname_num_p_ext;
-    file_status = MPI_File_open(mpi_comm_, &fname_new_base[0], MPI_MODE_RDONLY,
-                                MPI_INFO_NULL, &fh);
-    if(file_status) // Failed to open the file
-    {
-        printMessage(fname_new_base);
-        return nullptr;
-    }
+    // Array that contains integer numbers of the partition data header.
+    // See description of readBinary() function.
+    std::array<long, 14> mesh_controls;
 
-    const long num_controls = 14;
-    /*
-    Array that contains integer numbers of the partition data header
-    and its size is 14.
-            0:    Number of all nodes of a partition,
-            1:    Number of nodes for linear element of a parition,
-            2:    Number of non-ghost elements of a partition,
-            3:    Number of ghost element of a partition,
-            4:    Number of active nodes for linear element of a parition,
-            5:    Number of all active nodes a parition,
-            6:    Number of nodes for linear element of global mesh,
-            7:    Number of all nodes of global mesh,
-            8~12: Offsets of positions of partitions in the data arrays,
-            13:   Reserved for exra flag.
-    */
-    long mesh_controls[num_controls];
+    if (!readBinaryDataFromFile(fname_header + "cfg" + fname_num_p_ext,
+            static_cast<MPI_Offset>(
+                static_cast<unsigned>(_mpi_rank) * mesh_controls.size() * sizeof(long)),
+            MPI_LONG, mesh_controls))
+        return nullptr;
 
-    MPI_Offset offset_new;
-    offset_new = _rank * num_controls * sizeof(long);
-    MPI_File_set_view(fh, offset_new, MPI_LONG, MPI_LONG, ftype, MPI_INFO_NULL);
-    MPI_File_read(fh, mesh_controls, num_controls, MPI_LONG, MPI_STATUS_IGNORE); //_all
-    MPI_File_close(&fh);
     _num_nodes_part = mesh_controls[0];
     _num_regular_elems_part = mesh_controls[2];
     _num_ghost_elems_part = mesh_controls[3];
 
     //----------------------------------------------------------------------------------
     // Read Nodes
-    fname_new_base = fname_header + "nod" + fname_num_p_ext;
-    file_status = MPI_File_open(mpi_comm_, &fname_new_base[0], MPI_MODE_RDONLY,
-                                MPI_INFO_NULL, &fh);
-    if(file_status) // Failed to open the file
-    {
-        printMessage(fname_new_base);
-        return nullptr;
-    }
-
-    MPI_Datatype MPI_node;
-    std::vector<NodeData> s_nodes(_num_nodes_part);
-    buildNodeStrucTypeMPI(&s_nodes[0], &MPI_node);
+    std::vector<NodeData> nodes(static_cast<std::size_t>(_num_nodes_part));
 
-    offset_new =  mesh_controls[10];
-    MPI_File_set_view(fh, offset_new, MPI_node, MPI_node, ftype, MPI_INFO_NULL);
-    MPI_File_read(fh, &s_nodes[0], _num_nodes_part, MPI_node, MPI_STATUS_IGNORE);
-    MPI_File_close(&fh);
+    if (!readBinaryDataFromFile(fname_header + "nod" + fname_num_p_ext,
+             static_cast<MPI_Offset>(mesh_controls[10]), _mpi_node_type, nodes))
+        return nullptr;
 
     std::vector<MeshLib::Node*> mesh_nodes;
-    std::vector<unsigned> glb_node_ids;
-    setNodes(s_nodes, mesh_nodes, glb_node_ids);
-
-    MPI_Type_free(&MPI_node);
+    std::vector<std::size_t> glb_node_ids;
+    setNodes(nodes, mesh_nodes, glb_node_ids);
 
     //----------------------------------------------------------------------------------
     // Read non-ghost elements
-    fname_new_base = fname_header +"ele" + fname_num_p_ext;
-    file_status = MPI_File_open(mpi_comm_, &fname_new_base[0], MPI_MODE_RDONLY,
-                                MPI_INFO_NULL, &fh);
-    if(file_status) // Failed to open the file
-    {
-        printMessage(fname_new_base);
-        return nullptr;
-    }
 
-    long size_elem_info = _num_regular_elems_part + mesh_controls[8];
-    std::vector<long> elem_data(size_elem_info);
-    offset_new =  mesh_controls[11];
-    MPI_File_set_view(fh, offset_new, MPI_LONG, MPI_LONG, ftype, MPI_INFO_NULL);
-    MPI_File_read(fh, &elem_data[0], size_elem_info, MPI_LONG, MPI_STATUS_IGNORE);
-    MPI_File_close(&fh);
+    std::vector<long> elem_data(static_cast<std::size_t>(
+        _num_regular_elems_part + mesh_controls[8]));
+    if (!readBinaryDataFromFile(fname_header +"ele" + fname_num_p_ext,
+            static_cast<MPI_Offset>(mesh_controls[11]), MPI_LONG, elem_data))
+        return nullptr;
 
     std::vector<MeshLib::Element*> mesh_elems(_num_regular_elems_part + _num_ghost_elems_part);
-    setElements(mesh_nodes, elem_data.data(), mesh_elems);
+    setElements(mesh_nodes, elem_data, mesh_elems);
 
     //----------------------------------------------------------------------------------
     //Read ghost element
-    fname_new_base = fname_header + "ele_g" + fname_num_p_ext;
-    file_status = MPI_File_open(mpi_comm_, &fname_new_base[0], MPI_MODE_RDONLY,
-                                MPI_INFO_NULL, &fh);
-    if(file_status)
-    {
-        printMessage(fname_new_base);
-        return nullptr;
-    }
+    std::vector<long> ghost_elem_data(static_cast<std::size_t>(
+        _num_ghost_elems_part + mesh_controls[9]));
 
-    size_elem_info = _num_ghost_elems_part + mesh_controls[9];
-    elem_data.resize(size_elem_info);
-    offset_new =  mesh_controls[12];
-    MPI_File_set_view(fh, offset_new, MPI_LONG, MPI_LONG, ftype, MPI_INFO_NULL);
-    MPI_File_read(fh, &elem_data[0], size_elem_info, MPI_LONG, MPI_STATUS_IGNORE);
-    MPI_File_close(&fh);
+    if (!readBinaryDataFromFile(fname_header + "ele_g" + fname_num_p_ext,
+            static_cast<MPI_Offset>(mesh_controls[12]), MPI_LONG, ghost_elem_data))
+        return nullptr;
 
     const bool process_ghost = true;
-    setElements(mesh_nodes, elem_data.data(), mesh_elems, process_ghost);
+    setElements(mesh_nodes, ghost_elem_data, mesh_elems, process_ghost);
 
     //----------------------------------------------------------------------------------
     //Create a mesh and return it
@@ -190,114 +174,110 @@ MeshLib::NodePartitionedMesh* NodePartitionedMeshReader
     const unsigned n_active_base_nodes = static_cast<unsigned>(mesh_controls[4]);
     const unsigned n_active_nodes = static_cast<unsigned>(mesh_controls[5]);
 
-    return new NodePartitionedMesh(BaseLib::extractBaseName(file_name_base) + _size_str,
-                                   mesh_nodes, glb_node_ids,
-                                   mesh_elems, n_nghost_elem,
-                                   n_global_base_nodes, n_global_nodes,
-                                   n_base_nodes, n_active_base_nodes, n_active_nodes);
+    return new MeshLib::NodePartitionedMesh(
+            BaseLib::extractBaseName(file_name_base) + std::to_string(_mpi_comm_size),
+            mesh_nodes, glb_node_ids,
+            mesh_elems, n_nghost_elem,
+            n_global_base_nodes, n_global_nodes,
+            n_base_nodes, n_active_base_nodes, n_active_nodes);
 }
 
-bool NodePartitionedMeshReader::
-openASCIIFiles(std::string const& file_name_base,
-               std::ifstream& is_cfg, std::ifstream& is_node, std::ifstream& is_elem)
+bool NodePartitionedMeshReader::openASCIIFiles(std::string const& file_name_base,
+        std::ifstream& is_cfg, std::ifstream& is_node, std::ifstream& is_elem) const
 {
     const std::string fname_header = file_name_base +  "_partitioned_";
-    const std::string fname_num_p_ext = _size_str + ".msh";
+    const std::string fname_num_p_ext = std::to_string(_mpi_comm_size) + ".msh";
 
-    std::string str_var = fname_header + "cfg"+ fname_num_p_ext;
-    is_cfg.open(str_var.c_str());
+    {   // Configuration.
+        std::string const filename = fname_header + "cfg"+ fname_num_p_ext;
+        is_cfg.open(filename);
 
-    if( !is_cfg.good() )
-    {
-        printMessage(str_var);
-        return false;
-    }
+        if( !is_cfg.good() )
+        {
+            ERR("Error opening file %s for input.", filename.c_str());
+            return false;
+        }
 
-    getline(is_cfg, str_var);
-    int num_parts;
-    is_cfg >> num_parts >> std::ws;
+        std::string tmp_line;
+        std::getline(is_cfg, tmp_line);
+        int num_parts;
+        is_cfg >> num_parts >> std::ws;
 
-    if(num_parts != _size)
-    {
-        std::string str_var = "Aborting computation because of number of cores / subdomains mismatch.";
-        printMessage(str_var, false);
-        return false;
+        if(num_parts != _mpi_comm_size)
+        {
+            ERR("Aborting computation because of number of cores"
+                "/ subdomains mismatch.");
+            return false;
+        }
     }
 
-    str_var = fname_header + "nodes_" + fname_num_p_ext;
-    is_node.open(str_var.c_str());
-    if( !is_node.good() )
-    {
-        return false;
+    {   // Nodes.
+        std::string const filename = fname_header + "nodes_" + fname_num_p_ext;
+        is_node.open(filename);
+        if( !is_node.good() )
+        {
+            ERR("Error opening file %s for input.", filename.c_str());
+            return false;
+        }
     }
 
-    str_var = fname_header + "elems_" + fname_num_p_ext;
-    is_elem.open(str_var.c_str());
-    if( !is_elem.good() )
-    {
-        printMessage(str_var);
-        return false;
+    {   // Elements.
+        std::string const filename = fname_header + "elems_" + fname_num_p_ext;
+        is_elem.open(filename);
+        if( !is_elem.good() )
+        {
+            ERR("Error opening file %s for input.", filename.c_str());
+            return false;
+        }
     }
 
     return true;
 }
 
-void NodePartitionedMeshReader
-::readCastNodesASCII(std::ifstream& is_node, const int part_id,
-                     std::vector<MeshLib::Node*> &mesh_nodes,
-                     std::vector<unsigned> &glb_node_ids)
+void NodePartitionedMeshReader::readCastNodesASCII(std::ifstream& is_node,
+        const int part_id, std::vector<MeshLib::Node*> &mesh_nodes,
+        std::vector<std::size_t> &glb_node_ids) const
 {
-    int tag = 0;
-    MPI_Status status;
+    int const message_tag = 0;
 
     //----------------------------------------------------------------------------------
     // Read Nodes
-    std::vector<NodeData> s_nodes(_num_nodes_part);
-
-    MPI_Datatype MPI_node;
-    if(part_id > 0)
-        buildNodeStrucTypeMPI(&s_nodes[0], &MPI_node);
+    std::vector<NodeData> nodes(static_cast<std::size_t>(_num_nodes_part));
 
-    if(_rank == 0)
+    if(_mpi_rank == 0)
     {
-        for(long k=0; k<_num_nodes_part; k++)
+        for(std::size_t k=0; k<_num_nodes_part; k++)
         {
-            NodeData *anode = &s_nodes[k];
-            is_node >> anode->index
-                    >> anode->x >> anode->y >> anode->z >> std::ws;
+            NodeData &node = nodes[k];
+            is_node >> node.index
+                    >> node.x >> node.y >> node.z >> std::ws;
         }
 
         if(part_id == 0)
         {
-            setNodes(s_nodes, mesh_nodes, glb_node_ids);
+            setNodes(nodes, mesh_nodes, glb_node_ids);
         }
         else
         {
-            MPI_Send(&s_nodes[0], _num_nodes_part, MPI_node, part_id, tag, mpi_comm_);
+            MPI_Send(nodes.data(), _num_nodes_part, _mpi_node_type, part_id, message_tag, _mpi_comm);
         }
     }
-    else if(part_id > 0 && _rank == part_id)
+    else if(part_id > 0 && _mpi_rank == part_id)
     {
-        MPI_Recv(&s_nodes[0], _num_nodes_part, MPI_node, 0, tag, mpi_comm_, &status);
-        setNodes(s_nodes, mesh_nodes, glb_node_ids);
+        MPI_Recv(nodes.data(), _num_nodes_part, _mpi_node_type, 0, message_tag, _mpi_comm, MPI_STATUS_IGNORE);
+        setNodes(nodes, mesh_nodes, glb_node_ids);
     }
-
-    if(part_id > 0)
-        MPI_Type_free(&MPI_node);
-
 }
 
-void NodePartitionedMeshReader
-::readCastElemsASCII(std::ifstream& is_elem, const int part_id,
-                     const long data_size, const bool process_ghost,
-                     const std::vector<MeshLib::Node*> &mesh_nodes,
-                     std::vector<MeshLib::Element*> &mesh_elems)
+void NodePartitionedMeshReader::readCastElemsASCII(std::ifstream& is_elem,
+        const int part_id, const int data_size, const bool process_ghost,
+        const std::vector<MeshLib::Node*> &mesh_nodes,
+        std::vector<MeshLib::Element*> &mesh_elems) const
 {
-    int tag = 0;
-    MPI_Status status;
+    int const message_tag = 0;
 
-    long *elem_data = new long[data_size];
-    if(_rank == 0)
+    std::vector<long> elem_data(static_cast<std::size_t>(data_size));
+    if(_mpi_rank == 0)
     {
         readElementASCII(is_elem, elem_data, process_ghost);
 
@@ -309,30 +289,28 @@ void NodePartitionedMeshReader
         }
         else
         {
-            MPI_Send(elem_data, data_size, MPI_LONG, part_id, tag, mpi_comm_);
+            MPI_Send(elem_data.data(), data_size, MPI_LONG, part_id, message_tag, _mpi_comm);
         }
     }
-    else if(part_id > 0 && _rank == part_id)
+    else if(part_id > 0 && _mpi_rank == part_id)
     {
-        MPI_Recv(elem_data, data_size, MPI_LONG, 0, tag, mpi_comm_, &status);
+        MPI_Recv(elem_data.data(), data_size, MPI_LONG, 0, message_tag, _mpi_comm, MPI_STATUS_IGNORE);
 
         if(!process_ghost)
             mesh_elems.resize(_num_regular_elems_part + _num_ghost_elems_part);
         setElements(mesh_nodes, elem_data, mesh_elems, process_ghost);
     }
-
-    delete [] elem_data;
 }
 
-MeshLib::NodePartitionedMesh* NodePartitionedMeshReader
-::readASCII(const std::string &file_name_base)
+MeshLib::NodePartitionedMesh* NodePartitionedMeshReader::readASCII(
+        const std::string &file_name_base)
 {
     std::ifstream is_cfg;
     std::ifstream is_node;
     std::ifstream is_elem;
 
     bool file_opened = false;
-    if(_rank == 0)
+    if(_mpi_rank == 0)
     {
         file_opened = openASCIIFiles(file_name_base, is_cfg, is_node, is_elem);
 
@@ -344,12 +322,11 @@ MeshLib::NodePartitionedMesh* NodePartitionedMeshReader
         }
     }
 
-    MPI_Bcast(&file_opened, 1, MPI_INT, 0, mpi_comm_);
+    MPI_Bcast(&file_opened, 1, MPI_INT, 0, _mpi_comm);
 
     if(!file_opened)
         return nullptr;
 
-    const long num_controls = 11;
     /*
     Array that contains integer numbers of the partition data header
     and its size is 11.
@@ -364,25 +341,25 @@ MeshLib::NodePartitionedMesh* NodePartitionedMeshReader
             8~9:  Offsets of positions of partitions in the data arrays,
             11:   Reserved for exra flag.
     */
-    long mesh_controls[num_controls];
+    std::array<long, 11> mesh_controls;
 
-    NodePartitionedMesh *np_mesh = nullptr;
+    MeshLib::NodePartitionedMesh *np_mesh = nullptr;
     std::vector<MeshLib::Node*> mesh_nodes;
-    std::vector<unsigned> glb_node_ids;
+    std::vector<std::size_t> glb_node_ids;
     std::vector<MeshLib::Element*> mesh_elems;
 
-    for(int i=0; i<_size; i++)
+    for(int i = 0; i < _mpi_comm_size; i++)
     {
-        if(_rank == 0)
+        if(_mpi_rank == 0)
         {
             INFO("-->Parallel reading the partitioned mesh: ");
 
-            for(long j=0; j< num_controls; j++)
-                is_cfg >> mesh_controls[j];
+            for(long& v : mesh_controls)
+                is_cfg >> v;
             is_cfg >> std::ws;
         }
 
-        MPI_Bcast(mesh_controls, num_controls, MPI_LONG, 0, mpi_comm_);
+        MPI_Bcast(mesh_controls.data(), mesh_controls.size(), MPI_LONG, 0, _mpi_comm);
 
         _num_nodes_part = mesh_controls[0];
         _num_regular_elems_part = mesh_controls[2];
@@ -406,39 +383,40 @@ MeshLib::NodePartitionedMesh* NodePartitionedMeshReader
         readCastElemsASCII(is_elem, i, size_elem_g_info, process_ghost,
                            mesh_nodes, mesh_elems);
 
-        if(_rank == i)
+        if(_mpi_rank == i)
         {
             //----------------------------------------------------------------------------------
             //Create a mesh
-            const std::size_t n_nghost_elem = static_cast<size_t>(mesh_controls[2]);
+            const std::size_t n_nghost_elem = static_cast<std::size_t>(mesh_controls[2]);
             const unsigned n_global_base_nodes = static_cast<unsigned>(mesh_controls[6]);
             const unsigned n_global_nodes = static_cast<unsigned>(mesh_controls[7]);
             const unsigned n_base_nodes = static_cast<unsigned>(mesh_controls[1]);
             const unsigned n_active_base_nodes = static_cast<unsigned>(mesh_controls[4]);
             const unsigned n_active_nodes = static_cast<unsigned>(mesh_controls[5]);
 
-            np_mesh = new  NodePartitionedMesh(BaseLib::extractBaseName(file_name_base) + _size_str,
-                                               mesh_nodes, glb_node_ids,
-                                               mesh_elems, n_nghost_elem,
-                                               n_global_base_nodes, n_global_nodes,
-                                               n_base_nodes, n_active_base_nodes, n_active_nodes);
+            np_mesh = new  MeshLib::NodePartitionedMesh(
+                    BaseLib::extractBaseName(file_name_base) + std::to_string(_mpi_comm_size),
+                    mesh_nodes, glb_node_ids,
+                    mesh_elems, n_nghost_elem,
+                    n_global_base_nodes, n_global_nodes,
+                    n_base_nodes, n_active_base_nodes, n_active_nodes);
         }
     }
 
-    if(_rank == 0)
+    if(_mpi_rank == 0)
     {
         is_cfg.close();
         is_node.close();
         is_elem.close();
     }
 
-    MPI_Barrier(mpi_comm_);
+    MPI_Barrier(_mpi_comm);
 
     return  np_mesh;
 }
 
 void NodePartitionedMeshReader::readElementASCII(std::ifstream &ins,
-        long *elem_data, const bool ghost)
+        std::vector<long>& elem_data, const bool ghost) const
 {
     // Set number of elements.
     const long ne = ghost ? _num_ghost_elems_part : _num_regular_elems_part;
@@ -446,62 +424,55 @@ void NodePartitionedMeshReader::readElementASCII(std::ifstream &ins,
     for(long j=0; j<ne; j++)
     {
         elem_data[j] = counter;
-        ins >> elem_data[counter];  //mat. idx
-        counter++;
-        ins >> elem_data[counter];  //type
-        counter++;
+        ins >> elem_data[counter++];  //mat. idx
+        ins >> elem_data[counter++];  //type
         ins >> elem_data[counter];  //nnodes
-        const long nn_e =  elem_data[counter];
-        counter++;
+        const long nn_e =  elem_data[counter++];
         for(long k=0; k<nn_e; k++)
-        {
-            ins >> elem_data[counter];
-            counter++;
-        }
+            ins >> elem_data[counter++];
     }
 }
 
 void NodePartitionedMeshReader::setNodes(const std::vector<NodeData> &node_data,
-        std::vector<MeshLib::Node*> &mesh_node, std::vector<unsigned> &glb_node_ids)
+        std::vector<MeshLib::Node*> &mesh_node,
+        std::vector<std::size_t> &glb_node_ids) const
 {
     mesh_node.resize( _num_nodes_part );
     glb_node_ids.resize( _num_nodes_part );
 
-    for(size_t i=0; i<mesh_node.size(); i++)
+    for(std::size_t i=0; i<mesh_node.size(); i++)
     {
-        const NodeData *nd = &node_data[i];
-        glb_node_ids[i] = static_cast<unsigned>(nd->index);
-        mesh_node[i] = new MeshLib::Node(nd->x, nd->y, nd->z, i);
+        NodeData const& nd = node_data[i];
+        glb_node_ids[i] = nd.index;
+        mesh_node[i] = new MeshLib::Node(nd.x, nd.y, nd.z, i);
     }
 }
 
-void NodePartitionedMeshReader::setElements(const std::vector<MeshLib::Node*> &mesh_nodes,
-        const long *elem_data, std::vector<MeshLib::Element*> &mesh_elems, const bool ghost)
+void NodePartitionedMeshReader::setElements(
+        const std::vector<MeshLib::Node*> &mesh_nodes,
+        const std::vector<long> &elem_data,
+        std::vector<MeshLib::Element*> &mesh_elems, const bool ghost) const
 {
     // Number of elements, ether ghost or regular
     const long ne = ghost ? _num_ghost_elems_part : _num_regular_elems_part;
     const long id_offset = ghost ? _num_regular_elems_part : 0;
-    long counter;
-    for(long i=0; i<ne; i++)
+
+    for(std::size_t i=0; i < ne; i++)
     {
-        counter = elem_data[i];
+        std::size_t counter = elem_data[i];
 
-        const long mat_idx = static_cast<size_t>( elem_data[counter] );
-        counter++;
-        const long e_type = elem_data[counter];
-        counter++;
-        const long nnodes = elem_data[counter];
-        counter++;
+        const unsigned mat_idx = static_cast<unsigned>( elem_data[counter++] );
+        const long e_type = elem_data[counter++];
+        const long nnodes = elem_data[counter++];
 
         MeshLib::Node **elem_nodes = new MeshLib::Node*[nnodes];
-        for(long k=0; k<nnodes; k++)
-        {
-            elem_nodes[k] = mesh_nodes[ elem_data[counter] ];
-            counter++;
-        }
+        for(std::size_t k=0; k<nnodes; k++)
+            elem_nodes[k] = mesh_nodes[ elem_data[counter++] ];
 
         MeshLib::Element *elem = nullptr;
 
+        // The element types below are defined by the mesh_partition tool
+        // available at https://github.com/ufz/mesh_partition .
         switch(e_type)
         {
             case 1:
@@ -531,42 +502,15 @@ void NodePartitionedMeshReader::setElements(const std::vector<MeshLib::Node*> &m
     }
 }
 
-void NodePartitionedMeshReader::buildNodeStrucTypeMPI(NodeData *anode, MPI_Datatype *mpi_node_ptr)
+void NodePartitionedMeshReader::registerNodeDataMpiType()
 {
-    int nblocklen[4] = {1, 1, 1, 1};
-
-    MPI_Aint disp[4], base;
-    MPI_Get_address(anode, disp);
-    MPI_Get_address(&(anode[0].x), disp+1);
-    MPI_Get_address(&(anode[0].y), disp+2);
-    MPI_Get_address(&(anode[0].z), disp+3);
-    base = disp[0];
-    for(int j=0; j <4; j++)
-    {
-        disp[j] -= base;
-    }
-
-    MPI_Datatype my_comp_type[4];
-    my_comp_type[0] = MPI_LONG;
-    my_comp_type[1] = MPI_DOUBLE;
-    my_comp_type[2] = MPI_DOUBLE;
-    my_comp_type[3] = MPI_DOUBLE;
+    int const count = 2;
+    int blocks[count] = {1, 3};
+    MPI_Datatype types[count] = {MPI_UNSIGNED_LONG, MPI_DOUBLE};
+    MPI_Aint displacements[count] = {0, sizeof(NodeData::index)};
 
-    // build datatype describing structure
-    MPI_Type_create_struct(4, nblocklen, disp, my_comp_type, mpi_node_ptr);
-    MPI_Type_commit(mpi_node_ptr);
-}
-
-void NodePartitionedMeshReader::printMessage(const std::string & err_message, const bool for_fileopen)
-{
-    if( for_fileopen )
-    {
-        ERR("! File %s does not exist.", err_message.c_str());
-    }
-    else
-    {
-        ERR( err_message.c_str() );
-    }
+    MPI_Type_create_struct(count, blocks, displacements, types, &_mpi_node_type);
+    MPI_Type_commit(&_mpi_node_type);
 }
 
 }   // namespace FileIO
diff --git a/FileIO/MPI_IO/NodePartitionedMeshReader.h b/FileIO/MPI_IO/NodePartitionedMeshReader.h
index 8756e70a68d..0fbfd221779 100644
--- a/FileIO/MPI_IO/NodePartitionedMeshReader.h
+++ b/FileIO/MPI_IO/NodePartitionedMeshReader.h
@@ -14,13 +14,13 @@
 #ifndef NODE_PARTITIONED_MESH_READER_H
 #define NODE_PARTITIONED_MESH_READER_H
 
-#include <string>
 #include <fstream>
+#include <string>
+#include <vector>
 
 #include <mpi.h>
 
 #include "MeshLib/NodePartitionedMesh.h"
-#include "MeshLib/Node.h"
 
 namespace MeshLib
 {
@@ -30,24 +30,42 @@ class Element;
 
 namespace FileIO
 {
-/// Class to handle reading data of partitioned mesh.
+/// Class for reading of ascii or binary partitioned mesh files into a
+/// NodePartitionedMesh.
 class NodePartitionedMeshReader
 {
     public:
-        NodePartitionedMeshReader() = default;
+        /*!
+             \param comm            MPI Communicator.
+         */
+        NodePartitionedMeshReader(MPI_Comm comm);
+
+        ~NodePartitionedMeshReader();
 
         /*!
              \brief Create a NodePartitionedMesh object, read data to it,
                     and return a pointer to it. Data files are either in
                     ASCII format or binary format.
-             \param comm            MPI Communicator.
              \param file_name_base  Name of file to be read, and it must be base name without name extension.
              \return           Pointer to Mesh object. If the creation of mesh object
                                fails, return a null pointer.
         */
-        MeshLib::NodePartitionedMesh* read(MPI_Comm comm, const std::string &file_name_base);
+        MeshLib::NodePartitionedMesh* read(const std::string &file_name_base);
 
     private:
+        /// Pointer to MPI commumicator;
+        MPI_Comm _mpi_comm = MPI_COMM_WORLD;
+
+        /// Number of MPI processes
+        int _mpi_comm_size;
+
+        /// Rank of compute core
+        int _mpi_rank;
+
+        /// MPI data type description for sending/receiving of node data.
+        MPI_Datatype _mpi_node_type;
+
+
         /// Number of all nodes of a partition.
         long _num_nodes_part;
 
@@ -57,18 +75,6 @@ class NodePartitionedMeshReader
         /// Number of ghost elements of a partition.
         long _num_ghost_elems_part;
 
-        /// Number of MPI processes
-        int _size;
-
-        /// _size converted to string
-        std::string _size_str;
-
-        /// MPI commumicator;
-        MPI_Comm mpi_comm_ = MPI_COMM_WORLD;
-
-        /// Rank of compute core
-        int _rank;
-
         /*!
              \brief Create a NodePartitionedMesh object, read binary mesh data
                     in the manner of parallel, and return a pointer to it.
@@ -88,7 +94,7 @@ class NodePartitionedMeshReader
                         6:    Number of nodes for linear element of global mesh,
                         7:    Number of all nodes of global mesh,
                         8~12: Offsets of positions of partitions in the data arrays,
-                        13:   Reserved for exra flag.
+                        13:   Reserved for extra flag.
                      for all partitions
 
                      the second file contains a struct type (long, double double double) array of
@@ -105,7 +111,7 @@ class NodePartitionedMeshReader
         */
         MeshLib::NodePartitionedMesh* readBinary(const std::string &file_name_base);
 
-        /*
+        /*!
             \brief Open ASCII files of node partitioned mesh data.
 
             \param file_name_base  Name of file to be read, which must be a name with the
@@ -116,34 +122,35 @@ class NodePartitionedMeshReader
             \return                Return true if all files are good.
         */
         bool openASCIIFiles(std::string const& file_name_base,std::ifstream& is_cfg,
-                            std::ifstream& is_node, std::ifstream& is_elem);
+                            std::ifstream& is_node, std::ifstream& is_elem) const;
 
-        /*
-            \brief Read mesh nodes from an ASCII file and cast to the correponding rank.
+        /*!
+            \brief Read mesh nodes from an ASCII file and cast to the corresponding rank.
 
             \param is_node    Input stream for the file contains node data.
             \param part_id    Partition ID.
             \param mesh_nodes Node vector to be filled.
-            \param part_id    Global Node ID to be filled.
+            \param glb_node_ids Global Node IDs to be filled.
         */
         void readCastNodesASCII(std::ifstream& is_node, const int part_id,
                                 std::vector<MeshLib::Node*> &mesh_nodes,
-                                std::vector<unsigned> &glb_node_ids);
+                                std::vector<std::size_t> &glb_node_ids) const;
 
-        /*
-            \brief Read mesh elements from an ASCII file  and cast to the correponding rank.
+        /*!
+            \brief Read mesh elements from an ASCII file and cast to the corresponding rank.
 
             \param is_elem    Input stream for the file contains element data.
             \param part_id    Partition ID.
-            \param data_size  Total size of the data to be read.
-            \param proc_ghost Flag to process ghost element.
+            \param data_size  Total size of the data to be read. This type is an
+                              int because of MPI_Send() implicit cast.
+            \param process_ghost Flag to process ghost element.
             \param mesh_nodes Node vector to be filled.
             \param mesh_elems Element vector to be filled.
         */
         void readCastElemsASCII(std::ifstream& is_elem, const int part_id,
-                                const long data_size, const bool process_ghost,
+                                const int data_size, const bool process_ghost,
                                 const std::vector<MeshLib::Node*> &mesh_nodes,
-                                std::vector<MeshLib::Element*> &mesh_elems);
+                                std::vector<MeshLib::Element*> &mesh_elems) const;
 
         /*!
              \brief Create a NodePartitionedMesh object, read ASCII mesh data,
@@ -163,7 +170,7 @@ class NodePartitionedMeshReader
                          6:    Number of nodes for linear element of global mesh,
                          7:    Number of all nodes of global mesh,
                          8~9:  Offsets of positions of partitions in the data arrays,
-                        11:   Reserved for exra flag.
+                        11:   Reserved for extra flag.
                         for all partitions
 
                      the second file contains nodes information of global IDs and coordinates
@@ -183,31 +190,31 @@ class NodePartitionedMeshReader
              \param elem_data Pointer to array that contains element data, which to be filled.
              \param ghost     Flag to read ghost elements.
         */
-        void readElementASCII(std::ifstream &ins, long *elem_data,
-                              const bool ghost = false);
+        void readElementASCII(std::ifstream &ins,
+                std::vector<long>& elem_data,
+                const bool ghost = false) const;
 
         /// Node data only for parallel reading.
         struct NodeData
         {
-            long index; ///< Global node index.
+            std::size_t index; ///< Global node index.
             double x;
             double y;
             double z;
         };
 
-        /*! Define MPI data type, mpi_node_ptr, for struct MeshNode for palllel reading of nodes
-              \param anode        a NodeData variable.
-              \param mpi_node_ptr Defined MPI data type of struct NodeData.
-        */
-        void buildNodeStrucTypeMPI(NodeData *anode, MPI_Datatype *mpi_node_ptr);
+        /// Define MPI data type for NodeData struct.
+        void registerNodeDataMpiType();
+
         /*!
              \brief Set mesh nodes from a tempory array containing node data read from file.
              \param node_data  Array containing node data read from file.
              \param mesh_node  Vector of mesh nodes to be set.
              \param glb_node_ids  Global IDs of nodes of a partition.
         */
-        void setNodes(const std::vector<NodeData> &node_data, std::vector<MeshLib::Node*> &mesh_node,
-                      std::vector<unsigned> &glb_node_ids);
+        void setNodes(const std::vector<NodeData> &node_data,
+                std::vector<MeshLib::Node*> &mesh_node,
+                    std::vector<std::size_t> &glb_node_ids) const;
 
         /*!
              \brief Set mesh elements from a tempory array containing node data read from file.
@@ -216,13 +223,29 @@ class NodePartitionedMeshReader
              \param mesh_elems        Vector of mesh elements to be set.
              \param ghost             Flag of processing ghost elements.
         */
-        void setElements(const std::vector<MeshLib::Node*> &mesh_nodes, const long *elem_data,
-                         std::vector<MeshLib::Element*> &mesh_elems, const bool ghost = false);
-
-        /// Print message when file opening fails or the requested numbers mismatch
-        void printMessage(const std::string & err_message, const bool for_fileopen = true);
+        void setElements(const std::vector<MeshLib::Node*> &mesh_nodes,
+                const std::vector<long> &elem_data,
+                std::vector<MeshLib::Element*> &mesh_elems,
+                const bool ghost = false) const;
+
+        /*! Fills the given data vector with data read from file starting at an
+            offset.
+            \note           In case of failure during opening of the file, an
+                            error message is printed.
+            \param filename File name containing data.
+            \param offset   Displacement of the data accessible from the view;
+                            see MPI_File_set_view() documentation.
+            \param type     Type of data.
+            \param data     A container to be filled with data. Its size is used
+                            to determine how many values should be read.
+            \tparam DATA    A homogeneous contaner type supporting data() and size().
+            \return         True on success and false otherwise.
+         */
+        template <typename DATA>
+        bool readBinaryDataFromFile(std::string const& filename, MPI_Offset offset,
+                MPI_Datatype type, DATA& data) const;
 };
 
-} // End of namespace
+}   // FileIO
 
-#endif // end of #ifndef READ_NODE_PARTITIONED_MESH_H
+#endif  // READ_NODE_PARTITIONED_MESH_H
diff --git a/MeshLib/NodePartitionedMesh.h b/MeshLib/NodePartitionedMesh.h
index 505f8630275..d8a391ae360 100644
--- a/MeshLib/NodePartitionedMesh.h
+++ b/MeshLib/NodePartitionedMesh.h
@@ -21,11 +21,6 @@
 
 #include "Mesh.h"
 
-namespace FileIO
-{
-class readNodePartitionedMesh;
-};
-
 namespace MeshLib
 {
 class Node;
@@ -55,14 +50,14 @@ class NodePartitionedMesh : public Mesh
         */
         NodePartitionedMesh(const std::string &name,
                             const std::vector<Node*> &nodes,
-                            const std::vector<unsigned> &glb_node_ids,
+                            const std::vector<std::size_t> &glb_node_ids,
                             const std::vector<Element*> &elements,
                             const std::size_t n_nghost_elem,
-                            const unsigned n_global_base_nodes,
-                            const unsigned n_global_nodes,
-                            const unsigned n_base_nodes,
-                            const unsigned n_active_base_nodes,
-                            const unsigned n_active_nodes)
+                            const std::size_t n_global_base_nodes,
+                            const std::size_t n_global_nodes,
+                            const std::size_t n_base_nodes,
+                            const std::size_t n_active_base_nodes,
+                            const std::size_t n_active_nodes)
             : Mesh(name, nodes, elements, n_base_nodes),
               _global_node_ids(glb_node_ids), _n_nghost_elem(n_nghost_elem),
               _n_global_base_nodes(n_global_base_nodes),
@@ -72,36 +67,32 @@ class NodePartitionedMesh : public Mesh
         {
         }
 
-        ~NodePartitionedMesh()
-        {
-        }
-
         /// Get the number of nodes of the global mesh for linear elements.
-        unsigned getNGlobalBaseNodes() const
+        std::size_t getNGlobalBaseNodes() const
         {
             return _n_global_base_nodes;
         }
 
         /// Get the number of all nodes of the global mesh.
-        unsigned getNGlobalNodes() const
+        std::size_t getNGlobalNodes() const
         {
             return _n_global_nodes;
         }
 
         /// Get the number of the active nodes of the partition for linear elements.
-        unsigned getNActiveBaseNodes() const
+        std::size_t getNActiveBaseNodes() const
         {
             return _n_active_base_nodes;
         }
 
         /// Get the number of all active nodes of the partition.
-        unsigned getNActiveNodes() const
+        std::size_t getNActiveNodes() const
         {
             return _n_active_nodes;
         }
 
         /// Check whether a node with ID of node_id is a ghost node
-        bool isGhostNode(const unsigned node_id)
+        bool isGhostNode(const std::size_t node_id) const
         {
             if(node_id < _n_active_base_nodes)
                 return true;
@@ -112,35 +103,35 @@ class NodePartitionedMesh : public Mesh
         }
 
         /// Get the largest ID of active nodes for higher order elements in a partition.
-        unsigned getLargestActiveNodeID() const
+        std::size_t getLargestActiveNodeID() const
         {
             return _n_base_nodes + _n_active_nodes - _n_active_base_nodes;
         }
 
         /// Get the number of non-ghost elements, or the start entry ID of ghost elements in element vector.
-        size_t getNNonGhostElements() const
+        std::size_t getNNonGhostElements() const
         {
             return _n_nghost_elem;
         }
 
     private:
         /// Global IDs of nodes of a partition
-        std::vector<unsigned> _global_node_ids;
+        std::vector<std::size_t> _global_node_ids;
 
         /// Number of non-ghost elements, or the ID of the start entry of ghost elements in _elements vector.
         std::size_t _n_nghost_elem;
 
         /// Number of the nodes of the global mesh linear interpolations.
-        unsigned _n_global_base_nodes;
+        std::size_t _n_global_base_nodes;
 
         /// Number of all nodes of the global mesh.
-        unsigned _n_global_nodes;
+        std::size_t _n_global_nodes;
 
         /// Number of the active nodes for linear interpolations
-        unsigned _n_active_base_nodes;
+        std::size_t _n_active_base_nodes;
 
         /// Number of the all active nodes.
-        unsigned _n_active_nodes;
+        std::size_t _n_active_nodes;
 };
 
 }   // namespace MeshLib
diff --git a/SimpleTests/MeshTests/MPI/NodePartitionedMeshTester.cpp b/SimpleTests/MeshTests/MPI/NodePartitionedMeshTester.cpp
index 3495b70ff43..c7d9421ac57 100644
--- a/SimpleTests/MeshTests/MPI/NodePartitionedMeshTester.cpp
+++ b/SimpleTests/MeshTests/MPI/NodePartitionedMeshTester.cpp
@@ -37,65 +37,78 @@ using namespace FileIO;
 int main(int argc, char *argv[])
 {
     LOGOG_INITIALIZE();
-    {
-        MPI_Init(&argc, &argv);
+
+    MPI_Init(&argc, &argv);
 
 #ifdef USE_PETSC
-        char help[] = "ogs6 with PETSc \n";
-        PetscInitialize(&argc, &argv, nullptr, help);
+    char help[] = "ogs6 with PETSc \n";
+    PetscInitialize(&argc, &argv, nullptr, help);
 #endif
 
-        BaseLib::LogogCustomCout out(1);
-        BaseLib::TemplateLogogFormatterSuppressedGCC<TOPIC_LEVEL_FLAG | TOPIC_FILE_NAME_FLAG | TOPIC_LINE_NUMBER_FLAG> custom_format;
-        out.SetFormatter(custom_format);
+    BaseLib::LogogCustomCout* out = new BaseLib::LogogCustomCout(1);
+    using LogogFormatter = BaseLib::TemplateLogogFormatterSuppressedGCC
+        <TOPIC_LEVEL_FLAG | TOPIC_FILE_NAME_FLAG | TOPIC_LINE_NUMBER_FLAG>;
+    LogogFormatter* fmt = new LogogFormatter();
 
-        const std::string file_name = argv[1];
+    out->SetFormatter(*fmt);
 
-        NodePartitionedMeshReader read_pmesh;
-        NodePartitionedMesh *mesh = read_pmesh.read(MPI_COMM_WORLD, file_name);
+    const std::string file_name = argv[1];
 
-        int rank;
-        MPI_Comm_rank(MPI_COMM_WORLD, &rank);
-        const std::string rank_str = std::to_string(rank);
-        const std::string ofile_name = file_name + "_partition_" + rank_str + ".msh";
-        std::ofstream os(ofile_name.data(), std::ios::trunc);
+    NodePartitionedMesh *mesh = nullptr;
+    {
+        NodePartitionedMeshReader read_pmesh(MPI_COMM_WORLD);
+        mesh = read_pmesh.read(file_name);
+    }
+    if (!mesh)
+    {
+        ERR("Could not read mesh from files with prefix %s.", file_name.c_str());
+        return EXIT_FAILURE;
+    }
+
+    int rank;
+    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+    const std::string rank_str = std::to_string(rank);
+    const std::string ofile_name = file_name + "_partition_" + rank_str + ".msh";
+    std::ofstream os(ofile_name.data(), std::ios::trunc);
+
+    // Output nodes
+    os.setf(std::ios::scientific, std::ios::floatfield);
+    std::setprecision(10);
+    const std::size_t nn = mesh->getNNodes();
+    for(std::size_t i=0; i<nn; i++)
+    {
+        const double *x = mesh->getNode(i)->getCoords();
+        os << mesh->getNode(i)->getID() << " "
+            << std::setw(14) << x[0]  << " " << x[1] << " "<< x[2] << "\n";
+    }
+    os.flush();
+
+    // Output elements
+    const std::size_t ne = mesh->getNElements();
+    for(std::size_t i=0; i<ne; i++)
+    {
+        const Element *elem = mesh->getElement(i);
+        Node* const* ele_nodes = elem->getNodes();
 
-        // Output nodes
-        os.setf(std::ios::scientific, std::ios::floatfield);
-        std::setprecision(10);
-        const size_t nn = mesh->getNNodes();
-        for(size_t i=0; i<nn; i++)
+        for(unsigned j=0; j<elem->getNNodes(); j++)
         {
-            const double *x = mesh->getNode(i)->getCoords();
-            os << mesh->getNode(i)->getID() << " "
-               << std::setw(14) << x[0]  << " " << x[1] << " "<< x[2] << "\n";
+            os << ele_nodes[j]->getID() << " ";
         }
-        os.flush();
+        os << "\n";
+    }
+    os.flush();
 
-        // Output elements
-        const size_t ne = mesh->getNElements();
-        for(size_t i=0; i<ne; i++)
-        {
-            const Element *elem = mesh->getElement(i);
-            Node* const* ele_nodes = elem->getNodes();
-
-            for(unsigned j=0; j<elem->getNNodes(); j++)
-            {
-                os << ele_nodes[j]->getID() << " ";
-            }
-            os << "\n";
-        }
-        os.flush();
+    delete mesh;
 
-        delete mesh;
+    delete out;
+    delete fmt;
 
 #ifdef USE_PETSC
-        PetscFinalize();
+    PetscFinalize();
 #endif
 
-        MPI_Finalize();
+    MPI_Finalize();
 
-    } // make sure no logog objects exist when LOGOG_SHUTDOWN() is called.
     LOGOG_SHUTDOWN();
 }
 
-- 
GitLab