diff --git a/python/mesa_pd.py b/python/mesa_pd.py
index 57a8f138210daf92b7d18997adf739780d9c8b90..94cd212a7d618e9381898cb0c3068883052c2bff 100755
--- a/python/mesa_pd.py
+++ b/python/mesa_pd.py
@@ -120,6 +120,7 @@ if __name__ == '__main__':
    comm.append(mpi.ClearNextNeighborSync())
    comm.append(mpi.ReduceContactHistory())
    comm.append(mpi.ReduceProperty())
+   comm.append(mpi.ShapePackUnpack(shapes))
    comm.append(mpi.SyncGhostOwners(ps))
    comm.append(mpi.SyncNextNeighbors(ps))
 
diff --git a/python/mesa_pd/mpi/ShapePackUnpack.py b/python/mesa_pd/mpi/ShapePackUnpack.py
new file mode 100644
index 0000000000000000000000000000000000000000..cb52010d7fd7e353f712ede06f204131c659f15e
--- /dev/null
+++ b/python/mesa_pd/mpi/ShapePackUnpack.py
@@ -0,0 +1,11 @@
+# -*- coding: utf-8 -*-
+
+from ..utility import generateFile
+
+class ShapePackUnpack:
+   def __init__(self, shapes):
+      self.shapes = shapes
+   def generate(self, path):
+      context = dict()
+      context["shapes"] = self.shapes
+      generateFile(path, 'mpi/ShapePackUnpack.templ.h', context)
diff --git a/python/mesa_pd/mpi/__init__.py b/python/mesa_pd/mpi/__init__.py
index 7714d1098c0e44f3d40bbe34e3fd3366347abb1f..c319a8feca8c92c1e302a50b9bce2abb570b1461 100644
--- a/python/mesa_pd/mpi/__init__.py
+++ b/python/mesa_pd/mpi/__init__.py
@@ -4,6 +4,7 @@ from .BroadcastProperty import BroadcastProperty
 from .ClearNextNeighborSync import ClearNextNeighborSync
 from .ReduceContactHistory import ReduceContactHistory
 from .ReduceProperty import ReduceProperty
+from .ShapePackUnpack import ShapePackUnpack
 from .SyncGhostOwners import SyncGhostOwners
 from .SyncNextNeighbors import SyncNextNeighbors
 
@@ -11,6 +12,7 @@ __all__ = ['BroadcastProperty',
            'ClearNextNeighborSync',
            'ReduceContactHistory',
            'ReduceProperty',
+           'ShapePackUnpack',
            'SyncGhostOwners',
            'SyncNextNeighbors',
            ]
diff --git a/python/mesa_pd/templates/mpi/ShapePackUnpack.templ.h b/python/mesa_pd/templates/mpi/ShapePackUnpack.templ.h
new file mode 100644
index 0000000000000000000000000000000000000000..47e5bd7fc678b353ed6c363b09903edf1e6306f8
--- /dev/null
+++ b/python/mesa_pd/templates/mpi/ShapePackUnpack.templ.h
@@ -0,0 +1,75 @@
+//======================================================================================================================
+//
+//  This file is part of waLBerla. waLBerla is free software: you can
+//  redistribute it and/or modify it under the terms of the GNU General Public
+//  License as published by the Free Software Foundation, either version 3 of
+//  the License, or (at your option) any later version.
+//
+//  waLBerla is distributed in the hope that it will be useful, but WITHOUT
+//  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+//  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+//  for more details.
+//
+//  You should have received a copy of the GNU General Public License along
+//  with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file ShapePackUnpack.h
+//! \author Sebastian Eibl <sebastian.eibl@fau.de>
+//
+//======================================================================================================================
+
+//======================================================================================================================
+//
+//  THIS FILE IS GENERATED - PLEASE CHANGE THE TEMPLATE !!!
+//
+//======================================================================================================================
+
+#pragma once
+
+#include <mesa_pd/data/shape/BaseShape.h>
+{%- for shape in shapes %}
+#include <mesa_pd/data/shape/{{shape}}.h>
+{%- endfor %}
+
+#include <core/mpi/RecvBuffer.h>
+#include <core/mpi/SendBuffer.h>
+
+#include <memory>
+
+namespace walberla {
+namespace mpi {
+   template< typename T,    // Element type of SendBuffer
+             typename G>    // Growth policy of SendBuffer
+   mpi::GenericSendBuffer<T,G>& operator<<( mpi::GenericSendBuffer<T,G> & buf,
+                                            const std::shared_ptr<mesa_pd::data::BaseShape>& bs )
+   {
+      buf.addDebugMarker( "up" );
+      buf << bs->getShapeType();
+      bs->pack(buf);
+      return buf;
+   }
+
+   template< typename T>    // Element type  of RecvBuffer
+   mpi::GenericRecvBuffer<T>& operator>>( mpi::GenericRecvBuffer<T> & buf,
+                                          std::shared_ptr<mesa_pd::data::BaseShape>& bs )
+   {
+      using namespace mesa_pd::data;
+
+      buf.readDebugMarker( "up" );
+
+      mesa_pd::data::BaseShape::ShapeTypeT shapeType;
+      buf >> shapeType;
+      switch (shapeType)
+      {
+         {%- for shape in shapes %}
+         case {{shape}}::SHAPE_TYPE :
+            bs = std::make_unique<mesa_pd::data::{{shape}}>();
+            bs->unpack(buf);
+            break;
+         {%- endfor %}
+         default : WALBERLA_ABORT("Shape type (" << shapeType << ") could not be determined!");
+      }
+      return buf;
+   }
+} //namespace mpi
+} //namespace walberla
diff --git a/python/mesa_pd/templates/mpi/notifications/ParticleCopyNotification.templ.h b/python/mesa_pd/templates/mpi/notifications/ParticleCopyNotification.templ.h
index f9dbf1988e1cc7f3b690d7171e2181d1207d83f3..c2ea7d768bf5471c725bf4e2e4a53c3a1de5e093 100644
--- a/python/mesa_pd/templates/mpi/notifications/ParticleCopyNotification.templ.h
+++ b/python/mesa_pd/templates/mpi/notifications/ParticleCopyNotification.templ.h
@@ -28,6 +28,7 @@
 
 #include <mesa_pd/data/DataTypes.h>
 #include <mesa_pd/data/ParticleStorage.h>
+#include <mesa_pd/mpi/ShapePackUnpack.h>
 #include <mesa_pd/mpi/notifications/NotificationType.h>
 
 #include <core/mpi/Datatype.h>
diff --git a/src/mesa_pd/data/shape/BaseShape.h b/src/mesa_pd/data/shape/BaseShape.h
index d00b0adeeaf2f87361380cdb89598710044b374b..20ab37d2e2fe296edcb3dcf1ac41b0412f57b99a 100644
--- a/src/mesa_pd/data/shape/BaseShape.h
+++ b/src/mesa_pd/data/shape/BaseShape.h
@@ -22,6 +22,9 @@
 
 #include <mesa_pd/data/DataTypes.h>
 
+#include <core/mpi/RecvBuffer.h>
+#include <core/mpi/SendBuffer.h>
+
 namespace walberla {
 namespace mesa_pd {
 namespace data {
@@ -35,6 +38,8 @@ namespace data {
 class BaseShape
 {
 public:
+   using ShapeTypeT = int;
+
    explicit BaseShape(const int shapeType) : shapeType_(shapeType) {}
    virtual ~BaseShape() = default;
 
@@ -49,17 +54,20 @@ public:
    const Mat3& getInertiaBF() const {return inertiaBF_;}
    const Mat3& getInvInertiaBF() const {return invInertiaBF_;}
 
-   const int& getShapeType() const {return shapeType_;}
+   const ShapeTypeT& getShapeType() const {return shapeType_;}
 
    virtual Vec3 support( const Vec3& /*d*/ ) const {WALBERLA_ABORT("Not implemented!");}
 
+   virtual void pack(walberla::mpi::SendBuffer& buf);
+   virtual void unpack(walberla::mpi::RecvBuffer& buf);
+
    static const int INVALID_SHAPE = -1; ///< Unique *invalid* shape type identifier.\ingroup mesa_pd_shape
 protected:
-   real_t mass_         = real_t(0);       ///< mass
-   real_t invMass_      = real_t(0);       ///< inverse mass
-   Mat3   inertiaBF_    = Mat3(real_t(0)); ///< inertia matrix in the body frame
-   Mat3   invInertiaBF_ = Mat3(real_t(0)); ///< inverse inertia matrix in the body frame
-   int    shapeType_    = INVALID_SHAPE;   ///< \ingroup mesa_pd_shape
+   real_t     mass_         = real_t(0);       ///< mass
+   real_t     invMass_      = real_t(0);       ///< inverse mass
+   Mat3       inertiaBF_    = Mat3(real_t(0)); ///< inertia matrix in the body frame
+   Mat3       invInertiaBF_ = Mat3(real_t(0)); ///< inverse inertia matrix in the body frame
+   ShapeTypeT shapeType_    = INVALID_SHAPE;   ///< \ingroup mesa_pd_shape
 };
 
 inline
@@ -68,6 +76,23 @@ void BaseShape::updateMassAndInertia(const real_t /*density*/)
    WALBERLA_ABORT("updateMassAndInertia not implemented!");
 }
 
+inline
+void BaseShape::pack(walberla::mpi::SendBuffer& buf)
+{
+   buf << mass_;
+   buf << invMass_;
+   buf << inertiaBF_;
+   buf << invInertiaBF_;
+}
+inline
+void BaseShape::unpack(walberla::mpi::RecvBuffer& buf)
+{
+   buf >> mass_;
+   buf >> invMass_;
+   buf >> inertiaBF_;
+   buf >> invInertiaBF_;
+}
+
 } //namespace data
 } //namespace mesa_pd
 } //namespace walberla
diff --git a/src/mesa_pd/data/shape/Box.h b/src/mesa_pd/data/shape/Box.h
index 95fcd9d0e027c8684255f42721e3c5287f53c19c..7cc5606785586fea4c1156a3bb796b5fc34a1456 100644
--- a/src/mesa_pd/data/shape/Box.h
+++ b/src/mesa_pd/data/shape/Box.h
@@ -31,7 +31,7 @@ namespace data {
 class Box : public BaseShape
 {
 public:
-   explicit Box(const Vec3& edgeLength)
+   explicit Box(const Vec3& edgeLength = Vec3(real_t(1)))
       : BaseShape(Box::SHAPE_TYPE)
       , edgeLength_(edgeLength)
    {}
@@ -43,6 +43,9 @@ public:
 
    Vec3 support( const Vec3& bfD ) const override;
 
+   void pack(walberla::mpi::SendBuffer& buf) override;
+   void unpack(walberla::mpi::RecvBuffer& buf) override;
+
    constexpr static int SHAPE_TYPE = 3; ///< Unique shape type identifier for boxes.\ingroup mesa_pd_shape
 
 private:
@@ -73,6 +76,19 @@ Vec3 Box::support( const Vec3& bfD ) const
    return relativSupport;
 }
 
+inline
+void Box::pack(walberla::mpi::SendBuffer& buf)
+{
+   BaseShape::pack(buf);
+   buf << edgeLength_;
+}
+inline
+void Box::unpack(walberla::mpi::RecvBuffer& buf)
+{
+   BaseShape::unpack(buf);
+   buf >> edgeLength_;
+}
+
 } //namespace data
 } //namespace mesa_pd
 } //namespace walberla
diff --git a/src/mesa_pd/data/shape/CylindricalBoundary.h b/src/mesa_pd/data/shape/CylindricalBoundary.h
index 86380cfa14e3aa672519e46665d0f4367a1be3c8..abe3bca759184a7f8f167ebdc2d5cffb67a7634c 100644
--- a/src/mesa_pd/data/shape/CylindricalBoundary.h
+++ b/src/mesa_pd/data/shape/CylindricalBoundary.h
@@ -31,7 +31,8 @@ namespace data {
 class CylindricalBoundary : public BaseShape
 {
 public:
-   explicit CylindricalBoundary(const real_t& radius, const Vec3& axis)
+   explicit CylindricalBoundary(const real_t& radius = real_t(1),
+                                const Vec3& axis = Vec3(real_t(1), real_t(0), real_t(0)))
       : BaseShape(CylindricalBoundary::SHAPE_TYPE)
       , radius_(radius)
       , axis_(axis)
@@ -45,6 +46,9 @@ public:
    real_t getVolume() const override { return std::numeric_limits<real_t>::infinity(); };
    void   updateMassAndInertia(const real_t density) override;
 
+   void pack(walberla::mpi::SendBuffer& buf) override;
+   void unpack(walberla::mpi::RecvBuffer& buf) override;
+
    constexpr static int SHAPE_TYPE = 2; ///< Unique shape type identifier for cylindrical boundaries.\ingroup mesa_pd_shape
 
 private:
@@ -59,6 +63,21 @@ void CylindricalBoundary::updateMassAndInertia(const real_t /*density*/)
    invInertiaBF_ = Mat3(real_t(0.0));
 }
 
+inline
+void CylindricalBoundary::pack(walberla::mpi::SendBuffer& buf)
+{
+   BaseShape::pack(buf);
+   buf << radius_;
+   buf << axis_;
+}
+inline
+void CylindricalBoundary::unpack(walberla::mpi::RecvBuffer& buf)
+{
+   BaseShape::unpack(buf);
+   buf >> radius_;
+   buf >> axis_;
+}
+
 } //namespace data
 } //namespace mesa_pd
 } //namespace walberla
diff --git a/src/mesa_pd/data/shape/Ellipsoid.h b/src/mesa_pd/data/shape/Ellipsoid.h
index 9a07488e38dc00aafc933f4772a2976de6348dbd..8ff9411852f7f08de766a5409b31cc5e68a05d5d 100644
--- a/src/mesa_pd/data/shape/Ellipsoid.h
+++ b/src/mesa_pd/data/shape/Ellipsoid.h
@@ -31,7 +31,7 @@ namespace data {
 class Ellipsoid : public BaseShape
 {
 public:
-   explicit Ellipsoid(const Vec3& semiAxes)
+   explicit Ellipsoid(const Vec3& semiAxes = Vec3(real_t(1)))
       : BaseShape(Ellipsoid::SHAPE_TYPE)
       , semiAxes_(semiAxes)
    {}
@@ -43,6 +43,9 @@ public:
 
    Vec3 support( const Vec3& d_loc ) const override;
 
+   void pack(walberla::mpi::SendBuffer& buf) override;
+   void unpack(walberla::mpi::RecvBuffer& buf) override;
+
    constexpr static int SHAPE_TYPE = 4; ///< Unique shape type identifier for boxes.\ingroup mesa_pd_shape
 
 private:
@@ -73,6 +76,19 @@ Vec3 Ellipsoid::support( const Vec3& d_loc ) const
    return local_support;
 }
 
+inline
+void Ellipsoid::pack(walberla::mpi::SendBuffer& buf)
+{
+   BaseShape::pack(buf);
+   buf << semiAxes_;
+}
+inline
+void Ellipsoid::unpack(walberla::mpi::RecvBuffer& buf)
+{
+   BaseShape::unpack(buf);
+   buf >> semiAxes_;
+}
+
 } //namespace data
 } //namespace mesa_pd
 } //namespace walberla
diff --git a/src/mesa_pd/data/shape/HalfSpace.h b/src/mesa_pd/data/shape/HalfSpace.h
index d24db7ad1b5fbd359aba714c8e485f035ad623b1..8691938fa11ac570d7a285121c26f343d59e4ca4 100644
--- a/src/mesa_pd/data/shape/HalfSpace.h
+++ b/src/mesa_pd/data/shape/HalfSpace.h
@@ -35,7 +35,9 @@ namespace data {
 class HalfSpace : public BaseShape
 {
 public:
-   explicit HalfSpace(const Vec3& normal) : BaseShape(HalfSpace::SHAPE_TYPE), normal_(normal) { updateMassAndInertia(real_t(1.0)); }
+   explicit HalfSpace(const Vec3& normal = Vec3(real_t(1), real_t(0), real_t(0)))
+      : BaseShape(HalfSpace::SHAPE_TYPE), normal_(normal)
+   { updateMassAndInertia(real_t(1.0)); }
 
    void updateMassAndInertia(const real_t density) override;
 
@@ -43,6 +45,9 @@ public:
 
    const Vec3& getNormal() const { return normal_; }
 
+   void pack(walberla::mpi::SendBuffer& buf) override;
+   void unpack(walberla::mpi::RecvBuffer& buf) override;
+
    constexpr static int SHAPE_TYPE = 0; ///< Unique shape type identifier for planes.\ingroup mesa_pd_shape
 private:
    /**
@@ -63,6 +68,19 @@ void HalfSpace::updateMassAndInertia(const real_t /*density*/)
    invInertiaBF_ = Mat3(real_t(0));
 }
 
+inline
+void HalfSpace::pack(walberla::mpi::SendBuffer& buf)
+{
+   BaseShape::pack(buf);
+   buf << normal_;
+}
+inline
+void HalfSpace::unpack(walberla::mpi::RecvBuffer& buf)
+{
+   BaseShape::unpack(buf);
+   buf >> normal_;
+}
+
 } //namespace data
 } //namespace mesa_pd
 } //namespace walberla
diff --git a/src/mesa_pd/data/shape/Sphere.h b/src/mesa_pd/data/shape/Sphere.h
index 3c24aff0cc87635fcc7b5a7de70c9b957d9d07c7..5192c58b156ff061d9c0f5dd74c14f9d86542635 100644
--- a/src/mesa_pd/data/shape/Sphere.h
+++ b/src/mesa_pd/data/shape/Sphere.h
@@ -31,7 +31,9 @@ namespace data {
 class Sphere : public BaseShape
 {
 public:
-   explicit Sphere(const real_t& radius) : BaseShape(Sphere::SHAPE_TYPE), radius_(radius) {}
+   explicit Sphere(const real_t& radius = real_t(1))
+      : BaseShape(Sphere::SHAPE_TYPE), radius_(radius)
+   {}
 
    const real_t& getRadius() const { return radius_; }
 
@@ -41,6 +43,9 @@ public:
 
    Vec3 support( const Vec3& d ) const override;
 
+   void pack(walberla::mpi::SendBuffer& buf) override;
+   void unpack(walberla::mpi::RecvBuffer& buf) override;
+
    constexpr static int SHAPE_TYPE = 1; ///< Unique shape type identifier for spheres.\ingroup mesa_pd_shape
 
 private:
@@ -66,6 +71,19 @@ Vec3 Sphere::support( const Vec3& d ) const
    return radius_ * d;
 }
 
+inline
+void Sphere::pack(walberla::mpi::SendBuffer& buf)
+{
+   BaseShape::pack(buf);
+   buf << radius_;
+}
+inline
+void Sphere::unpack(walberla::mpi::RecvBuffer& buf)
+{
+   BaseShape::unpack(buf);
+   buf >> radius_;
+}
+
 } //namespace data
 } //namespace mesa_pd
 } //namespace walberla
diff --git a/src/mesa_pd/mpi/ShapePackUnpack.h b/src/mesa_pd/mpi/ShapePackUnpack.h
new file mode 100644
index 0000000000000000000000000000000000000000..0b5ab10e22738c55482d50d36e08a62367014aa3
--- /dev/null
+++ b/src/mesa_pd/mpi/ShapePackUnpack.h
@@ -0,0 +1,91 @@
+//======================================================================================================================
+//
+//  This file is part of waLBerla. waLBerla is free software: you can
+//  redistribute it and/or modify it under the terms of the GNU General Public
+//  License as published by the Free Software Foundation, either version 3 of
+//  the License, or (at your option) any later version.
+//
+//  waLBerla is distributed in the hope that it will be useful, but WITHOUT
+//  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+//  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+//  for more details.
+//
+//  You should have received a copy of the GNU General Public License along
+//  with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file ShapePackUnpack.h
+//! \author Sebastian Eibl <sebastian.eibl@fau.de>
+//
+//======================================================================================================================
+
+//======================================================================================================================
+//
+//  THIS FILE IS GENERATED - PLEASE CHANGE THE TEMPLATE !!!
+//
+//======================================================================================================================
+
+#pragma once
+
+#include <mesa_pd/data/shape/BaseShape.h>
+#include <mesa_pd/data/shape/Sphere.h>
+#include <mesa_pd/data/shape/HalfSpace.h>
+#include <mesa_pd/data/shape/CylindricalBoundary.h>
+#include <mesa_pd/data/shape/Box.h>
+#include <mesa_pd/data/shape/Ellipsoid.h>
+
+#include <core/mpi/RecvBuffer.h>
+#include <core/mpi/SendBuffer.h>
+
+#include <memory>
+
+namespace walberla {
+namespace mpi {
+   template< typename T,    // Element type of SendBuffer
+             typename G>    // Growth policy of SendBuffer
+   mpi::GenericSendBuffer<T,G>& operator<<( mpi::GenericSendBuffer<T,G> & buf,
+                                            const std::shared_ptr<mesa_pd::data::BaseShape>& bs )
+   {
+      buf.addDebugMarker( "up" );
+      buf << bs->getShapeType();
+      bs->pack(buf);
+      return buf;
+   }
+
+   template< typename T>    // Element type  of RecvBuffer
+   mpi::GenericRecvBuffer<T>& operator>>( mpi::GenericRecvBuffer<T> & buf,
+                                          std::shared_ptr<mesa_pd::data::BaseShape>& bs )
+   {
+      using namespace mesa_pd::data;
+
+      buf.readDebugMarker( "up" );
+
+      mesa_pd::data::BaseShape::ShapeTypeT shapeType;
+      buf >> shapeType;
+      switch (shapeType)
+      {
+         case Sphere::SHAPE_TYPE :
+            bs = std::make_unique<mesa_pd::data::Sphere>();
+            bs->unpack(buf);
+            break;
+         case HalfSpace::SHAPE_TYPE :
+            bs = std::make_unique<mesa_pd::data::HalfSpace>();
+            bs->unpack(buf);
+            break;
+         case CylindricalBoundary::SHAPE_TYPE :
+            bs = std::make_unique<mesa_pd::data::CylindricalBoundary>();
+            bs->unpack(buf);
+            break;
+         case Box::SHAPE_TYPE :
+            bs = std::make_unique<mesa_pd::data::Box>();
+            bs->unpack(buf);
+            break;
+         case Ellipsoid::SHAPE_TYPE :
+            bs = std::make_unique<mesa_pd::data::Ellipsoid>();
+            bs->unpack(buf);
+            break;
+         default : WALBERLA_ABORT("Shape type (" << shapeType << ") could not be determined!");
+      }
+      return buf;
+   }
+} //namespace mpi
+} //namespace walberla
\ No newline at end of file
diff --git a/src/mesa_pd/mpi/notifications/ParticleCopyNotification.h b/src/mesa_pd/mpi/notifications/ParticleCopyNotification.h
index e58a0e750a122a40dee8579a59610ab34ae47907..5fdb79680bce3c05a36fc1f3db6b99fd13062939 100644
--- a/src/mesa_pd/mpi/notifications/ParticleCopyNotification.h
+++ b/src/mesa_pd/mpi/notifications/ParticleCopyNotification.h
@@ -28,6 +28,7 @@
 
 #include <mesa_pd/data/DataTypes.h>
 #include <mesa_pd/data/ParticleStorage.h>
+#include <mesa_pd/mpi/ShapePackUnpack.h>
 #include <mesa_pd/mpi/notifications/NotificationType.h>
 
 #include <core/mpi/Datatype.h>
diff --git a/tests/mesa_pd/CMakeLists.txt b/tests/mesa_pd/CMakeLists.txt
index 5555ac9cfdae03f92baf272ed9c59564d6aed5d5..efb7340505f21de934d657d521b833b203fcc261 100644
--- a/tests/mesa_pd/CMakeLists.txt
+++ b/tests/mesa_pd/CMakeLists.txt
@@ -170,6 +170,9 @@ waLBerla_execute_test( NAME   MESA_PD_MPI_ReduceContactHistory PROCESSES 8 )
 waLBerla_compile_test( NAME   MESA_PD_MPI_ReduceProperty FILES mpi/ReduceProperty.cpp DEPENDS core )
 waLBerla_execute_test( NAME   MESA_PD_MPI_ReduceProperty PROCESSES 8 )
 
+waLBerla_compile_test( NAME   MESA_PD_MPI_ShapePackUnpack FILES mpi/ShapePackUnpack.cpp DEPENDS core )
+waLBerla_execute_test( NAME   MESA_PD_MPI_ShapePackUnpack )
+
 waLBerla_compile_test( NAME   MESA_PD_MPI_VelocityCorrectionNotification FILES mpi/VelocityCorrectionNotification.cpp DEPENDS core )
 waLBerla_execute_test( NAME   MESA_PD_MPI_VelocityCorrectionNotification PROCESSES 8)
 
diff --git a/tests/mesa_pd/mpi/ShapePackUnpack.cpp b/tests/mesa_pd/mpi/ShapePackUnpack.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a26177f4896fc66680279ea4e197f72a3025fe34
--- /dev/null
+++ b/tests/mesa_pd/mpi/ShapePackUnpack.cpp
@@ -0,0 +1,207 @@
+//======================================================================================================================
+//
+//  This file is part of waLBerla. waLBerla is free software: you can
+//  redistribute it and/or modify it under the terms of the GNU General Public
+//  License as published by the Free Software Foundation, either version 3 of
+//  the License, or (at your option) any later version.
+//
+//  waLBerla is distributed in the hope that it will be useful, but WITHOUT
+//  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+//  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+//  for more details.
+//
+//  You should have received a copy of the GNU General Public License along
+//  with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file   PackUnpack.cpp
+//! \author Sebastian Eibl <sebastian.eibl@fau.de>
+//
+//======================================================================================================================
+
+#include <mesa_pd/data/shape/Box.h>
+#include <mesa_pd/data/shape/CylindricalBoundary.h>
+#include <mesa_pd/data/shape/Ellipsoid.h>
+#include <mesa_pd/data/shape/HalfSpace.h>
+#include <mesa_pd/data/shape/Sphere.h>
+#include <mesa_pd/mpi/ShapePackUnpack.h>
+
+#include <core/Environment.h>
+#include <core/logging/Logging.h>
+#include <core/mpi/RecvBuffer.h>
+#include <core/mpi/SendBuffer.h>
+
+#include <iostream>
+#include <memory>
+
+namespace walberla {
+
+using namespace walberla::mesa_pd;
+
+void checkBox()
+{
+   using namespace walberla::mpi;
+
+   std::shared_ptr<data::BaseShape> bs0 = std::make_shared<data::Box>(Vec3(real_t(2.53), real_t(4.53), real_t(3.53)));
+   bs0->updateMassAndInertia(real_t(123));
+   std::shared_ptr<data::BaseShape> bs1 = nullptr;
+
+   WALBERLA_LOG_INFO("packing box");
+   SendBuffer sb;
+   sb << bs0;
+   WALBERLA_LOG_INFO("unpacking box");
+   RecvBuffer rb(sb);
+   rb >> bs1;
+
+   WALBERLA_LOG_INFO("checking box");
+   WALBERLA_CHECK_EQUAL(bs0->getShapeType(), data::Box::SHAPE_TYPE);
+   WALBERLA_CHECK_EQUAL(bs1->getShapeType(), data::Box::SHAPE_TYPE);
+   WALBERLA_CHECK_IDENTICAL(bs0->getMass(), bs1->getMass());
+   WALBERLA_CHECK_IDENTICAL(bs0->getInvMass(), bs1->getInvMass());
+   WALBERLA_CHECK_IDENTICAL(bs0->getInertiaBF(), bs1->getInertiaBF());
+   WALBERLA_CHECK_IDENTICAL(bs0->getInvInertiaBF(), bs1->getInvInertiaBF());
+
+   auto bx0 = static_cast<data::Box*> (bs0.get());
+   auto bx1 = static_cast<data::Box*> (bs1.get());
+
+   WALBERLA_CHECK_IDENTICAL(bx0->getEdgeLength(), bx1->getEdgeLength());
+}
+
+void checkCylindricalBoundary()
+{
+   using namespace walberla::mpi;
+
+   std::shared_ptr<data::BaseShape> bs0 = std::make_shared<data::CylindricalBoundary>(real_t(9.99),
+                                                                                      Vec3(real_t(2.53), real_t(4.53), real_t(3.53)).getNormalized());
+   bs0->updateMassAndInertia(real_t(123));
+   std::shared_ptr<data::BaseShape> bs1 = nullptr;
+
+   WALBERLA_LOG_INFO("packing cylindrical boundary");
+   SendBuffer sb;
+   sb << bs0;
+   WALBERLA_LOG_INFO("unpacking cylindrical boundary");
+   RecvBuffer rb(sb);
+   rb >> bs1;
+
+   WALBERLA_LOG_INFO("checking cylindrical boundary");
+   WALBERLA_CHECK_EQUAL(bs0->getShapeType(), data::CylindricalBoundary::SHAPE_TYPE);
+   WALBERLA_CHECK_EQUAL(bs1->getShapeType(), data::CylindricalBoundary::SHAPE_TYPE);
+   WALBERLA_CHECK_IDENTICAL(bs0->getMass(), bs1->getMass());
+   WALBERLA_CHECK_IDENTICAL(bs0->getInvMass(), bs1->getInvMass());
+   WALBERLA_CHECK_IDENTICAL(bs0->getInertiaBF(), bs1->getInertiaBF());
+   WALBERLA_CHECK_IDENTICAL(bs0->getInvInertiaBF(), bs1->getInvInertiaBF());
+
+   auto cb0 = static_cast<data::CylindricalBoundary*> (bs0.get());
+   auto cb1 = static_cast<data::CylindricalBoundary*> (bs1.get());
+
+   WALBERLA_CHECK_IDENTICAL(cb0->getAxis(), cb1->getAxis());
+   WALBERLA_CHECK_IDENTICAL(cb0->getRadius(), cb1->getRadius());
+}
+
+void checkEllipsoid()
+{
+   using namespace walberla::mpi;
+
+   std::shared_ptr<data::BaseShape> bs0 = std::make_shared<data::Ellipsoid>(Vec3(real_t(2.53), real_t(4.53), real_t(3.53)));
+   bs0->updateMassAndInertia(real_t(123));
+   std::shared_ptr<data::BaseShape> bs1 = nullptr;
+
+   WALBERLA_LOG_INFO("packing ellipsoid");
+   SendBuffer sb;
+   sb << bs0;
+   WALBERLA_LOG_INFO("unpacking ellipsoid");
+   RecvBuffer rb(sb);
+   rb >> bs1;
+
+   WALBERLA_LOG_INFO("checking ellipsoid");
+   WALBERLA_CHECK_EQUAL(bs0->getShapeType(), data::Ellipsoid::SHAPE_TYPE);
+   WALBERLA_CHECK_EQUAL(bs1->getShapeType(), data::Ellipsoid::SHAPE_TYPE);
+   WALBERLA_CHECK_IDENTICAL(bs0->getMass(), bs1->getMass());
+   WALBERLA_CHECK_IDENTICAL(bs0->getInvMass(), bs1->getInvMass());
+   WALBERLA_CHECK_IDENTICAL(bs0->getInertiaBF(), bs1->getInertiaBF());
+   WALBERLA_CHECK_IDENTICAL(bs0->getInvInertiaBF(), bs1->getInvInertiaBF());
+
+   auto el0 = static_cast<data::Ellipsoid*> (bs0.get());
+   auto el1 = static_cast<data::Ellipsoid*> (bs1.get());
+
+   WALBERLA_CHECK_IDENTICAL(el0->getSemiAxes(), el1->getSemiAxes());
+}
+
+void checkHalfSpace()
+{
+   using namespace walberla::mpi;
+
+   std::shared_ptr<data::BaseShape> bs0 = std::make_shared<data::HalfSpace>(Vec3(real_t(2.53), real_t(4.53), real_t(3.53)));
+   bs0->updateMassAndInertia(real_t(123));
+   std::shared_ptr<data::BaseShape> bs1 = nullptr;
+
+   WALBERLA_LOG_INFO("packing half space");
+   SendBuffer sb;
+   sb << bs0;
+   WALBERLA_LOG_INFO("unpacking half space");
+   RecvBuffer rb(sb);
+   rb >> bs1;
+
+   WALBERLA_LOG_INFO("checking half space");
+   WALBERLA_CHECK_EQUAL(bs0->getShapeType(), data::HalfSpace::SHAPE_TYPE);
+   WALBERLA_CHECK_EQUAL(bs1->getShapeType(), data::HalfSpace::SHAPE_TYPE);
+//   WALBERLA_CHECK_IDENTICAL(bs0->getMass(), bs1->getMass()); //INF
+   WALBERLA_CHECK_IDENTICAL(bs0->getInvMass(), bs1->getInvMass());
+//   WALBERLA_CHECK_IDENTICAL(bs0->getInertiaBF(), bs1->getInertiaBF()); //INF
+   WALBERLA_CHECK_IDENTICAL(bs0->getInvInertiaBF(), bs1->getInvInertiaBF());
+
+   auto hs0 = static_cast<data::HalfSpace*> (bs0.get());
+   auto hs1 = static_cast<data::HalfSpace*> (bs1.get());
+
+   WALBERLA_CHECK_IDENTICAL(hs0->getNormal(), hs1->getNormal());
+}
+
+void checkSphere()
+{
+   using namespace walberla::mpi;
+
+   std::shared_ptr<data::BaseShape> bs0 = std::make_shared<data::Sphere>(real_t(2.53));
+   bs0->updateMassAndInertia(real_t(123));
+   std::shared_ptr<data::BaseShape> bs1 = nullptr;
+
+   WALBERLA_LOG_INFO("packing sphere");
+   SendBuffer sb;
+   sb << bs0;
+   WALBERLA_LOG_INFO("unpacking sphere");
+   RecvBuffer rb(sb);
+   rb >> bs1;
+
+   WALBERLA_LOG_INFO("checking sphere");
+   WALBERLA_CHECK_EQUAL(bs0->getShapeType(), data::Sphere::SHAPE_TYPE);
+   WALBERLA_CHECK_EQUAL(bs1->getShapeType(), data::Sphere::SHAPE_TYPE);
+   WALBERLA_CHECK_IDENTICAL(bs0->getMass(), bs1->getMass());
+   WALBERLA_CHECK_IDENTICAL(bs0->getInvMass(), bs1->getInvMass());
+   WALBERLA_CHECK_IDENTICAL(bs0->getInertiaBF(), bs1->getInertiaBF());
+   WALBERLA_CHECK_IDENTICAL(bs0->getInvInertiaBF(), bs1->getInvInertiaBF());
+
+   auto sp0 = static_cast<data::Sphere*> (bs0.get());
+   auto sp1 = static_cast<data::Sphere*> (bs1.get());
+
+   WALBERLA_CHECK_IDENTICAL(sp0->getRadius(), sp1->getRadius());
+}
+
+int main( int argc, char ** argv )
+{
+   Environment env(argc, argv);
+   WALBERLA_UNUSED(env);
+   mpi::MPIManager::instance()->useWorldComm();
+
+   checkBox();
+   checkCylindricalBoundary();
+   checkEllipsoid();
+   checkHalfSpace();
+   checkSphere();
+
+   return EXIT_SUCCESS;
+}
+
+} //namespace walberla
+
+int main( int argc, char ** argv )
+{
+   return walberla::main(argc, argv);
+}