diff --git a/apps/tutorials/pe/02_ConfinedGasExtended.cpp b/apps/tutorials/pe/02_ConfinedGasExtended.cpp
index 01dd2c625c127ccdac6f0662be89bb9e26274cd0..b4d166a25f4f8ebc8d86cd83e2604755d90144be 100644
--- a/apps/tutorials/pe/02_ConfinedGasExtended.cpp
+++ b/apps/tutorials/pe/02_ConfinedGasExtended.cpp
@@ -149,7 +149,7 @@ int main( int argc, char ** argv )
    if (cfg == NULL) {
       WALBERLA_ABORT("raytracer needs a working config");
    }
-   Raytracer raytracer(forest, storageID, globalBodyStorage, cfg->getBlock("Raytracing"));
+   Raytracer raytracer(forest, storageID, globalBodyStorage, ccdID, cfg->getBlock("Raytracing"));
    
    WALBERLA_LOG_INFO_ON_ROOT("*** INTEGRATOR ***");
    cr::HCSITS cr(globalBodyStorage, forest, storageID, ccdID, fcdID);
diff --git a/src/pe/raytracing/Raytracer.cpp b/src/pe/raytracing/Raytracer.cpp
index 59edeb08d9eb0cabe5ecc329e65adaccef3300ca..9c76af29b8832e07689ee336fef4842e8a2d7e1e 100644
--- a/src/pe/raytracing/Raytracer.cpp
+++ b/src/pe/raytracing/Raytracer.cpp
@@ -45,8 +45,9 @@ namespace raytracing {
  *                                     Set it to the value of the farthest distance a object might protrude from
  *                                     its containing block.
  */
-Raytracer::Raytracer(const shared_ptr<BlockStorage> forest, BlockDataID storageID,
+Raytracer::Raytracer(const shared_ptr<BlockStorage> forest, const BlockDataID storageID,
                      const shared_ptr<BodyStorage> globalBodyStorage,
+                     const BlockDataID ccdID,
                      uint16_t pixelsHorizontal, uint16_t pixelsVertical,
                      real_t fov_vertical,
                      const Vec3& cameraPosition, const Vec3& lookAtPoint, const Vec3& upVector,
@@ -54,7 +55,7 @@ Raytracer::Raytracer(const shared_ptr<BlockStorage> forest, BlockDataID storageI
                      const Color& backgroundColor,
                      real_t blockAABBIntersectionPadding,
                      std::function<ShadingParameters (const BodyID)> bodyToShadingParamsFunction)
-   : forest_(forest), storageID_(storageID), globalBodyStorage_(globalBodyStorage),
+   : forest_(forest), storageID_(storageID), globalBodyStorage_(globalBodyStorage), ccdID_(ccdID),
    pixelsHorizontal_(pixelsHorizontal), pixelsVertical_(pixelsVertical),
    fov_vertical_(fov_vertical),
    cameraPosition_(cameraPosition), lookAtPoint_(lookAtPoint), upVector_(upVector),
@@ -85,11 +86,12 @@ Raytracer::Raytracer(const shared_ptr<BlockStorage> forest, BlockDataID storageI
  * local_image_output_enabled (bool) to true. outputFilenameTimestepZeroPadding (int) sets zero padding for timesteps of output filenames.
  * For the lighting a config block named Lighting has to be defined, information about its contents is in Lighting.h.
  */
-Raytracer::Raytracer(const shared_ptr<BlockStorage> forest, BlockDataID storageID,
+Raytracer::Raytracer(const shared_ptr<BlockStorage> forest, const BlockDataID storageID,
                      const shared_ptr<BodyStorage> globalBodyStorage,
+                     const BlockDataID ccdID,
                      const Config::BlockHandle& config,
                      std::function<ShadingParameters (const BodyID)> bodyToShadingParamsFunction)
-   : forest_(forest), storageID_(storageID), globalBodyStorage_(globalBodyStorage),
+   : forest_(forest), storageID_(storageID), globalBodyStorage_(globalBodyStorage), ccdID_(ccdID),
    bodyToShadingParamsFunction_(bodyToShadingParamsFunction) {
    WALBERLA_CHECK(config.isValid(), "No valid config passed to raytracer");
    
diff --git a/src/pe/raytracing/Raytracer.h b/src/pe/raytracing/Raytracer.h
index b53fb5cdbc81058e3bc1a2cc5681e13d2f6ae2b4..1c845024ff6db1a6440d75bd92c5450db23b2221 100644
--- a/src/pe/raytracing/Raytracer.h
+++ b/src/pe/raytracing/Raytracer.h
@@ -32,6 +32,8 @@
 #include "Intersects.h"
 #include "Lighting.h"
 #include "ShadingFunctions.h"
+#include "pe/ccd/ICCD.h"
+#include <pe/ccd/HashGrids.h>
 
 using namespace walberla;
 using namespace walberla::pe;
@@ -55,8 +57,9 @@ class Raytracer {
 public:
    /*!\name Constructors */
    //@{
-   explicit Raytracer(const shared_ptr<BlockStorage> forest, BlockDataID storageID,
+   explicit Raytracer(const shared_ptr<BlockStorage> forest, const BlockDataID storageID,
                       const shared_ptr<BodyStorage> globalBodyStorage,
+                      const BlockDataID ccdID,
                       uint16_t pixelsHorizontal, uint16_t pixelsVertical,
                       real_t fov_vertical,
                       const Vec3& cameraPosition, const Vec3& lookAtPoint, const Vec3& upVector,
@@ -64,8 +67,9 @@ public:
                       const Color& backgroundColor = Color(0.1, 0.1, 0.1),
                       real_t blockAABBIntersectionPadding = real_t(0.0),
                       std::function<ShadingParameters (const BodyID)> bodyToShadingParamsFunction = defaultBodyTypeDependentShadingParams);
-   explicit Raytracer(const shared_ptr<BlockStorage> forest, BlockDataID storageID,
+   explicit Raytracer(const shared_ptr<BlockStorage> forest, const BlockDataID storageID,
                       const shared_ptr<BodyStorage> globalBodyStorage,
+                      const BlockDataID ccdID,
                       const Config::BlockHandle& config,
                       std::function<ShadingParameters (const BodyID)> bodyToShadingParamsFunction = defaultBodyTypeDependentShadingParams);
    //@}
@@ -74,8 +78,9 @@ private:
    /*!\name Member variables */
    //@{
    const shared_ptr<BlockStorage> forest_; //!< The BlockForest the raytracer operates on.
-   BlockDataID storageID_;    //!< The storage ID of the block data storage the raytracer operates on.
+   const BlockDataID storageID_;    //!< The storage ID of the block data storage the raytracer operates on.
    const shared_ptr<BodyStorage> globalBodyStorage_; //!< The global body storage the raytracer operates on.
+   const BlockDataID ccdID_;  //!< The ID of the hash grids block data.
    
    uint16_t pixelsHorizontal_;  //!< The horizontal amount of pixels of the generated image.
    uint16_t pixelsVertical_;    //!< The vertical amount of pixels of the generated image.
@@ -382,6 +387,11 @@ 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
    
+   for (auto blockIt = forest_->begin(); blockIt != forest_->end(); ++blockIt) {
+      ccd::HashGrids* ccd = blockIt->getData<ccd::HashGrids>(ccdID_);
+      ccd->update();
+   }
+   
    real_t t, t_closest;
    Vec3 n;
    Vec3 n_closest;
@@ -406,6 +416,16 @@ void Raytracer::rayTrace(const size_t timestep, WcTimingTree* tt) {
                continue;
             }
 #endif
+#ifndef DISABLE_RAYTRACING_USING_HASHGRIDS
+            ccd::HashGrids* ccd = blockIt->getData<ccd::HashGrids>(ccdID_);
+            BodyID body = ccd->getClosestBodyIntersectingWithRay<BodyTypeTuple>(ray, blockAabb, t, n);
+            
+            if (body != NULL) {
+               t_closest = t;
+               body_closest = body;
+               n_closest = n;
+            }
+#else
             for (auto bodyIt = LocalBodyIterator::begin(*blockIt, storageID_); bodyIt != LocalBodyIterator::end(); ++bodyIt) {
                if (bodyIt->getTypeID() == Plane::getStaticTypeID()) {
                   PlaneID plane = (Plane*)(*bodyIt);
@@ -423,6 +443,7 @@ void Raytracer::rayTrace(const size_t timestep, WcTimingTree* tt) {
                   n_closest = n;
                }
             }
+#endif
          }
          
          int i = 0;
diff --git a/tests/pe/Raytracing.cpp b/tests/pe/Raytracing.cpp
index 67369067907929ed8ccfb6a8083fc0493e326ad2..f30b86980adafb6bf440c67d4dc85e00b450b179 100644
--- a/tests/pe/Raytracing.cpp
+++ b/tests/pe/Raytracing.cpp
@@ -233,11 +233,13 @@ void RaytracerTest() {
    shared_ptr<BodyStorage> globalBodyStorage = make_shared<BodyStorage>();
    shared_ptr<BlockForest> forest = createBlockForest(AABB(0,0,0,10,10,10), Vec3(1,1,1), Vec3(false, false, false));
    auto storageID = forest->addBlockData(createStorageDataHandling<BodyTuple>(), "Storage");
+   auto ccdID = forest->addBlockData(ccd::createHashGridsDataHandling( globalBodyStorage, storageID ), "CCD");
+
    Lighting lighting(Vec3(0, 5, 8), // 8, 5, 9.5 gut für ebenen, 0,5,8
                      Color(1, 1, 1), //diffuse
                      Color(1, 1, 1), //specular
                      Color(0.4, 0.4, 0.4)); //ambient
-   Raytracer raytracer(forest, storageID, globalBodyStorage,
+   Raytracer raytracer(forest, storageID, globalBodyStorage, ccdID,
                        size_t(640), size_t(480),
                        49.13,
                        Vec3(-5,5,5), Vec3(-1,5,5), Vec3(0,0,1), //-5,5,5; -1,5,5
@@ -333,11 +335,13 @@ void RaytracerSpheresTest() {
    shared_ptr<BodyStorage> globalBodyStorage = make_shared<BodyStorage>();
    shared_ptr<BlockForest> forest = createBlockForest(AABB(0,0,0,10,10,10), Vec3(1,1,1), Vec3(false, false, false));
    auto storageID = forest->addBlockData(createStorageDataHandling<BodyTuple>(), "Storage");
+   auto ccdID = forest->addBlockData(ccd::createHashGridsDataHandling( globalBodyStorage, storageID ), "CCD");
+
    Lighting lighting(Vec3(0, 5, 8), // 8, 5, 9.5 gut für ebenen, 0,5,8
                      Color(1, 1, 1), //diffuse
                      Color(1, 1, 1), //specular
                      Color(0.4, 0.4, 0.4)); //ambient
-   Raytracer raytracer(forest, storageID, globalBodyStorage,
+   Raytracer raytracer(forest, storageID, globalBodyStorage, ccdID,
                        size_t(640), size_t(480),
                        49.13,
                        Vec3(-5,5,5), Vec3(-1,5,5), Vec3(0,0,1), //-5,5,5; -1,5,5
@@ -537,7 +541,7 @@ void HashGridsTest() {
    BodyID closestBody_hashgrids_first = NULL;
    real_t t_closest_hashgrids_first = inf;
    
-   int i = 0;
+   /*int i = 0;
    for (const Ray& ray: rays) {
       WALBERLA_LOG_INFO("RAY " << i << ": " << ray.getOrigin() << ", " << ray.getDirection() << " ----");
 
@@ -586,7 +590,7 @@ void HashGridsTest() {
       
       //WALBERLA_CHECK(closestBody_naive == closestBody_allpossible && closestBody_naive == closestBody_first,
       //               "Different intersection methods dont match");
-      */
+      *----/
       
       // -- using hashgrids and only until closest body found
       
@@ -609,36 +613,68 @@ void HashGridsTest() {
 
       WALBERLA_LOG_INFO("RAY " << i << " end. ----");
       i++;
-   }
-
+   }*/
+   
    WcTimingTree tt;
    tt.start("Hashgrids Loop");
    Ray ray(Vec3(0, 0, -7), Vec3(1, 0, 0));
 
-   int rays_x = 1000;
-   int rays_y = 1000;
+   int rays_x = 100;
+   int rays_y = 100;
+   
+   std::vector<BodyID> hashgridsBodyBuffer(uint_c(rays_x*rays_y));
+   std::vector<real_t> hashgridstBuffer(uint_c(rays_x*rays_y));
 
    for (int x = 0; x < rays_x; ++x) {
       for (int y = 0; y < rays_y; ++y) {
          Vec3 dir = (Vec3(-4+8*real_t(x)/real_t(rays_x), -4+8*real_t(y)/real_t(rays_y), 4) - ray.getOrigin()).getNormalized();
          ray.setDirection(dir);
          closestBody_hashgrids_first = hashGrids.getClosestBodyIntersectingWithRay<BodyTuple>(ray, blockAABB, t_closest_hashgrids_first, n);
+         hashgridsBodyBuffer[uint_c(y*rays_x+x)] = closestBody_hashgrids_first;
+         hashgridstBuffer[uint_c(y*rays_x+x)] = t_closest_hashgrids_first;
       }
    }
    tt.stop("Hashgrids Loop");
 
-   /*tt.start("Naive Loop");
+   int errors = 0;
+   
+   tt.start("Naive Loop");
    IntersectsFunctor naiveIntersectsFunc(ray, t, n);
    for (int x = 0; x < rays_x; ++x) {
       for (int y = 0; y < rays_y; ++y) {
          Vec3 dir = (Vec3(-4+8*real_t(x)/real_t(rays_x), -4+8*real_t(y)/real_t(rays_y), 4) - ray.getOrigin()).getNormalized();
          ray.setDirection(dir);
+         
+         t_closest_naive = inf;
+         closestBody_naive = NULL;
+         
          for (const BodyID& body: bodies) {
-            SingleCast<BodyTuple, IntersectsFunctor, bool>::execute(body, naiveIntersectsFunc);
+            bool intersects = SingleCast<BodyTuple, IntersectsFunctor, bool>::execute(body, naiveIntersectsFunc);
+            if (intersects && t < t_closest_naive) {
+               closestBody_naive = body;
+               t_closest_naive = t;
+            }
+         }
+         
+         if (hashgridsBodyBuffer[uint_c(y*rays_x+x)] != closestBody_naive) {
+            WALBERLA_LOG_INFO("Hashgrid and naive intersections dont match up at " << x << "/" << y);
+            WALBERLA_LOG_INFO(" " << t_closest_naive << " != " << hashgridstBuffer[uint_c(y*rays_x+x)]);
+            if (closestBody_naive != NULL) {
+               WALBERLA_LOG_INFO(" naive body:     " << closestBody_naive->getID() << " minCorner: "
+                                 << closestBody_naive->getAABB().minCorner());
+            }
+            if (hashgridsBodyBuffer[uint_c(y*rays_x+x)] != NULL) {
+               WALBERLA_LOG_INFO(" hashgrids body: " << hashgridsBodyBuffer[uint_c(y*rays_x+x)]->getID() << " minCorner: "
+                                 << hashgridsBodyBuffer[uint_c(y*rays_x+x)]->getAABB().minCorner());
+            }
+            //WALBERLA_LOG_INFO(" " << closestBody_naive << " != " << hashgridsBodyBuffer[y*rays_x+x]);
+            errors++;
          }
       }
    }
-   tt.stop("Naive Loop");*/
+   tt.stop("Naive Loop");
+   
+   WALBERLA_LOG_INFO("errors: " << errors);
    
    auto temp = tt.getReduced( );
    WALBERLA_ROOT_SECTION()