diff --git a/Applications/CLI/Tests.cmake b/Applications/CLI/Tests.cmake
index 61c88a9c010e6d500e89acb84c9328339d69c67c..10aca02ef7d30d726a58df0e903ca7aebcd821bf 100644
--- a/Applications/CLI/Tests.cmake
+++ b/Applications/CLI/Tests.cmake
@@ -200,4 +200,159 @@ else()
         cube_1e3_neumann_pcs_0_ts_1_t_1.000000_1.vtu pressure pressure
         cube_1e3_neumann_pcs_0_ts_1_t_1.000000_2.vtu pressure pressure
     )
+
+    # Single core
+    # CUBE 1x1x1 GROUNDWATER FLOW TESTS
+    foreach(mesh_size 1e0 1e1 1e2 1e3)
+        AddTest(
+            NAME GroundWaterFlowProcess_cube_1x1x1_${mesh_size}
+            PATH Elliptic/cube_1x1x1_GroundWaterFlow
+            EXECUTABLE_ARGS cube_${mesh_size}.prj
+            WRAPPER mpirun
+            WRAPPER_ARGS -np 1
+            TESTER vtkdiff
+            ABSTOL 1e-15 RELTOL 1e-15
+            DIFF_DATA cube_${mesh_size}_pcs_0_ts_1_t_1_0.vtu Linear_1_to_minus1 pressure
+        )
+
+        AddTest(
+            NAME GroundWaterFlowProcess_cube_1x1x1_Neumann_${mesh_size}
+            PATH Elliptic/cube_1x1x1_GroundWaterFlow
+            EXECUTABLE_ARGS cube_${mesh_size}_neumann.prj
+            WRAPPER mpirun
+            WRAPPER_ARGS -np 1
+            TESTER vtkdiff
+            ABSTOL 1e-1 RELTOL 1e-1
+            DIFF_DATA cube_${mesh_size}_neumann_pcs_0_ts_1_t_1_0.vtu D1_left_front_N1_right pressure
+        )
+    endforeach()
+
+
+    foreach(mesh_size 1e4 2e4 3e4 4e4 5e4 1e5 1e6)
+        AddTest(
+            NAME LARGE_GroundWaterFlowProcess_cube_1x1x1_${mesh_size}
+            PATH Elliptic/cube_1x1x1_GroundWaterFlow
+            EXECUTABLE_ARGS cube_${mesh_size}.prj
+            WRAPPER mpirun
+            WRAPPER_ARGS -np 1
+            TESTER vtkdiff
+            ABSTOL 1e-7 RELTOL 1e-7
+            DIFF_DATA cube_${mesh_size}_pcs_0_ts_1_t_1_0.vtu Linear_1_to_minus1 pressure
+        )
+
+        AddTest(
+            NAME LARGE_GroundWaterFlowProcess_cube_1x1x1_Neumann_${mesh_size}
+            PATH Elliptic/cube_1x1x1_GroundWaterFlow
+            EXECUTABLE_ARGS cube_${mesh_size}_neumann.prj
+            WRAPPER mpirun
+            WRAPPER_ARGS -np 1
+            TESTER vtkdiff
+            ABSTOL 1e-2 RELTOL 1e-2
+            DIFF_DATA cube_${mesh_size}_neumann_pcs_0_ts_1_t_1_0.vtu D1_left_front_N1_right pressure
+        )
+    endforeach()
+
+    # SQUARE 1x1 GROUNDWATER FLOW TESTS
+    foreach(mesh_size 1e0 1e1 1e2 1e3 1e4)
+        AddTest(
+            NAME GroundWaterFlowProcess_square_1x1_${mesh_size}
+            PATH Elliptic/square_1x1_GroundWaterFlow
+            EXECUTABLE_ARGS square_${mesh_size}.prj
+            WRAPPER mpirun
+            WRAPPER_ARGS -np 1
+            TESTER vtkdiff
+            ABSTOL 1e-13 RELTOL 1e-13
+            DIFF_DATA square_${mesh_size}_pcs_0_ts_1_t_1_0.vtu Linear_1_to_minus1 pressure
+        )
+
+        AddTest(
+            NAME GroundWaterFlowProcess_square_1x1_Neumann_${mesh_size}
+            PATH Elliptic/square_1x1_GroundWaterFlow
+            EXECUTABLE_ARGS square_${mesh_size}_neumann.prj
+            WRAPPER mpirun
+            WRAPPER_ARGS -np 1
+            TESTER vtkdiff
+            ABSTOL 1e-1 RELTOL 1e-1
+            DIFF_DATA square_${mesh_size}_neumann_pcs_0_ts_1_t_1_0.vtu D1_left_bottom_N1_right pressure
+        )
+    endforeach()
+
+    foreach(mesh_size 1e5 1e6)
+        AddTest(
+            NAME LARGE_GroundWaterFlowProcess_square_1x1_${mesh_size}
+            PATH Elliptic/square_1x1_GroundWaterFlow
+            EXECUTABLE_ARGS square_${mesh_size}.prj
+            WRAPPER mpirun
+            WRAPPER_ARGS -np 1
+            TESTER vtkdiff
+            ABSTOL 1e-7 RELTOL 1e-7
+            DIFF_DATA square_${mesh_size}_pcs_0_ts_1_t_1_0.vtu Linear_1_to_minus1 pressure
+        )
+
+        AddTest(
+            NAME LARGE_GroundWaterFlowProcess_square_1x1_Neumann_${mesh_size}
+            PATH Elliptic/square_1x1_GroundWaterFlow
+            EXECUTABLE_ARGS square_${mesh_size}_neumann.prj
+            WRAPPER mpirun
+            WRAPPER_ARGS -np 1
+            TESTER vtkdiff
+            ABSTOL 1e-02 RELTOL 1e-02
+            DIFF_DATA square_${mesh_size}_neumann_pcs_0_ts_1_t_1_0.vtu D1_left_bottom_N1_right pressure
+        )
+    endforeach()
+
+    # LINE 1 GROUNDWATER FLOW TESTS
+    foreach(mesh_size 1e1)
+        AddTest(
+            NAME GroundWaterFlowProcess_line_1_${mesh_size}
+            PATH Elliptic/line_1_GroundWaterFlow
+            EXECUTABLE_ARGS line_${mesh_size}.prj
+            WRAPPER mpirun
+            WRAPPER_ARGS -np 1
+            TESTER vtkdiff
+            ABSTOL 1e-15 RELTOL 1e-15
+            DIFF_DATA line_${mesh_size}_pcs_0_ts_1_t_1_0.vtu Linear_1_to_minus1 pressure
+        )
+
+        AddTest(
+            NAME GroundWaterFlowProcess_line_1_Neumann_${mesh_size}
+            PATH Elliptic/line_1_GroundWaterFlow
+            EXECUTABLE_ARGS line_${mesh_size}_neumann.prj
+            WRAPPER mpirun
+            WRAPPER_ARGS -np 1
+            TESTER vtkdiff
+            ABSTOL 1e-14 RELTOL 1e-14
+            DIFF_DATA line_${mesh_size}_neumann_pcs_0_ts_1_t_1_0.vtu D1_left_N1_right pressure
+        )
+        endforeach()
+
+    AddTest(
+        NAME TES_zeolite_discharge_small
+        PATH Parabolic/TES/1D
+        EXECUTABLE_ARGS tes-1D-zeolite-discharge-small.prj
+        WRAPPER mpirun
+        WRAPPER_ARGS -np 1
+        TESTER vtkdiff
+        ABSTOL 1e-16 RELTOL 1e-16
+        DIFF_DATA
+        tes_zeolite_discharge_small_pcs_0_ts_19_t_0.100000_0.vtu pressure pressure
+        tes_zeolite_discharge_small_pcs_0_ts_19_t_0.100000_0.vtu temperature temperature
+        tes_zeolite_discharge_small_pcs_0_ts_19_t_0.100000_0.vtu v_mass_frac v_mass_frac
+#        tes_zeolite_discharge_small_pcs_0_ts_19_t_0.100000_0.vtu solid_density solid_density
+    )
+
+    AddTest(
+        NAME LARGE_TES_zeolite_discharge
+        PATH Parabolic/TES/1D
+        EXECUTABLE_ARGS tes-1D-zeolite-discharge-large.prj
+        WRAPPER mpirun
+        WRAPPER_ARGS -np 1
+        TESTER vtkdiff
+        ABSTOL 1e-16 RELTOL 1e-16
+        DIFF_DATA
+        tes_zeolite_discharge_large_pcs_0_ts_28_t_1.000000_0.vtu pressure pressure
+        tes_zeolite_discharge_large_pcs_0_ts_28_t_1.000000_0.vtu temperature temperature
+        tes_zeolite_discharge_large_pcs_0_ts_28_t_1.000000_0.vtu v_mass_frac v_mass_frac
+#        tes_zeolite_discharge_large_pcs_0_ts_28_t_1_0.vtu solid_density solid_density
+    )
 endif()
diff --git a/MathLib/LinAlg/PETSc/PETScLinearSolver.cpp b/MathLib/LinAlg/PETSc/PETScLinearSolver.cpp
index 59d0ba603712f55c16e823417c2e1498cef6e3c9..961678f85bf8d423d9cf039d5cb2ec1463f0a5be 100644
--- a/MathLib/LinAlg/PETSc/PETScLinearSolver.cpp
+++ b/MathLib/LinAlg/PETSc/PETScLinearSolver.cpp
@@ -107,6 +107,12 @@ bool PETScLinearSolver::solve(PETScMatrix& A, PETScVector &b, PETScVector &x)
     }
     else if(reason == KSP_DIVERGED_ITS)
     {
+        const char *ksp_type;
+        const char *pc_type;
+        KSPGetType(_solver, &ksp_type);
+        PCGetType(_pc, &pc_type);
+        PetscPrintf(PETSC_COMM_WORLD, "\nLinear solver %s with %s preconditioner",
+                    ksp_type, pc_type);
         PetscPrintf(PETSC_COMM_WORLD, "\nWarning: maximum number of iterations reached.\n");
     }
     else
diff --git a/MathLib/LinAlg/PETSc/PETScMatrix.cpp b/MathLib/LinAlg/PETSc/PETScMatrix.cpp
index 2695a1b755a75aca736e6fae3449d82e5deaa351..6d380a12cee3ab88047f48690b1c75225d9d7e99 100644
--- a/MathLib/LinAlg/PETSc/PETScMatrix.cpp
+++ b/MathLib/LinAlg/PETSc/PETScMatrix.cpp
@@ -91,6 +91,10 @@ void PETScMatrix::setRowsColumnsZero(std::vector<PetscInt> const& row_pos)
     // and thus improves performance for very large process counts.
     // See PETSc doc about MAT_NO_OFF_PROC_ZERO_ROWS.
     MatSetOption(_A, MAT_NO_OFF_PROC_ZERO_ROWS, PETSC_TRUE);
+
+    // Keep the non-zero pattern for the assignment operator.
+    MatSetOption(_A, MAT_KEEP_NONZERO_PATTERN,PETSC_TRUE);
+
     if(nrows>0)
         MatZeroRows(_A, nrows, &row_pos[0], one, PETSC_NULL, PETSC_NULL);
     else
diff --git a/MeshLib/IO/MPI_IO/NodePartitionedMeshReader.cpp b/MeshLib/IO/MPI_IO/NodePartitionedMeshReader.cpp
index c48980a5e1db4ae6eaa7064b69a3d7a2835d9f16..f578847886d9860d67a668de05ca341f486c6d3b 100644
--- a/MeshLib/IO/MPI_IO/NodePartitionedMeshReader.cpp
+++ b/MeshLib/IO/MPI_IO/NodePartitionedMeshReader.cpp
@@ -418,7 +418,6 @@ NodePartitionedMeshReader::newMesh(
         mesh_name + std::to_string(_mpi_comm_size),
         mesh_nodes, glb_node_ids, mesh_elems,
         MeshLib::Properties(),
-        _mesh_info.regular_elements,
         _mesh_info.global_base_nodes,
         _mesh_info.global_nodes,
         _mesh_info.base_nodes,
diff --git a/MeshLib/IO/readMeshFromFile.cpp b/MeshLib/IO/readMeshFromFile.cpp
index f76cb53320e6fbc26372598dfd084ffc94490f57..9f0fcf9f7102e4a9168eea2909ae649fded3808c 100644
--- a/MeshLib/IO/readMeshFromFile.cpp
+++ b/MeshLib/IO/readMeshFromFile.cpp
@@ -45,10 +45,30 @@ namespace IO
 MeshLib::Mesh* readMeshFromFile(const std::string &file_name)
 {
 #ifdef USE_PETSC
-    MeshLib::IO::NodePartitionedMeshReader read_pmesh(PETSC_COMM_WORLD);
-    const std::string file_name_base = BaseLib::dropFileExtension(file_name);
-    return read_pmesh.read(file_name_base);
+    int world_size;
+    MPI_Comm_size(MPI_COMM_WORLD, &world_size);
+    if (world_size > 1)
+    {
+        MeshLib::IO::NodePartitionedMeshReader read_pmesh(PETSC_COMM_WORLD);
+        const std::string file_name_base = BaseLib::dropFileExtension(file_name);
+        return read_pmesh.read(file_name_base);
+    }
+    else if (world_size == 1)
+    {
+        MeshLib::Mesh* mesh = readMeshFromFileSerial(file_name);
+        MeshLib::NodePartitionedMesh* part_mesh
+                               = new MeshLib::NodePartitionedMesh(*mesh);
+        delete mesh;
+        return part_mesh;
+    }
+    return nullptr;
 #else
+    return readMeshFromFileSerial(file_name);
+#endif
+}
+
+MeshLib::Mesh* readMeshFromFileSerial(const std::string &file_name)
+{
     if (BaseLib::hasFileExtension("msh", file_name))
     {
         MeshLib::IO::Legacy::MeshIO meshIO;
@@ -60,7 +80,8 @@ MeshLib::Mesh* readMeshFromFile(const std::string &file_name)
 
     ERR("readMeshFromFile(): Unknown mesh file format in file %s.", file_name.c_str());
     return nullptr;
-#endif
 }
+
+
 } // end namespace IO
 } // end namespace MeshLib
diff --git a/MeshLib/IO/readMeshFromFile.h b/MeshLib/IO/readMeshFromFile.h
index 7fa9e8fa464ded7ae3a1d0cde86278332db7f497..15801bf3747ce02609458d48dd350eb8f5b7280f 100644
--- a/MeshLib/IO/readMeshFromFile.h
+++ b/MeshLib/IO/readMeshFromFile.h
@@ -27,6 +27,7 @@ class Mesh;
 
 namespace IO
 {
+MeshLib::Mesh* readMeshFromFileSerial(const std::string &file_name);
 MeshLib::Mesh* readMeshFromFile(const std::string &file_name);
 }
 }
diff --git a/MeshLib/Node.h b/MeshLib/Node.h
index 410f25614f997524b5e563a0add6a9cd812c7385..8b3b573d8ef05634281295e187d974090205a351 100644
--- a/MeshLib/Node.h
+++ b/MeshLib/Node.h
@@ -38,6 +38,7 @@ class Node final : public MathLib::Point3dWithID
 {
     /* friend classes: */
     friend class Mesh;
+    friend class NodePartitionedMesh;
     friend class MeshRevision;
     friend class MeshLayerMapper;
     friend class ApplicationUtils::NodeWiseMeshPartitioner;
diff --git a/MeshLib/NodePartitionedMesh.h b/MeshLib/NodePartitionedMesh.h
index eab5679910e1931811e190ada2590e77302bbeb4..5cf60f536fb1892c34ef12b963109d2e9c25f343 100644
--- a/MeshLib/NodePartitionedMesh.h
+++ b/MeshLib/NodePartitionedMesh.h
@@ -29,6 +29,36 @@ namespace MeshLib
 class NodePartitionedMesh : public Mesh
 {
     public:
+        // Copy a global mesh for the case of the thread number is one,
+        // i.e the gobal mesh is not partitioned.
+        // \param mesh The gobal mesh
+        explicit NodePartitionedMesh(const Mesh& mesh)
+            : Mesh(mesh), _global_node_ids(mesh.getNumberOfNodes()),
+              _n_global_base_nodes(mesh.getNumberOfBaseNodes()),
+              _n_global_nodes(mesh.getNumberOfNodes()),
+              _n_active_base_nodes(mesh.getNumberOfBaseNodes()),
+              _n_active_nodes(mesh.getNumberOfNodes())
+        {
+            const auto& mesh_nodes = mesh.getNodes();
+            for (std::size_t i = 0; i < _nodes.size(); i++)
+            {
+                _global_node_ids[i] = _nodes[i]->getID();
+
+                // TODO To add copying of the connected nodes (and elements)
+                //      in the copy constructor of class Node in order to
+                //      drop the following lines.
+                auto node = _nodes[i];
+                // Copy constructor of Mesh does not copy the connected
+                // nodes to node.
+                if (node->_connected_nodes.size() == 0)
+                {
+                    std::copy(mesh_nodes[i]->_connected_nodes.begin(),
+                              mesh_nodes[i]->_connected_nodes.end(),
+                              std::back_inserter(node->_connected_nodes));
+                }
+            }
+        }
+
         /*!
             \brief Constructor
             \param name          Name assigned to the mesh.
@@ -39,8 +69,7 @@ class NodePartitionedMesh : public Mesh
             \param glb_node_ids  Global IDs of nodes of a partition.
             \param elements      Vector for elements. Ghost elements are stored
                                  after regular (non-ghost) elements.
-            \param n_nghost_elem Number of non-ghost elements, or the start ID of
-                                 the entry of ghost element in the element vector.
+            \param properties    Mesh property.
             \param n_global_base_nodes Number of the base nodes of the global mesh.
             \param n_global_nodes      Number of all nodes of the global mesh.
             \param n_base_nodes        Number of the base nodes.
@@ -52,14 +81,13 @@ class NodePartitionedMesh : public Mesh
                             const std::vector<std::size_t> &glb_node_ids,
                             const std::vector<Element*> &elements,
                             Properties properties,
-                            const std::size_t n_nghost_elem,
                             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, properties, n_base_nodes),
-              _global_node_ids(glb_node_ids), _n_nghost_elem(n_nghost_elem),
+              _global_node_ids(glb_node_ids),
               _n_global_base_nodes(n_global_base_nodes),
               _n_global_nodes(n_global_nodes),
               _n_active_base_nodes(n_active_base_nodes),
@@ -114,12 +142,6 @@ class NodePartitionedMesh : public Mesh
             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.
-        std::size_t getNumberOfNonGhostElements() const
-        {
-            return _n_nghost_elem;
-        }
-
         // TODO I guess that is a simplified version of computeSparsityPattern()
         /// Get the maximum number of connected nodes to node.
         std::size_t getMaximumNConnectedNodesToNode() const
@@ -139,9 +161,6 @@ class NodePartitionedMesh : public Mesh
         /// Global IDs of nodes of a partition
         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.
         std::size_t _n_global_base_nodes;
 
diff --git a/NumLib/DOF/ComputeSparsityPattern.cpp b/NumLib/DOF/ComputeSparsityPattern.cpp
index 46d2ad519d03acca1792ad15e3b469da6417bf16..cf80de61fe44ea3ce04494bd2ea693fbcb05c2bd 100644
--- a/NumLib/DOF/ComputeSparsityPattern.cpp
+++ b/NumLib/DOF/ComputeSparsityPattern.cpp
@@ -16,14 +16,15 @@
 #include "MeshLib/NodePartitionedMesh.h"
 
 GlobalSparsityPattern computeSparsityPatternPETSc(
-    NumLib::LocalToGlobalIndexMap const& /*dof_table*/,
+    NumLib::LocalToGlobalIndexMap const& dof_table,
     MeshLib::Mesh const& mesh)
 {
     assert(dynamic_cast<MeshLib::NodePartitionedMesh const*>(&mesh));
     auto const& npmesh =
         *static_cast<MeshLib::NodePartitionedMesh const*>(&mesh);
 
-    auto const max_nonzeroes = npmesh.getMaximumNConnectedNodesToNode();
+    auto const max_nonzeroes =   dof_table.getNumberOfComponents()
+                               * npmesh.getMaximumNConnectedNodesToNode();
 
     // The sparsity pattern is misused here in the sense that it will only
     // contain a single value.
diff --git a/Tests/MathLib/TestGlobalMatrixInterface.cpp b/Tests/MathLib/TestGlobalMatrixInterface.cpp
index af0dc0486c8748c0646ecfedc8e0bf9732091326..b52772d98fef9f2fa115121b1e75e06b34cc4fde 100644
--- a/Tests/MathLib/TestGlobalMatrixInterface.cpp
+++ b/Tests/MathLib/TestGlobalMatrixInterface.cpp
@@ -94,23 +94,28 @@ void checkGlobalMatrixInterfaceMPI(T_MATRIX &m, T_VECTOR &v)
 
     MathLib::finalizeMatrixAssembly(m);
 
+    // Test basic assignment operator with an empty T_MATRIX._A
+    T_MATRIX m_c = m;
+    // Test basic assignment operator with an initalized T_MATRIX._A
+    m_c = m;
+
     // Multiply by a vector
     // v = 1.;
     set(v, 1.);
     const bool deep_copy = false;
     T_VECTOR y(v, deep_copy);
-    matMult(m, v, y);
+    matMult(m_c, v, y);
 
     ASSERT_EQ(sqrt(3*(3*3 + 7*7)), norm2(y));
 
     // set a value
-    m.set(2 * mrank, 2 * mrank, 5.0);
+    m_c.set(2 * mrank, 2 * mrank, 5.0);
     MathLib::finalizeMatrixAssembly(m);
     // add a value
-    m.add(2 * mrank+1, 2 * mrank+1, 5.0);
-    MathLib::finalizeMatrixAssembly(m);
+    m_c.add(2 * mrank+1, 2 * mrank+1, 5.0);
+    MathLib::finalizeMatrixAssembly(m_c);
 
-    matMult(m, v, y);
+    matMult(m_c, v, y);
 
     ASSERT_EQ(sqrt((3*7*7 + 3*12*12)), norm2(y));
 }