diff --git a/src/language/modules/CouplageModule.cpp b/src/language/modules/CouplageModule.cpp
index cdb9e2194afb4ba944b08dda5dfd7c3a8309b844..1b818561336b70541a4ac76162bf00d535ade720 100644
--- a/src/language/modules/CouplageModule.cpp
+++ b/src/language/modules/CouplageModule.cpp
@@ -11,7 +11,7 @@
 #include <mesh/Connectivity.hpp>
 #include <mesh/Mesh.hpp>
 #include <mesh/MeshNodeBoundary.hpp>
-#include <mesh/MeshNodeZone.hpp>
+#include <mesh/MeshNodeInterface.hpp>
 #include <scheme/DirichletBoundaryConditionDescriptor.hpp>
 #include <scheme/DiscreteFunctionVariant.hpp>
 #include <scheme/FixedBoundaryConditionDescriptor.hpp>
@@ -25,50 +25,32 @@
 
 CouplageModule::CouplageModule()
 {
-  this->_addBuiltinFunction("serialize_new",
+  this->_addBuiltinFunction("serialize",
                             std::function(
                               [](std::shared_ptr<const IMesh> i_mesh,
-                                 const std::vector<std::shared_ptr<const IZoneDescriptor>>& i_zone_list) -> void {
-                                for (const auto& i_zone : i_zone_list) {
-                                  const int tag                = 10;
-                                  using MeshType               = Mesh<Connectivity<2>>;
-                                  const std::shared_ptr p_mesh = std::dynamic_pointer_cast<const MeshType>(i_mesh);
-
-                                  auto mesh_node_zone = getMeshNodeZone(*p_mesh, *i_zone);
-                                  std::cout << "\033[01;31m"
-                                            << "mesh_node_zone" << mesh_node_zone << "\033[00;00m" << std::endl;
-
-                                  /*   for (size_t i_ref_node_list = 0; */
-                                  /*        i_ref_node_list < */
-                                  /*        mesh->connectivity().template numberOfRefItemList<ItemType::edge>(); */
-                                  /*        ++i_ref_node_list) { */
-                                  /*     const auto& ref_node_list = */
-                                  /*       mesh->connectivity().template refItemList<ItemType::edge>(i_ref_node_list);
-                                   */
-                                  /*     const RefId& ref = ref_node_list.refId(); */
-                                  /*     if (ref == i_zone) { */
-                                  /*       return ref_node_list; */
-                                  /*     } */
-                                  /*   } */
-                                }
-                                return;
+                                 const std::vector<std::shared_ptr<const IInterfaceDescriptor>>& i_interface_list)
+                                -> void {
+                                const int tag = 20;
+                                return Serializer().apply(i_mesh, i_interface_list, tag);
                               }));
-  this->_addBuiltinFunction("serialize", std::function([](std::shared_ptr<const IMesh> mesh) -> void {
-                              const int tag = 10;
-                              return Serializer().apply(mesh, tag);
+
+  this->_addBuiltinFunction("serialize", std::function([](std::shared_ptr<const IMesh> mesh, const int64_t dest,
+                                                          const int64_t tag) -> void {
+                              return Serializer().apply(mesh, dest, tag);
                             }));
 
   this->_addBuiltinFunction("serialize", std::function([](const std::shared_ptr<const IBoundaryDescriptor>& boundary,
-                                                          std::shared_ptr<const IMesh> mesh, int64_t location) -> void {
-                              const int tag = 100;
-                              return Serializer().apply(boundary, mesh, location, tag);
+                                                          std::shared_ptr<const IMesh> mesh, int64_t location,
+                                                          const int64_t dest, const int64_t tag) -> void {
+                              std::cout << "\033[01;32m"
+                                        << "dest: " << dest << "\ntag: " << tag << "\033[00;00m" << std::endl;
+                              return Serializer().apply(boundary, mesh, location, dest, tag);
                             }));
 
   this->_addBuiltinFunction("serialize_field",
-                            std::function([](const std::shared_ptr<const IBoundaryDescriptor>& boundary,
-                                             const std::shared_ptr<const DiscreteFunctionVariant>& field) -> void {
+                            std::function([](const std::shared_ptr<const DiscreteFunctionVariant>& field) -> void {
                               const int tag = 300;
-                              return Serializer().apply(boundary, field, tag);
+                              return Serializer().apply(field, tag);
                             }));
 
   this->_addBuiltinFunction("serialize_field",
@@ -81,7 +63,7 @@ CouplageModule::CouplageModule()
 
   this->_addBuiltinFunction("cpl_change_mesh_position",
                             std::function([](std::shared_ptr<const IMesh> mesh) -> std::shared_ptr<const IMesh> {
-                              const int tag = -1;
+                              const int tag = 400;
                               return Serializer().change_mesh_position(mesh, tag);
                             }));
 
diff --git a/src/mesh/CMakeLists.txt b/src/mesh/CMakeLists.txt
index f58d236369197634973987c3d07e92ca184fc091..ee69a9710d8706072e1fbd80eb51a6d3e0dd9b5c 100644
--- a/src/mesh/CMakeLists.txt
+++ b/src/mesh/CMakeLists.txt
@@ -36,7 +36,6 @@ add_library(
   MeshLineFaceBoundary.cpp
   MeshLineNodeBoundary.cpp
   MeshNodeBoundary.cpp
-  MeshNodeZone.cpp
   MeshNodeInterface.cpp
   MeshRandomizer.cpp
   MeshSmoother.cpp
diff --git a/src/mesh/MeshNodeZone.cpp b/src/mesh/MeshNodeZone.cpp
deleted file mode 100644
index 9c2c3599e3742a120ab40ed16e3d3f4105ee454a..0000000000000000000000000000000000000000
--- a/src/mesh/MeshNodeZone.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
-#include <mesh/MeshNodeZone.hpp>
-
-#include <mesh/Connectivity.hpp>
-#include <mesh/Mesh.hpp>
-#include <utils/Messenger.hpp>
-
-template <size_t Dimension>
-MeshNodeZone<Dimension>::MeshNodeZone(const Mesh<Connectivity<Dimension>>&, const RefNodeList& ref_node_list)
-  : m_node_list(ref_node_list.list()), m_zone_name(ref_node_list.refId().tagName())
-{}
-
-template <size_t Dimension>
-// MeshNodeZone<Dimension>
-int
-getMeshNodeZone(const Mesh<Connectivity<Dimension>>& mesh, const IZoneDescriptor& zone_descriptor)
-{
-  for (size_t i_ref_edge_list = 0; i_ref_edge_list < mesh.connectivity().template numberOfRefItemList<ItemType::edge>();
-       ++i_ref_edge_list) {
-    const auto& ref_edge_list = mesh.connectivity().template refItemList<ItemType::edge>(i_ref_edge_list);
-
-    const RefId& ref = ref_edge_list.refId();
-    if (ref == zone_descriptor) {
-      std::cout << "\033[01;31m"
-                << "ref" << ref << "\033[00;00m" << std::endl;
-      return 1;
-      /* return MeshNodeZone<Dimension>{mesh, ref_node_list}; */
-    }
-  }
-
-  std::ostringstream ost;
-  ost << "cannot find node set with name \"" << rang::fgB::red << zone_descriptor << rang::style::reset << '\"';
-
-  throw NormalError(ost.str());
-}
-
-/* template MeshNodeZone<1> getMeshNodeZone(const Mesh<Connectivity<1>>&, const IZoneDescriptor&); */
-/* template MeshNodeZone<2> getMeshNodeZone(const Mesh<Connectivity<2>>&, const IZoneDescriptor&); */
-/* template MeshNodeZone<3> getMeshNodeZone(const Mesh<Connectivity<3>>&, const IZoneDescriptor&); */
-
-template int getMeshNodeZone(const Mesh<Connectivity<1>>&, const IZoneDescriptor&);
-template int getMeshNodeZone(const Mesh<Connectivity<2>>&, const IZoneDescriptor&);
-template int getMeshNodeZone(const Mesh<Connectivity<3>>&, const IZoneDescriptor&);
diff --git a/src/mesh/MeshNodeZone.hpp b/src/mesh/MeshNodeZone.hpp
deleted file mode 100644
index 14d6295f84e7d0c7bf31ee57216f6bf9ca32a2bf..0000000000000000000000000000000000000000
--- a/src/mesh/MeshNodeZone.hpp
+++ /dev/null
@@ -1,53 +0,0 @@
-#ifndef MESH_NODE_ZONE_HPP
-#define MESH_NODE_ZONE_HPP
-
-#include <mesh/IZoneDescriptor.hpp>
-#include <mesh/RefItemList.hpp>
-#include <utils/Array.hpp>
-
-template <size_t Dimension>
-class Connectivity;
-
-template <typename ConnectivityType>
-class Mesh;
-
-template <size_t Dimension>
-class [[nodiscard]] MeshNodeZone   // clazy:exclude=copyable-polymorphic
-{
- protected:
-  Array<const NodeId> m_node_list;
-  std::string m_zone_name;
-
- public:
-  template <size_t MeshDimension>
-  friend MeshNodeZone<MeshDimension> getMeshNodeZone(const Mesh<Connectivity<MeshDimension>>& mesh,
-                                                     const IZoneDescriptor& zone_descriptor);
-
-  MeshNodeZone& operator=(const MeshNodeZone&) = default;
-  MeshNodeZone& operator=(MeshNodeZone&&)      = default;
-
-  const Array<const NodeId>&
-  nodeList() const
-  {
-    return m_node_list;
-  }
-
- protected:
-  MeshNodeZone(const Mesh<Connectivity<Dimension>>& mesh, const RefNodeList& ref_node_list);
-
- public:
-  MeshNodeZone(const MeshNodeZone&) = default;
-  MeshNodeZone(MeshNodeZone&&)      = default;
-
-  MeshNodeZone()          = default;
-  virtual ~MeshNodeZone() = default;
-};
-
-/* template <size_t Dimension> */
-/* MeshNodeZone<Dimension> getMeshNodeZone(const Mesh<Connectivity<Dimension>>& mesh, */
-/*                                         const IZoneDescriptor& zone_descriptor); */
-
-template <size_t Dimension>
-int getMeshNodeZone(const Mesh<Connectivity<Dimension>>& mesh, const IZoneDescriptor& zone_descriptor);
-
-#endif   // MESH_NODE_ZONE_HPP
diff --git a/src/utils/CMakeLists.txt b/src/utils/CMakeLists.txt
index ddc38d41fcdc2f054738d5eaa29e7afcf7898c74..d7fb9ec881bfce8c13d9f5ecd75ac39e1eb21c89 100644
--- a/src/utils/CMakeLists.txt
+++ b/src/utils/CMakeLists.txt
@@ -18,10 +18,9 @@ add_library(
   SignalManager.cpp
   SLEPcWrapper.cpp
   Serializer.cpp
-  Socket.cpp
-  )
+  Socket.cpp)
 
-  target_link_libraries(
+target_link_libraries(
   PugsUtils
   ${PETSC_LIBRARIES}
   ${SLEPC_LIBRARIES}
diff --git a/src/utils/Serializer.cpp b/src/utils/Serializer.cpp
index d8b79bc92b97a3e6dd4f0e047f99794ecca1d1c5..4e20ab62e0003c99378ce5eefb713fe81f353176 100644
--- a/src/utils/Serializer.cpp
+++ b/src/utils/Serializer.cpp
@@ -11,14 +11,36 @@ Serializer::~Serializer() = default;
 
 // MESH
 void
-Serializer::apply(std::shared_ptr<const IMesh> i_mesh, const int tag)
+Serializer::apply(std::shared_ptr<const IMesh> i_mesh, const int dest, const int tag)
 {
-  auto costo     = parallel::Messenger::getInstance().myCoupling;
-  const int dest = costo->myGlobalSize() - 1;
+  auto costo = parallel::Messenger::getInstance().myCoupling;
   std::vector<int> shape;
   std::vector<double> pts;
   switch (i_mesh->dimension()) {
   case 1: {
+    using MeshType             = Mesh<Connectivity<1>>;
+    const std::shared_ptr mesh = std::dynamic_pointer_cast<const MeshType>(i_mesh);
+
+    using Rd                      = TinyVector<MeshType::Dimension>;
+    const NodeValue<const Rd>& xr = mesh->xr();
+    Array<TinyVector<1>> positions(mesh->numberOfNodes());
+    parallel_for(
+      mesh->numberOfNodes(), PUGS_LAMBDA(NodeId r) {
+        for (unsigned short i = 0; i < MeshType::Dimension; ++i) {
+          positions[r][i] = xr[r][i];
+        }
+      });
+    pts.resize(mesh->numberOfNodes() * MeshType::Dimension);
+    for (unsigned short r = 0; r < mesh->numberOfNodes(); ++r) {
+      for (unsigned short j = 0; j < MeshType::Dimension; ++j) {
+        pts[MeshType::Dimension * r + j] = positions[r][j];
+      }
+    }
+
+    shape.resize(3);
+    shape[0] = mesh->numberOfNodes();
+    shape[1] = i_mesh->dimension();
+    shape[2] = 0;
     break;
   }
   case 2: {
@@ -43,7 +65,7 @@ Serializer::apply(std::shared_ptr<const IMesh> i_mesh, const int tag)
 
     shape.resize(3);
     shape[0] = mesh->numberOfNodes();
-    shape[1] = 2;
+    shape[1] = i_mesh->dimension();
     shape[2] = 0;
     break;
   }
@@ -71,7 +93,7 @@ Serializer::apply(std::shared_ptr<const IMesh> i_mesh, const int tag)
 
     shape.resize(3);
     shape[0] = mesh->numberOfNodes();
-    shape[1] = 3;
+    shape[1] = i_mesh->dimension();
     shape[2] = 0;
     break;
   }
@@ -87,10 +109,10 @@ void
 Serializer::apply(const std::shared_ptr<const IBoundaryDescriptor>& boundary,
                   std::shared_ptr<const IMesh> i_mesh,
                   const int location,
+                  const int dest,
                   const int tag)
 {
-  auto costo     = parallel::Messenger::getInstance().myCoupling;
-  const int dest = costo->myGlobalSize() - 1;
+  auto costo = parallel::Messenger::getInstance().myCoupling;
   std::vector<int> shape;
   std::vector<double> pts;
   std::cout << "\033[01;31m"
@@ -102,6 +124,42 @@ Serializer::apply(const std::shared_ptr<const IBoundaryDescriptor>& boundary,
               << "\033[00;00m" << std::endl;
     switch (i_mesh->dimension()) {
     case 1: {
+      using MeshType             = Mesh<Connectivity<1>>;
+      const std::shared_ptr mesh = std::dynamic_pointer_cast<const MeshType>(i_mesh);
+
+      using MeshDataType = MeshData<1>;
+
+      MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(*mesh);
+      /* const ItemValue<const Rd>& xl = mesh_data.xl(); */
+      const auto xl = mesh_data.xl();
+
+      Array<TinyVector<1>> fpositions(mesh->numberOfFaces());
+      parallel_for(
+        mesh->numberOfFaces(), PUGS_LAMBDA(FaceId l) {
+          for (unsigned short i = 0; i < MeshType::Dimension; ++i) {
+            fpositions[l][i] = xl[l][i];
+          }
+          /* for (unsigned short i = MeshType::Dimension; i < 3; ++i) { */
+          /*   positions[r][i] = 0; */
+          /* } */
+        });
+
+      MeshFaceBoundary<1> mesh_face_boundary = getMeshFaceBoundary(*mesh, *boundary);
+      /* mesh_face_boundary.faceList() */
+      const auto face_list = mesh_face_boundary.faceList();
+      pts.resize(face_list.size() * MeshType::Dimension);
+
+      for (size_t i_face = 0; i_face < face_list.size(); ++i_face) {
+        const FaceId face_id = face_list[i_face];
+        for (unsigned short j = 0; j < MeshType::Dimension; ++j) {
+          pts[MeshType::Dimension * i_face + j] = fpositions[face_id][j];
+        }
+        /* std::cout << "\033[01;31m" << pts[2 * r] << "; " << pts[2 * r + 1] << "\033[00;00m" << std::endl; */
+      }
+      shape.resize(3);
+      shape[0] = face_list.size();
+      shape[1] = i_mesh->dimension();
+      shape[2] = 0;
       break;
     }
     case 2: {
@@ -191,6 +249,39 @@ Serializer::apply(const std::shared_ptr<const IBoundaryDescriptor>& boundary,
               << "\033[00;00m" << std::endl;
     switch (i_mesh->dimension()) {
     case 1: {
+      using MeshType             = Mesh<Connectivity<1>>;
+      const std::shared_ptr mesh = std::dynamic_pointer_cast<const MeshType>(i_mesh);
+
+      /* const ItemValue<const Rd>& xl = mesh_data.xl(); */
+      const auto xr = mesh->xr();
+
+      Array<TinyVector<1>> positions(mesh->numberOfNodes());
+      parallel_for(
+        mesh->numberOfNodes(), PUGS_LAMBDA(NodeId r) {
+          for (unsigned short i = 0; i < MeshType::Dimension; ++i) {
+            positions[r][i] = xr[r][i];
+          }
+          /* for (unsigned short i = MeshType::Dimension; i < 3; ++i) { */
+          /*   positions[r][i] = 0; */
+          /* } */
+        });
+
+      MeshNodeBoundary<1> mesh_node_boundary = getMeshNodeBoundary(*mesh, *boundary);
+      /* mesh_face_boundary.faceList() */
+      const auto node_list = mesh_node_boundary.nodeList();
+      pts.resize(node_list.size() * MeshType::Dimension);
+
+      for (size_t i_node = 0; i_node < node_list.size(); ++i_node) {
+        const NodeId node_id = node_list[i_node];
+        for (unsigned short j = 0; j < MeshType::Dimension; ++j) {
+          pts[MeshType::Dimension * i_node + j] = positions[node_id][j];
+        }
+        /* std::cout << "\033[01;31m" << pts[2 * r] << "; " << pts[2 * r + 1] << "\033[00;00m" << std::endl; */
+      }
+      shape.resize(3);
+      shape[0] = node_list.size();
+      shape[1] = i_mesh->dimension();
+      shape[2] = 0;
       break;
     }
     case 2: {
@@ -276,6 +367,66 @@ Serializer::apply(const std::shared_ptr<const IBoundaryDescriptor>& boundary,
   /* parallel::Messenger::getInstance().myCoupling->recvData(recv, src, tag + 1); */
 }
 
+void
+Serializer::apply(std::shared_ptr<const IMesh> i_mesh,
+                  const std::vector<std::shared_ptr<const IInterfaceDescriptor>>& i_interface_list,
+                  const int tag)
+{
+  auto costo     = parallel::Messenger::getInstance().myCoupling;
+  const int dest = costo->myGlobalSize() - 1;
+  std::vector<int> shape;
+  std::vector<double> data;
+
+  switch (i_mesh->dimension()) {
+  case 1: {
+    throw NotImplementedError("1D not implemented");
+    break;
+  }
+  case 2: {
+    using MeshType               = Mesh<Connectivity<2>>;
+    const std::shared_ptr p_mesh = std::dynamic_pointer_cast<const MeshType>(i_mesh);
+
+    for (const auto& i_interface : i_interface_list) {
+      auto node_interface = getMeshNodeInterface(*p_mesh, *i_interface);
+      auto node_list      = node_interface.nodeList();
+
+      data.resize(node_list.size() * MeshType::Dimension);
+
+      const auto xr = p_mesh->xr();
+
+      Array<TinyVector<2>> positions(p_mesh->numberOfNodes());
+      parallel_for(
+        p_mesh->numberOfNodes(), PUGS_LAMBDA(NodeId r) {
+          for (unsigned short i = 0; i < MeshType::Dimension; ++i) {
+            positions[r][i] = xr[r][i];
+          }
+          /* for (unsigned short i = MeshType::Dimension; i < 3; ++i) { */
+          /*   positions[r][i] = 0; */
+          /* } */
+        });
+
+      for (size_t i_node = 0; i_node < node_list.size(); ++i_node) {
+        const NodeId node_id = node_list[i_node];
+        for (unsigned short i_dim = 0; i_dim < MeshType::Dimension; ++i_dim) {
+          data[i_node * MeshType::Dimension + i_dim] = positions[node_id][i_dim];
+        }
+      }
+
+      shape.resize(3);
+      shape[0] = node_list.size();
+      shape[1] = 2;
+      shape[2] = 0;
+      costo->sendData(shape, data, dest, tag);
+    }
+
+    break;
+  }
+  case 3: {
+    throw NotImplementedError("3D not implemented");
+    break;
+  }
+  }
+}
 // Field at node
 void
 Serializer::apply(std::shared_ptr<const IMesh> i_mesh,
@@ -334,9 +485,7 @@ Serializer::apply(std::shared_ptr<const IMesh> i_mesh,
 
 // Field (faces)
 void
-Serializer::apply(const std::shared_ptr<const IBoundaryDescriptor>& boundary,
-                  const std::shared_ptr<const DiscreteFunctionVariant>& field,
-                  const int tag)
+Serializer::apply(const std::shared_ptr<const DiscreteFunctionVariant>& field, const int tag)
 {
   const std::shared_ptr i_mesh = getCommonMesh({field});
   if (not i_mesh) {
@@ -466,5 +615,10 @@ Serializer::change_mesh_position(std::shared_ptr<const IMesh> i_mesh, const int
 
     return std::make_shared<MeshType>(given_mesh->shared_connectivity(), new_xr);
   }
+  default: {
+    throw NormalError("Must not pass here");
+  }
   }
 }
+
+#endif   // PUGS_HAS_COSTO
diff --git a/src/utils/Serializer.hpp b/src/utils/Serializer.hpp
index 5c372873dced3821527b30e66f99768dbe917bbb..26779f778c4ceae4b6d1328fa6e8db27064e39d1 100644
--- a/src/utils/Serializer.hpp
+++ b/src/utils/Serializer.hpp
@@ -11,6 +11,7 @@
 #include <mesh/MeshDataManager.hpp>
 #include <mesh/MeshFaceBoundary.hpp>
 #include <mesh/MeshFlatFaceBoundary.hpp>
+#include <mesh/MeshNodeInterface.hpp>
 #include <scheme/DirichletBoundaryConditionDescriptor.hpp>
 #include <scheme/DiscreteFunctionUtils.hpp>
 #include <scheme/NeumannBoundaryConditionDescriptor.hpp>
@@ -37,10 +38,11 @@ class Serializer
   };
   Serializer();
   ~Serializer();
-  void apply(std::shared_ptr<const IMesh> i_mesh, const int tag);
+  void apply(std::shared_ptr<const IMesh> i_mesh, const int dest, const int tag);
   void apply(const std::shared_ptr<const IBoundaryDescriptor>& boundary,
              std::shared_ptr<const IMesh> i_mesh,
              const int location,
+             const int dest,
              const int tag);
 
   void apply(std::shared_ptr<const IMesh> i_mesh,
@@ -48,10 +50,12 @@ class Serializer
              const std::shared_ptr<const ItemValueVariant>& field,
              const int tag);
 
-  void apply(const std::shared_ptr<const IBoundaryDescriptor>& boundary,
-             const std::shared_ptr<const DiscreteFunctionVariant>& field,
+  void apply(std::shared_ptr<const IMesh> i_mesh,
+             const std::vector<std::shared_ptr<const IInterfaceDescriptor>>& i_interface_list,
              const int tag);
 
+  void apply(const std::shared_ptr<const DiscreteFunctionVariant>& field, const int tag);
+
   std::shared_ptr<const IMesh> change_mesh_position(std::shared_ptr<const IMesh> i_mesh, const int tag);
 };