diff --git a/include/gmsh_mpi.h b/include/gmsh_mpi.h
index 28361d6b51c4326a765274a18ca07737c2886f2b..cce679e74e1cc14a1fda2b1baa44d064e3f14988 100644
--- a/include/gmsh_mpi.h
+++ b/include/gmsh_mpi.h
@@ -83,6 +83,22 @@ priv_MPI_Recv(std::vector<T>& vec, int src, MPI_Comm comm)
     MPI_Recv(vec.data(), vec.size()*sizeof(T), MPI_PACKED, src, 0, comm, &status);
 }
 
+template<typename T>
+void
+priv_MPI_Send(T& elem, int dst, MPI_Comm comm)
+{
+    static_assert(std::is_trivially_copyable<T>::value, "Type must be trivially copyable");
+    MPI_Send(&elem, sizeof(T), MPI_PACKED, dst, 0, comm);
+}
+
+template<typename T>
+void
+priv_MPI_Recv(T& elem, int src, MPI_Comm comm)
+{
+    static_assert(std::is_trivially_copyable<T>::value, "Type must be trivially copyable");
+    MPI_Status status;
+    MPI_Recv(&elem, sizeof(T), MPI_PACKED, src, 0, comm, &status);
+}
 
 
 template<typename T>
diff --git a/include/physical_element.h b/include/physical_element.h
index b8dad8c262954a5d952dd056d8005ee04584b39a..87e798f54afeb3a7ad3fe511f7e3ff172572802a 100644
--- a/include/physical_element.h
+++ b/include/physical_element.h
@@ -5,6 +5,10 @@
 #include "eigen.h"
 #include "types.h"
 
+#ifdef USE_MPI
+#include "gmsh_mpi.h"
+#endif /* USE_MPI */
+
 /* This is a key for a basis function. Did this
  * class to protect the code from the GMSH api,
  * which is apparently changing */
@@ -72,6 +76,11 @@ public:
     point_3d        barycenter(void) const;
     double          measure(void) const;
 
+#ifdef USE_MPI
+    void            mpi_send(int dst, MPI_Comm comm);
+    void            mpi_recv(int src, MPI_Comm comm);
+#endif /* USE_MPI */
+
     /* This class is not intended to be constructed
      * by the user but by the appropriate factory */
     friend class physical_elements_factory;
diff --git a/src/physical_element.cpp b/src/physical_element.cpp
index ed18d55a2339024ac093b105f4f0d7d2b549a77e..9c9dc3059ef821db5f028938f2a9ec8e9a933698 100644
--- a/src/physical_element.cpp
+++ b/src/physical_element.cpp
@@ -232,6 +232,76 @@ physical_elements_factory::get_elements()
     return ret;
 }
 
+#ifdef USE_MPI
+void
+physical_element::mpi_send(int dst, MPI_Comm comm)
+{
+    MPI_Send(&m_original_position, 1, MPI_UNSIGNED_LONG_LONG, dst, 0, comm);
+    MPI_Send(&m_dimension, 1, MPI_INT, dst, 0, comm);
+    MPI_Send(&m_orientation, 1, MPI_INT, dst, 0, comm);
+    MPI_Send(&m_parent_entity_tag, 1, MPI_INT, dst, 0, comm);
+    MPI_Send(&m_gmsh_elemtype, 1, MPI_INT, dst, 0, comm);
+    MPI_Send(&m_element_tag, 1, MPI_UNSIGNED_LONG_LONG, dst, 0, comm);
+    priv_MPI_Send(m_node_tags, dst, comm);
+    priv_MPI_Send(m_determinants, dst, comm);
+
+    std::vector<double> jacs;
+    jacs.resize( m_jacobians.size() * 9 );
+    for (size_t i = 0; i < m_jacobians.size(); i++)
+    {
+        auto& M = m_jacobians[i];
+        for (size_t mi = 0; mi < 3; mi++)
+            for (size_t mj = 0; mj < 3; mj++)
+                jacs[9*i + 3*mi + mj] = M(mi, mj);
+    }
+    priv_MPI_Send(jacs, dst, comm);
+
+    priv_MPI_Send(m_phys_quadpoints, dst, comm);
+    priv_MPI_Send(m_barycenter, dst, comm);
+    MPI_Send(&m_measure, 1, MPI_DOUBLE, dst, 0, comm);
+    MPI_Send(&m_geometric_order, 1, MPI_INT, dst, 0, comm);
+    MPI_Send(&m_approximation_order, 1, MPI_INT, dst, 0, comm);
+    priv_MPI_Send(m_bf_keys, dst, comm);
+}
+
+void
+physical_element::mpi_recv(int src, MPI_Comm comm)
+{
+    MPI_Status status;
+    MPI_Recv(&m_original_position, 1, MPI_UNSIGNED_LONG_LONG, src, 0, comm, &status);
+    MPI_Recv(&m_dimension, 1, MPI_INT, src, 0, comm, &status);
+    MPI_Recv(&m_orientation, 1, MPI_INT, src, 0, comm, &status);
+    MPI_Recv(&m_parent_entity_tag, 1, MPI_INT, src, 0, comm, &status);
+    MPI_Recv(&m_gmsh_elemtype, 1, MPI_INT, src, 0, comm, &status);
+    MPI_Recv(&m_element_tag, 1, MPI_UNSIGNED_LONG_LONG, src, 0, comm, &status);
+    priv_MPI_Recv(m_node_tags, src, comm);
+    priv_MPI_Recv(m_determinants, src, comm);
+
+    std::vector<double> jacs;
+    priv_MPI_Recv(jacs, src, comm);
+    m_jacobians.resize( jacs.size() / 9 );
+    assert( m_jacobians.size() * 9 == jacs.size() );
+    for (size_t i = 0; i < m_jacobians.size(); i++)
+    {
+        auto& M = m_jacobians[i];
+        for (size_t mi = 0; mi < 3; mi++)
+            for (size_t mj = 0; mj < 3; mj++)
+                M(mi, mj) = jacs[9*i + 3*mi + mj];
+    }
+
+    priv_MPI_Recv(m_phys_quadpoints, src, comm);
+    priv_MPI_Recv(m_barycenter, src, comm);
+    MPI_Recv(&m_measure, 1, MPI_DOUBLE, src, 0, comm, &status);
+    MPI_Recv(&m_geometric_order, 1, MPI_INT, src, 0, comm, &status);
+    MPI_Recv(&m_approximation_order, 1, MPI_INT, src, 0, comm, &status);
+    priv_MPI_Recv(m_bf_keys, src, comm);
+}
+#endif /* USE_MPI */
+
+
+
+
+
 element_key::element_key()
 {}