diff --git a/src/pe/raytracing/Raytracer.cpp b/src/pe/raytracing/Raytracer.cpp
index 59edeb08d9eb0cabe5ecc329e65adaccef3300ca..cec5c854e6df769154f355ea2daa6bd34459f829 100644
--- a/src/pe/raytracing/Raytracer.cpp
+++ b/src/pe/raytracing/Raytracer.cpp
@@ -30,6 +30,33 @@ real_t deg2rad(real_t deg) {
 namespace walberla {
 namespace pe {
 namespace raytracing {
+   
+void BodyIntersectionInfo_Comparator_MPI_OP( BodyIntersectionInfo_MPI *in, BodyIntersectionInfo_MPI *inout, int *len, MPI_Datatype *dptr) {
+   for (int i = 0; i < *len; i++) {
+      if (in->bodySystemID != 0 && inout->bodySystemID != 0) {
+         /*if (in->imageX != inout->imageX || in->imageY != inout->imageY) {
+            WALBERLA_LOG_INFO("coordinates of infos do not match: " << in->imageX << "/" << in->imageY << " and " << inout->imageX << "/" << inout->imageY << ", bodyIDs: " << in->bodySystemID << ", " << inout->bodySystemID << ", i: " << i);
+         }*/
+         WALBERLA_ASSERT(in->imageX == inout->imageX, "coordinates of infos do not match: " << in->imageX << "/" << in->imageY << " and " << inout->imageX << "/" << inout->imageY << ", bodyIDs: " << in->bodySystemID << ", " << inout->bodySystemID << ", i: " << i);
+         WALBERLA_ASSERT(in->imageY == inout->imageY, "coordinates of infos do not match: " << in->imageX << "/" << in->imageY << " and " << inout->imageX << "/" << inout->imageY << ", bodyIDs: " << in->bodySystemID << ", " << inout->bodySystemID << ", i: " << i);
+      }
+      
+      if ((in->t < inout->t && in->bodySystemID != 0) || (inout->bodySystemID == 0 && in->bodySystemID != 0)) {
+         // info in "in" is closer than the one in "inout" -> update inout to values of in
+         inout->imageX = in->imageX;
+         inout->imageY = in->imageY;
+         inout->bodySystemID = in->bodySystemID;
+         inout->t = in->t;
+         inout->r = in->r;
+         inout->g = in->g;
+         inout->b = in->b;
+      }
+      
+      in++;
+      inout++;
+   }
+}
+   
 /*!\brief Instantiation constructor for the Raytracer class.
  *
  * \param forest BlockForest the raytracer operates on.
@@ -69,6 +96,7 @@ Raytracer::Raytracer(const shared_ptr<BlockStorage> forest, BlockDataID storageI
    
    setupView_();
    setupFilenameRankWidth_();
+   setupMPI_();
 }
 
 /*!\brief Instantiation constructor for the Raytracer class using a config object for view setup.
@@ -125,6 +153,7 @@ Raytracer::Raytracer(const shared_ptr<BlockStorage> forest, BlockDataID storageI
       
    setupView_();
    setupFilenameRankWidth_();
+   setupMPI_();
 }
 
 /*!\brief Utility function for setting up the view plane and calculating required variables.
@@ -153,6 +182,10 @@ void Raytracer::setupFilenameRankWidth_() {
    filenameRankWidth_ = int8_c(log10(numProcesses))+1;
 }
 
+void Raytracer::setupMPI_() {
+   MPI_Op_create((MPI_User_function *)BodyIntersectionInfo_Comparator_MPI_OP, true, &bodyIntersectionInfo_reduction_op);
+}
+   
 /*!\brief Generates the filename for output files.
  * \param base String that precedes the timestap and rank info.
  * \param timestep Timestep this image is from.
diff --git a/src/pe/raytracing/Raytracer.h b/src/pe/raytracing/Raytracer.h
index b53fb5cdbc81058e3bc1a2cc5681e13d2f6ae2b4..fcf960f92c0d066a43d74f1c6af3fbe9fe2270bc 100644
--- a/src/pe/raytracing/Raytracer.h
+++ b/src/pe/raytracing/Raytracer.h
@@ -33,6 +33,11 @@
 #include "Lighting.h"
 #include "ShadingFunctions.h"
 
+#include "core/mpi/MPIManager.h"
+#include "core/mpi/MPIWrapper.h"
+#include "core/mpi/all.h"
+#include <stddef.h>
+
 using namespace walberla;
 using namespace walberla::pe;
 using namespace walberla::timing;
@@ -44,13 +49,23 @@ namespace raytracing {
 /*!\brief Contains information about a ray-body intersection.
  */
 struct BodyIntersectionInfo {
-   size_t imageX;                //!< viewing plane x pixel coordinate the ray belongs to.
-   size_t imageY;                //!< viewing plane y pixel coordinate the ray belongs to.
-   walberla::id_t bodySystemID;  //!< system ID of body which was hit.
-   real_t t;                     //!< distance from camera to intersection point on body.
-   Vec3 color;                   //!< color computed for the pixel.
+   size_t imageX;                //!< Viewing plane x pixel coordinate the ray belongs to.
+   size_t imageY;                //!< Viewing plane y pixel coordinate the ray belongs to.
+   walberla::id_t bodySystemID;  //!< System ID of body which was hit.
+   real_t t;                     //!< Distance from camera to intersection point on body.
+   Vec3 color;                   //!< Color computed for the pixel.
 };
 
+struct BodyIntersectionInfo_MPI {
+   unsigned int imageX;          //!< Viewing plane x pixel coordinate the ray belongs to.   -> MPI_UNSIGNED
+   unsigned int imageY;          //!< Viewing plane y pixel coordinate the ray belongs to.   -> MPI_UNSIGNED
+   walberla::id_t bodySystemID;  //!< System ID of body which was hit.                       -> MPI_UNSIGNED_LONG_LONG
+   double t;                     //!< Distance from camera to intersection point on body.    -> MPI_DOUBLE
+   double r;                     //!< Red value for the pixel.                               -> MPI_DOUBLE
+   double g;                     //!< Green value for the pixel.                             -> MPI_DOUBLE
+   double b;                     //!< Blue value for the pixel.                              -> MPI_DOUBLE
+};
+   
 class Raytracer {
 public:
    /*!\name Constructors */
@@ -119,6 +134,8 @@ private:
    real_t pixelHeight_;       //!< The height of a pixel of the generated image in the viewing plane.
    //@}
    
+   MPI_Op bodyIntersectionInfo_reduction_op;
+   
 public:
    /*!\name Get functions */
    //@{
@@ -155,6 +172,7 @@ public:
    
    void setupView_();
    void setupFilenameRankWidth_();
+   void setupMPI_();
    
 private:
    std::string getOutputFilename(const std::string& base, size_t timestep, bool isGlobalImage) const;
@@ -382,6 +400,9 @@ void Raytracer::rayTrace(const size_t timestep, WcTimingTree* tt) {
    std::vector<Color> imageBuffer(pixelsVertical_ * pixelsHorizontal_);
    std::vector<BodyIntersectionInfo> intersections; // contains for each pixel information about an intersection, if existent
    
+   std::vector<BodyIntersectionInfo_MPI> intersectionsBuffer(pixelsVertical_ * pixelsHorizontal_);
+
+   
    real_t t, t_closest;
    Vec3 n;
    Vec3 n_closest;
@@ -460,7 +481,19 @@ void Raytracer::rayTrace(const size_t timestep, WcTimingTree* tt) {
                t_closest,
                color
             };
+            
+            BodyIntersectionInfo_MPI mpi_intersectionInfo = {
+               static_cast<unsigned int>(x),
+               static_cast<unsigned int>(y),
+               body_closest->getSystemID(),
+               t_closest,
+               color[0],
+               color[1],
+               color[2]
+            };
+            
             intersections.push_back(intersectionInfo);
+            intersectionsBuffer[coordinateToArrayIndex(x, y)] = mpi_intersectionInfo;
          }
          
          tBuffer[coordinateToArrayIndex(x, y)] = t_closest;
@@ -470,7 +503,83 @@ void Raytracer::rayTrace(const size_t timestep, WcTimingTree* tt) {
 
    if (tt != NULL) tt->start("Reduction");
    // intersections synchronisieren
-   mpi::SendBuffer sendBuffer;
+   
+   
+   const int recvRank = 0;
+   int myRank;
+   MPI_Comm_rank( MPI_COMM_WORLD, &myRank );
+   
+   const int nblocks = 7;
+   const int blocklengths[nblocks] = {1,1,1,1,1,1,1};
+   MPI_Datatype types[nblocks] = {
+      MPI_UNSIGNED, // for coordinate
+      MPI_UNSIGNED, // for coordinate
+      MPI_UNSIGNED_LONG_LONG, // for id
+      MPI_DOUBLE, // for distance
+      MPI_DOUBLE, // for color
+      MPI_DOUBLE, // for color
+      MPI_DOUBLE // for color
+   };
+   MPI_Aint displacements[nblocks];
+   displacements[0] = offsetof(BodyIntersectionInfo_MPI, imageX);
+   displacements[1] = offsetof(BodyIntersectionInfo_MPI, imageY);
+   displacements[2] = offsetof(BodyIntersectionInfo_MPI, bodySystemID);
+   displacements[3] = offsetof(BodyIntersectionInfo_MPI, t);
+   displacements[4] = offsetof(BodyIntersectionInfo_MPI, r);
+   displacements[5] = offsetof(BodyIntersectionInfo_MPI, g);
+   displacements[6] = offsetof(BodyIntersectionInfo_MPI, b);
+
+   MPI_Datatype tmp_type;
+   MPI_Type_create_struct(nblocks, blocklengths, displacements, types, &tmp_type);
+   
+   MPI_Aint lb, extent;
+   MPI_Type_get_extent( tmp_type, &lb, &extent );
+   MPI_Datatype mpi_bodyintersection_type;
+   MPI_Type_create_resized( tmp_type, lb, extent, &mpi_bodyintersection_type );
+   
+   MPI_Type_commit(&mpi_bodyintersection_type);
+   
+   /*BodyIntersectionInfo_MPI testInfo = {
+      500, 500,
+      12,
+      real_t(14.323),
+      real_t(14.323),
+      real_t(14.323),
+      real_t(14.323)
+   };
+   
+   if (myRank == recvRank) {
+      BodyIntersectionInfo_MPI testRecInfo;
+      MPI_Recv(&testRecInfo, 1, mpi_bodyintersection_type, 2, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
+      WALBERLA_LOG_INFO("Received info: " << testRecInfo.imageX << ", " << testRecInfo.bodySystemID << ", " << testRecInfo.t);
+   } else if (myRank == 2) {
+      MPI_Send(&testInfo, 1, mpi_bodyintersection_type, recvRank, 0, MPI_COMM_WORLD);
+      WALBERLA_LOG_INFO("Sent info.");
+   }*/
+   
+   if( myRank == recvRank ) {
+      MPI_Reduce(MPI_IN_PLACE,
+                 &intersectionsBuffer[0], int_c(intersectionsBuffer.size()),
+                 mpi_bodyintersection_type, bodyIntersectionInfo_reduction_op,
+                 recvRank, MPI_COMM_WORLD);
+   } else {
+      MPI_Reduce(&intersectionsBuffer[0], 0, int_c(intersectionsBuffer.size()),
+                 mpi_bodyintersection_type, bodyIntersectionInfo_reduction_op,
+                 recvRank, MPI_COMM_WORLD);
+   }
+   
+   if (tt != NULL) tt->stop("Reduction");
+
+   
+   WALBERLA_ROOT_SECTION() {
+      std::vector<Color> fullImageBuffer(pixelsHorizontal_ * pixelsVertical_, backgroundColor_);
+      for (auto& info: intersectionsBuffer) {
+         fullImageBuffer[coordinateToArrayIndex(info.imageX, info.imageY)] = Color(info.r, info.g, info.b);
+      }
+      writeImageBufferToFile(fullImageBuffer, timestep, true);
+   }
+   
+   /*mpi::SendBuffer sendBuffer;
    for (auto& info: intersections) {
       sendBuffer << info.imageX << info.imageY
       << info.bodySystemID << info.t
@@ -526,7 +635,7 @@ void Raytracer::rayTrace(const size_t timestep, WcTimingTree* tt) {
          writeTBufferToFile(fullTBuffer, timestep, true);
       }
    }
-   if (tt != NULL) tt->stop("Output");
+   if (tt != NULL) tt->stop("Output");*/
    if (tt != NULL) tt->stop("Raytracing");
 }