diff --git a/src/blockforest/communication/UniformBufferedScheme.h b/src/blockforest/communication/UniformBufferedScheme.h
index 1abd5a95592d12247a944137679446bf788e9c43..c16a9146dd39bc683fc00cebf52be5dc8eeb0e1d 100644
--- a/src/blockforest/communication/UniformBufferedScheme.h
+++ b/src/blockforest/communication/UniformBufferedScheme.h
@@ -210,7 +210,7 @@ protected:
 template< typename Stencil >
 inline void UniformBufferedScheme<Stencil>::addPackInfo( const PackInfo & packInfo )
 {
-   WALBERLA_ASSERT( !communicationInProgress_ ); // You cannot add PackInfo's while the communication is in progress!
+   WALBERLA_ASSERT( !communicationInProgress_, "Cannot add pack info while communication is in progress");
 
    packInfos_.push_back( packInfo );
    setupBeforeNextCommunication_ = true;
diff --git a/src/core/mpi/BufferSystem.h b/src/core/mpi/BufferSystem.h
index 926a7181ffca5cab7ff418cef67057aef20c2066..2a04730f7e2cbade9c4bf2e8addc612786945234 100644
--- a/src/core/mpi/BufferSystem.h
+++ b/src/core/mpi/BufferSystem.h
@@ -35,7 +35,8 @@
 namespace walberla {
 namespace mpi  {
 
-class OpenMPBufferSystem;
+template< typename RecvBuffer_T, typename SendBuffer_T>
+class GenericOpenMPBufferSystem;
 
 //**********************************************************************************************************************
 /*! Manages MPI Communication with a set of known communication partners.
@@ -106,7 +107,8 @@ class OpenMPBufferSystem;
 *
 */
 //**********************************************************************************************************************
-class BufferSystem
+template< typename RecvBuffer_T = RecvBuffer, typename SendBuffer_T = SendBuffer>
+class GenericBufferSystem
 {
 public:
    class iterator;
@@ -114,10 +116,10 @@ public:
    //**Construction and Destruction*************************************************************************************
    /*!\name Constructors */
    //@{
-   explicit BufferSystem( const MPI_Comm & communicator, int tag = 0 );
-   BufferSystem( const BufferSystem & other );
-   BufferSystem & operator=( const BufferSystem & other );
-   ~BufferSystem() {}
+   explicit GenericBufferSystem( const MPI_Comm & communicator, int tag = 0 );
+   GenericBufferSystem( const GenericBufferSystem & other );
+   GenericBufferSystem & operator=( const GenericBufferSystem & other );
+   ~GenericBufferSystem() {}
    //@}
    //*******************************************************************************************************************
 
@@ -127,7 +129,7 @@ public:
    //@{
    template<typename RankIter> void setReceiverInfo( RankIter begin, RankIter end,              bool changingSize );
    template<typename Range>    void setReceiverInfo( const Range & range,                       bool changingSize );
-                               void setReceiverInfo( const std::set<MPIRank> & ranksToRecvFrom, bool changingSize );
+              void setReceiverInfo( const std::set<MPIRank> & ranksToRecvFrom, bool changingSize );
 
    void setReceiverInfo( const std::map<MPIRank,MPISize> & ranksToRecvFrom );
    void setReceiverInfoFromSendBufferState( bool useSizeFromSendBuffers, bool changingSize );
@@ -142,8 +144,8 @@ public:
    //@{
    void scheduleReceives() { startCommunication(); }
 
-   SendBuffer & sendBuffer ( MPIRank rank );
-   SendBuffer & sendBuffer ( uint_t  rank ) { return sendBuffer( int_c( rank ) ); }
+   SendBuffer_T & sendBuffer ( MPIRank rank );
+   SendBuffer_T & sendBuffer ( uint_t  rank ) { return sendBuffer( int_c( rank ) ); }
    inline size_t size() const;
 
 
@@ -162,22 +164,22 @@ public:
    class iterator
    {
    public:
-      MPIRank      rank()   { return currentSenderRank_;  }
-      RecvBuffer & buffer() { return *currentRecvBuffer_; }
+      MPIRank        rank()   { return currentSenderRank_;  }
+      RecvBuffer_T & buffer() { return *currentRecvBuffer_; }
 
       void operator++();
       bool operator==( const iterator & other );
       bool operator!=( const iterator & other );
 
    private:
-      iterator( BufferSystem & bufferSystem, bool begin );
+      iterator( GenericBufferSystem & bufferSystem, bool begin );
 
-      BufferSystem & bufferSystem_;
+      GenericBufferSystem & bufferSystem_;
 
-      RecvBuffer * currentRecvBuffer_;
-      MPIRank      currentSenderRank_;
+      RecvBuffer_T * currentRecvBuffer_;
+      MPIRank        currentSenderRank_;
 
-      friend class BufferSystem;
+      friend class GenericBufferSystem;
    };
    friend class iterator;
    //@}
@@ -219,17 +221,17 @@ public:
 
 protected:
 
-   friend class OpenMPBufferSystem;
+   friend class GenericOpenMPBufferSystem<RecvBuffer_T, SendBuffer_T>;
 
    void startCommunication();
    void endCommunication();
-   RecvBuffer * waitForNext( MPIRank & fromRank );
+   RecvBuffer_T * waitForNext( MPIRank & fromRank );
    void setCommunicationType( const bool knownSize );
 
-   internal::KnownSizeCommunication   knownSizeComm_;
-   internal::UnknownSizeCommunication unknownSizeComm_;
-   internal::NoMPICommunication       noMPIComm_;
-   internal::AbstractCommunication *  currentComm_;  //< after receiver setup, this points to unknown- or knownSizeComm_
+   internal::KnownSizeCommunication<RecvBuffer_T, SendBuffer_T>   knownSizeComm_;
+   internal::UnknownSizeCommunication<RecvBuffer_T, SendBuffer_T> unknownSizeComm_;
+   internal::NoMPICommunication<RecvBuffer_T, SendBuffer_T>       noMPIComm_;
+   internal::AbstractCommunication<RecvBuffer_T, SendBuffer_T> *  currentComm_;  //< after receiver setup, this points to unknown- or knownSizeComm_
 
    bool sizeChangesEverytime_; //< if set to true, the receiveSizeUnknown_ is set to true before communicating
    bool communicationRunning_; //< indicates if a communication step is currently running
@@ -237,12 +239,12 @@ protected:
 
    /// Info about the message to be received from a certain rank:
    /// information holds the buffer and, if known, the message size
-   std::map<MPIRank, internal::AbstractCommunication::ReceiveInfo> recvInfos_;
+   std::map<MPIRank, typename internal::AbstractCommunication<RecvBuffer_T, SendBuffer_T>::ReceiveInfo> recvInfos_;
 
 
    struct SendInfo {
       SendInfo() : alreadySent(false) {}
-      SendBuffer buffer;
+      SendBuffer_T buffer;
       bool alreadySent;
    };
    std::map<MPIRank, SendInfo> sendInfos_;
@@ -258,55 +260,10 @@ protected:
    int64_t numberOfReceives_ = 0; ///< number of communication partners during last receive
 };
 
-
-
-
-
-
-
-//======================================================================================================================
-//
-//  Template function definitions
-//
-//======================================================================================================================
-
-
-
-template<typename Range>
-void BufferSystem::setReceiverInfo( const Range & range, bool changingSize )
-{
-   setReceiverInfo( range.begin(), range.end(), changingSize );
-}
-
-template<typename RankIter>
-void BufferSystem::setReceiverInfo( RankIter rankBegin, RankIter rankEnd, bool changingSize )
-{
-   WALBERLA_ASSERT( ! communicationRunning_ );
-
-   recvInfos_.clear();
-   for ( auto it = rankBegin; it != rankEnd; ++it )
-   {
-      const MPIRank sender = *it;
-      recvInfos_[ sender ].size = INVALID_SIZE;
-   }
-
-   sizeChangesEverytime_ = changingSize;
-   setCommunicationType( false );
-}
-
-inline size_t BufferSystem::size() const
-{
-   size_t sum = 0;
-   for( auto iter = sendInfos_.begin(); iter != sendInfos_.end(); ++iter )
-   {
-      sum += iter->second.buffer.size();
-   }
-   return sum;
-}
-
-
+typedef GenericBufferSystem<RecvBuffer, SendBuffer> BufferSystem;
 
 } // namespace mpi
 } // namespace walberla
 
+#include "BufferSystem.impl.h"
 
diff --git a/src/core/mpi/BufferSystem.cpp b/src/core/mpi/BufferSystem.impl.h
similarity index 78%
rename from src/core/mpi/BufferSystem.cpp
rename to src/core/mpi/BufferSystem.impl.h
index a6e64b887be17fe5aaf3a91c160c61a2363b8467..852c7a1fac9a14f490917a4340d4fa180d3525c8 100644
--- a/src/core/mpi/BufferSystem.cpp
+++ b/src/core/mpi/BufferSystem.impl.h
@@ -13,13 +13,12 @@
 //  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 BufferSystem.cpp
+//! \file GenericBufferSystem.cpp
 //! \ingroup core
 //! \author Martin Bauer <martin.bauer@fau.de>
 //
 //======================================================================================================================
 
-#include "BufferSystem.h"
 #include "core/logging/Logging.h"
 #include "core/mpi/MPIManager.h"
 #include "core/debug/CheckFunctions.h"
@@ -29,8 +28,9 @@ namespace walberla {
 namespace mpi {
 
 
+template< typename Rb, typename Sb>
+std::set<int> GenericBufferSystem<Rb, Sb>::activeTags_;
 
-std::set<int> BufferSystem::activeTags_;
 
 //======================================================================================================================
 //
@@ -39,16 +39,16 @@ std::set<int> BufferSystem::activeTags_;
 //======================================================================================================================
 
 
-
-BufferSystem::iterator::iterator( BufferSystem & bufferSystem, bool begin )
+template< typename Rb, typename Sb>
+GenericBufferSystem<Rb, Sb>::iterator::iterator( GenericBufferSystem<Rb, Sb> & bufferSystem, bool begin )
     : bufferSystem_( bufferSystem), currentRecvBuffer_( nullptr ), currentSenderRank_( -1 )
 {
    if ( begin ) // init iterator
       ++(*this);
 }
 
-
-void BufferSystem::iterator::operator++()
+template< typename Rb, typename Sb>
+void GenericBufferSystem<Rb, Sb>::iterator::operator++()
 {
    currentRecvBuffer_ = bufferSystem_.waitForNext( currentSenderRank_ );
    if ( ! currentRecvBuffer_ ) {
@@ -60,7 +60,8 @@ void BufferSystem::iterator::operator++()
    }
 }
 
-bool BufferSystem::iterator::operator==( const BufferSystem::iterator & other )
+template< typename Rb, typename Sb>
+bool GenericBufferSystem<Rb, Sb>::iterator::operator==( const typename GenericBufferSystem<Rb, Sb>::iterator & other )
 {
    // only equality checks with end iterators are allowed
    WALBERLA_ASSERT( other.currentSenderRank_ == -1 || currentSenderRank_ == -1 );
@@ -68,7 +69,8 @@ bool BufferSystem::iterator::operator==( const BufferSystem::iterator & other )
    return ( currentSenderRank_ == other.currentSenderRank_ );
 }
 
-bool BufferSystem::iterator::operator!=( const BufferSystem::iterator & other )
+template< typename Rb, typename Sb>
+bool GenericBufferSystem<Rb, Sb>::iterator::operator!=( const typename GenericBufferSystem<Rb, Sb>::iterator & other )
 {
    // only equality checks with end iterators are allowed
    WALBERLA_ASSERT( other.currentSenderRank_ == -1 || currentSenderRank_ == -1 );
@@ -77,6 +79,42 @@ bool BufferSystem::iterator::operator!=( const BufferSystem::iterator & other )
 }
 
 
+template< typename Rb, typename Sb>
+template<typename Range>
+void GenericBufferSystem<Rb, Sb>::setReceiverInfo( const Range & range, bool changingSize )
+{
+   setReceiverInfo( range.begin(), range.end(), changingSize );
+}
+
+template< typename Rb, typename Sb>
+template<typename RankIter>
+void GenericBufferSystem<Rb, Sb>::setReceiverInfo( RankIter rankBegin, RankIter rankEnd, bool changingSize )
+{
+   WALBERLA_ASSERT( ! communicationRunning_ );
+
+   recvInfos_.clear();
+   for ( auto it = rankBegin; it != rankEnd; ++it )
+   {
+      const MPIRank sender = *it;
+      recvInfos_[ sender ].size = INVALID_SIZE;
+   }
+
+   sizeChangesEverytime_ = changingSize;
+   setCommunicationType( false );
+}
+
+template< typename Rb, typename Sb>
+inline size_t GenericBufferSystem<Rb, Sb>::size() const
+{
+   size_t sum = 0;
+   for( auto iter = sendInfos_.begin(); iter != sendInfos_.end(); ++iter )
+   {
+      sum += iter->second.buffer.size();
+   }
+   return sum;
+}
+
+
 
 
 //======================================================================================================================
@@ -85,8 +123,8 @@ bool BufferSystem::iterator::operator!=( const BufferSystem::iterator & other )
 //
 //======================================================================================================================
 
-
-BufferSystem::BufferSystem( const MPI_Comm & communicator, int tag )
+template< typename Rb, typename Sb>
+GenericBufferSystem<Rb, Sb>::GenericBufferSystem( const MPI_Comm & communicator, int tag )
    : knownSizeComm_  ( communicator, tag ),
      unknownSizeComm_( communicator, tag ),
      noMPIComm_( communicator, tag ),
@@ -96,8 +134,8 @@ BufferSystem::BufferSystem( const MPI_Comm & communicator, int tag )
 {
 }
 
-
-BufferSystem::BufferSystem( const BufferSystem &other )
+template< typename Rb, typename Sb>
+GenericBufferSystem<Rb, Sb>::GenericBufferSystem( const GenericBufferSystem &other )
    : knownSizeComm_  ( other.knownSizeComm_.getCommunicator(), other.knownSizeComm_.getTag() ),
      unknownSizeComm_( other.knownSizeComm_.getCommunicator(), other.knownSizeComm_.getTag() ),
      noMPIComm_      ( other.knownSizeComm_.getCommunicator(), other.knownSizeComm_.getTag() ),
@@ -107,7 +145,7 @@ BufferSystem::BufferSystem( const BufferSystem &other )
      recvInfos_( other.recvInfos_ ),
      sendInfos_( other.sendInfos_ )
 {
-   WALBERLA_ASSERT( !communicationRunning_, "Can't copy BufferSystem while communication is running" );
+   WALBERLA_ASSERT( !communicationRunning_, "Can't copy GenericBufferSystem while communication is running" );
    if( other.currentComm_ == &other.knownSizeComm_ )
       currentComm_ = &knownSizeComm_;
    else if ( other.currentComm_ == &other.unknownSizeComm_ )
@@ -118,10 +156,10 @@ BufferSystem::BufferSystem( const BufferSystem &other )
       currentComm_ = nullptr; // receiver information not yet set
 }
 
-
-BufferSystem & BufferSystem::operator=( const BufferSystem & other )
+template< typename Rb, typename Sb>
+GenericBufferSystem<Rb, Sb> & GenericBufferSystem<Rb, Sb>::operator=( const GenericBufferSystem<Rb, Sb> & other )
 {
-   WALBERLA_ASSERT( !communicationRunning_, "Can't copy BufferSystem while communication is running" );
+   WALBERLA_ASSERT( !communicationRunning_, "Can't copy GenericBufferSystem while communication is running" );
 
    sizeChangesEverytime_ = other.sizeChangesEverytime_;
    communicationRunning_ = other.communicationRunning_;
@@ -157,7 +195,8 @@ BufferSystem & BufferSystem::operator=( const BufferSystem & other )
 *                         The behavior can be changed later one using setReceiverInfo() or sizeHasChanged().
 */
 //**********************************************************************************************************************
-void BufferSystem::setReceiverInfo( const std::set<MPIRank> & ranksToRecvFrom, bool changingSize )
+template< typename Rb, typename Sb>
+void GenericBufferSystem<Rb, Sb>::setReceiverInfo( const std::set<MPIRank> & ranksToRecvFrom, bool changingSize )
 {
    WALBERLA_ASSERT( ! communicationRunning_ );
 
@@ -183,7 +222,8 @@ void BufferSystem::setReceiverInfo( const std::set<MPIRank> & ranksToRecvFrom, b
 *                         behavior is changed with setReceiverInfo*() or sizeHasChanged()
 */
 //**********************************************************************************************************************
-void BufferSystem::setReceiverInfo( const std::map<MPIRank,MPISize> & ranksToRecvFrom )
+template< typename Rb, typename Sb>
+void GenericBufferSystem<Rb, Sb>::setReceiverInfo( const std::map<MPIRank,MPISize> & ranksToRecvFrom )
 {
    WALBERLA_ASSERT( ! communicationRunning_ );
 
@@ -205,7 +245,7 @@ void BufferSystem::setReceiverInfo( const std::map<MPIRank,MPISize> & ranksToRec
 //**********************************************************************************************************************
 /*! Sets receiver information, using SendBuffers (symmetric communication)
 *
-* Gives the BufferSystem the information that messages are received from the same processes that we
+* Gives the GenericBufferSystem the information that messages are received from the same processes that we
 * send to (i.e. from all ranks where SendBuffers were already filled )
 * sendBuffer() has to be called before, and corresponding SendBuffers have to be filled.
 *
@@ -220,7 +260,8 @@ void BufferSystem::setReceiverInfo( const std::map<MPIRank,MPISize> & ranksToRec
 *                                communicated in the first step but in all following steps.
 */
 //**********************************************************************************************************************
-void BufferSystem::setReceiverInfoFromSendBufferState( bool useSizeFromSendBuffers, bool changingSize )
+template< typename Rb, typename Sb>
+void GenericBufferSystem<Rb, Sb>::setReceiverInfoFromSendBufferState( bool useSizeFromSendBuffers, bool changingSize )
 {
    WALBERLA_ASSERT( ! communicationRunning_ );
 
@@ -228,7 +269,7 @@ void BufferSystem::setReceiverInfoFromSendBufferState( bool useSizeFromSendBuffe
    for ( auto it = sendInfos_.begin(); it != sendInfos_.end(); ++it )
    {
       const MPIRank sender = it->first;
-      const SendBuffer & buffer = it->second.buffer;
+      const Sb & buffer = it->second.buffer;
 
       if ( buffer.size() == 0 && useSizeFromSendBuffers )
          continue;
@@ -244,16 +285,17 @@ void BufferSystem::setReceiverInfoFromSendBufferState( bool useSizeFromSendBuffe
 
 
 //**********************************************************************************************************************
-/*! Notifies that BufferSystem that message sizes have changed ( and optionally are changing in all following steps)
+/*! Notifies that GenericBufferSystem that message sizes have changed ( and optionally are changing in all following steps)
 *
-* Useful when setReceiverInfo was set such that BufferSystem assumes constant message sizes for all steps.
+* Useful when setReceiverInfo was set such that GenericBufferSystem assumes constant message sizes for all steps.
 * Can only be called if no communication is currently running.
 *
 * \param alwaysChangingSize  if true the message sizes is communicated in all following steps, if false
 *                            only in the next step.
 */
 //**********************************************************************************************************************
-void BufferSystem::sizeHasChanged( bool alwaysChangingSize )
+template< typename Rb, typename Sb>
+void GenericBufferSystem<Rb, Sb>::sizeHasChanged( bool alwaysChangingSize )
 {
    WALBERLA_ASSERT( ! communicationRunning_ );
 
@@ -277,7 +319,8 @@ void BufferSystem::sizeHasChanged( bool alwaysChangingSize )
 * \param rank  the rank where the buffer should be sent to
 */
 //**********************************************************************************************************************
-SendBuffer & BufferSystem::sendBuffer( MPIRank rank )
+template< typename Rb, typename Sb>
+Sb & GenericBufferSystem<Rb, Sb>::sendBuffer( MPIRank rank )
 {
    return sendInfos_[rank].buffer;
 }
@@ -295,7 +338,8 @@ SendBuffer & BufferSystem::sendBuffer( MPIRank rank )
 * If communication was not started before, it is started with this function.
 */
 //**********************************************************************************************************************
-void BufferSystem::sendAll()
+template< typename Rb, typename Sb>
+void GenericBufferSystem<Rb, Sb>::sendAll()
 {
    WALBERLA_ASSERT_NOT_NULLPTR( currentComm_ ); // call setReceiverInfo first!
 
@@ -327,7 +371,8 @@ void BufferSystem::sendAll()
 * If communication was not started before, it is started with this function.
 */
 //**********************************************************************************************************************
-void BufferSystem::send( MPIRank rank )
+template< typename Rb, typename Sb>
+void GenericBufferSystem<Rb, Sb>::send( MPIRank rank )
 {
    WALBERLA_ASSERT_NOT_NULLPTR( currentComm_ ); // call setReceiverInfo first!
 
@@ -363,7 +408,8 @@ void BufferSystem::send( MPIRank rank )
 * - schedules receives and reserves space for MPI_Request vectors in the currentComm_ member
 */
 //**********************************************************************************************************************
-void BufferSystem::startCommunication()
+template< typename Rb, typename Sb>
+void GenericBufferSystem<Rb, Sb>::startCommunication()
 {
    const auto tag = currentComm_->getTag();
    WALBERLA_CHECK_EQUAL(activeTags_.find(tag), activeTags_.end(),
@@ -392,7 +438,8 @@ void BufferSystem::startCommunication()
 * - manage sizeChangesEverytime
 */
 //**********************************************************************************************************************
-void BufferSystem::endCommunication()
+template< typename Rb, typename Sb>
+void GenericBufferSystem<Rb, Sb>::endCommunication()
 {
    WALBERLA_CHECK( communicationRunning_ );
    currentComm_->waitForSends();
@@ -426,7 +473,8 @@ void BufferSystem::endCommunication()
 *  See documentation of AbstractCommunication::waitForNext()
 */
 //**********************************************************************************************************************
-RecvBuffer * BufferSystem::waitForNext( MPIRank & fromRank )
+template< typename Rb, typename Sb>
+Rb * GenericBufferSystem<Rb, Sb>::waitForNext( MPIRank & fromRank )
 {
    WALBERLA_ASSERT( communicationRunning_ );
 
@@ -448,7 +496,8 @@ RecvBuffer * BufferSystem::waitForNext( MPIRank & fromRank )
 /*! Sets the communication type to known size, unknown size or NoMPI comm
 */
 //**********************************************************************************************************************
-void BufferSystem::setCommunicationType( const bool knownSize )
+template< typename Rb, typename Sb>
+void GenericBufferSystem<Rb, Sb>::setCommunicationType( const bool knownSize )
 {
    WALBERLA_NON_MPI_SECTION()
    {
@@ -473,36 +522,36 @@ void BufferSystem::setCommunicationType( const bool knownSize )
 
 // using boost::counting_range didn't work on all supported compilers
 // so the range is created explicitly
-
-BufferSystem::RankRange BufferSystem::noRanks()
+template< typename Rb, typename Sb>
+typename GenericBufferSystem<Rb, Sb>::RankRange GenericBufferSystem<Rb,Sb>::noRanks()
 {
    return RankRange ( RankCountIter( 0 ),
                       RankCountIter( 0 ) );
 }
-
-BufferSystem::RankRange BufferSystem::allRanks()
+template< typename Rb, typename Sb>
+typename GenericBufferSystem<Rb, Sb>::RankRange GenericBufferSystem<Rb,Sb>::allRanks()
 {
    int numProcesses = MPIManager::instance()->numProcesses();
    return RankRange ( RankCountIter( 0            ),
                       RankCountIter( numProcesses ) );
 }
-
-BufferSystem::RankRange BufferSystem::allRanksButRoot()
+template< typename Rb, typename Sb>
+typename GenericBufferSystem<Rb, Sb>::RankRange GenericBufferSystem<Rb,Sb>::allRanksButRoot()
 {
    int numProcesses = MPIManager::instance()->numProcesses();
    return RankRange ( RankCountIter( 1            ),
                       RankCountIter( numProcesses ) );
 }
-
-BufferSystem::RankRange BufferSystem::onlyRank( int includedRank )
+template< typename Rb, typename Sb>
+typename GenericBufferSystem<Rb, Sb>::RankRange GenericBufferSystem<Rb,Sb>::onlyRank( int includedRank )
 {
    WALBERLA_ASSERT_LESS( includedRank, MPIManager::instance()->numProcesses() );
    return RankRange ( RankCountIter( includedRank   ),
                       RankCountIter( includedRank+1 ) );
 }
 
-
-BufferSystem::RankRange BufferSystem::onlyRoot()
+template< typename Rb, typename Sb>
+typename GenericBufferSystem<Rb, Sb>::RankRange GenericBufferSystem<Rb,Sb>::onlyRoot()
 {
    return RankRange ( RankCountIter( 0 ),
                       RankCountIter( 1 ) );
diff --git a/src/core/mpi/BufferSystemHelper.h b/src/core/mpi/BufferSystemHelper.h
index b8e7a29286eb786ad7d738bb3bbc72c5955e77eb..e143f6b10fba7ad99d4d687750a14b40f2123ce1 100644
--- a/src/core/mpi/BufferSystemHelper.h
+++ b/src/core/mpi/BufferSystemHelper.h
@@ -35,6 +35,7 @@ namespace walberla {
 namespace mpi {
 namespace internal {
 
+   template< typename RecvBuffer_T, typename SendBuffer_T>
    class AbstractCommunication
    {
    public:
@@ -46,7 +47,7 @@ namespace internal {
 
 
       struct ReceiveInfo {
-         RecvBuffer buffer;
+         RecvBuffer_T buffer;
          MPISize size;
       };
 
@@ -54,7 +55,7 @@ namespace internal {
       /*************************************************************************************************************//**
       * Send buffer content to receiver using MPI_ISend, request is stored internally -> see waitForSends()
       *****************************************************************************************************************/
-      virtual void send( MPIRank rank, const SendBuffer & sendBuffer ) = 0;
+      virtual void send( MPIRank rank, const SendBuffer_T & sendBuffer ) = 0;
 
 
       /*************************************************************************************************************//**
@@ -100,16 +101,18 @@ namespace internal {
    };
 
 
-
-   class KnownSizeCommunication : public AbstractCommunication
+   template< typename RecvBuffer_T, typename SendBuffer_T>
+   class KnownSizeCommunication : public AbstractCommunication<RecvBuffer_T, SendBuffer_T>
    {
    public:
+      using typename AbstractCommunication<RecvBuffer_T, SendBuffer_T>::ReceiveInfo;
+
       KnownSizeCommunication( const MPI_Comm & communicator, int tag = 0 )
-           : AbstractCommunication( communicator, tag ), sending_(false), receiving_(false) {}
+           : AbstractCommunication<RecvBuffer_T, SendBuffer_T>( communicator, tag ), sending_(false), receiving_(false) {}
 
       virtual ~KnownSizeCommunication() {}
 
-      virtual void send( MPIRank receiver, const SendBuffer & sendBuffer );
+      virtual void send( MPIRank receiver, const SendBuffer_T & sendBuffer );
       virtual void waitForSends();
 
       virtual void    scheduleReceives  ( std::map<MPIRank, ReceiveInfo> & recvInfos );
@@ -126,16 +129,18 @@ namespace internal {
    };
 
 
-
-   class UnknownSizeCommunication : public AbstractCommunication
+   template< typename RecvBuffer_T, typename SendBuffer_T>
+   class UnknownSizeCommunication : public AbstractCommunication<RecvBuffer_T, SendBuffer_T>
    {
    public:
+      using typename AbstractCommunication<RecvBuffer_T, SendBuffer_T>::ReceiveInfo;
+
       UnknownSizeCommunication( const MPI_Comm & communicator, int tag = 0 )
-           :  AbstractCommunication( communicator, tag ), sending_(false), receiving_(false) {}
+           :  AbstractCommunication<RecvBuffer_T, SendBuffer_T>( communicator, tag ), sending_(false), receiving_(false) {}
 
       virtual ~UnknownSizeCommunication() {}
 
-      virtual void send( MPIRank receiver, const SendBuffer & sendBuffer );
+      virtual void send( MPIRank receiver, const SendBuffer_T & sendBuffer );
       virtual void waitForSends();
 
       virtual void scheduleReceives( std::map<MPIRank, ReceiveInfo> & recvInfos );
@@ -156,16 +161,18 @@ namespace internal {
    };
 
 
-
-   class NoMPICommunication : public AbstractCommunication
+   template< typename RecvBuffer_T, typename SendBuffer_T>
+   class NoMPICommunication : public AbstractCommunication<RecvBuffer_T, SendBuffer_T>
    {
    public:
+      using typename AbstractCommunication<RecvBuffer_T, SendBuffer_T>::ReceiveInfo;
+
       NoMPICommunication( const MPI_Comm & communicator, int tag = 0 )
-         : AbstractCommunication( communicator, tag ), received_( false ) {}
+         : AbstractCommunication<RecvBuffer_T, SendBuffer_T>( communicator, tag ), received_( false ) {}
 
       virtual ~NoMPICommunication() {}
 
-      virtual void send( MPIRank receiver, const SendBuffer & sendBuffer );
+      virtual void send( MPIRank receiver, const SendBuffer_T & sendBuffer );
       virtual void waitForSends();
 
       virtual void scheduleReceives( std::map<MPIRank, ReceiveInfo> & recvInfos );
@@ -174,8 +181,8 @@ namespace internal {
       virtual MPIRank waitForNextReceive( std::map<MPIRank, ReceiveInfo> & recvInfos );
 
    private:
-      bool       received_;
-      RecvBuffer tmpBuffer_;
+      bool         received_;
+      RecvBuffer_T tmpBuffer_;
    };
 
 
@@ -184,4 +191,4 @@ namespace internal {
 } // namespace mpi
 } // namespace walberla
 
-
+#include "BufferSystemHelper.impl.h"
diff --git a/src/core/mpi/BufferSystemHelper.cpp b/src/core/mpi/BufferSystemHelper.impl.h
similarity index 83%
rename from src/core/mpi/BufferSystemHelper.cpp
rename to src/core/mpi/BufferSystemHelper.impl.h
index 8f8e510dcb5e85220b60c56101e27b0c897f35ca..f982aab6894e9aff58579f8875598caa11180cee 100644
--- a/src/core/mpi/BufferSystemHelper.cpp
+++ b/src/core/mpi/BufferSystemHelper.impl.h
@@ -37,8 +37,8 @@ namespace internal {
 //
 //======================================================================================================================
 
-
-void KnownSizeCommunication::send( MPIRank receiver, const SendBuffer & sendBuffer )
+template< typename Rb, typename Sb>
+void KnownSizeCommunication<Rb, Sb>::send( MPIRank receiver, const Sb & sendBuffer )
 {
    WALBERLA_NON_MPI_SECTION() { WALBERLA_ASSERT( false ); }
 
@@ -51,15 +51,15 @@ void KnownSizeCommunication::send( MPIRank receiver, const SendBuffer & sendBuff
               int_c(sendBuffer.size() ), // send one size
               MPI_BYTE,                  // type
               receiver,                  // receiver rank
-              tag_,                      // message tag
-              communicator_,             // communicator
+              this->tag_,                // message tag
+              this->communicator_,       // communicator
               &request                   // request needed for wait
               );
 }
 
 
-
-void KnownSizeCommunication::waitForSends( )
+template< typename Rb, typename Sb>
+void KnownSizeCommunication<Rb, Sb>::waitForSends( )
 {
    WALBERLA_NON_MPI_SECTION() { WALBERLA_ASSERT( false ); }
 
@@ -76,8 +76,8 @@ void KnownSizeCommunication::waitForSends( )
 }
 
 
-
-void KnownSizeCommunication::scheduleReceives( std::map<MPIRank, ReceiveInfo> & recvInfos )
+template< typename Rb, typename Sb>
+void KnownSizeCommunication<Rb, Sb>::scheduleReceives( std::map<MPIRank, ReceiveInfo> & recvInfos )
 {
    WALBERLA_NON_MPI_SECTION() { WALBERLA_ASSERT( false ); }
 
@@ -101,8 +101,8 @@ void KnownSizeCommunication::scheduleReceives( std::map<MPIRank, ReceiveInfo> &
                  recvInfo.size,             // size of expected message
                  MPI_BYTE,                  // type
                  senderRank,                // rank of sender process
-                 tag_,                      // message tag
-                 communicator_,             // communicator
+                 this->tag_,                // message tag
+                 this->communicator_,       // communicator
                  & recvRequests_[recvCount] // request, needed for wait
                  );
 
@@ -115,7 +115,8 @@ void KnownSizeCommunication::scheduleReceives( std::map<MPIRank, ReceiveInfo> &
 }
 
 
-MPIRank KnownSizeCommunication::waitForNextReceive( std::map<MPIRank, ReceiveInfo> & recvInfos )
+template< typename Rb, typename Sb>
+MPIRank KnownSizeCommunication<Rb, Sb>::waitForNextReceive( std::map<MPIRank, ReceiveInfo> & recvInfos )
 {
    WALBERLA_NON_MPI_SECTION() { WALBERLA_ASSERT( false ); }
 
@@ -170,8 +171,8 @@ MPIRank KnownSizeCommunication::waitForNextReceive( std::map<MPIRank, ReceiveInf
 //
 //======================================================================================================================
 
-
-void UnknownSizeCommunication::send( MPIRank receiver, const SendBuffer & sendBuffer )
+template< typename Rb, typename Sb>
+void UnknownSizeCommunication<Rb, Sb>::send( MPIRank receiver, const Sb & sendBuffer )
 {
    WALBERLA_NON_MPI_SECTION() { WALBERLA_ASSERT( false ); }
 
@@ -190,8 +191,8 @@ void UnknownSizeCommunication::send( MPIRank receiver, const SendBuffer & sendBu
              1,                         // one integer is sent
              MPITrait<MPISize>::type(), // type
              receiver,                  // receiver rank
-             tag_,                      // message tag
-             communicator_,             // communicator
+             this->tag_,                // message tag
+             this->communicator_,       // communicator
              & sizeMsgReq               // request needed for wait
              );
 
@@ -205,13 +206,14 @@ void UnknownSizeCommunication::send( MPIRank receiver, const SendBuffer & sendBu
              int_c( sendBuffer.size() ), // send one size
              MPI_BYTE,                   // type
              receiver,                   // receiver rank
-             tag_,                       // message tag
-             communicator_,              // communicator
+             this->tag_,                 // message tag
+             this->communicator_,        // communicator
              & contentMsgReq             // request needed for wait
              );
 }
 
-void UnknownSizeCommunication::waitForSends()
+template< typename Rb, typename Sb>
+void UnknownSizeCommunication<Rb, Sb>::waitForSends()
 {
    WALBERLA_NON_MPI_SECTION() { WALBERLA_ASSERT( false ); }
 
@@ -228,7 +230,8 @@ void UnknownSizeCommunication::waitForSends()
    outgoingBufferForSizes_.clear();
 }
 
-void UnknownSizeCommunication::scheduleReceives( std::map<MPIRank, ReceiveInfo> & recvInfos )
+template< typename Rb, typename Sb>
+void UnknownSizeCommunication<Rb, Sb>::scheduleReceives( std::map<MPIRank, ReceiveInfo> & recvInfos )
 {
    WALBERLA_NON_MPI_SECTION() { WALBERLA_ASSERT( false ); }
 
@@ -250,8 +253,8 @@ void UnknownSizeCommunication::scheduleReceives( std::map<MPIRank, ReceiveInfo>
                  1,                          // size of expected message
                  MPITrait<MPISize>::type(),  // type
                  sender,                     // rank of sender process
-                 tag_,                       // message tag
-                 communicator_,              // communicator
+                 this->tag_,                 // message tag
+                 this->communicator_,        // communicator
                  & recvRequests_[recvCount]  // request, needed for wait
                  );
 
@@ -261,7 +264,8 @@ void UnknownSizeCommunication::scheduleReceives( std::map<MPIRank, ReceiveInfo>
 }
 
 
-MPIRank UnknownSizeCommunication::waitForNextReceive( std::map<MPIRank, ReceiveInfo> & recvInfos )
+template< typename Rb, typename Sb>
+MPIRank UnknownSizeCommunication<Rb, Sb>::waitForNextReceive( std::map<MPIRank, ReceiveInfo> & recvInfos )
 {
    WALBERLA_NON_MPI_SECTION() { WALBERLA_ASSERT( false ); }
 
@@ -322,8 +326,8 @@ MPIRank UnknownSizeCommunication::waitForNextReceive( std::map<MPIRank, ReceiveI
                     recvInfo.size,                // size of expected message
                     MPI_BYTE,                     // type
                     senderRank,                   // rank of sender process
-                    tag_,                         // message tag
-                    communicator_,                // communicator
+                    this->tag_,                   // message tag
+                    this->communicator_,          // communicator
                     & recvRequests_[ uint_c( requestIndex ) ] // request, needed for wait
                     );
 
@@ -351,8 +355,8 @@ MPIRank UnknownSizeCommunication::waitForNextReceive( std::map<MPIRank, ReceiveI
 //
 //======================================================================================================================
 
-
-void NoMPICommunication::send( MPIRank receiver, const SendBuffer & sendBuffer )
+template< typename Rb, typename Sb>
+void NoMPICommunication<Rb, Sb>::send( MPIRank receiver, const Sb & sendBuffer )
 {
    WALBERLA_UNUSED( receiver);
 
@@ -361,12 +365,14 @@ void NoMPICommunication::send( MPIRank receiver, const SendBuffer & sendBuffer )
    received_ = false;
 }
 
-void NoMPICommunication::waitForSends()
+template< typename Rb, typename Sb>
+void NoMPICommunication<Rb, Sb>::waitForSends()
 {
    return;
 }
 
-void NoMPICommunication::scheduleReceives( std::map<MPIRank, ReceiveInfo> & recvInfos )
+template< typename Rb, typename Sb>
+void NoMPICommunication<Rb, Sb>::scheduleReceives( std::map<MPIRank, ReceiveInfo> & recvInfos )
 {
    WALBERLA_DEBUG_SECTION()
    {
@@ -380,7 +386,8 @@ void NoMPICommunication::scheduleReceives( std::map<MPIRank, ReceiveInfo> & recv
 }
 
 
-MPIRank NoMPICommunication::waitForNextReceive( std::map<MPIRank, ReceiveInfo> & recvInfos )
+template< typename Rb, typename Sb>
+MPIRank NoMPICommunication<Rb, Sb>::waitForNextReceive( std::map<MPIRank, ReceiveInfo> & recvInfos )
 {
    if( recvInfos.empty() )
    {
diff --git a/src/core/mpi/OpenMPBufferSystem.h b/src/core/mpi/OpenMPBufferSystem.h
index 3a41f36f0615a1aa2cd244f494438faee1d740a9..232f54f42a6dbe4037c4b2c8f2d7f02b98773bcb 100644
--- a/src/core/mpi/OpenMPBufferSystem.h
+++ b/src/core/mpi/OpenMPBufferSystem.h
@@ -44,12 +44,13 @@ namespace mpi {
 * for the systems: the tag can be passed in the constructor.
 */
 //**********************************************************************************************************************
-class OpenMPBufferSystem
+template< typename RecvBuffer_T, typename SendBuffer_T>
+class GenericOpenMPBufferSystem
 {
 public:
 
-   OpenMPBufferSystem( const MPI_Comm & communicator, int tag = 0,
-                       bool _serialSends = false, bool _serialRecvs = false );
+   GenericOpenMPBufferSystem( const MPI_Comm & communicator, int tag = 0,
+                              bool _serialSends = false, bool _serialRecvs = false );
 
 
    void enforceSerialSends( bool val ) { serialSends_ = val; }
@@ -60,8 +61,8 @@ public:
 
    bool isSizeCommunicatedInNextStep() const          { return bs_.isSizeCommunicatedInNextStep(); }
 
-   void addReceivingFunction( MPIRank rank, const std::function<void ( RecvBuffer & buf ) >& recvFunction );
-   void addSendingFunction  ( MPIRank rank, const std::function<void ( SendBuffer & buf ) >& sendFunction );
+   void addReceivingFunction( MPIRank rank, const std::function<void ( RecvBuffer_T & buf ) >& recvFunction );
+   void addSendingFunction  ( MPIRank rank, const std::function<void ( SendBuffer_T & buf ) >& sendFunction );
 
    void clearReceivingFunctions() { dirty_ = true; recvFunctions_.clear(); }
    void clearSendingFunctions()   { dirty_ = true; sendFunctions_.clear(); sendRanks_.clear(); }
@@ -75,7 +76,7 @@ public:
 
 
 private:
-   BufferSystem bs_;
+   GenericBufferSystem<RecvBuffer_T, SendBuffer_T> bs_;
 
    bool dirty_;
 
@@ -86,11 +87,11 @@ private:
 
    bool sizeChangesEverytime_;
 
-   std::map<MPIRank, std::function<void ( RecvBuffer & )> > recvFunctions_;
+   std::map<MPIRank, std::function<void ( RecvBuffer_T & )> > recvFunctions_;
 
 
    std::vector<MPIRank> sendRanks_;
-   std::vector< std::function<void ( SendBuffer & )> > sendFunctions_;
+   std::vector< std::function<void ( SendBuffer_T & )> > sendFunctions_;
 
    void startCommunicationOpenMP();
    void startCommunicationSerial();
@@ -99,7 +100,10 @@ private:
    void waitSerial();
 };
 
+typedef GenericOpenMPBufferSystem<RecvBuffer, SendBuffer> OpenMPBufferSystem;
 
 
 } // namespace mpi
 } // namespace walberla
+
+#include "OpenMPBufferSystem.impl.h"
\ No newline at end of file
diff --git a/src/core/mpi/OpenMPBufferSystem.cpp b/src/core/mpi/OpenMPBufferSystem.impl.h
similarity index 81%
rename from src/core/mpi/OpenMPBufferSystem.cpp
rename to src/core/mpi/OpenMPBufferSystem.impl.h
index 45a614eb42b87451d40418ef59e46a7b79f1815e..c79b961ba0b0deaf0a8af506fc508e80715900cb 100644
--- a/src/core/mpi/OpenMPBufferSystem.cpp
+++ b/src/core/mpi/OpenMPBufferSystem.impl.h
@@ -19,8 +19,6 @@
 //
 //======================================================================================================================
 
-#include "OpenMPBufferSystem.h"
-
 #include <boost/range/adaptor/map.hpp>
 
 
@@ -35,9 +33,9 @@ namespace mpi {
 //
 //======================================================================================================================
 
-
-OpenMPBufferSystem::OpenMPBufferSystem( const MPI_Comm & communicator, int tag,
-                                        bool _serialSends, bool _serialRecvs  )
+template<typename Rb, typename Sb>
+GenericOpenMPBufferSystem<Rb, Sb>::GenericOpenMPBufferSystem( const MPI_Comm & communicator, int tag,
+                                                              bool _serialSends, bool _serialRecvs  )
    : bs_( communicator, tag),
      dirty_( true ),
      serialSends_( _serialSends ),
@@ -47,14 +45,16 @@ OpenMPBufferSystem::OpenMPBufferSystem( const MPI_Comm & communicator, int tag,
 }
 
 
-void OpenMPBufferSystem::addReceivingFunction( MPIRank rank, const std::function<void ( RecvBuffer & buf ) >& recvFunction )
+template<typename Rb, typename Sb>
+void GenericOpenMPBufferSystem<Rb, Sb>::addReceivingFunction( MPIRank rank, const std::function<void ( Rb & buf ) >& recvFunction )
 {
    dirty_ = true;
    recvFunctions_[rank] = recvFunction;
 }
 
 
-void OpenMPBufferSystem::addSendingFunction  ( MPIRank rank, const std::function<void ( SendBuffer & buf ) >& sendFunction )
+template<typename Rb, typename Sb>
+void GenericOpenMPBufferSystem<Rb, Sb>::addSendingFunction( MPIRank rank, const std::function<void ( Sb & buf ) >& sendFunction )
 {
    dirty_ = true;
    sendRanks_.push_back( rank );
@@ -63,7 +63,8 @@ void OpenMPBufferSystem::addSendingFunction  ( MPIRank rank, const std::function
 }
 
 
-void OpenMPBufferSystem::setupBufferSystem()
+template<typename Rb, typename Sb>
+void GenericOpenMPBufferSystem<Rb, Sb>::setupBufferSystem()
 {
    if ( ! dirty_ )
       return;
@@ -85,7 +86,8 @@ void OpenMPBufferSystem::setupBufferSystem()
 //======================================================================================================================
 
 
-void OpenMPBufferSystem::startCommunication()
+template<typename Rb, typename Sb>
+void GenericOpenMPBufferSystem<Rb, Sb>::startCommunication()
 {
    setupBufferSystem();
    if( serialSends_ )
@@ -94,7 +96,8 @@ void OpenMPBufferSystem::startCommunication()
       startCommunicationOpenMP();
 }
 
-void OpenMPBufferSystem::startCommunicationSerial()
+template<typename Rb, typename Sb>
+void GenericOpenMPBufferSystem<Rb, Sb>::startCommunicationSerial()
 {
    bs_.scheduleReceives();
 
@@ -114,7 +117,8 @@ void OpenMPBufferSystem::startCommunicationSerial()
    bs_.sendAll(); // for the case where sendFunctions_ is empty
 }
 
-void OpenMPBufferSystem::startCommunicationOpenMP()
+template<typename Rb, typename Sb>
+void GenericOpenMPBufferSystem<Rb, Sb>::startCommunicationOpenMP()
 {
    bs_.scheduleReceives();
 
@@ -150,8 +154,8 @@ void OpenMPBufferSystem::startCommunicationOpenMP()
 //
 //======================================================================================================================
 
-
-void OpenMPBufferSystem::wait()
+template<typename Rb, typename Sb>
+void GenericOpenMPBufferSystem<Rb, Sb>::wait()
 {
    if ( serialRecvs_ )
       waitSerial();
@@ -160,7 +164,8 @@ void OpenMPBufferSystem::wait()
 }
 
 
-void OpenMPBufferSystem::waitSerial()
+template<typename Rb, typename Sb>
+void GenericOpenMPBufferSystem<Rb, Sb>::waitSerial()
 {
    for( auto recvIt = bs_.begin(); recvIt != bs_.end(); ++recvIt )
    {
@@ -174,7 +179,8 @@ void OpenMPBufferSystem::waitSerial()
 }
 
 
-void OpenMPBufferSystem::waitOpenMP()
+template<typename Rb, typename Sb>
+void GenericOpenMPBufferSystem<Rb, Sb>::waitOpenMP()
 {
    const int numReceives = int_c( bs_.recvInfos_.size() );