diff --git a/CMakeLists.txt b/CMakeLists.txt
index a0a46ed652ed3b586e56af163a749a86edf3c5be..03ed97b484e3cd3fc53d73d2ad0247f12503ea9c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -16,7 +16,7 @@ project(VirtualFluids CXX)
 
 set(CMAKE_BUILD_TYPE Release)
 
-set(CMAKE_CXX_STANDARD 14)
+set(CMAKE_CXX_STANDARD 17)
 set(CMAKE_CXX_STANDARD_REQUIRED ON)
 
 set_property(GLOBAL PROPERTY USE_FOLDERS ON)
diff --git a/apps/gpu/DiluteGravityCurrents_Case1/DiluteGravityCurrents_Case1.cpp b/apps/gpu/DiluteGravityCurrents_Case1/DiluteGravityCurrents_Case1.cpp
index 6473af944693e24440ce68137344d359f6c2e2df..838b2ccd5de9d89626ea8c61bf92592743a7ccba 100644
--- a/apps/gpu/DiluteGravityCurrents_Case1/DiluteGravityCurrents_Case1.cpp
+++ b/apps/gpu/DiluteGravityCurrents_Case1/DiluteGravityCurrents_Case1.cpp
@@ -100,9 +100,7 @@ int main(int argc, char *argv[])
         // setup gridGenerator
         //////////////////////////////////////////////////////////////////////////
 
-        auto gridFactory = GridFactory::make();
-        gridFactory->setGridStrategy(Device::CPU);
-        auto gridBuilder = MultipleGridBuilder::makeShared(gridFactory);
+        auto gridBuilder = MultipleGridBuilder::makeShared();
 
         //////////////////////////////////////////////////////////////////////////
         // create grid
diff --git a/apps/gpu/DiluteGravityCurrents_Case2/DiluteGravityCurrents_Case2.cpp b/apps/gpu/DiluteGravityCurrents_Case2/DiluteGravityCurrents_Case2.cpp
index f0400a718ff17fe0fbb2f6edcea7997e9bf4f151..dcbb47c4b811434f10c6546e2c7b8ad2f829e6ae 100644
--- a/apps/gpu/DiluteGravityCurrents_Case2/DiluteGravityCurrents_Case2.cpp
+++ b/apps/gpu/DiluteGravityCurrents_Case2/DiluteGravityCurrents_Case2.cpp
@@ -100,9 +100,7 @@ int main(int argc, char *argv[])
         // setup gridGenerator
         //////////////////////////////////////////////////////////////////////////
 
-        auto gridFactory = GridFactory::make();
-        gridFactory->setGridStrategy(Device::CPU);
-        auto gridBuilder = MultipleGridBuilder::makeShared(gridFactory);
+        auto gridBuilder = MultipleGridBuilder::makeShared();
 
         //////////////////////////////////////////////////////////////////////////
         // create grid
diff --git a/apps/gpu/DiluteGravityCurrents_Case3/DiluteGravityCurrents_Case3.cpp b/apps/gpu/DiluteGravityCurrents_Case3/DiluteGravityCurrents_Case3.cpp
index d452efdecabe07e730926d62efbd6af4f0bec555..e77d5f6ebc497bb8bd77a65cac6c6219c85ab5cc 100644
--- a/apps/gpu/DiluteGravityCurrents_Case3/DiluteGravityCurrents_Case3.cpp
+++ b/apps/gpu/DiluteGravityCurrents_Case3/DiluteGravityCurrents_Case3.cpp
@@ -100,9 +100,7 @@ int main(int argc, char *argv[])
         // setup gridGenerator
         //////////////////////////////////////////////////////////////////////////
 
-        auto gridFactory = GridFactory::make();
-        gridFactory->setGridStrategy(Device::CPU);
-        auto gridBuilder = MultipleGridBuilder::makeShared(gridFactory);
+        auto gridBuilder = MultipleGridBuilder::makeShared();
 
         //////////////////////////////////////////////////////////////////////////
         // create grid
diff --git a/apps/gpu/DiluteGravityCurrents_Case4/DiluteGravityCurrents_Case4.cpp b/apps/gpu/DiluteGravityCurrents_Case4/DiluteGravityCurrents_Case4.cpp
index 96ea163ea10c201eeb7270bdc24f06317e29d129..7427aa9b7887e3645819a692f952f0e8320a81a1 100644
--- a/apps/gpu/DiluteGravityCurrents_Case4/DiluteGravityCurrents_Case4.cpp
+++ b/apps/gpu/DiluteGravityCurrents_Case4/DiluteGravityCurrents_Case4.cpp
@@ -100,9 +100,7 @@ int main(int argc, char *argv[])
         // setup gridGenerator
         //////////////////////////////////////////////////////////////////////////
 
-        auto gridFactory = GridFactory::make();
-        gridFactory->setGridStrategy(Device::CPU);
-        auto gridBuilder = MultipleGridBuilder::makeShared(gridFactory);
+        auto gridBuilder = MultipleGridBuilder::makeShared();
 
         //////////////////////////////////////////////////////////////////////////
         // create grid
diff --git a/apps/gpu/DiluteGravityCurrents_Case5/DiluteGravityCurrents_Case5.cpp b/apps/gpu/DiluteGravityCurrents_Case5/DiluteGravityCurrents_Case5.cpp
index 849f1b35b3288c53f5c4925a2451dae083e0ef8d..9df9da2872112537b905fafc3f7275dfd6cb0430 100644
--- a/apps/gpu/DiluteGravityCurrents_Case5/DiluteGravityCurrents_Case5.cpp
+++ b/apps/gpu/DiluteGravityCurrents_Case5/DiluteGravityCurrents_Case5.cpp
@@ -100,9 +100,7 @@ int main(int argc, char *argv[])
         // setup gridGenerator
         //////////////////////////////////////////////////////////////////////////
 
-        auto gridFactory = GridFactory::make();
-        gridFactory->setGridStrategy(Device::CPU);
-        auto gridBuilder = MultipleGridBuilder::makeShared(gridFactory);
+        auto gridBuilder = MultipleGridBuilder::makeShared();
 
         //////////////////////////////////////////////////////////////////////////
         // create grid
diff --git a/apps/gpu/DiluteGravityCurrents_Case6/DiluteGravityCurrents_Case6.cpp b/apps/gpu/DiluteGravityCurrents_Case6/DiluteGravityCurrents_Case6.cpp
index 751928fca4de3038e8532cc8c020a522492606ee..f1c8aa5c20d7bf987d0282c6e03b66a1ce3f89e2 100644
--- a/apps/gpu/DiluteGravityCurrents_Case6/DiluteGravityCurrents_Case6.cpp
+++ b/apps/gpu/DiluteGravityCurrents_Case6/DiluteGravityCurrents_Case6.cpp
@@ -100,9 +100,7 @@ int main(int argc, char *argv[])
         // setup gridGenerator
         //////////////////////////////////////////////////////////////////////////
 
-        auto gridFactory = GridFactory::make();
-        gridFactory->setGridStrategy(Device::CPU);
-        auto gridBuilder = MultipleGridBuilder::makeShared(gridFactory);
+        auto gridBuilder = MultipleGridBuilder::makeShared();
 
         //////////////////////////////////////////////////////////////////////////
         // create grid
diff --git a/apps/gpu/DiluteGravityCurrents_Case7/DiluteGravityCurrents_Case7.cpp b/apps/gpu/DiluteGravityCurrents_Case7/DiluteGravityCurrents_Case7.cpp
index a6ac0ebb4a109889acbf6f7f4107a78c1e346c47..d6d4684369c03c90c63c02ae85ddfc2d5d88da89 100644
--- a/apps/gpu/DiluteGravityCurrents_Case7/DiluteGravityCurrents_Case7.cpp
+++ b/apps/gpu/DiluteGravityCurrents_Case7/DiluteGravityCurrents_Case7.cpp
@@ -100,9 +100,7 @@ int main(int argc, char *argv[])
         // setup gridGenerator
         //////////////////////////////////////////////////////////////////////////
 
-        auto gridFactory = GridFactory::make();
-        gridFactory->setGridStrategy(Device::CPU);
-        auto gridBuilder = MultipleGridBuilder::makeShared(gridFactory);
+        auto gridBuilder = MultipleGridBuilder::makeShared();
 
         //////////////////////////////////////////////////////////////////////////
         // create grid
diff --git a/apps/gpu/DiluteGravityCurrents_Case8/DiluteGravityCurrents_Case8.cpp b/apps/gpu/DiluteGravityCurrents_Case8/DiluteGravityCurrents_Case8.cpp
index 94c0d76ef5ec2ffb0ac3c6cf2556913ed4b9db92..09459acd8ca78d37501c68ada334a98a6fc4a525 100644
--- a/apps/gpu/DiluteGravityCurrents_Case8/DiluteGravityCurrents_Case8.cpp
+++ b/apps/gpu/DiluteGravityCurrents_Case8/DiluteGravityCurrents_Case8.cpp
@@ -100,9 +100,7 @@ int main(int argc, char *argv[])
         // setup gridGenerator
         //////////////////////////////////////////////////////////////////////////
 
-        auto gridFactory = GridFactory::make();
-        gridFactory->setGridStrategy(Device::CPU);
-        auto gridBuilder = MultipleGridBuilder::makeShared(gridFactory);
+        auto gridBuilder = MultipleGridBuilder::makeShared();
 
         //////////////////////////////////////////////////////////////////////////
         // create grid
diff --git a/apps/gpu/LidDrivenCavityGPU/LidDrivenCavity.cpp b/apps/gpu/LidDrivenCavityGPU/LidDrivenCavity.cpp
index 86b6f5f4a1176de85e689d6573a34667e0c74d47..a4fcec0f36e2c36b1fd90148b31a50fc998a8d26 100644
--- a/apps/gpu/LidDrivenCavityGPU/LidDrivenCavity.cpp
+++ b/apps/gpu/LidDrivenCavityGPU/LidDrivenCavity.cpp
@@ -94,7 +94,7 @@ int main(int argc, char *argv[])
         //////////////////////////////////////////////////////////////////////////
         // Simulation parameters
         //////////////////////////////////////////////////////////////////////////
-        std::string path("./output");
+        std::string path("D:/out/DrivenCavity");
         std::string simulationName("LidDrivenCavity");
 
         const real L        = 1.0;
@@ -123,9 +123,7 @@ int main(int argc, char *argv[])
         // setup gridGenerator
         //////////////////////////////////////////////////////////////////////////
 
-        auto gridFactory = GridFactory::make();
-        gridFactory->setGridStrategy(Device::CPU);
-        auto gridBuilder = MultipleGridBuilder::makeShared(gridFactory);
+        auto gridBuilder = MultipleGridBuilder::makeShared();
 
         //////////////////////////////////////////////////////////////////////////
         // create grid
diff --git a/src/basics/Core/ArrayTypes.h b/src/basics/Core/ArrayTypes.h
index 7d5d70374b04d7ad29a6443fbcac0263fd8d0ad6..f899c92a7be4f29065b55b13fb1a1181da0eaf7e 100644
--- a/src/basics/Core/ArrayTypes.h
+++ b/src/basics/Core/ArrayTypes.h
@@ -1,3 +1,35 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file ArrayTypes.h
+//! \ingroup Core
+//! \author Konstantin Kutscher, Soeren Textor, Sebastian Geller
+//=======================================================================================
 #ifndef ARRAYTYPES_H
 #define ARRAYTYPES_H
 
diff --git a/src/basics/Core/DataTypes.h b/src/basics/Core/DataTypes.h
index 49d269097b76cdf3ad350ed0cd65d72e6310d849..36fd33aaa0587382ce322c06b46bbb7cd0cdd8d0 100644
--- a/src/basics/Core/DataTypes.h
+++ b/src/basics/Core/DataTypes.h
@@ -1,3 +1,35 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file DataTypes.h
+//! \ingroup Core
+//! \author Soeren Peters
+//=======================================================================================
 #ifndef DATATYPES_H
 #define DATATYPES_H
 
diff --git a/src/basics/Core/Input/ConfigData/ConfigData.h b/src/basics/Core/Input/ConfigData/ConfigData.h
deleted file mode 100644
index 44d50557608817bff889ba9aa4316861d8ce2bca..0000000000000000000000000000000000000000
--- a/src/basics/Core/Input/ConfigData/ConfigData.h
+++ /dev/null
@@ -1,185 +0,0 @@
-#ifndef CONFIGDATA_H
-#define CONFIGDATA_H
-
-#include "../../DataTypes.h"
-
-#include <memory>
-#include <vector>
-
-class ConfigData
-{
-public:
-    virtual ~ConfigData() = default;
-
-    virtual real getViscosity()                              = 0;
-    virtual uint getNumberOfDevices()                        = 0;
-    virtual std::vector<uint> getDevices()                   = 0;
-    virtual std::string getOutputPath()                      = 0;
-    virtual std::string getPrefix()                          = 0;
-    virtual std::string getGridPath()                        = 0;
-    virtual bool getPrintOutputFiles()                       = 0;
-    virtual bool getGeometryValues()                         = 0;
-    virtual bool getCalc2ndOrderMoments()                    = 0;
-    virtual bool getCalc3rdOrderMoments()                    = 0;
-    virtual bool getCalcHighOrderMoments()                   = 0;
-    virtual bool getReadGeo()                                = 0;
-    virtual bool getCalcMedian()                             = 0;
-    virtual bool getCalcDragLift()                           = 0;
-    virtual bool getCalcCp()                                 = 0;
-    virtual bool getWriteVeloASCIIfiles()                    = 0;
-    virtual bool getCalcPlaneConc()                          = 0;
-    virtual bool getConcFile()                               = 0;
-    virtual bool getStreetVelocityFile()                     = 0;
-    virtual bool getUseMeasurePoints()                       = 0;
-    virtual bool getUseWale()                                = 0;
-    virtual bool getUseInitNeq()                             = 0;
-    virtual bool getSimulatePorousMedia()                    = 0;
-    virtual uint getD3Qxx()                                  = 0;
-    virtual uint getTEnd()                                   = 0;
-    virtual uint getTOut()                                   = 0;
-    virtual uint getTStartOut()                              = 0;
-    virtual uint getTimeCalcMedStart()                       = 0;
-    virtual uint getTimeCalcMedEnd()                         = 0;
-    virtual uint getPressInID()                              = 0;
-    virtual uint getPressOutID()                             = 0;
-    virtual uint getPressInZ()                               = 0;
-    virtual uint getPressOutZ()                              = 0;
-    virtual bool getDiffOn()                                 = 0;
-    virtual uint getDiffMod()                                = 0;
-    virtual real getDiffusivity()                            = 0;
-    virtual real getTemperatureInit()                        = 0;
-    virtual real getTemperatureBC()                          = 0;
-    virtual real getVelocity()                               = 0;
-    virtual real getViscosityRatio()                         = 0;
-    virtual real getVelocityRatio()                          = 0;
-    virtual real getDensityRatio()                           = 0;
-    virtual real getPressRatio()                             = 0;
-    virtual real getRealX()                                  = 0;
-    virtual real getRealY()                                  = 0;
-    virtual real getFactorPressBC()                          = 0;
-    virtual std::string getGeometryFileC()                   = 0;
-    virtual std::string getGeometryFileM()                   = 0;
-    virtual std::string getGeometryFileF()                   = 0;
-    virtual uint getClockCycleForMP()                        = 0;
-    virtual uint getTimestepForMP()                          = 0;
-    virtual real getForcingX()                               = 0;
-    virtual real getForcingY()                               = 0;
-    virtual real getForcingZ()                               = 0;
-    virtual real getQuadricLimiterP()                        = 0;
-    virtual real getQuadricLimiterM()                        = 0;
-    virtual real getQuadricLimiterD()                        = 0;
-    virtual bool getCalcParticles()                          = 0;
-    virtual int getParticleBasicLevel()                      = 0;
-    virtual int getParticleInitLevel()                       = 0;
-    virtual int getNumberOfParticles()                       = 0;
-    virtual real getStartXHotWall()                          = 0;
-    virtual real getEndXHotWall()                            = 0;
-    virtual std::vector<std::string> getPossNeighborFilesX() = 0;
-    virtual std::vector<std::string> getPossNeighborFilesY() = 0;
-    virtual std::vector<std::string> getPossNeighborFilesZ() = 0;
-    // virtual std::vector<std::string> getPossNeighborFilesX() = 0;
-    // virtual std::vector<std::string> getPossNeighborFilesY() = 0;
-    // virtual std::vector<std::string> getPossNeighborFilesZ() = 0;
-    virtual int getTimeDoCheckPoint()                     = 0;
-    virtual int getTimeDoRestart()                        = 0;
-    virtual bool getDoCheckPoint()                        = 0;
-    virtual bool getDoRestart()                           = 0;
-    virtual uint getMaxLevel()                            = 0;
-    virtual std::vector<int> getGridX()                   = 0;
-    virtual std::vector<int> getGridY()                   = 0;
-    virtual std::vector<int> getGridZ()                   = 0;
-    virtual std::vector<int> getDistX()                   = 0;
-    virtual std::vector<int> getDistY()                   = 0;
-    virtual std::vector<int> getDistZ()                   = 0;
-    virtual std::vector<bool> getNeedInterface()          = 0;
-    virtual std::string getMainKernel()                   = 0;
-    virtual bool getMultiKernelOn()                       = 0;
-    virtual std::vector<int> getMultiKernelLevel()        = 0;
-    virtual std::vector<std::string> getMultiKernelName() = 0;
-
-    virtual bool isViscosityInConfigFile()            = 0;
-    virtual bool isNumberOfDevicesInConfigFile()      = 0;
-    virtual bool isDevicesInConfigFile()              = 0;
-    virtual bool isOutputPathInConfigFile()           = 0;
-    virtual bool isPrefixInConfigFile()               = 0;
-    virtual bool isGridPathInConfigFile()             = 0;
-    virtual bool isPrintOutputFilesInConfigFile()     = 0;
-    virtual bool isGeometryValuesInConfigFile()       = 0;
-    virtual bool isCalc2ndOrderMomentsInConfigFile()  = 0;
-    virtual bool isCalc3rdOrderMomentsInConfigFile()  = 0;
-    virtual bool isCalcHighOrderMomentsInConfigFile() = 0;
-    virtual bool isReadGeoInConfigFile()              = 0;
-    virtual bool isCalcMedianInConfigFile()           = 0;
-    virtual bool isCalcDragLiftInConfigFile()         = 0;
-    virtual bool isCalcCpInConfigFile()               = 0;
-    virtual bool isWriteVeloASCIIfilesInConfigFile()  = 0;
-    virtual bool isCalcPlaneConcInConfigFile()        = 0;
-    virtual bool isConcFileInConfigFile()             = 0;
-    virtual bool isStreetVelocityFileInConfigFile()   = 0;
-    virtual bool isUseMeasurePointsInConfigFile()     = 0;
-    virtual bool isUseWaleInConfigFile()              = 0;
-    virtual bool isUseInitNeqInConfigFile()           = 0;
-    virtual bool isSimulatePorousMediaInConfigFile()  = 0;
-    virtual bool isD3QxxInConfigFile()                = 0;
-    virtual bool isTEndInConfigFile()                 = 0;
-    virtual bool isTOutInConfigFile()                 = 0;
-    virtual bool isTStartOutInConfigFile()            = 0;
-    virtual bool isTimeCalcMedStartInConfigFile()     = 0;
-    virtual bool isTimeCalcMedEndInConfigFile()       = 0;
-    virtual bool isPressInIDInConfigFile()            = 0;
-    virtual bool isPressOutIDInConfigFile()           = 0;
-    virtual bool isPressInZInConfigFile()             = 0;
-    virtual bool isPressOutZInConfigFile()            = 0;
-    virtual bool isDiffOnInConfigFile()               = 0;
-    virtual bool isDiffModInConfigFile()              = 0;
-    virtual bool isDiffusivityInConfigFile()          = 0;
-    virtual bool isTemperatureInitInConfigFile()      = 0;
-    virtual bool isTemperatureBCInConfigFile()        = 0;
-    // virtual bool isViscosityInConfigFile() = 0;
-    virtual bool isVelocityInConfigFile()           = 0;
-    virtual bool isViscosityRatioInConfigFile()     = 0;
-    virtual bool isVelocityRatioInConfigFile()      = 0;
-    virtual bool isDensityRatioInConfigFile()       = 0;
-    virtual bool isPressRatioInConfigFile()         = 0;
-    virtual bool isRealXInConfigFile()              = 0;
-    virtual bool isRealYInConfigFile()              = 0;
-    virtual bool isFactorPressBCInConfigFile()      = 0;
-    virtual bool isGeometryFileCInConfigFile()      = 0;
-    virtual bool isGeometryFileMInConfigFile()      = 0;
-    virtual bool isGeometryFileFInConfigFile()      = 0;
-    virtual bool isClockCycleForMPInConfigFile()    = 0;
-    virtual bool isTimestepForMPInConfigFile()      = 0;
-    virtual bool isForcingXInConfigFile()           = 0;
-    virtual bool isForcingYInConfigFile()           = 0;
-    virtual bool isForcingZInConfigFile()           = 0;
-    virtual bool isQuadricLimiterPInConfigFile()    = 0;
-    virtual bool isQuadricLimiterMInConfigFile()    = 0;
-    virtual bool isQuadricLimiterDInConfigFile()    = 0;
-    virtual bool isCalcParticlesInConfigFile()      = 0;
-    virtual bool isParticleBasicLevelInConfigFile() = 0;
-    virtual bool isParticleInitLevelInConfigFile()  = 0;
-    virtual bool isNumberOfParticlesInConfigFile()  = 0;
-    virtual bool isNeighborWSBInConfigFile()        = 0;
-    virtual bool isStartXHotWallInConfigFile()      = 0;
-    virtual bool isEndXHotWallInConfigFile()        = 0;
-    virtual bool isPossNeighborFilesXInConfigFile() = 0;
-    virtual bool isPossNeighborFilesYInConfigFile() = 0;
-    virtual bool isPossNeighborFilesZInConfigFile() = 0;
-    virtual bool isTimeDoCheckPointInConfigFile()   = 0;
-    virtual bool isTimeDoRestartInConfigFile()      = 0;
-    virtual bool isDoCheckPointInConfigFile()       = 0;
-    virtual bool isDoRestartInConfigFile()          = 0;
-    virtual bool isMaxLevelInConfigFile()           = 0;
-    virtual bool isGridXInConfigFile()              = 0;
-    virtual bool isGridYInConfigFile()              = 0;
-    virtual bool isGridZInConfigFile()              = 0;
-    virtual bool isDistXInConfigFile()              = 0;
-    virtual bool isDistYInConfigFile()              = 0;
-    virtual bool isDistZInConfigFile()              = 0;
-    virtual bool isNeedInterfaceInConfigFile()      = 0;
-    virtual bool isMainKernelInConfigFile()         = 0;
-    virtual bool isMultiKernelOnInConfigFile()      = 0;
-    virtual bool isMultiKernelLevelInConfigFile()   = 0;
-    virtual bool isMultiKernelNameInConfigFile()    = 0;
-};
-#endif
diff --git a/src/basics/Core/Input/ConfigData/ConfigDataImp.cpp b/src/basics/Core/Input/ConfigData/ConfigDataImp.cpp
deleted file mode 100644
index 0c53b32829eb989667b93fc7df156525267e930b..0000000000000000000000000000000000000000
--- a/src/basics/Core/Input/ConfigData/ConfigDataImp.cpp
+++ /dev/null
@@ -1,834 +0,0 @@
-#include "ConfigDataImp.h"
-
-std::shared_ptr<ConfigDataImp> ConfigDataImp::getNewInstance()
-{
-    return std::shared_ptr<ConfigDataImp>(new ConfigDataImp());
-}
-
-real ConfigDataImp::getViscosity() { return this->viscosity; }
-
-uint ConfigDataImp::getNumberOfDevices() { return this->numberOfDevices; }
-
-std::vector<uint> ConfigDataImp::getDevices() { return this->devices; }
-
-std::string ConfigDataImp::getOutputPath() { return this->outputPath; }
-
-std::string ConfigDataImp::getPrefix() { return this->prefix; }
-
-std::string ConfigDataImp::getGridPath() { return this->gridPath; }
-
-bool ConfigDataImp::getPrintOutputFiles() { return this->printOutputFiles; }
-
-bool ConfigDataImp::getGeometryValues() { return this->geometryValues; }
-
-bool ConfigDataImp::getCalc2ndOrderMoments() { return this->calc2ndOrderMoments; }
-
-bool ConfigDataImp::getCalc3rdOrderMoments() { return this->calc3rdOrderMoments; }
-
-bool ConfigDataImp::getCalcHighOrderMoments() { return this->calcHighOrderMoments; }
-
-bool ConfigDataImp::getReadGeo() { return this->readGeo; }
-
-bool ConfigDataImp::getCalcMedian() { return this->calcMedian; }
-
-bool ConfigDataImp::getCalcDragLift() { return this->calcDragLift; }
-
-bool ConfigDataImp::getCalcCp() { return this->calcCp; }
-
-bool ConfigDataImp::getWriteVeloASCIIfiles() { return this->writeVeloASCIIfiles; }
-
-bool ConfigDataImp::getCalcPlaneConc() { return this->calcPlaneConc; }
-
-bool ConfigDataImp::getConcFile() { return this->concFile; }
-
-bool ConfigDataImp::getStreetVelocityFile() { return this->streetVelocityFile; }
-
-bool ConfigDataImp::getUseMeasurePoints() { return this->useMeasurePoints; }
-
-bool ConfigDataImp::getUseWale() { return this->useWale; }
-
-bool ConfigDataImp::getUseInitNeq() { return this->useInitNeq; }
-
-bool ConfigDataImp::getSimulatePorousMedia() { return this->simulatePorousMedia; }
-
-uint ConfigDataImp::getD3Qxx() { return this->d3Qxx; }
-
-uint ConfigDataImp::getTEnd() { return this->tEnd; }
-
-uint ConfigDataImp::getTOut() { return this->tOut; }
-
-uint ConfigDataImp::getTStartOut() { return this->tStartOut; }
-
-uint ConfigDataImp::getTimeCalcMedStart() { return this->timeCalcMedStart; }
-
-uint ConfigDataImp::getTimeCalcMedEnd() { return this->timeCalcMedEnd; }
-
-uint ConfigDataImp::getPressInID() { return this->pressInID; }
-
-uint ConfigDataImp::getPressOutID() { return this->pressOutID; }
-
-uint ConfigDataImp::getPressInZ() { return this->pressInZ; }
-
-uint ConfigDataImp::getPressOutZ() { return this->pressOutZ; }
-
-bool ConfigDataImp::getDiffOn() { return this->diffOn; }
-
-uint ConfigDataImp::getDiffMod() { return this->diffMod; }
-
-real ConfigDataImp::getDiffusivity() { return this->diffusivity; }
-
-real ConfigDataImp::getTemperatureInit() { return this->temperatureInit; }
-
-real ConfigDataImp::getTemperatureBC() { return this->temperatureBC; }
-
-real ConfigDataImp::getVelocity() { return this->velocity; }
-
-real ConfigDataImp::getViscosityRatio() { return this->viscosityRatio; }
-
-real ConfigDataImp::getVelocityRatio() { return this->velocityRatio; }
-
-real ConfigDataImp::getDensityRatio() { return this->densityRatio; }
-
-real ConfigDataImp::getPressRatio() { return this->pressRatio; }
-
-real ConfigDataImp::getRealX() { return this->realX; }
-
-real ConfigDataImp::getRealY() { return this->realY; }
-
-real ConfigDataImp::getFactorPressBC() { return this->factorPressBC; }
-
-std::string ConfigDataImp::getGeometryFileC() { return this->geometryFileC; }
-
-std::string ConfigDataImp::getGeometryFileM() { return this->geometryFileM; }
-
-std::string ConfigDataImp::getGeometryFileF() { return this->geometryFileF; }
-
-uint ConfigDataImp::getClockCycleForMP() { return this->clockCycleForMP; }
-
-uint ConfigDataImp::getTimestepForMP() { return this->timestepForMP; }
-
-real ConfigDataImp::getForcingX() { return this->forcingX; }
-
-real ConfigDataImp::getForcingY() { return this->forcingY; }
-
-real ConfigDataImp::getForcingZ() { return this->forcingZ; }
-
-real ConfigDataImp::getQuadricLimiterP() { return this->quadricLimiterP; }
-
-real ConfigDataImp::getQuadricLimiterM() { return this->quadricLimiterM; }
-
-real ConfigDataImp::getQuadricLimiterD() { return this->quadricLimiterD; }
-
-bool ConfigDataImp::getCalcParticles() { return this->calcParticles; }
-
-int ConfigDataImp::getParticleBasicLevel() { return this->particleBasicLevel; }
-
-int ConfigDataImp::getParticleInitLevel() { return this->particleInitLevel; }
-
-int ConfigDataImp::getNumberOfParticles() { return this->numberOfParticles; }
-
-real ConfigDataImp::getStartXHotWall() { return this->startXHotWall; }
-
-real ConfigDataImp::getEndXHotWall() { return this->endXHotWall; }
-
-std::vector<std::string> ConfigDataImp::getPossNeighborFilesX() { return this->possNeighborFilesX; }
-
-std::vector<std::string> ConfigDataImp::getPossNeighborFilesY() { return this->possNeighborFilesY; }
-
-std::vector<std::string> ConfigDataImp::getPossNeighborFilesZ() { return this->possNeighborFilesZ; }
-
-int ConfigDataImp::getTimeDoCheckPoint() { return this->timeDoCheckPoint; }
-
-int ConfigDataImp::getTimeDoRestart() { return this->timeDoRestart; }
-
-bool ConfigDataImp::getDoCheckPoint() { return this->doCheckPoint; }
-
-bool ConfigDataImp::getDoRestart() { return this->doRestart; }
-
-uint ConfigDataImp::getMaxLevel() { return this->maxLevel; }
-
-std::vector<int> ConfigDataImp::getGridX() { return this->gridX; }
-
-std::vector<int> ConfigDataImp::getGridY() { return this->gridY; }
-
-std::vector<int> ConfigDataImp::getGridZ() { return this->gridZ; }
-
-std::vector<int> ConfigDataImp::getDistX() { return this->distX; }
-
-std::vector<int> ConfigDataImp::getDistY() { return this->distY; }
-
-std::vector<int> ConfigDataImp::getDistZ() { return this->distZ; }
-
-std::vector<bool> ConfigDataImp::getNeedInterface() { return this->needInterface; }
-
-std::string ConfigDataImp::getMainKernel() { return this->mainKernel; }
-
-bool ConfigDataImp::getMultiKernelOn() { return this->multiKernelOn; }
-
-std::vector<int> ConfigDataImp::getMultiKernelLevel() { return this->multiKernelLevel; }
-
-std::vector<std::string> ConfigDataImp::getMultiKernelName() { return this->multiKernelName; }
-
-void ConfigDataImp::setViscosity(real viscosity)
-{
-    this->viscosity   = viscosity;
-    this->isViscosity = true;
-}
-
-void ConfigDataImp::setNumberOfDevices(uint numberOfDevices)
-{
-    this->numberOfDevices   = numberOfDevices;
-    this->isNumberOfDevices = true;
-}
-
-void ConfigDataImp::setDevices(std::vector<uint> devices)
-{
-    this->devices   = devices;
-    this->isDevices = true;
-}
-
-void ConfigDataImp::setOutputPath(std::string outputPath)
-{
-    this->outputPath   = outputPath;
-    this->isOutputPath = true;
-}
-
-void ConfigDataImp::setPrefix(std::string prefix)
-{
-    this->prefix   = prefix;
-    this->isPrefix = true;
-}
-
-void ConfigDataImp::setGridPath(std::string gridPath)
-{
-    this->gridPath   = gridPath;
-    this->isGridPath = true;
-}
-
-void ConfigDataImp::setPrintOutputFiles(bool printOutputFiles)
-{
-    this->printOutputFiles   = printOutputFiles;
-    this->isPrintOutputFiles = true;
-}
-
-void ConfigDataImp::setGeometryValues(bool geometryValues)
-{
-    this->geometryValues   = geometryValues;
-    this->isGeometryValues = true;
-}
-
-void ConfigDataImp::setCalc2ndOrderMoments(bool calc2ndOrderMoments)
-{
-    this->calc2ndOrderMoments   = calc2ndOrderMoments;
-    this->isCalc2ndOrderMoments = true;
-}
-
-void ConfigDataImp::setCalc3rdOrderMoments(bool calc3rdOrderMoments)
-{
-    this->calc3rdOrderMoments   = calc3rdOrderMoments;
-    this->isCalc3rdOrderMoments = true;
-}
-
-void ConfigDataImp::setCalcHighOrderMoments(bool calcHighOrderMoments)
-{
-    this->calcHighOrderMoments   = calcHighOrderMoments;
-    this->isCalcHighOrderMoments = true;
-}
-
-void ConfigDataImp::setReadGeo(bool readGeo)
-{
-    this->readGeo   = readGeo;
-    this->isReadGeo = true;
-}
-
-void ConfigDataImp::setCalcMedian(bool calcMedian)
-{
-    this->calcMedian   = calcMedian;
-    this->isCalcMedian = true;
-}
-
-void ConfigDataImp::setCalcDragLift(bool calcDragLift)
-{
-    this->calcDragLift   = calcDragLift;
-    this->isCalcDragLift = true;
-}
-
-void ConfigDataImp::setCalcCp(bool calcCp)
-{
-    this->calcCp   = calcCp;
-    this->isCalcCp = true;
-}
-
-void ConfigDataImp::setWriteVeloASCIIfiles(bool writeVeloASCIIfiles)
-{
-    this->writeVeloASCIIfiles = writeVeloASCIIfiles;
-    this->isWriteVeloASCII    = true;
-}
-
-void ConfigDataImp::setCalcPlaneConc(bool calcPlaneConc)
-{
-    this->calcPlaneConc   = calcPlaneConc;
-    this->isCalcPlaneConc = true;
-}
-
-void ConfigDataImp::setConcFile(bool concFile)
-{
-    this->concFile   = concFile;
-    this->isConcFile = true;
-}
-
-void ConfigDataImp::setStreetVelocityFile(bool streetVelocityFile)
-{
-    this->streetVelocityFile   = streetVelocityFile;
-    this->isStreetVelocityFile = true;
-}
-
-void ConfigDataImp::setUseMeasurePoints(bool useMeasurePoints)
-{
-    this->useMeasurePoints   = useMeasurePoints;
-    this->isUseMeasurePoints = true;
-}
-
-void ConfigDataImp::setUseWale(bool useWale)
-{
-    this->useWale   = useWale;
-    this->isUseWale = true;
-}
-
-void ConfigDataImp::setUseInitNeq(bool useInitNeq)
-{
-    this->useInitNeq   = useInitNeq;
-    this->isUseInitNeq = true;
-}
-
-void ConfigDataImp::setSimulatePorousMedia(bool simulatePorousMedia)
-{
-    this->simulatePorousMedia   = simulatePorousMedia;
-    this->isSimulatePorousMedia = true;
-}
-
-void ConfigDataImp::setD3Qxx(uint d3Qxx)
-{
-    this->d3Qxx   = d3Qxx;
-    this->isD3Qxx = true;
-}
-
-void ConfigDataImp::setTEnd(uint tEnd)
-{
-    this->tEnd   = tEnd;
-    this->isTEnd = true;
-}
-
-void ConfigDataImp::setTOut(uint tOut)
-{
-    this->tOut   = tOut;
-    this->isTOut = true;
-}
-
-void ConfigDataImp::setTStartOut(uint tStartOut)
-{
-    this->tStartOut   = tStartOut;
-    this->isTStartOut = true;
-}
-
-void ConfigDataImp::setTimeCalcMedStart(uint timeCalcMedStart)
-{
-    this->timeCalcMedStart   = timeCalcMedStart;
-    this->isTimeCalcMedStart = true;
-}
-
-void ConfigDataImp::setTimeCalcMedEnd(uint timeCalcMedEnd)
-{
-    this->timeCalcMedEnd   = timeCalcMedEnd;
-    this->isTimeCalcMedEnd = true;
-}
-
-void ConfigDataImp::setPressInID(uint pressInID)
-{
-    this->pressInID   = pressInID;
-    this->isPressInID = true;
-}
-
-void ConfigDataImp::setPressOutID(uint pressOutID)
-{
-    this->pressOutID   = pressOutID;
-    this->isPressOutID = true;
-}
-
-void ConfigDataImp::setPressInZ(uint pressInZ)
-{
-    this->pressInZ   = pressInZ;
-    this->isPressInZ = true;
-}
-
-void ConfigDataImp::setPressOutZ(uint pressOutZ)
-{
-    this->pressOutZ   = pressOutZ;
-    this->isPressOutZ = true;
-}
-
-void ConfigDataImp::setDiffOn(bool diffOn)
-{
-    this->diffOn   = diffOn;
-    this->isDiffOn = true;
-}
-
-void ConfigDataImp::setDiffMod(uint diffMod)
-{
-    this->diffMod   = diffMod;
-    this->isDiffMod = true;
-}
-
-void ConfigDataImp::setDiffusivity(real diffusivity)
-{
-    this->diffusivity   = diffusivity;
-    this->isDiffusivity = true;
-}
-
-void ConfigDataImp::setTemperatureInit(real temperatureInit)
-{
-    this->temperatureInit   = temperatureInit;
-    this->isTemperatureInit = true;
-}
-
-void ConfigDataImp::setTemperatureBC(real temperatureBC)
-{
-    this->temperatureBC   = temperatureBC;
-    this->isTemperatureBC = true;
-}
-
-// void ConfigDataImp::setViscosity(real viscosity)
-//{
-//	this->viscosity = viscosity;
-//	this->isViscosity = true;
-//}
-
-void ConfigDataImp::setVelocity(real velocity)
-{
-    this->velocity   = velocity;
-    this->isVelocity = true;
-}
-
-void ConfigDataImp::setViscosityRatio(real viscosityRatio)
-{
-    this->viscosityRatio   = viscosityRatio;
-    this->isViscosityRatio = true;
-}
-
-void ConfigDataImp::setVelocityRatio(real velocityRatio)
-{
-    this->velocityRatio   = velocityRatio;
-    this->isVelocityRatio = true;
-}
-
-void ConfigDataImp::setDensityRatio(real densityRatio)
-{
-    this->densityRatio   = densityRatio;
-    this->isDensityRatio = true;
-}
-
-void ConfigDataImp::setPressRatio(real pressRatio)
-{
-    this->pressRatio   = pressRatio;
-    this->isPressRatio = true;
-}
-
-void ConfigDataImp::setRealX(real realX)
-{
-    this->realX   = realX;
-    this->isRealX = true;
-}
-
-void ConfigDataImp::setRealY(real realY)
-{
-    this->realY   = realY;
-    this->isRealY = true;
-}
-
-void ConfigDataImp::setFactorPressBC(real factorPressBC)
-{
-    this->factorPressBC   = factorPressBC;
-    this->isFactorPressBC = true;
-}
-
-void ConfigDataImp::setGeometryFileC(std::string geometryFileC)
-{
-    this->geometryFileC   = geometryFileC;
-    this->isGeometryFileC = true;
-}
-
-void ConfigDataImp::setGeometryFileM(std::string geometryFileM)
-{
-    this->geometryFileM   = geometryFileM;
-    this->isGeometryFileM = true;
-}
-
-void ConfigDataImp::setGeometryFileF(std::string geometryFileF)
-{
-    this->geometryFileF   = geometryFileF;
-    this->isGeometryFileF = true;
-}
-
-void ConfigDataImp::setClockCycleForMP(uint clockCycleForMP)
-{
-    this->clockCycleForMP   = clockCycleForMP;
-    this->isClockCycleForMP = true;
-}
-
-void ConfigDataImp::setTimestepForMP(uint timestepForMP)
-{
-    this->timestepForMP   = timestepForMP;
-    this->isTimestepForMP = true;
-}
-
-void ConfigDataImp::setForcingX(real forcingX)
-{
-    this->forcingX   = forcingX;
-    this->isForcingX = true;
-}
-
-void ConfigDataImp::setForcingY(real forcingY)
-{
-    this->forcingY   = forcingY;
-    this->isForcingY = true;
-}
-
-void ConfigDataImp::setForcingZ(real forcingZ)
-{
-    this->forcingZ   = forcingZ;
-    this->isForcingZ = true;
-}
-
-void ConfigDataImp::setQuadricLimiterP(real quadricLimiterP)
-{
-    this->quadricLimiterP   = quadricLimiterP;
-    this->isQuadricLimiterP = true;
-}
-
-void ConfigDataImp::setQuadricLimiterM(real quadricLimiterM)
-{
-    this->quadricLimiterM   = quadricLimiterM;
-    this->isQuadricLimiterM = true;
-}
-
-void ConfigDataImp::setQuadricLimiterD(real quadricLimiterD)
-{
-    this->quadricLimiterD   = quadricLimiterD;
-    this->isQuadricLimiterD = true;
-}
-
-void ConfigDataImp::setCalcParticles(bool calcParticles)
-{
-    this->calcParticles   = calcParticles;
-    this->isCalcParticles = true;
-}
-
-void ConfigDataImp::setParticleBasicLevel(int particleBasicLevel)
-{
-    this->particleBasicLevel   = particleBasicLevel;
-    this->isParticleBasicLevel = true;
-}
-
-void ConfigDataImp::setParticleInitLevel(int particleInitLevel)
-{
-    this->particleInitLevel   = particleInitLevel;
-    this->isParticleInitLevel = true;
-}
-
-void ConfigDataImp::setNumberOfParticles(int numberOfParticles)
-{
-    this->numberOfParticles   = numberOfParticles;
-    this->isNumberOfParticles = true;
-}
-
-void ConfigDataImp::setStartXHotWall(real startXHotWall)
-{
-    this->startXHotWall   = startXHotWall;
-    this->isStartXHotWall = true;
-}
-
-void ConfigDataImp::setEndXHotWall(real endXHotWall)
-{
-    this->endXHotWall   = endXHotWall;
-    this->isEndXHotWall = true;
-}
-
-void ConfigDataImp::setPossNeighborFilesX(const std::vector<std::string> &possNeighborFilesX)
-{
-    this->possNeighborFilesX   = possNeighborFilesX;
-    this->isPossNeighborFilesX = true;
-}
-
-void ConfigDataImp::setPossNeighborFilesY(const std::vector<std::string> &possNeighborFilesY)
-{
-    this->possNeighborFilesY   = possNeighborFilesY;
-    this->isPossNeighborFilesY = true;
-}
-
-void ConfigDataImp::setPossNeighborFilesZ(const std::vector<std::string> &possNeighborFilesZ)
-{
-    this->possNeighborFilesZ   = possNeighborFilesZ;
-    this->isPossNeighborFilesZ = true;
-}
-
-void ConfigDataImp::setTimeDoCheckPoint(int timeDoCheckPoint)
-{
-    this->timeDoCheckPoint   = timeDoCheckPoint;
-    this->isTimeDoCheckPoint = true;
-}
-
-void ConfigDataImp::setTimeDoRestart(int timeDoRestart)
-{
-    this->timeDoRestart   = timeDoRestart;
-    this->isTimeDoRestart = true;
-}
-
-void ConfigDataImp::setDoCheckPoint(bool doCheckPoint)
-{
-    this->doCheckPoint   = doCheckPoint;
-    this->isDoCheckPoint = true;
-}
-
-void ConfigDataImp::setDoRestart(bool doRestart)
-{
-    this->doRestart   = doRestart;
-    this->isDoRestart = true;
-}
-
-void ConfigDataImp::setMaxLevel(uint maxLevel)
-{
-    this->maxLevel   = maxLevel;
-    this->isMaxLevel = true;
-}
-
-void ConfigDataImp::setGridX(const std::vector<int> &gridX)
-{
-    this->gridX   = gridX;
-    this->isGridX = true;
-}
-
-void ConfigDataImp::setGridY(const std::vector<int> &gridY)
-{
-    this->gridY   = gridY;
-    this->isGridY = true;
-}
-
-void ConfigDataImp::setGridZ(const std::vector<int> &gridZ)
-{
-    this->gridZ   = gridZ;
-    this->isGridZ = true;
-}
-
-void ConfigDataImp::setDistX(const std::vector<int> &distX)
-{
-    this->distX   = distX;
-    this->isDistX = true;
-}
-
-void ConfigDataImp::setDistY(const std::vector<int> &distY)
-{
-    this->distY   = distY;
-    this->isDistY = true;
-}
-
-void ConfigDataImp::setDistZ(const std::vector<int> &distZ)
-{
-    this->distZ   = distZ;
-    this->isDistZ = true;
-}
-
-void ConfigDataImp::setNeedInterface(const std::vector<bool> &needInterface)
-{
-    this->needInterface   = needInterface;
-    this->isNeedInterface = true;
-}
-
-void ConfigDataImp::setMainKernel(const std::string &mainKernel)
-{
-    this->mainKernel   = mainKernel;
-    this->isMainKernel = true;
-}
-
-void ConfigDataImp::setMultiKernelOn(bool multiKernelOn)
-{
-    this->multiKernelOn   = multiKernelOn;
-    this->isMultiKernelOn = true;
-}
-
-void ConfigDataImp::setMultiKernelLevel(const std::vector<int> &multiKernelLevel)
-{
-    this->multiKernelLevel   = multiKernelLevel;
-    this->isMultiKernelLevel = true;
-}
-
-void ConfigDataImp::setMultiKernelName(const std::vector<std::string> &multiKernelName)
-{
-    this->multiKernelName   = multiKernelName;
-    this->isMultiKernelName = true;
-}
-
-bool ConfigDataImp::isCalc2ndOrderMomentsInConfigFile() { return this->isCalc2ndOrderMoments; }
-
-bool ConfigDataImp::isCalc3rdOrderMomentsInConfigFile() { return this->isCalc2ndOrderMoments; }
-
-bool ConfigDataImp::isCalcHighOrderMomentsInConfigFile() { return this->isCalcHighOrderMoments; }
-
-bool ConfigDataImp::isReadGeoInConfigFile() { return this->isReadGeo; }
-
-bool ConfigDataImp::isCalcMedianInConfigFile() { return this->isCalcMedian; }
-
-bool ConfigDataImp::isCalcDragLiftInConfigFile() { return this->isCalcDragLift; }
-
-bool ConfigDataImp::isCalcCpInConfigFile() { return this->isCalcCp; }
-
-bool ConfigDataImp::isWriteVeloASCIIfilesInConfigFile() { return this->isWriteVeloASCII; }
-
-bool ConfigDataImp::isCalcPlaneConcInConfigFile() { return this->isCalcPlaneConc; }
-
-bool ConfigDataImp::isConcFileInConfigFile() { return this->isConcFile; }
-
-bool ConfigDataImp::isStreetVelocityFileInConfigFile() { return this->isStreetVelocityFile; }
-
-bool ConfigDataImp::isUseMeasurePointsInConfigFile() { return this->isUseMeasurePoints; }
-
-bool ConfigDataImp::isUseWaleInConfigFile() { return this->isUseWale; }
-
-bool ConfigDataImp::isUseInitNeqInConfigFile() { return this->isUseInitNeq; }
-
-bool ConfigDataImp::isSimulatePorousMediaInConfigFile() { return this->isSimulatePorousMedia; }
-
-bool ConfigDataImp::isD3QxxInConfigFile() { return this->isD3Qxx; }
-
-bool ConfigDataImp::isTEndInConfigFile() { return this->isTEnd; }
-
-bool ConfigDataImp::isTOutInConfigFile() { return this->isTOut; }
-
-bool ConfigDataImp::isTStartOutInConfigFile() { return this->isTStartOut; }
-
-bool ConfigDataImp::isTimeCalcMedStartInConfigFile() { return this->isTimeCalcMedStart; }
-
-bool ConfigDataImp::isTimeCalcMedEndInConfigFile() { return this->isTimeCalcMedEnd; }
-
-bool ConfigDataImp::isPressInIDInConfigFile() { return this->isPressInID; }
-
-bool ConfigDataImp::isPressOutIDInConfigFile() { return this->isPressOutID; }
-
-bool ConfigDataImp::isPressInZInConfigFile() { return this->isPressInZ; }
-
-bool ConfigDataImp::isPressOutZInConfigFile() { return this->isPressOutZ; }
-
-bool ConfigDataImp::isDiffOnInConfigFile() { return this->isDiffOn; }
-
-bool ConfigDataImp::isDiffModInConfigFile() { return this->isDiffMod; }
-
-bool ConfigDataImp::isDiffusivityInConfigFile() { return this->isDiffusivity; }
-
-bool ConfigDataImp::isTemperatureInitInConfigFile() { return this->isTemperatureInit; }
-
-bool ConfigDataImp::isTemperatureBCInConfigFile() { return this->isTemperatureBC; }
-
-bool ConfigDataImp::isViscosityInConfigFile() { return this->isViscosity; }
-
-bool ConfigDataImp::isNumberOfDevicesInConfigFile() { return this->isNumberOfDevices; }
-
-bool ConfigDataImp::isDevicesInConfigFile() { return this->isDevices; }
-
-bool ConfigDataImp::isOutputPathInConfigFile() { return this->isOutputPath; }
-
-bool ConfigDataImp::isPrefixInConfigFile() { return this->isPrefix; }
-
-bool ConfigDataImp::isGridPathInConfigFile() { return this->isGridPath; }
-
-bool ConfigDataImp::isPrintOutputFilesInConfigFile() { return this->isPrintOutputFiles; }
-
-bool ConfigDataImp::isGeometryValuesInConfigFile() { return this->isGeometryValues; }
-
-bool ConfigDataImp::isVelocityInConfigFile() { return this->isVelocity; }
-
-bool ConfigDataImp::isViscosityRatioInConfigFile() { return this->isViscosityRatio; }
-
-bool ConfigDataImp::isVelocityRatioInConfigFile() { return this->isVelocityRatio; }
-
-bool ConfigDataImp::isDensityRatioInConfigFile() { return this->isDensityRatio; }
-
-bool ConfigDataImp::isPressRatioInConfigFile() { return this->isPressRatio; }
-
-bool ConfigDataImp::isRealXInConfigFile() { return this->isRealX; }
-
-bool ConfigDataImp::isRealYInConfigFile() { return this->isRealY; }
-
-bool ConfigDataImp::isFactorPressBCInConfigFile() { return this->isFactorPressBC; }
-
-bool ConfigDataImp::isGeometryFileCInConfigFile() { return this->isGeometryFileC; }
-
-bool ConfigDataImp::isGeometryFileMInConfigFile() { return this->isGeometryFileM; }
-
-bool ConfigDataImp::isGeometryFileFInConfigFile() { return this->isGeometryFileF; }
-
-bool ConfigDataImp::isClockCycleForMPInConfigFile() { return this->isClockCycleForMP; }
-
-bool ConfigDataImp::isTimestepForMPInConfigFile() { return this->isTimestepForMP; }
-
-bool ConfigDataImp::isForcingXInConfigFile() { return this->isForcingX; }
-
-bool ConfigDataImp::isForcingYInConfigFile() { return this->isForcingY; }
-
-bool ConfigDataImp::isForcingZInConfigFile() { return this->isForcingZ; }
-
-bool ConfigDataImp::isQuadricLimiterPInConfigFile() { return this->isQuadricLimiterP; }
-
-bool ConfigDataImp::isQuadricLimiterMInConfigFile() { return this->isQuadricLimiterM; }
-
-bool ConfigDataImp::isQuadricLimiterDInConfigFile() { return this->isQuadricLimiterD; }
-
-bool ConfigDataImp::isCalcParticlesInConfigFile() { return this->isCalcParticles; }
-
-bool ConfigDataImp::isParticleBasicLevelInConfigFile() { return this->isParticleBasicLevel; }
-
-bool ConfigDataImp::isParticleInitLevelInConfigFile() { return this->isParticleInitLevel; }
-
-bool ConfigDataImp::isNumberOfParticlesInConfigFile() { return this->isNumberOfParticles; }
-
-bool ConfigDataImp::isNeighborWSBInConfigFile() { return this->isNeighborWSB; }
-
-bool ConfigDataImp::isStartXHotWallInConfigFile() { return this->isStartXHotWall; }
-
-bool ConfigDataImp::isEndXHotWallInConfigFile() { return this->isEndXHotWall; }
-
-bool ConfigDataImp::isPossNeighborFilesXInConfigFile() { return this->isPossNeighborFilesX; }
-
-bool ConfigDataImp::isPossNeighborFilesYInConfigFile() { return this->isPossNeighborFilesY; }
-
-bool ConfigDataImp::isPossNeighborFilesZInConfigFile() { return this->isPossNeighborFilesZ; }
-
-bool ConfigDataImp::isTimeDoCheckPointInConfigFile() { return this->isTimeDoCheckPoint; }
-
-bool ConfigDataImp::isTimeDoRestartInConfigFile() { return this->isTimeDoCheckPoint; }
-
-bool ConfigDataImp::isDoCheckPointInConfigFile() { return this->isDoCheckPoint; }
-
-bool ConfigDataImp::isDoRestartInConfigFile() { return this->isDoRestart; }
-
-bool ConfigDataImp::isMaxLevelInConfigFile() { return this->isMaxLevel; }
-
-bool ConfigDataImp::isGridXInConfigFile() { return this->isGridX; }
-
-bool ConfigDataImp::isGridYInConfigFile() { return this->isGridY; }
-
-bool ConfigDataImp::isGridZInConfigFile() { return this->isGridZ; }
-
-bool ConfigDataImp::isDistXInConfigFile() { return this->isDistX; }
-
-bool ConfigDataImp::isDistYInConfigFile() { return this->isDistY; }
-
-bool ConfigDataImp::isDistZInConfigFile() { return this->isDistZ; }
-
-bool ConfigDataImp::isNeedInterfaceInConfigFile() { return this->isNeedInterface; }
-
-bool ConfigDataImp::isMainKernelInConfigFile() { return this->isMainKernel; }
-
-bool ConfigDataImp::isMultiKernelOnInConfigFile() { return this->isMultiKernelOn; }
-
-bool ConfigDataImp::isMultiKernelLevelInConfigFile() { return this->isMultiKernelLevel; }
-
-bool ConfigDataImp::isMultiKernelNameInConfigFile() { return this->isMultiKernelName; }
diff --git a/src/basics/Core/Input/ConfigData/ConfigDataImp.h b/src/basics/Core/Input/ConfigData/ConfigDataImp.h
deleted file mode 100644
index 511ac4be166c7e43885209f144f0cdac6821c6f1..0000000000000000000000000000000000000000
--- a/src/basics/Core/Input/ConfigData/ConfigDataImp.h
+++ /dev/null
@@ -1,447 +0,0 @@
-#ifndef CONFIGDATAIMP_H
-#define CONFIGDATAIMP_H
-
-#include "ConfigData.h"
-
-#include <memory>
-#include <string>
-
-class ConfigDataImp : public ConfigData
-{
-public:
-    static std::shared_ptr<ConfigDataImp> getNewInstance();
-
-    real getViscosity() override;
-    uint getNumberOfDevices() override;
-    std::vector<uint> getDevices() override;
-    std::string getOutputPath() override;
-    std::string getPrefix() override;
-    std::string getGridPath() override;
-    bool getPrintOutputFiles() override;
-    bool getGeometryValues() override;
-    bool getCalc2ndOrderMoments() override;
-    bool getCalc3rdOrderMoments() override;
-    bool getCalcHighOrderMoments() override;
-    bool getReadGeo() override;
-    bool getCalcMedian() override;
-    bool getCalcDragLift() override;
-    bool getCalcCp() override;
-    bool getWriteVeloASCIIfiles() override;
-    bool getCalcPlaneConc() override;
-    bool getConcFile() override;
-    bool getStreetVelocityFile() override;
-    bool getUseMeasurePoints() override;
-    bool getUseWale() override;
-    bool getUseInitNeq() override;
-    bool getSimulatePorousMedia() override;
-    uint getD3Qxx() override;
-    uint getTEnd() override;
-    uint getTOut() override;
-    uint getTStartOut() override;
-    uint getTimeCalcMedStart() override;
-    uint getTimeCalcMedEnd() override;
-    uint getPressInID() override;
-    uint getPressOutID() override;
-    uint getPressInZ() override;
-    uint getPressOutZ() override;
-    bool getDiffOn() override;
-    uint getDiffMod() override;
-    real getDiffusivity() override;
-    real getTemperatureInit() override;
-    real getTemperatureBC() override;
-    real getVelocity() override;
-    real getViscosityRatio() override;
-    real getVelocityRatio() override;
-    real getDensityRatio() override;
-    real getPressRatio() override;
-    real getRealX() override;
-    real getRealY() override;
-    real getFactorPressBC() override;
-    std::string getGeometryFileC() override;
-    std::string getGeometryFileM() override;
-    std::string getGeometryFileF() override;
-    uint getClockCycleForMP() override;
-    uint getTimestepForMP() override;
-    real getForcingX() override;
-    real getForcingY() override;
-    real getForcingZ() override;
-    real getQuadricLimiterP() override;
-    real getQuadricLimiterM() override;
-    real getQuadricLimiterD() override;
-    bool getCalcParticles() override;
-    int getParticleBasicLevel() override;
-    int getParticleInitLevel() override;
-    int getNumberOfParticles() override;
-    real getStartXHotWall() override;
-    real getEndXHotWall() override;
-    std::vector<std::string> getPossNeighborFilesX() override;
-    std::vector<std::string> getPossNeighborFilesY() override;
-    std::vector<std::string> getPossNeighborFilesZ() override;
-    // std::vector<std::string> getPossNeighborFilesX();
-    // std::vector<std::string> getPossNeighborFilesY();
-    // std::vector<std::string> getPossNeighborFilesZ();
-    int getTimeDoCheckPoint() override;
-    int getTimeDoRestart() override;
-    bool getDoCheckPoint() override;
-    bool getDoRestart() override;
-    uint getMaxLevel() override;
-    std::vector<int> getGridX() override;
-    std::vector<int> getGridY() override;
-    std::vector<int> getGridZ() override;
-    std::vector<int> getDistX() override;
-    std::vector<int> getDistY() override;
-    std::vector<int> getDistZ() override;
-    std::vector<bool> getNeedInterface() override;
-    std::string getMainKernel() override;
-    bool getMultiKernelOn() override;
-    std::vector<int> getMultiKernelLevel() override;
-    std::vector<std::string> getMultiKernelName() override;
-
-    void setViscosity(real viscosity);
-    void setNumberOfDevices(uint numberOfDevices);
-    void setDevices(std::vector<uint> devices);
-    void setOutputPath(std::string outputPath);
-    void setPrefix(std::string prefix);
-    void setGridPath(std::string gridPath);
-    void setPrintOutputFiles(bool printOutputFiles);
-    void setGeometryValues(bool geometryValues);
-    void setCalc2ndOrderMoments(bool calc2ndOrderMoments);
-    void setCalc3rdOrderMoments(bool calc3rdOrderMoments);
-    void setCalcHighOrderMoments(bool calcHighOrderMoment);
-    void setReadGeo(bool readGeo);
-    void setCalcMedian(bool calcMedian);
-    void setCalcDragLift(bool calcDragLift);
-    void setCalcCp(bool calcCp);
-    void setWriteVeloASCIIfiles(bool writeVeloASCIIfiles);
-    void setCalcPlaneConc(bool calcPlaneConc);
-    void setConcFile(bool concFile);
-    void setStreetVelocityFile(bool streetVelocityFile);
-    void setUseMeasurePoints(bool useMeasurePoints);
-    void setUseWale(bool useWale);
-    void setUseInitNeq(bool useInitNeq);
-    void setSimulatePorousMedia(bool simulatePorousMedia);
-    void setD3Qxx(uint d3Qxx);
-    void setTEnd(uint tEnd);
-    void setTOut(uint tOut);
-    void setTStartOut(uint tStartOut);
-    void setTimeCalcMedStart(uint timeCalcMedStart);
-    void setTimeCalcMedEnd(uint timeCalcMedEnd);
-    void setPressInID(uint pressInID);
-    void setPressOutID(uint pressOutID);
-    void setPressInZ(uint pressInZ);
-    void setPressOutZ(uint pressOutZ);
-    void setDiffOn(bool diffOn);
-    void setDiffMod(uint diffMod);
-    void setDiffusivity(real diffusivity);
-    void setTemperatureInit(real temperatureInit);
-    void setTemperatureBC(real temperatureBC);
-    // void setViscosity(real viscosity);
-    void setVelocity(real velocity);
-    void setViscosityRatio(real viscosityRatio);
-    void setVelocityRatio(real velocityRatio);
-    void setDensityRatio(real fensityRatio);
-    void setPressRatio(real pressRatio);
-    void setRealX(real realX);
-    void setRealY(real realY);
-    void setFactorPressBC(real factorPressBC);
-    void setGeometryFileC(std::string geometryFileC);
-    void setGeometryFileM(std::string geometryFileM);
-    void setGeometryFileF(std::string geometryFileF);
-    void setClockCycleForMP(uint clockCycleForMP);
-    void setTimestepForMP(uint timestepForMP);
-    void setForcingX(real forcingX);
-    void setForcingY(real forcingY);
-    void setForcingZ(real forcingZ);
-    void setQuadricLimiterP(real quadricLimiterP);
-    void setQuadricLimiterM(real quadricLimiterM);
-    void setQuadricLimiterD(real quadricLimiterD);
-    void setCalcParticles(bool calcParticles);
-    void setParticleBasicLevel(int particleBasicLevel);
-    void setParticleInitLevel(int particleInitLevel);
-    void setNumberOfParticles(int numberOfParticles);
-    void setStartXHotWall(real startXHotWall);
-    void setEndXHotWall(real endXHotWall);
-    void setPossNeighborFilesX(const std::vector<std::string> &possNeighborFilesX);
-    void setPossNeighborFilesY(const std::vector<std::string> &possNeighborFilesY);
-    void setPossNeighborFilesZ(const std::vector<std::string> &possNeighborFilesZ);
-    // void setPossNeighborFilesX(std::vector<std::string> possNeighborFilesX);
-    // void setPossNeighborFilesY(std::vector<std::string> possNeighborFilesY);
-    // void setPossNeighborFilesZ(std::vector<std::string> possNeighborFilesZ);
-    void setTimeDoCheckPoint(int timeDoCheckPoint);
-    void setTimeDoRestart(int timeDoRestart);
-    void setDoCheckPoint(bool doCheckPoint);
-    void setDoRestart(bool doRestart);
-    void setMaxLevel(uint maxLevel);
-    void setGridX(const std::vector<int> &gridX);
-    void setGridY(const std::vector<int> &gridY);
-    void setGridZ(const std::vector<int> &gridZ);
-    void setDistX(const std::vector<int> &distX);
-    void setDistY(const std::vector<int> &distY);
-    void setDistZ(const std::vector<int> &distZ);
-    void setNeedInterface(const std::vector<bool> &needInterface);
-    void setMainKernel(const std::string &mainKernel);
-    void setMultiKernelOn(bool multiKernelOn);
-    void setMultiKernelLevel(const std::vector<int> &multiKernelLevel);
-    void setMultiKernelName(const std::vector<std::string> &multiKernelName);
-
-    bool isViscosityInConfigFile() override;
-    bool isNumberOfDevicesInConfigFile() override;
-    bool isDevicesInConfigFile() override;
-    bool isOutputPathInConfigFile() override;
-    bool isPrefixInConfigFile() override;
-    bool isGridPathInConfigFile() override;
-    bool isPrintOutputFilesInConfigFile() override;
-    bool isGeometryValuesInConfigFile() override;
-    bool isCalc2ndOrderMomentsInConfigFile() override;
-    bool isCalc3rdOrderMomentsInConfigFile() override;
-    bool isCalcHighOrderMomentsInConfigFile() override;
-    bool isReadGeoInConfigFile() override;
-    bool isCalcMedianInConfigFile() override;
-    bool isCalcDragLiftInConfigFile() override;
-    bool isCalcCpInConfigFile() override;
-    bool isWriteVeloASCIIfilesInConfigFile() override;
-    bool isCalcPlaneConcInConfigFile() override;
-    bool isConcFileInConfigFile() override;
-    bool isStreetVelocityFileInConfigFile() override;
-    bool isUseMeasurePointsInConfigFile() override;
-    bool isUseWaleInConfigFile() override;
-    bool isUseInitNeqInConfigFile() override;
-    bool isSimulatePorousMediaInConfigFile() override;
-    bool isD3QxxInConfigFile() override;
-    bool isTEndInConfigFile() override;
-    bool isTOutInConfigFile() override;
-    bool isTStartOutInConfigFile() override;
-    bool isTimeCalcMedStartInConfigFile() override;
-    bool isTimeCalcMedEndInConfigFile() override;
-    bool isPressInIDInConfigFile() override;
-    bool isPressOutIDInConfigFile() override;
-    bool isPressInZInConfigFile() override;
-    bool isPressOutZInConfigFile() override;
-    bool isDiffOnInConfigFile() override;
-    bool isDiffModInConfigFile() override;
-    bool isDiffusivityInConfigFile() override;
-    bool isTemperatureInitInConfigFile() override;
-    bool isTemperatureBCInConfigFile() override;
-    // bool isViscosityInConfigFile();
-    bool isVelocityInConfigFile() override;
-    bool isViscosityRatioInConfigFile() override;
-    bool isVelocityRatioInConfigFile() override;
-    bool isDensityRatioInConfigFile() override;
-    bool isPressRatioInConfigFile() override;
-    bool isRealXInConfigFile() override;
-    bool isRealYInConfigFile() override;
-    bool isFactorPressBCInConfigFile() override;
-    bool isGeometryFileCInConfigFile() override;
-    bool isGeometryFileMInConfigFile() override;
-    bool isGeometryFileFInConfigFile() override;
-    bool isClockCycleForMPInConfigFile() override;
-    bool isTimestepForMPInConfigFile() override;
-    bool isForcingXInConfigFile() override;
-    bool isForcingYInConfigFile() override;
-    bool isForcingZInConfigFile() override;
-    bool isQuadricLimiterPInConfigFile() override;
-    bool isQuadricLimiterMInConfigFile() override;
-    bool isQuadricLimiterDInConfigFile() override;
-    bool isCalcParticlesInConfigFile() override;
-    bool isParticleBasicLevelInConfigFile() override;
-    bool isParticleInitLevelInConfigFile() override;
-    bool isNumberOfParticlesInConfigFile() override;
-    bool isNeighborWSBInConfigFile() override;
-    bool isStartXHotWallInConfigFile() override;
-    bool isEndXHotWallInConfigFile() override;
-    bool isPossNeighborFilesXInConfigFile() override;
-    bool isPossNeighborFilesYInConfigFile() override;
-    bool isPossNeighborFilesZInConfigFile() override;
-    bool isTimeDoCheckPointInConfigFile() override;
-    bool isTimeDoRestartInConfigFile() override;
-    bool isDoCheckPointInConfigFile() override;
-    bool isDoRestartInConfigFile() override;
-    bool isMaxLevelInConfigFile() override;
-    bool isGridXInConfigFile() override;
-    bool isGridYInConfigFile() override;
-    bool isGridZInConfigFile() override;
-    bool isDistXInConfigFile() override;
-    bool isDistYInConfigFile() override;
-    bool isDistZInConfigFile() override;
-    bool isNeedInterfaceInConfigFile() override;
-    bool isMainKernelInConfigFile() override;
-    bool isMultiKernelOnInConfigFile() override;
-    bool isMultiKernelLevelInConfigFile() override;
-    bool isMultiKernelNameInConfigFile() override;
-
-private:
-    ConfigDataImp() = default;
-
-    real viscosity { 0. };
-    uint numberOfDevices { 0 };
-    std::vector<uint> devices;
-    std::string outputPath;
-    std::string prefix;
-    std::string gridPath;
-    bool printOutputFiles { false };
-    bool geometryValues { false };
-    bool calc2ndOrderMoments { false };
-    bool calc3rdOrderMoments { false };
-    bool calcHighOrderMoments { false };
-    bool readGeo { false };
-    bool calcMedian { false };
-    bool calcDragLift { false };
-    bool calcCp { false };
-    bool writeVeloASCIIfiles { false };
-    bool calcPlaneConc { false };
-    bool concFile { false };
-    bool streetVelocityFile { false };
-    bool useMeasurePoints { false };
-    bool useWale { false };
-    bool useInitNeq { false };
-    bool simulatePorousMedia { false };
-    uint d3Qxx { 0 };
-    uint tEnd { 0 };
-    uint tOut { 0 };
-    uint tStartOut { 0 };
-    uint timeCalcMedStart { 0 };
-    uint timeCalcMedEnd { 0 };
-    uint pressInID { 0 };
-    uint pressOutID { 0 };
-    uint pressInZ { 0 };
-    uint pressOutZ { 0 };
-    bool diffOn { false };
-    uint diffMod { 0 };
-    real diffusivity { 0. };
-    real temperatureInit { 0. };
-    real temperatureBC { 0. };
-    // real viscosity { 0 };
-    real velocity { 0. };
-    real viscosityRatio { 0. };
-    real velocityRatio { 0. };
-    real densityRatio { 0. };
-    real pressRatio { 0. };
-    real realX { 0. };
-    real realY { 0. };
-    real factorPressBC { 0. };
-    std::string geometryFileC;
-    std::string geometryFileM;
-    std::string geometryFileF;
-    uint clockCycleForMP { 0 };
-    uint timestepForMP { 0 };
-    real forcingX { 0. };
-    real forcingY { 0. };
-    real forcingZ { 0. };
-    real quadricLimiterP { 0. };
-    real quadricLimiterM { 0. };
-    real quadricLimiterD { 0. };
-    bool calcParticles { false };
-    int particleBasicLevel { 0 };
-    int particleInitLevel { 0 };
-    int numberOfParticles { 0 };
-    real startXHotWall { 0. };
-    real endXHotWall { 0. };
-    std::vector<std::string> possNeighborFilesX;
-    std::vector<std::string> possNeighborFilesY;
-    std::vector<std::string> possNeighborFilesZ;
-    // std::vector<std::string> possNeighborFilesX;
-    // std::vector<std::string> possNeighborFilesY;
-    // std::vector<std::string> possNeighborFilesZ;
-    int timeDoCheckPoint { 0 };
-    int timeDoRestart { 0 };
-    bool doCheckPoint{ false };
-    bool doRestart{ false };
-    int maxLevel { 0 };
-    std::vector<int> gridX;
-    std::vector<int> gridY;
-    std::vector<int> gridZ;
-    std::vector<int> distX;
-    std::vector<int> distY;
-    std::vector<int> distZ;
-    std::vector<bool> needInterface;
-    std::string mainKernel;
-    bool multiKernelOn{ false };
-    std::vector<int> multiKernelLevel;
-    std::vector<std::string> multiKernelName;
-
-    bool isViscosity { false };
-    bool isNumberOfDevices {false};
-    bool isDevices { false };
-    bool isOutputPath { false };
-    bool isPrefix { false };
-    bool isGridPath { false };
-    bool isPrintOutputFiles { false };
-    bool isGeometryValues { false };
-    bool isCalc2ndOrderMoments { false };
-    bool isCalc3rdOrderMoments { false };
-    bool isCalcHighOrderMoments { false };
-    bool isReadGeo { false };
-    bool isCalcMedian { false };
-    bool isCalcDragLift { false };
-    bool isCalcCp { false };
-    bool isWriteVeloASCII { false };
-    bool isCalcPlaneConc { false };
-    bool isConcFile { false };
-    bool isStreetVelocityFile { false };
-    bool isUseMeasurePoints { false };
-    bool isUseWale { false };
-    bool isUseInitNeq { false };
-    bool isSimulatePorousMedia { false };
-    bool isD3Qxx { false };
-    bool isTEnd { false };
-    bool isTOut { false };
-    bool isTStartOut { false };
-    bool isTimeCalcMedStart { false };
-    bool isTimeCalcMedEnd { false };
-    bool isPressInID { false };
-    bool isPressOutID { false };
-    bool isPressInZ { false };
-    bool isPressOutZ { false };
-    bool isDiffOn { false };
-    bool isDiffMod { false };
-    bool isDiffusivity { false };
-    bool isTemperatureInit { false };
-    bool isTemperatureBC { false };
-    // bool isViscosity { false };
-    bool isVelocity { false };
-    bool isViscosityRatio { false };
-    bool isVelocityRatio { false };
-    bool isDensityRatio { false };
-    bool isPressRatio { false };
-    bool isRealX { false };
-    bool isRealY { false };
-    bool isFactorPressBC { false };
-    bool isGeometryFileC { false };
-    bool isGeometryFileM { false };
-    bool isGeometryFileF { false };
-    bool isClockCycleForMP { false };
-    bool isTimestepForMP { false };
-    bool isForcingX { false };
-    bool isForcingY { false };
-    bool isForcingZ { false };
-    bool isQuadricLimiterP { false };
-    bool isQuadricLimiterM { false };
-    bool isQuadricLimiterD { false };
-    bool isCalcParticles { false };
-    bool isParticleBasicLevel { false };
-    bool isParticleInitLevel { false };
-    bool isNumberOfParticles { false };
-    bool isNeighborWSB { false };
-    bool isStartXHotWall { false };
-    bool isEndXHotWall { false };
-    bool isPossNeighborFilesX { false };
-    bool isPossNeighborFilesY { false };
-    bool isPossNeighborFilesZ { false };
-    bool isTimeDoCheckPoint { false };
-    bool isTimeDoRestart { false };
-    bool isDoCheckPoint { false };
-    bool isDoRestart { false };
-    bool isMaxLevel { false };
-    bool isGridX { false };
-    bool isGridY { false };
-    bool isGridZ { false };
-    bool isDistX { false };
-    bool isDistY { false };
-    bool isDistZ { false };
-    bool isNeedInterface { false };
-    bool isMainKernel { false };
-    bool isMultiKernelOn { false };
-    bool isMultiKernelLevel { false };
-    bool isMultiKernelName { false };
-};
-#endif
diff --git a/src/basics/Core/Input/ConfigFileReader/ConfigFileReader.cpp b/src/basics/Core/Input/ConfigFileReader/ConfigFileReader.cpp
deleted file mode 100644
index 8fdb9fe1bc7f5dfe10dbfb522a87a4a3187dd60b..0000000000000000000000000000000000000000
--- a/src/basics/Core/Input/ConfigFileReader/ConfigFileReader.cpp
+++ /dev/null
@@ -1,262 +0,0 @@
-#include "ConfigFileReader.h"
-#include "../../StringUtilities/StringUtil.h"
-#include "../ConfigData/ConfigDataImp.h"
-#include "../Input.h"
-
-#include <fstream>
-#include <iostream>
-
-std::shared_ptr<ConfigFileReader> ConfigFileReader::getNewInstance()
-{
-    return std::shared_ptr<ConfigFileReader>(new ConfigFileReader());
-}
-
-std::shared_ptr<ConfigData> ConfigFileReader::readConfigFile(const char* filePath) const
-{
-    std::cout << filePath << std::endl;
-    std::shared_ptr<ConfigDataImp> data = ConfigDataImp::getNewInstance();
-    std::ifstream stream;
-    stream.open(filePath, std::ios::in);
-    if (stream.fail())
-        throw std::runtime_error("can not open config file!");
-    std::unique_ptr<input::Input> input = input::Input::makeInput(stream, "config");
-
-    if (input->getValue("NumberOfDevices") != "")
-        data->setNumberOfDevices(StringUtil::toInt(input->getValue("NumberOfDevices")));
-
-    if (input->getValue("Devices") != "")
-        data->setDevices(StringUtil::toUintVector(input->getValue("Devices")));
-
-    if (input->getValue("Path") != "")
-        data->setOutputPath(input->getValue("Path"));
-
-    if (input->getValue("Prefix") != "")
-        data->setPrefix(input->getValue("Prefix"));
-
-    if (input->getValue("GridPath") != "")
-        data->setGridPath(input->getValue("GridPath"));
-    else {
-        std::cout << "GridPath has to be defined!" << std::endl;
-        exit(1);
-    }
-
-    if (input->getValue("WriteGrid") != "")
-        data->setPrintOutputFiles(StringUtil::toBool(input->getValue("WriteGrid")));
-
-    if (input->getValue("GeometryValues") != "")
-        data->setGeometryValues(StringUtil::toBool(input->getValue("GeometryValues")));
-
-    if (input->getValue("calc2ndOrderMoments") != "")
-        data->setCalc2ndOrderMoments(StringUtil::toBool(input->getValue("calc2ndOrderMoments")));
-
-    if (input->getValue("calc3rdOrderMoments") != "")
-        data->setCalc3rdOrderMoments(StringUtil::toBool(input->getValue("calc3rdOrderMoments")));
-
-    if (input->getValue("calcHigherOrderMoments") != "")
-        data->setCalcHighOrderMoments(StringUtil::toBool(input->getValue("calcHigherOrderMoments")));
-
-    if (input->getValue("ReadGeometry") != "")
-        data->setReadGeo(StringUtil::toBool(input->getValue("ReadGeometry")));
-
-    if (input->getValue("calcMedian") != "")
-        data->setCalcMedian(StringUtil::toBool(input->getValue("calcMedian")));
-
-    if (input->getValue("UseConcFile") != "")
-        data->setConcFile(StringUtil::toBool(input->getValue("UseConcFile")));
-
-    if (input->getValue("UseStreetVelocityFile") != "")
-        data->setStreetVelocityFile(StringUtil::toBool(input->getValue("UseStreetVelocityFile")));
-
-    if (input->getValue("UseMeasurePoints") != "")
-        data->setUseMeasurePoints(StringUtil::toBool(input->getValue("UseMeasurePoints")));
-
-    if (input->getValue("UseWale") != "")
-        data->setUseWale(StringUtil::toBool(input->getValue("UseWale")));
-
-    if (input->getValue("UseInitNeq") != "")
-        data->setUseInitNeq(StringUtil::toBool(input->getValue("UseInitNeq")));
-
-    if (input->getValue("SimulatePorousMedia") != "")
-        data->setSimulatePorousMedia(StringUtil::toBool(input->getValue("SimulatePorousMedia")));
-
-    if (input->getValue("D3Qxx") != "")
-        data->setD3Qxx(StringUtil::toInt(input->getValue("D3Qxx")));
-
-    if (input->getValue("TimeEnd") != "")
-        data->setTEnd(StringUtil::toInt(input->getValue("TimeEnd")));
-
-    if (input->getValue("TimeOut") != "")
-        data->setTOut(StringUtil::toInt(input->getValue("TimeOut")));
-
-    if (input->getValue("TimeStartOut") != "")
-        data->setTStartOut(StringUtil::toInt(input->getValue("TimeStartOut")));
-
-    if (input->getValue("TimeStartCalcMedian") != "")
-        data->setTimeCalcMedStart(StringUtil::toInt(input->getValue("TimeStartCalcMedian")));
-
-    if (input->getValue("TimeEndCalcMedian") != "")
-        data->setTimeCalcMedEnd(StringUtil::toInt(input->getValue("TimeEndCalcMedian")));
-
-    if (input->getValue("PressInID") != "")
-        data->setPressInID(StringUtil::toInt(input->getValue("PressInID")));
-
-    if (input->getValue("PressOutID") != "")
-        data->setPressOutID(StringUtil::toInt(input->getValue("PressOutID")));
-
-    if (input->getValue("PressInZ") != "")
-        data->setPressInZ(StringUtil::toInt(input->getValue("PressInZ")));
-
-    if (input->getValue("PressOutZ") != "")
-        data->setPressOutZ(StringUtil::toInt(input->getValue("PressOutZ")));
-    //////////////////////////////////////////////////////////////////////////
-    if (input->getValue("DiffOn") != "")
-        data->setDiffOn(StringUtil::toBool(input->getValue("DiffOn")));
-
-    if (input->getValue("DiffMod") != "")
-        data->setDiffMod(StringUtil::toInt(input->getValue("DiffMod")));
-
-    if (input->getValue("Diffusivity") != "")
-        data->setDiffusivity(StringUtil::toFloat(input->getValue("Diffusivity")));
-
-    if (input->getValue("Temp") != "")
-        data->setTemperatureInit(StringUtil::toFloat(input->getValue("Temp")));
-
-    if (input->getValue("TempBC") != "")
-        data->setTemperatureBC(StringUtil::toFloat(input->getValue("TempBC")));
-    //////////////////////////////////////////////////////////////////////////
-    if (input->getValue("Viscosity_LB") != "")
-        data->setViscosity(StringUtil::toFloat(input->getValue("Viscosity_LB")));
-
-    if (input->getValue("Velocity_LB") != "")
-        data->setVelocity(StringUtil::toFloat(input->getValue("Velocity_LB")));
-
-    if (input->getValue("Viscosity_Ratio_World_to_LB") != "")
-        data->setViscosityRatio(StringUtil::toFloat(input->getValue("Viscosity_Ratio_World_to_LB")));
-
-    if (input->getValue("Velocity_Ratio_World_to_LB") != "")
-        data->setVelocityRatio(StringUtil::toFloat(input->getValue("Velocity_Ratio_World_to_LB")));
-
-    if (input->getValue("Density_Ratio_World_to_LB") != "")
-        data->setDensityRatio(StringUtil::toFloat(input->getValue("Density_Ratio_World_to_LB")));
-
-    if (input->getValue("Delta_Press") != "")
-        data->setPressRatio(StringUtil::toFloat(input->getValue("Delta_Press")));
-
-    if (input->getValue("SliceRealX") != "")
-        data->setRealX(StringUtil::toFloat(input->getValue("SliceRealX")));
-
-    if (input->getValue("SliceRealY") != "")
-        data->setRealY(StringUtil::toFloat(input->getValue("SliceRealY")));
-
-    if (input->getValue("FactorPressBC") != "")
-        data->setFactorPressBC(StringUtil::toFloat(input->getValue("FactorPressBC")));
-
-    if (input->getValue("GeometryC") != "")
-        data->setGeometryFileC(input->getValue("GeometryC"));
-
-    if (input->getValue("GeometryM") != "")
-        data->setGeometryFileM(input->getValue("GeometryM"));
-
-    if (input->getValue("GeometryF") != "")
-        data->setGeometryFileF(input->getValue("GeometryF"));
-    //////////////////////////////////////////////////////////////////////////
-    if (input->getValue("measureClockCycle") != "")
-        data->setClockCycleForMP(StringUtil::toInt(input->getValue("measureClockCycle")));
-
-    if (input->getValue("measureTimestep") != "")
-        data->setTimestepForMP(StringUtil::toInt(input->getValue("measureTimestep")));
-    //////////////////////////////////////////////////////////////////////////
-    // Forcing
-    if (input->getValue("ForcingX") != "")
-        data->setForcingX(StringUtil::toFloat(input->getValue("ForcingX")));
-    if (input->getValue("ForcingY") != "")
-        data->setForcingY(StringUtil::toFloat(input->getValue("ForcingY")));
-    if (input->getValue("ForcingZ") != "")
-        data->setForcingZ(StringUtil::toFloat(input->getValue("ForcingZ")));
-    //////////////////////////////////////////////////////////////////////////
-    // Quadric Limiters
-    if (input->getValue("QuadricLimiterP") != "")
-        data->setQuadricLimiterP(StringUtil::toFloat(input->getValue("QuadricLimiterP")));
-    if (input->getValue("QuadricLimiterM") != "")
-        data->setQuadricLimiterM(StringUtil::toFloat(input->getValue("QuadricLimiterM")));
-    if (input->getValue("QuadricLimiterD") != "")
-        data->setQuadricLimiterD(StringUtil::toFloat(input->getValue("QuadricLimiterD")));
-    //////////////////////////////////////////////////////////////////////////
-    // Particles
-    if (input->getValue("calcParticles") != "")
-        data->setCalcParticles(StringUtil::toBool(input->getValue("calcParticles")));
-
-    if (input->getValue("baseLevel") != "")
-        data->setParticleBasicLevel(StringUtil::toInt(input->getValue("baseLevel")));
-
-    if (input->getValue("initLevel") != "")
-        data->setParticleInitLevel(StringUtil::toInt(input->getValue("initLevel")));
-
-    if (input->getValue("numberOfParticles") != "")
-        data->setNumberOfParticles(StringUtil::toInt(input->getValue("numberOfParticles")));
-
-    if (input->getValue("startXHotWall") != "")
-        data->setStartXHotWall(real(StringUtil::toDouble(input->getValue("startXHotWall"))));
-
-    if (input->getValue("endXHotWall") != "")
-        data->setEndXHotWall(real(StringUtil::toDouble(input->getValue("endXHotWall"))));
-    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-    // Restart
-    if (input->getValue("TimeDoCheckPoint") != "")
-        data->setTimeDoCheckPoint(StringUtil::toInt(input->getValue("TimeDoCheckPoint")));
-
-    if (input->getValue("TimeDoRestart") != "")
-        data->setTimeDoRestart(StringUtil::toInt(input->getValue("TimeDoRestart")));
-
-    if (input->getValue("DoCheckPoint") != "")
-        data->setDoCheckPoint(StringUtil::toBool(input->getValue("DoCheckPoint")));
-
-    if (input->getValue("DoRestart") != "")
-        data->setDoRestart(StringUtil::toBool(input->getValue("DoRestart")));
-    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-    if (input->getValue("NOGL") != "")
-        data->setMaxLevel(StringUtil::toInt(input->getValue("NOGL")));
-
-    if (input->getValue("GridX") != "")
-        data->setGridX(StringUtil::toIntVector(input->getValue("GridX")));
-
-    if (input->getValue("GridY") != "")
-        data->setGridY(StringUtil::toIntVector(input->getValue("GridY")));
-
-    if (input->getValue("GridZ") != "")
-        data->setGridZ(StringUtil::toIntVector(input->getValue("GridZ")));
-
-    if (input->getValue("DistX") != "")
-        data->setDistX(StringUtil::toIntVector(input->getValue("DistX")));
-
-    if (input->getValue("DistY") != "")
-        data->setDistY(StringUtil::toIntVector(input->getValue("DistY")));
-
-    if (input->getValue("DistZ") != "")
-        data->setDistZ(StringUtil::toIntVector(input->getValue("DistZ")));
-
-    if (input->getValue("NeedInterface") != "")
-        data->setNeedInterface(StringUtil::toBoolVector(input->getValue("NeedInterface")));
-    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-    // Kernel
-    if (input->getValue("MainKernelName") != "")
-        data->setMainKernel(input->getValue("MainKernelName"));
-
-    if (input->getValue("MultiKernelOn") != "")
-        data->setMultiKernelOn(StringUtil::toBool(input->getValue("MultiKernelOn")));
-
-    if (input->getValue("MultiKernelLevel") != "")
-        data->setMultiKernelLevel(StringUtil::toIntVector(input->getValue("MultiKernelLevel")));
-
-    if (input->getValue("MultiKernelName") != "")
-        data->setMultiKernelName(StringUtil::toStringVector(input->getValue("MultiKernelName")));
-
-    if (StringUtil::toStringVector(input->getValue("MultiKernelName")).size() !=
-        StringUtil::toIntVector(input->getValue("MultiKernelLevel")).size()) {
-        std::cout << "MultiKernelName and MultiKernelLevel has to be of same size!" << std::endl;
-        exit(1);
-    }
-    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-    return data;
-}
diff --git a/src/basics/Core/Input/ConfigFileReader/ConfigFileReader.h b/src/basics/Core/Input/ConfigFileReader/ConfigFileReader.h
deleted file mode 100644
index 77c93ebfa4ba8564188d8e4a5442963382cf91e3..0000000000000000000000000000000000000000
--- a/src/basics/Core/Input/ConfigFileReader/ConfigFileReader.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef CONFIGFILEREADER_H
-#define CONFIGFILEREADER_H
-
-
-#include <memory>
-#include <string>
-
-#include "basics_export.h"
-
-class ConfigData;
-
-class ConfigFileReader
-{
-public:
-    BASICS_EXPORT static std::shared_ptr<ConfigFileReader> getNewInstance();
-
-    BASICS_EXPORT std::shared_ptr<ConfigData> readConfigFile(const char* filePath) const;
-
-private:
-    ConfigFileReader() = default;
-};
-#endif
diff --git a/src/basics/Core/Input/ConfigInput/ConfigInput.cpp b/src/basics/Core/Input/ConfigInput/ConfigInput.cpp
deleted file mode 100644
index 1fdff1e8794b5cb58f6b1a8a2e97a536531df829..0000000000000000000000000000000000000000
--- a/src/basics/Core/Input/ConfigInput/ConfigInput.cpp
+++ /dev/null
@@ -1,222 +0,0 @@
-#include "ConfigInput.h"
-#include <algorithm>
-#include <cerrno>
-#include <iostream>
-#include <sstream>
-#include <string>
-
-#define COMMENT '#'
-
-namespace input
-{
-// Trim the given characters from the beginning and end of a string.
-// the default is to trim whitespace. If the string is empty or contains
-// only the trim characters, an empty string is returned.
-std::string trim(const std::string &instring, const std::string &trimstring = std::string(" \t\n"))
-{
-    if (trimstring.size() == 0)
-        return instring;
-    std::string temp              = "";
-    std::string::size_type begpos = instring.find_first_not_of(trimstring);
-    if (begpos == std::string::npos) {
-        return temp;
-    } else {
-        std::string::size_type endpos = instring.find_last_not_of(trimstring);
-        temp                          = instring.substr(begpos, endpos - begpos + 1);
-    }
-    return temp;
-}
-
-ConfigInput::ConfigInput(std::istream &stream) : stream(stream)
-{
-    while (!stream.eof())
-        this->setTokenValuePair();
-}
-
-ConfigInput::~ConfigInput() = default;
-
-bool ConfigInput::hasValue(const std::string &key) const
-{
-    bool valueFound     = false;
-    std::string keyCopy = key;
-    this->makeLower(keyCopy);
-    if (configEntries.find(keyCopy.c_str()) != configEntries.end())
-        valueFound = true;
-
-    return valueFound;
-}
-
-std::string ConfigInput::getValue(const std::string &key)
-{
-    std::string keyCopy = key;
-    this->makeLower(keyCopy);
-    if (configEntries.find(keyCopy.c_str()) != configEntries.end())
-        return (*configEntries.find(keyCopy.c_str())).second;
-    return "";
-}
-
-//////////////////////////////////////////////////////////////////////////
-//                        private methods                               //
-//////////////////////////////////////////////////////////////////////////
-
-void ConfigInput::makeLower(std::string &value) const
-{
-    for (size_t i = 0; i < value.size(); i++)
-        value[i] = tolower(value[i]);
-}
-
-void ConfigInput::setTokenValuePair()
-{
-    this->eatWhiteAndComments(true);
-
-    std::string token;
-    if (!this->setToken(token))
-        return;
-
-    std::string value;
-    this->setValue(value);
-
-    configEntries.insert(String_Pair(token, value));
-}
-
-bool ConfigInput::setToken(std::string &token)
-{
-    char tokenChar[1024];
-    bool foundEqualSign = false;
-    int charIndex       = 0;
-
-    this->findToken(foundEqualSign, tokenChar, charIndex);
-
-    if (!isToken(charIndex, foundEqualSign))
-        return false;
-
-    this->nullTerminate(tokenChar, charIndex);
-    token = tokenChar;
-    makeLower(token);
-    return true;
-}
-
-void ConfigInput::findToken(bool &foundEqualSign, char *token, int &i)
-{
-    char ch;
-    while (!(stream.get(ch)).fail()) {
-        if ((ch != '\t')) {
-            if ((ch == '=') || (ch == ' ') || (ch == '\n') || (ch == '\r') || (ch == '\t')) {
-                foundEqualSign = true;
-                break;
-            }
-            token[i++] = ch;
-        }
-    }
-}
-
-bool ConfigInput::isToken(int charIndex, bool foundEqualSign)
-{
-    if (charIndex == 0) {
-        configEntries.insert(String_Pair("", ""));
-        return false;
-    }
-
-    if (!foundEqualSign && !advanceToEqualSignOnLine()) {
-        configEntries.insert(String_Pair("", ""));
-        return false;
-    }
-    return true;
-}
-
-void ConfigInput::setValue(std::string &value)
-{
-    int charIndex = 0;
-    char valueChar[1024];
-    this->findValue(charIndex, valueChar);
-
-    if (charIndex == 0)
-        value = "";
-    else {
-        this->nullTerminate(valueChar, charIndex);
-        value = valueChar;
-        value = trim(value);
-        this->stripLeadingAndTrailingQuotes(value);
-    }
-}
-
-int ConfigInput::findValue(int &charIndex, char *value)
-{
-    char ch;
-    char c = eatWhiteAndComments(false);
-    if (c != '\n') {
-        charIndex = 0;
-        while (!(stream.get(ch)).fail()) {
-            if ((ch == '\t') || (ch == '\r') || (ch == '\n') || (ch == '#')) {
-                while (ch != '\n') {
-                    if (stream.get(ch).fail())
-                        break;
-                }
-                break;
-            } else {
-                value[charIndex++] = ch;
-            }
-        }
-    }
-    return charIndex;
-}
-
-void ConfigInput::stripLeadingAndTrailingQuotes(std::string &m_value)
-{
-    if (m_value[0] == '"')
-        m_value = m_value.substr(1);
-    if (m_value[m_value.length() - 1] == '"')
-        m_value = m_value.substr(0, m_value.length() - 1);
-}
-
-void ConfigInput::nullTerminate(char *value, int &i) { value[i++] = '\0'; }
-
-bool ConfigInput::advanceToEqualSignOnLine()
-{
-    char ch;
-    bool foundEqual = false;
-    while (!(stream.get(ch)).fail()) {
-        if (isNewLine(ch) || isCarriageReturn(ch))
-            break;
-        if (isEqualSign(ch)) {
-            foundEqual = true;
-            break;
-        }
-    }
-    return foundEqual;
-}
-
-char ConfigInput::eatWhiteAndComments(bool traverseNewlines)
-{
-    char ch;
-    bool isComment = false;
-
-    while (!(stream.get(ch)).fail()) {
-        if (isCommentSign(ch))
-            isComment = true;
-        else if (isNewLine(ch)) {
-            isComment = false;
-            if (!traverseNewlines)
-                return (ch);
-        } else if (isRegularChar(isComment, ch)) {
-            stream.putback(ch);
-            return 0;
-        }
-    }
-    return 0;
-}
-
-bool ConfigInput::isRegularChar(bool isComment, char ch)
-{
-    return (!isComment) && (ch != ' ') && (ch != '\t') && (ch != '\r');
-}
-
-bool ConfigInput::isCommentSign(char ch) { return ch == COMMENT; }
-
-bool ConfigInput::isEqualSign(char ch) { return ch == '='; }
-
-bool ConfigInput::isNewLine(char ch) { return ch == '\n'; }
-
-bool ConfigInput::isCarriageReturn(char ch) { return ch == '\r'; }
-
-} // namespace input
diff --git a/src/basics/Core/Input/ConfigInput/ConfigInput.h b/src/basics/Core/Input/ConfigInput/ConfigInput.h
deleted file mode 100644
index aee9242ca7cb63ac259fe27869c0d4f9d5036b05..0000000000000000000000000000000000000000
--- a/src/basics/Core/Input/ConfigInput/ConfigInput.h
+++ /dev/null
@@ -1,48 +0,0 @@
-#ifndef ConfigInput_H
-#define ConfigInput_H
-#include <istream>
-#include <list>
-#include <map>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "../Input.h"
-#include "basics_export.h"
-
-namespace input
-{
-class ConfigInput : public Input
-{
-public:
-    BASICS_EXPORT ConfigInput(std::istream &stream);
-    BASICS_EXPORT ~ConfigInput() override;
-
-    BASICS_EXPORT bool hasValue(const std::string &key) const override;
-    BASICS_EXPORT std::string getValue(const std::string &key) override;
-
-protected:
-    virtual void setTokenValuePair();
-    void setValue(std::string &value);
-    bool setToken(std::string &token);
-    bool isToken(int charIndex, bool foundEqualSign);
-    int findValue(int &charIndex, char *value);
-    void stripLeadingAndTrailingQuotes(std::string &m_value);
-    void nullTerminate(char *token, int &i);
-    void findToken(bool &foundEqualSign, char *token, int &i);
-    char eatWhiteAndComments(bool traverse_newlines = true);
-    bool isRegularChar(bool isComment, char ch);
-    bool isNewLine(char ch);
-    bool isCommentSign(char ch);
-    bool advanceToEqualSignOnLine();
-    bool isCarriageReturn(char ch);
-    bool isEqualSign(char ch);
-    void makeLower(std::string &instring) const;
-
-protected:
-    std::istream &stream;
-    using String_Pair = std::pair<std::string, std::string>;
-    std::map<std::string, std::string> configEntries;
-};
-} // namespace input
-#endif
diff --git a/src/basics/Core/Input/Input.cpp b/src/basics/Core/Input/Input.cpp
deleted file mode 100644
index f971dd2260d97c28c6e84f60d9b0415eb971ea16..0000000000000000000000000000000000000000
--- a/src/basics/Core/Input/Input.cpp
+++ /dev/null
@@ -1,24 +0,0 @@
-#include "Input.h"
-
-#include <memory>
-
-#ifdef BUILD_JSONCPP
-#include "JsonInput/JsonInput.h"
-#endif
-
-#include "ConfigInput/ConfigInput.h"
-
-namespace input
-{
-
-std::unique_ptr<input::Input> Input::makeInput(std::istream &stream, const std::string & /*inputType*/)
-{
-#ifdef BUILD_JSONCPP
-    if (inputType == "json")
-        return std::unique_ptr<Input>(new JsonInput(stream));
-#endif
-
-    return std::make_unique<ConfigInput>(stream);
-}
-
-} // namespace input
diff --git a/src/basics/Core/Input/Input.h b/src/basics/Core/Input/Input.h
deleted file mode 100644
index 3b07b8b32d99293c3216e1a14dc9df9fc9688bea..0000000000000000000000000000000000000000
--- a/src/basics/Core/Input/Input.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef Input_H
-#define Input_H
-
-#include "basics_export.h"
-
-#include <istream>
-#include <memory>
-#include <string>
-
-namespace input
-{
-class Input
-{
-public:
-    static BASICS_EXPORT std::unique_ptr<Input> makeInput(std::istream &stream, const std::string &inputType);
-
-    virtual ~Input() = default;
-
-    virtual bool hasValue(const std::string &key) const  = 0;
-    virtual std::string getValue(const std::string &key) = 0;
-};
-} // namespace input
-
-#endif
diff --git a/src/basics/Core/Input/JsonInput/JsonInput.cpp b/src/basics/Core/Input/JsonInput/JsonInput.cpp
deleted file mode 100644
index 34a1d154a386d267c4d086e28b5f7e5f64c302cc..0000000000000000000000000000000000000000
--- a/src/basics/Core/Input/JsonInput/JsonInput.cpp
+++ /dev/null
@@ -1,67 +0,0 @@
-#ifdef BUILD_JSONCPP
-
-#include "JsonInput.h"
-
-#include <fstream>
-#include <iterator>
-#include <sstream>
-#include <string>
-#include <vector>
-
-namespace input
-{
-template <typename Out>
-void split(const std::string &s, char delim, Out result)
-{
-    std::stringstream ss;
-    ss.str(s);
-    std::string item;
-    while (std::getline(ss, item, delim)) {
-        *(result++) = item;
-    }
-}
-
-std::vector<std::string> split(const std::string &s, char delim)
-{
-    std::vector<std::string> elems;
-    split(s, delim, std::back_inserter(elems));
-    return elems;
-}
-
-JsonInput::JsonInput(std::istream &stream)
-{
-    Json::Reader reader;
-    reader.parse(stream, jsonValue);
-}
-
-bool JsonInput::hasValue(const std::string &key) const
-{
-    auto keys = split(key, ' ');
-
-    if (keys.size() == 1 && !jsonValue[keys[0]].isNull())
-        return true;
-    else if (keys.size() == 2 && !jsonValue[keys[0]][keys[1]].isNull())
-        return true;
-    else if (keys.size() == 3 && !jsonValue[keys[0]][keys[1]][keys[2]].isNull())
-        return true;
-    else
-        return false;
-}
-
-std::string JsonInput::getValue(const std::string &key)
-{
-    auto keys = split(key, ' ');
-
-    if (keys.size() == 1)
-        return jsonValue[keys[0]].asString();
-    else if (keys.size() == 2)
-        return jsonValue[keys[0]][keys[1]].asString();
-    else if (keys.size() == 3)
-        return jsonValue[keys[0]][keys[1]][keys[2]].asString();
-    else
-        return "";
-}
-
-} // namespace input
-
-#endif
diff --git a/src/basics/Core/Input/JsonInput/JsonInput.h b/src/basics/Core/Input/JsonInput/JsonInput.h
deleted file mode 100644
index 8a33e99bfe2904caff82349caaf2579049892b15..0000000000000000000000000000000000000000
--- a/src/basics/Core/Input/JsonInput/JsonInput.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifdef BUILD_JSONCPP
-
-#ifndef JsonInput_H
-#define JsonInput_H
-
-#include <json/json.h>
-#include <string>
-
-#include "basics_export.h"
-
-#include "../Input.h"
-
-namespace input
-{
-class JsonInput : public Input
-{
-public:
-    BASICS_EXPORT JsonInput(std::istream &stream);
-
-    BASICS_EXPORT virtual bool hasValue(const std::string &key) const override;
-    BASICS_EXPORT virtual std::string getValue(const std::string &key) override;
-
-private:
-    Json::Value jsonValue;
-};
-} // namespace input
-
-#endif
-
-#endif
diff --git a/src/basics/Core/Logger/Logger.cpp b/src/basics/Core/Logger/Logger.cpp
index 6ee96cba58ad6a4c95e25792963027b2e53a4df7..1a27ef6f2a33bf46b9f488a4cf8d17705c2a64e6 100644
--- a/src/basics/Core/Logger/Logger.cpp
+++ b/src/basics/Core/Logger/Logger.cpp
@@ -1,5 +1,36 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file Logger.cpp
+//! \ingroup Logger
+//! \author Stephan Lenz
+//=======================================================================================
 #include "Logger.h"
-//#include "mpi.h"
 #include <iostream>
 #include <memory>
 
diff --git a/src/basics/Core/Logger/Logger.h b/src/basics/Core/Logger/Logger.h
index d0cd91938868283ec7d13faa7439cf22d7c00729..53cb974b8e409a8ba6eb555abac41ca99eb2bbcf 100644
--- a/src/basics/Core/Logger/Logger.h
+++ b/src/basics/Core/Logger/Logger.h
@@ -1,3 +1,35 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file Logger.h
+//! \ingroup Logger
+//! \author Stephan Lenz
+//=======================================================================================
 #ifndef Logger_H
 #define Logger_H
 
diff --git a/src/basics/Core/Logger/implementations/LoggerImp.cpp b/src/basics/Core/Logger/implementations/LoggerImp.cpp
index f002fdc59ee0a92bdc1be79a74aa347f0451600d..086c0e3aa5153f017905cd8476248ea7a7434335 100644
--- a/src/basics/Core/Logger/implementations/LoggerImp.cpp
+++ b/src/basics/Core/Logger/implementations/LoggerImp.cpp
@@ -1,3 +1,35 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file LoggerImp.cpp
+//! \ingroup Logger
+//! \author Stephan Lenz
+//=======================================================================================
 #include "LoggerImp.h"
 
 #include <chrono>
diff --git a/src/basics/Core/Logger/implementations/LoggerImp.h b/src/basics/Core/Logger/implementations/LoggerImp.h
index 45b64b6dc2208991ca3c1ac67ad80af0b2ea6f22..070b06a23ee59a1d387f09fc86960dd3083c4e61 100644
--- a/src/basics/Core/Logger/implementations/LoggerImp.h
+++ b/src/basics/Core/Logger/implementations/LoggerImp.h
@@ -1,3 +1,35 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file LoggerImp.h
+//! \ingroup Logger
+//! \author Stephan Lenz
+//=======================================================================================
 #ifndef LoggerImp_H
 #define LoggerImp_H
 
diff --git a/src/basics/Core/NonCreatable.h b/src/basics/Core/NonCreatable.h
index b25fc808bf0607a047b46643b412b23fb71037b0..c581a19ec92b666f45109f1e3c66b9e57fb54614 100644
--- a/src/basics/Core/NonCreatable.h
+++ b/src/basics/Core/NonCreatable.h
@@ -1,7 +1,35 @@
-/*
- *  Author: S. Peters
- *  mail: peters@irmb.tu-bs.de
- */
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file NonCreatable.h
+//! \ingroup Core
+//! \author Soeren Peters
+//=======================================================================================
 #ifndef NON_CREATABLE_H
 #define NON_CREATABLE_H
 
diff --git a/src/basics/Core/RealConstants.h b/src/basics/Core/RealConstants.h
index d353a341c9f75d58d11ede3048f3cb0521be40b3..697d628986bb417ab124c465526d0538b2734438 100644
--- a/src/basics/Core/RealConstants.h
+++ b/src/basics/Core/RealConstants.h
@@ -1,3 +1,35 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file RealConstants.h
+//! \ingroup Core
+//! \author Martin Schoenherr
+//=======================================================================================
 #ifndef REAL_CONSTANT_H
 #define REAL_CONSTANT_H
 
diff --git a/src/basics/Core/StringUtilities/StringUtil.cpp b/src/basics/Core/StringUtilities/StringUtil.cpp
index 327a62346a91073834c8b710e90968a524ee2d28..d8bcae7a513d498418c62d2f39a8b7bdd450468d 100644
--- a/src/basics/Core/StringUtilities/StringUtil.cpp
+++ b/src/basics/Core/StringUtilities/StringUtil.cpp
@@ -1,3 +1,35 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file StringUtil.cpp
+//! \ingroup StringUtilities
+//! \author Konstantin Kutscher, Soeren Textor, Sebastian Geller
+//=======================================================================================
 #include "StringUtil.h"
 
 #include <string.h>
diff --git a/src/basics/Core/StringUtilities/StringUtil.h b/src/basics/Core/StringUtilities/StringUtil.h
index 1927a69bc60bf2467fb09893463b3c9363191890..b1b777ad2a512ec78061f019df6e043bfb1cf37b 100644
--- a/src/basics/Core/StringUtilities/StringUtil.h
+++ b/src/basics/Core/StringUtilities/StringUtil.h
@@ -1,3 +1,35 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file StringUtil.h
+//! \ingroup StringUtilities
+//! \author Konstantin Kutscher, Soeren Textor, Sebastian Geller
+//=======================================================================================
 #ifndef STRINGUTIL_H
 #define STRINGUTIL_H
 
diff --git a/src/basics/Core/Timer/Timer.cpp b/src/basics/Core/Timer/Timer.cpp
index 9ca58ed190a5ff68d9f57e8d27fda73f94958ef8..c8856f72adffe0c407ff29ee74246638ce5c8280 100644
--- a/src/basics/Core/Timer/Timer.cpp
+++ b/src/basics/Core/Timer/Timer.cpp
@@ -1,3 +1,35 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file Timer.cpp
+//! \ingroup Timer
+//! \author Stephan Lenz
+//=======================================================================================
 #include "Timer.h"
 #include "TimerImp.h"
 
diff --git a/src/basics/Core/Timer/Timer.h b/src/basics/Core/Timer/Timer.h
index e8a97000fb8cc3967490e60edca1c564cc8431c7..6de04b2f3d5573ac6266bd2c35cf18cd232384dd 100644
--- a/src/basics/Core/Timer/Timer.h
+++ b/src/basics/Core/Timer/Timer.h
@@ -1,3 +1,35 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file Timer.h
+//! \ingroup Timer
+//! \author Stephan Lenz
+//=======================================================================================
 #ifndef TIMER_H
 #define TIMER_H
 
diff --git a/src/basics/Core/Timer/TimerImp.cpp b/src/basics/Core/Timer/TimerImp.cpp
index 7aef3e999c0d5466fb69b08eafa32fa95370383b..76f9ac36793f2e2543abe9086f2780ee94b50eb7 100644
--- a/src/basics/Core/Timer/TimerImp.cpp
+++ b/src/basics/Core/Timer/TimerImp.cpp
@@ -1,3 +1,35 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file TimerImp.cpp
+//! \ingroup Timer
+//! \author Stephan Lenz
+//=======================================================================================
 #include "TimerImp.h"
 
 void TimerImp::start() { this->startTime = std::chrono::high_resolution_clock::now(); }
diff --git a/src/basics/Core/Timer/TimerImp.h b/src/basics/Core/Timer/TimerImp.h
index bcc078db9a4f00eb23abe93a9a1e16509c948820..e180ae084cb19b939f6e7a82cae7a0db3cc1ea15 100644
--- a/src/basics/Core/Timer/TimerImp.h
+++ b/src/basics/Core/Timer/TimerImp.h
@@ -1,3 +1,35 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file TimerImp.h
+//! \ingroup Timer
+//! \author Stephan Lenz
+//=======================================================================================
 #ifndef TIMER_IMP_H
 #define TIMER_IMP_H
 
diff --git a/src/basics/Core/VectorTypes.cpp b/src/basics/Core/VectorTypes.cpp
index dab2675093415ec103d1bf7ffd3666d57b0977f5..ecc986be836cb3c85d760f4db408707bfb1180b4 100644
--- a/src/basics/Core/VectorTypes.cpp
+++ b/src/basics/Core/VectorTypes.cpp
@@ -1,3 +1,35 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file VectorTypes.cpp
+//! \ingroup Core
+//! \author Soeren Peters
+//=======================================================================================
 #include "VectorTypes.h"
 
 // Vec3 Vec3::operator+( Vec3& left, Vec3& right ){
diff --git a/src/basics/Core/VectorTypes.h b/src/basics/Core/VectorTypes.h
index 3109112b299e5ac169d9f536a4d4e66b7970cff2..2ca45b359397c712b8b8695b9a99b4c5f8c324d1 100644
--- a/src/basics/Core/VectorTypes.h
+++ b/src/basics/Core/VectorTypes.h
@@ -1,3 +1,35 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file VectorTypes.h
+//! \ingroup Core
+//! \author Soeren Peters
+//=======================================================================================
 #ifndef VECTORTYPES_H
 #define VECTORTYPES_H
 
@@ -20,7 +52,7 @@
 #include "RealConstants.h"
 
 struct BASICS_EXPORT Vec3 {
-    real x{ c0o1 }, y{ c0o1 }, z{ c0o1 };
+    real x{ 0. }, y{ 0. }, z{ 0. };
 
     __host__ __device__ Vec3(real x, real y, real z) : x(x), y(y), z(z) {}
     Vec3() = default;
diff --git a/src/basics/Core/buildInfo.h b/src/basics/Core/buildInfo.h
index a5499518c7a13ea52d470895b702ca0aab1294e0..598d5ee742fc329c01c66a24429cd20b2cebe89e 100644
--- a/src/basics/Core/buildInfo.h
+++ b/src/basics/Core/buildInfo.h
@@ -1,3 +1,35 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file buildInfo.h
+//! \ingroup Core
+//! \author Soeren Peters
+//=======================================================================================
 #ifndef buildInfo_H
 #define buildInfo_H
 
diff --git a/src/basics/basics/container/CbVectorPool.h b/src/basics/basics/container/CbVectorPool.h
new file mode 100644
index 0000000000000000000000000000000000000000..f764dd9e53df7b3b0f07500a3cfa6577476819f7
--- /dev/null
+++ b/src/basics/basics/container/CbVectorPool.h
@@ -0,0 +1,500 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file CbVectorPool.h
+//! \ingroup container
+//! \author Soeren Freudiger, Sebastian Geller
+//=======================================================================================
+#ifndef CBVECTORPOOL_H
+#define CBVECTORPOOL_H
+
+#include <iostream>
+#include <limits>
+#include <map>
+#include <sstream>
+#include <typeinfo>
+#include <vector>
+
+#include <basics/container/CbVector.h>
+#include <basics/utilities/UbException.h>
+#include <basics/utilities/UbLogger.h>
+#include <basics/utilities/UbTuple.h>
+
+//#include "MPICommunicator.h"
+//
+//#include <execinfo.h>
+//#include <stdio.h>
+//#include <stdlib.h>
+//#include <unistd.h>
+
+/*=========================================================================*/
+/*  CbVectorPool                                                               */
+/*                                                                         */
+/**
+<BR><BR>
+@author <A HREF="mailto:muffmolch@gmx.de">S. Freudiger</A>
+@version 1.0 - 08.11.07
+@version 1.1 - 09.02.08
+*/
+
+/*
+Durch Verwendung eines CbVectors in Verbindung mit einem CbVectorAllocatorPool
+wird der Datenvector nicht direkt im CbVector gehalten, sondern ist ein Teil
+des Datenvectors des Uebergabe-CbVectorPools.
+Die Methoden der von CbVectors funktionieren fehlerfrei
+Es mss einem jedoch bewusst sein, dass die "resize"-Methoden l�nger ben�tigen, da
+u.U. viele Elemente im Speicher verschoeben werden muessen.
+Der Poolvector enthaelt KEINE gaps, so dass er z.B. gut zur �bertragung via MPI
+geeignet ist...
+
+Verhaltensweise bei Zerstoeren des Pools:
+wird der Pool zerst�rt bevor man die CbVectoren zerst�rt, so wird beim n�chsten
+Datenzugriffsversuch eine entsprechende Exception geworfen, denn alle DatenElemente
+des CbVEctors werden restet und der Pool dort zu NULL gesetzt.
+
+Verhaltensweise bei Zerstoeren eines CbVectors:
+hier ganz normal der Datenspeicher wieder freigegen und der Poolvektor verk�rzt
+*/
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
+template <typename T>
+class CbVectorAllocatorPool;
+
+/*==================================================================*/
+template <typename T>
+class CbVectorPool
+{
+public:
+    using value_type = typename CbVector<T>::value_type;
+    using size_type  = typename CbVector<T>::size_type;
+    using Pool       = std::vector<value_type>;
+
+    using CbVectorKey     = std::string;
+    using CbVectorMap     = std::map<CbVectorKey, CbVector<value_type> *>;
+    using CbVectorMapIter = typename CbVectorMap::iterator;
+
+public:
+    //////////////////////////////////////////////////////////////////////////
+    CbVectorPool(const size_type &startPoolSize = 20000) // startPoolSize*sizeof(T)/1024/1024 [MB]
+        : poolStartAdress(NULL), nextCbVectorStartIndexInPool(0), nextCbVectorKey()
+    {
+        pool.reserve(startPoolSize);
+    }
+    /*==================================================================*/
+    virtual ~CbVectorPool()
+    {
+        // hier werden lediglich ihre datenvektoren "resetet"
+        for (CbVectorMapIter it = cbVectorMap.begin(); it != cbVectorMap.end(); ++it) {
+            CbVector<value_type> &vec = *it->second;
+            CbVectorAllocatorPool<value_type> &allocator =
+                dynamic_cast<CbVectorAllocatorPool<value_type> &>(*vec.getAllocator());
+            // FIXME: //if(allocator.ptrVectorPool != this) UB_THROW( UbException(UB_EXARGS,"CbVectorAllocator is part
+            // of different Pool") );
+
+            // allocator daten reseten
+            allocator.ptrVectorPool    = NULL;
+            allocator.key              = CbVectorKey();
+            allocator.startIndexInPool = 0;
+
+            // Datenzeiger/-groessen reseten
+            allocator.ptrDataOf(vec)  = NULL;
+            allocator.dataSizeOf(vec) = 0;
+        }
+    }
+    /*==========================================================*/
+    CbVectorKey getNextCbVectorKey() const { return this->nextCbVectorKey; }
+    /*==================================================================*/
+    bool allocVectorData(CbVector<value_type> &vec, const size_type &dataSize, const value_type &value = value_type())
+    {
+        // pool-allocator holen
+        CbVectorAllocatorPool<value_type> &allocator =
+            dynamic_cast<CbVectorAllocatorPool<value_type> &>(*vec.getAllocator());
+        if (allocator.ptrVectorPool != this)
+            UB_THROW(UbException(UB_EXARGS, "CbVectorAllocator is part of different Pool"));
+
+        // alloc nur wenn cbVector noch kein Element von Pool!
+        if (cbVectorMap.find(allocator.key) == cbVectorMap.end()) {
+            return this->allocData(allocator, vec, dataSize, value);
+        }
+
+        UB_THROW(UbException(UB_EXARGS, "vector-key=" + UbSystem::toString(allocator.key) + " already taken! (e.g. SetConnectorBlockVisitor was called several times"));
+    }
+    /*==================================================================*/
+    bool resizeVectorData(CbVector<value_type> &vec, const size_type &dataSize, const value_type &value = value_type())
+    {
+        CbVectorAllocatorPool<value_type> &allocator =
+            dynamic_cast<CbVectorAllocatorPool<value_type> &>(*vec.getAllocator());
+        if (allocator.ptrVectorPool != this)
+            UB_THROW(UbException(UB_EXARGS, "CbVectorAllocator is part of different Pool"));
+
+        // cbVector noch nicht in map?
+        CbVectorMapIter pos = cbVectorMap.find(allocator.key);
+
+        if (pos != cbVectorMap.end()) // cbVector vorhanden
+        {
+            // wenn bei alloc keine Laenge zugewiesen wurde, so erfolgt das nun
+            if (allocator.startIndexInPool == 0 && allocator.ptrDataOf(vec) == NULL)
+                return this->allocData(allocator, vec, dataSize, value);
+            else
+                return this->resizeData(allocator, vec, dataSize, value);
+        }
+
+        UB_THROW(UbException(UB_EXARGS,
+                             "vector gehoert laut allocator zum pool aber den key gibt s nicht... wie kann das sein?"));
+    }
+    /*==================================================================*/
+    bool deallocVectorData(CbVector<value_type> &vec)
+    {
+        CbVectorAllocatorPool<value_type> &allocator =
+            dynamic_cast<CbVectorAllocatorPool<value_type> &>(*vec.getAllocator());
+        if (allocator.ptrVectorPool != this)
+            UB_THROW(UbException(UB_EXARGS, "CbVectorAllocator is part of different Pool"));
+
+        // nur wenn vector auch teil des
+        if (cbVectorMap.erase(allocator.key) > 0) {
+            if (this->resizeData(allocator, vec, 0, 0)) {
+                allocator.ptrVectorPool    = NULL;
+                allocator.key              = CbVectorKey();
+                allocator.startIndexInPool = 0;
+
+                // das Datenzeiger/-groessen reseten wird bereits in resize durchgefuehrt
+                return true;
+            } else
+                UB_THROW(UbException(UB_EXARGS, "unknown error"));
+        }
+
+        // SPtr<Communicator> comm = MPICommunicator::getInstance();
+        // int myid = comm->getProcessID();
+
+        //      // Get the name of the processor
+        //      char machinename[MPI_MAX_PROCESSOR_NAME];
+        //      int name_len;
+        //      MPI_Get_processor_name(machinename, &name_len);
+        //      UBLOG(logINFO, "PID = " << myid << " host name: " << machinename);
+        //
+        //      int j, nptrs;
+        //#define SIZE 100
+        //      void *buffer[100];
+        //      char **strings;
+        //
+        //      nptrs = backtrace(buffer, SIZE);
+        //      printf("backtrace() returned %d addresses\n", nptrs);
+        //
+        //      /* The call backtrace_symbols_fd(buffer, nptrs, STDOUT_FILENO)
+        //      would produce similar output to the following: */
+        //
+        //      strings = backtrace_symbols(buffer, nptrs);
+        //      if (strings == NULL)
+        //      {
+        //         perror("backtrace_symbols");
+        //         exit(EXIT_FAILURE);
+        //      }
+        //
+        //      for (j = 0; j < nptrs; j++)
+        //         printf("%s\n", strings[j]);
+        //
+        //      free(strings);
+
+        UB_THROW(UbException(UB_EXARGS,
+                             "vector gehoert laut allocator zum pool aber den key gibt s nicht... wie kann das sein?"));
+    }
+    /*==================================================================*/
+    friend std::ostream &operator<<(std::ostream &os, const CbVectorPool &cbPool)
+    {
+        os << "map" << std::endl;
+        for (CbVectorMapIter pos = cbPool.cbVectorMap.begin(); pos != cbPool.cbVectorMap.end(); ++pos) {
+            CbVectorAllocatorPool<value_type> &tmpAllocator =
+                dynamic_cast<CbVectorAllocatorPool<value_type> &>(*pos->second->getAllocator());
+            os << "vector-size=" << pos->second->size() << "vector-Adress=" << tmpAllocator->ptrDataOf(*pos->second)
+               << ", allocator(key=" << tmpAllocator.key << ", startIndex=" << tmpAllocator.startIndexInPool << ")"
+               << std::endl;
+            for (size_type i = 0; i < pos->second->size(); i++)
+                os << (*pos->second)[i] << ",";
+            os << std::endl;
+        }
+        os << "pool" << std::endl;
+        for (size_type i = 0; i < cbPool.pool.size(); i++) {
+            os << cbPool.pool[i] << ",";
+            os << std::endl;
+        }
+
+        return os;
+    }
+    /*==================================================================*/
+    typename CbVectorMap::size_type getNofStoredVectors() const { return this->cbVectorMap.size(); }
+    /*==================================================================*/
+    typename Pool::size_type getPoolSize() const { return this->pool.size(); }
+    /*==================================================================*/
+    // checks if all vectors have one to one pool-entries
+    bool consistencyCheck()
+    {
+        std::vector<int> pool2(pool.size(), 0);
+        for (CbVectorMapIter it = cbVectorMap.begin(); it != cbVectorMap.end(); ++it) {
+            CbVector<value_type> &tmpVec = *it->second;
+            CbVectorAllocatorPool<value_type> &tmpAllocator =
+                dynamic_cast<CbVectorAllocatorPool<value_type> &>(*tmpVec.getAllocator());
+            for (size_type i = tmpAllocator.startIndexInPool; i < tmpAllocator.startIndexInPool + tmpVec.size(); ++i) {
+                pool2.at(i)++;
+            }
+        }
+        for (size_type i = 0; i < pool2.size(); ++i) {
+            if (pool2.at(i) > 1) {
+                UBLOG(logERROR, UB_FUNCTION << " - test failed typo 1");
+                return false;
+            }
+            if (pool2.at(i) < 1) {
+                UBLOG(logERROR, UB_FUNCTION << " - test failed typo 2");
+                return false;
+            }
+        }
+        return true;
+    }
+
+protected:
+    /*==================================================================*/
+    inline bool allocData(CbVectorAllocatorPool<value_type> &allocator, CbVector<value_type> &vec,
+                          const size_type &dataSize, const value_type &value)
+    {
+        // safety checks
+        if (allocator.startIndexInPool != 0 || allocator.ptrDataOf(vec) != NULL || allocator.dataSizeOf(vec) != 0) {
+            UB_THROW(UbException(UB_EXARGS, "zu allokierender vector ist nicht ganz sauber!!"));
+        }
+
+        // poolVector vergroessern
+        if (dataSize > 0) {
+            pool.resize(pool.size() + dataSize, value);
+
+            // Zeiger der vorhandenen CbVectoren neu setzen, wenn Pool im Speicher verschoben wurde
+            if (poolStartAdress != &pool.front()) {
+                poolStartAdress = &pool.front();
+                for (CbVectorMapIter it = cbVectorMap.begin(); it != cbVectorMap.end(); ++it) {
+                    CbVector<value_type> &tmpVec = *it->second;
+                    CbVectorAllocatorPool<value_type> &tmpAllocator =
+                        dynamic_cast<CbVectorAllocatorPool<value_type> &>(*tmpVec.getAllocator());
+
+                    if (!tmpAllocator.ptrDataOf(tmpVec))
+                        continue; // Fall: CbVector hat noch keinen Datenbereich (data zeigt auf NULL)
+                    tmpAllocator.ptrDataOf(tmpVec) = &pool[tmpAllocator.startIndexInPool];
+                }
+                // std::cout<<"CbVectorPoolMpi::allocVectorData vector wurde im speicher verschoben - adressen
+                // angepasst!!!"<<std::endl;
+            }
+
+            // aktuellem element adresse zuweisen (wurde evtl schon inder schleife zuvor gemacht)
+            allocator.ptrDataOf(vec)   = &pool.at(nextCbVectorStartIndexInPool);
+            allocator.startIndexInPool = nextCbVectorStartIndexInPool;
+
+            // neuen StartIndex fuer naechstes Element berechnen
+            nextCbVectorStartIndexInPool += dataSize;
+            if (nextCbVectorStartIndexInPool != pool.size())
+                UB_THROW(UbException(UB_EXARGS, "index Problem... Annahme falsch?"));
+        }
+
+        // vector zu map hinzuf�gen (speicher wird dann anschliessend zugwiesen)
+        cbVectorMap.insert(
+            std::make_pair(allocator.key, &vec)); // ist angeblich performanter als  cbVectorMap[ allocator.key ] =
+                                                  // cbVector; //aus Effective STL von Scott Meyer
+        allocator.dataSizeOf(vec) = dataSize;
+
+        // dummDoof nextKey-Generung...
+        if (allocator.key >= this->nextCbVectorKey)
+            this->nextCbVectorKey = allocator.key + "1";
+
+        return true;
+    }
+    /*==========================================================*/
+    bool resizeData(CbVectorAllocatorPool<value_type> &allocator, CbVector<value_type> &vec, const size_type &dataSize,
+                    const value_type &value)
+    {
+        // datenvector verlaengern/-kuerzen
+        typename Pool::iterator startPos =
+            pool.begin() + allocator.startIndexInPool; // startPosition der cbVector-Daten im Pool
+        if (vec.size() > dataSize)
+            pool.erase(startPos + dataSize, startPos + vec.size());
+        else
+            pool.insert(startPos + vec.size(), dataSize - vec.size(), value);
+
+        //////////////////////////////////////////////////////////////////////////
+        // adressen und laengen der einzelnen vectoren anpassen
+        if (!pool.empty()) {
+            bool poolMoved  = (poolStartAdress != &pool.front());
+            poolStartAdress = &pool.front();
+
+            for (CbVectorMapIter it = cbVectorMap.begin(); it != cbVectorMap.end(); ++it) {
+                CbVector<value_type> &tmpVec = *it->second;
+
+                if (tmpVec.size() > 0) {
+                    CbVectorAllocatorPool<value_type> &tmpAllocator =
+                        dynamic_cast<CbVectorAllocatorPool<value_type> &>(*tmpVec.getAllocator());
+                    // liegt CbVector VOR ver�ndertem CbVector?
+                    if (tmpAllocator.startIndexInPool <=
+                        allocator.startIndexInPool) // ja: anpassung NUR wenn pool verschoben wurde!
+                    {
+                        if (poolMoved && tmpVec.size() > 0)
+                            tmpAllocator.ptrDataOf(tmpVec) = &pool[tmpAllocator.startIndexInPool];
+                    } else // nein: -> Adresse + Index MUSS immer angepasst werden
+                    {
+                        tmpAllocator.startIndexInPool += dataSize - vec.size();
+                        tmpAllocator.ptrDataOf(tmpVec) = &pool[tmpAllocator.startIndexInPool];
+                    }
+                }
+            }
+        } else // Sonderfall: alle Elemente haben Laenge 0 -> kein pool -> alle Feld-Adressen auf NULL setzen!
+        {
+            poolStartAdress = NULL;
+            for (CbVectorMapIter it = cbVectorMap.begin(); it != cbVectorMap.end(); ++it) {
+                CbVector<value_type> &tmpVec = *it->second;
+                CbVectorAllocatorPool<value_type> &tmpAllocator =
+                    dynamic_cast<CbVectorAllocatorPool<value_type> &>(*tmpVec.getAllocator());
+                tmpAllocator.startIndexInPool = 0;
+            }
+        }
+
+        // restliche Daten von cbVector + allocator aktualisieren
+        allocator.dataSizeOf(vec) = dataSize;
+        if (dataSize == 0) {
+            allocator.ptrDataOf(vec)   = NULL;
+            allocator.startIndexInPool = 0;
+        }
+
+        nextCbVectorStartIndexInPool = pool.size();
+
+        return true;
+    }
+
+protected:
+    /*==================================================================*/
+    void getCbVectorData(const CbVector<value_type> &vec, CbVectorKey &vectorKey, size_type &startIndexInPool,
+                         size_type &dataSize)
+    {
+        CbVectorAllocatorPool<value_type> &allocator =
+            dynamic_cast<CbVectorAllocatorPool<value_type> &>(*vec.getAllocator());
+
+        startIndexInPool = allocator.startIndexInPool;
+        vectorKey        = allocator.key;
+        dataSize         = vec.size();
+    }
+    /*==================================================================*/
+    void setCbVectorData(CbVector<value_type> &vec, const CbVectorKey &vectorKey, const size_type &startIndexInPool,
+                         const size_type &dataSize)
+    {
+        CbVectorAllocatorPool<value_type> &allocator =
+            dynamic_cast<CbVectorAllocatorPool<value_type> &>(*vec.getAllocator());
+
+        allocator.startIndexInPool = startIndexInPool;
+        allocator.key              = vectorKey;
+        allocator.dataSizeOf(vec)  = dataSize;
+        allocator.ptrDataOf(vec)   = &this->pool[startIndexInPool];
+    }
+    /*==================================================================*/
+
+    CbVectorMap cbVectorMap; // informationsmap fuer MPIData und zugewiesener vector
+
+    Pool pool;                                             // globaler Datenvector
+    typename Pool::pointer poolStartAdress;                // StartAdresse des aktuellen Datenvektors
+    typename Pool::size_type nextCbVectorStartIndexInPool; // StartIndex fuer den naechsten CbVector
+
+    // key - erstmal dummdoof
+    CbVectorKey nextCbVectorKey;
+};
+
+//////////////////////////////////////////////////////////////////////////
+//  CbVectorAllocatorPool
+//////////////////////////////////////////////////////////////////////////
+template <typename T>
+class CbVectorAllocatorPool : public CbVectorAllocator<T>
+{
+public:
+    // typedefs wiederholen, da Basisklasse = template -> "Dependent-Base"-Problem
+    using value_type = typename CbVector<T>::value_type;
+    using size_type  = typename CbVector<value_type>::size_type;
+
+    friend class CbVectorPool<value_type>;
+
+    CbVectorAllocatorPool(const CbVectorAllocatorPool &) = delete;
+    const CbVectorAllocatorPool &operator=(const CbVectorAllocatorPool &) = delete;
+
+public:
+    /*==========================================================*/
+    CbVectorAllocatorPool(const typename CbVectorPool<value_type>::CbVectorKey &key,
+                          CbVectorPool<value_type> *const &ptrVectorPool)
+        : CbVectorAllocator<value_type>(), key(key), startIndexInPool(0), ptrVectorPool(ptrVectorPool)
+    {
+        if (!ptrVectorPool)
+            UB_THROW(UbException(UB_EXARGS, "ptrVectorPool==NULL"));
+    }
+    /*==========================================================*/
+    // hier wird der key automatisch erzeugt!
+    CbVectorAllocatorPool(CbVectorPool<value_type> *const &ptrVectorPool)
+        : CbVectorAllocator<value_type>(), startIndexInPool(0), ptrVectorPool(ptrVectorPool)
+    {
+        if (!ptrVectorPool)
+            UB_THROW(UbException(UB_EXARGS, "ptrVectorPool==NULL"));
+        key = ptrVectorPool->getNextCbVectorKey();
+    }
+    /*==========================================================*/
+    bool alloc(CbVector<value_type> &vec, const size_type &dataSize, const value_type &value = value_type()) override
+    {
+        if (!ptrVectorPool)
+            UB_THROW(UbException(UB_EXARGS, "vectorPool seems to be destroyed, ptrVectorPool==NULL"));
+        return ptrVectorPool->allocVectorData(vec, dataSize, value);
+    }
+    /*==========================================================*/
+    bool resize(CbVector<value_type> &vec, const size_type &dataSize, const value_type &value = value_type()) override
+    {
+        if (!ptrVectorPool)
+            UB_THROW(UbException(UB_EXARGS, "vectorPool seems to be destroyed, ptrVectorPool==NULL"));
+        return ptrVectorPool->resizeVectorData(vec, dataSize, value);
+    }
+    /*==========================================================*/
+    bool dealloc(CbVector<value_type> &vec) override
+    {
+        if (ptrVectorPool)
+            return this->ptrVectorPool->deallocVectorData(vec);
+        // wenn kein ptrVectorPool -> wurde bereits deallokiert
+        return true;
+    }
+    /*==========================================================*/
+    const CbVectorPool<value_type> &getCbVectorPool()
+    {
+        if (!ptrVectorPool)
+            UB_THROW(UbException(UB_EXARGS, "vectorPool seems to be destroyed, ptrVectorPool==NULL"));
+        return *ptrVectorPool;
+    }
+    /*==========================================================*/
+
+private:
+    typename CbVectorPool<value_type>::CbVectorKey key;
+    typename CbVectorPool<value_type>::Pool::size_type startIndexInPool;
+
+    CbVectorPool<value_type> *ptrVectorPool;
+};
+
+#endif // CBVECTORPOOL_H
diff --git a/src/basics/basics/memory/MbSmartPtr.h b/src/basics/basics/memory/MbSmartPtr.h
new file mode 100644
index 0000000000000000000000000000000000000000..9c36cd97301c0fb3be3e98e612e4d05ab3fc899c
--- /dev/null
+++ b/src/basics/basics/memory/MbSmartPtr.h
@@ -0,0 +1,134 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file MbSmartPtr.h
+//! \ingroup memory
+//! \author Soeren Freudiger, Sebastian Geller
+//=======================================================================================
+#ifndef MBSMARTPTR_H
+#define MBSMARTPTR_H
+
+#include <basics/memory/MbSmartPtrBase.h>
+
+#ifdef __clang__
+#pragma clang system_header
+#endif
+
+//=====================================================
+// Globale Funktion, um das Loeschen des referenzierten
+// Objektes flexibler zu gestalten.
+//
+template <class ObjType>
+void deleteRefPtr(ObjType *ptr)
+{
+    delete ptr;
+}
+
+//======================================================
+// Die Reference-Pointer Klasse:
+//
+// Beim Referenzieren eines Objektes ueber einen SmartPointer wird ein Zaehler fuer die referezierte Objekt-
+// adresse inkrementiert. Wird der Pointer wieder einem anderen Objekt zugewiesen, so wird der Zaehler fuer das
+// urspruenglich referenzierte Objekt wieder dekremtiert, ebenfalls beim Destruktor des Reference-Pointers.
+// Tatsaechlich geloescht wird das referenzierte Objekt erst, wenn der zugehoerige Zaehler auf 0 ist. Dies geschieht
+// ueber die globale Template-Funktion deleteRefPtr(), die bei Bedarf ueberschrieben werden kann.
+// Der Reference-Pointer verfuegt also sozusagen ueber eine automatische Garbage Collection
+
+template <class ObjType>
+class MbSmartPtr : public MbSmartPtrBase
+{
+public:
+    // Konstruktoren //bei explicit geht der implizite cast nicht mehr, aber um keinen stress zu verursachen
+    /*explicit*/ MbSmartPtr<ObjType>(const ObjType *pPtr = NULL) : MbSmartPtrBase(), mpPtr(NULL) { init(pPtr); }
+    template <class ParamType>
+    MbSmartPtr<ObjType>(const MbSmartPtr<ParamType> &ptr) : MbSmartPtrBase(), mpPtr(NULL)
+    {
+        init(ptr.get());
+    }
+    // Destruktor
+    ~MbSmartPtr<ObjType>() override { init(NULL); }
+    //---------------------------------------------------
+    // Kopierkonstruktor
+    MbSmartPtr<ObjType>(const MbSmartPtr<ObjType> &ptr) : MbSmartPtrBase(), mpPtr(NULL) { init(ptr.get()); }
+    //---------------------------------------------------
+    // Zuweisungsoperatoren
+    template <class ParamType>
+    const MbSmartPtr<ObjType> &operator=(const MbSmartPtr<ParamType> &ptr)
+    {
+        init(ptr.get());
+        return *this;
+    }
+    const MbSmartPtr<ObjType> &operator=(const MbSmartPtr<ObjType> &ptr)
+    {
+        init(ptr.get());
+        return *this;
+    }
+
+    const MbSmartPtr<ObjType> &operator=(const ObjType *pPtr)
+    {
+        init(pPtr);
+        return *this;
+    }
+    //---------------------------------------------------
+    // Dereferenzierung-Operatoren
+    ObjType &operator*() const { return *mpPtr; }
+    ObjType *operator->() const { return mpPtr; }
+    bool operator!() const { return !mpPtr; }
+    operator ObjType *() const { return mpPtr; }
+    //---------------------------------------------------
+    // Methoden
+    ObjType *get() const { return mpPtr; }
+    //---------------------------------------------------
+    int ref_count() const { return MbSmartPtrBase::ref_count(mpPtr); }
+    //---------------------------------------------------
+    bool release() const { return MbSmartPtrBase::removeFromGC(mpPtr); }
+
+private:
+    void init(const ObjType *pPtr)
+    {
+        // Nur was tun, wenn wirklich noetig
+        if (pPtr == mpPtr)
+            return;
+
+        // Aktuell referenziertes Objekt freigeben, dabei ueberpruefen, ob letztes Release
+        if (mpPtr && releaseRef(mpPtr)) {
+            // referenziertes Objekt loeschen
+            deleteRefPtr(mpPtr);
+        }
+
+        // Wenn pPtr ein neues Objekt ist, Zugriffszaehler auf neues Objekt erhoehen
+        mpPtr = const_cast<ObjType *>(pPtr);
+        if (mpPtr)
+            addRef(mpPtr);
+    }
+
+private:
+    ObjType *mpPtr;
+};
+
+#endif // MBSMARTPTR_H
diff --git a/src/basics/basics/memory/MbSmartPtrBase.cpp b/src/basics/basics/memory/MbSmartPtrBase.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cebff4e4d5c99a6d05865d7cb9d6f936a064efe5
--- /dev/null
+++ b/src/basics/basics/memory/MbSmartPtrBase.cpp
@@ -0,0 +1,75 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file MbSmartPtrBase.cpp
+//! \ingroup memory
+//! \author Soeren Freudiger, Sebastian Geller
+//=======================================================================================
+#include <basics/memory/MbSmartPtrBase.h>
+
+using namespace std;
+
+bool MbSmartPtrBase::addRef(void *ptr)
+{
+    MbSmartPtrBaseMap::getInstance()->getMap()[ptr]++;
+    return true;
+}
+//-------------------------------------------------
+bool MbSmartPtrBase::releaseRef(void *ptr)
+{
+    map<void *, int> &ptrMap       = MbSmartPtrBaseMap::getInstance()->getMap();
+    map<void *, int>::iterator pos = ptrMap.find(ptr);
+
+    if (pos != ptrMap.end()) {
+        pos->second--;
+
+        if (pos->second == 0) {
+            ptrMap.erase(pos);
+            return true;
+        }
+    }
+    return false;
+}
+//-------------------------------------------------
+bool MbSmartPtrBase::removeFromGC(void *ptr) const
+{
+    if (MbSmartPtrBaseMap::getInstance()->getMap().erase(ptr))
+        return true;
+    return false;
+}
+//-------------------------------------------------
+int MbSmartPtrBase::ref_count(void *ptr) const
+{
+    map<void *, int> &ptrMap       = MbSmartPtrBaseMap::getInstance()->getMap();
+    map<void *, int>::iterator pos = ptrMap.find(ptr);
+
+    if (pos != ptrMap.end())
+        return pos->second;
+    else
+        return 0;
+}
diff --git a/src/basics/basics/memory/MbSmartPtrBase.h b/src/basics/basics/memory/MbSmartPtrBase.h
new file mode 100644
index 0000000000000000000000000000000000000000..697af8f3b01e183043dcc2f04bab670c3d42f78f
--- /dev/null
+++ b/src/basics/basics/memory/MbSmartPtrBase.h
@@ -0,0 +1,82 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file MbSmartPtrBase.h
+//! \ingroup memory
+//! \author Soeren Freudiger, Sebastian Geller
+//=======================================================================================
+#ifndef MBSMARTPTRBASE_H
+#define MBSMARTPTRBASE_H
+
+#include <iostream>
+#include <map>
+
+//============================================================
+// Klasse MbSmartPtrBase
+//
+// Basisklasse, speziell fuer MbSmartPtr, die das eigentliche
+// Reference-Counting uebernimmt.
+//
+class MbSmartPtrBase
+{
+    // Ursprung:
+    // mpCntrMap ist ein Pointer, weil sichergestellt sein muss, dass die
+    // Map existiert, wenn das erste mal darauf zugegriffen wird.
+    // Ein Zugriff zwischen zwei statischen Objekten kann zum Fehler fuehren, da
+    // die Reihenfolge der Konstruktorenaufrufe dann vom Linker bestimmt wird.
+
+    // Anpassung a la UbWriter mit SingletonMap
+    class MbSmartPtrBaseMap
+    {
+    private:
+        MbSmartPtrBaseMap() = default;
+
+        std::map<void *, int> mpCntrMap;
+
+    public:
+        MbSmartPtrBaseMap(const MbSmartPtrBaseMap &) = delete;
+        const MbSmartPtrBaseMap &operator=(const MbSmartPtrBaseMap &) = delete;
+
+        static MbSmartPtrBaseMap *getInstance()
+        {
+            static MbSmartPtrBaseMap instance;
+            return &instance;
+        }
+        std::map<void *, int> &getMap() { return mpCntrMap; }
+    };
+
+protected:
+    MbSmartPtrBase()          = default;
+    virtual ~MbSmartPtrBase() = default;
+    bool addRef(void *p);
+    bool releaseRef(void *p);
+    bool removeFromGC(void *ptr) const;
+    int ref_count(void *ptr) const;
+};
+
+#endif // MBSMARTPTRBASE_H
diff --git a/src/basics/basics/parallel/PbMpi.h b/src/basics/basics/parallel/PbMpi.h
new file mode 100644
index 0000000000000000000000000000000000000000..7f73da85b4ee333a3f266ea8fc082fc5d88f1b40
--- /dev/null
+++ b/src/basics/basics/parallel/PbMpi.h
@@ -0,0 +1,503 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file PbMpi.h
+//! \ingroup parallel
+//! \author Soeren Freudiger, Sebastian Geller
+//=======================================================================================
+#ifndef PbMpi_H
+#define PbMpi_H
+
+#include <sstream>
+#include <vector>
+
+#ifndef VF_MPI
+#error VF_MPI has to be defined
+#endif
+
+// As we doing a lot of const-cast here we define PbMpi.h to system_header to mute clang-tidy
+#ifdef __clang__
+#pragma clang system_header
+#endif
+
+//#undef SEEK_SET
+//#undef SEEK_CUR
+//#undef SEEK_END
+#include <mpi.h>
+
+#include <basics/utilities/UbException.h>
+
+#ifdef USE_MPI_CXX_SYNTAX
+#define PbMpi_COMM_WORLD MPI::COMM_WORLD
+#define PbMpi_INT MPI::INT
+#define PbMpi_CHAR MPI::CHAR
+#define PbMpi_SHORT MPI::SHORT
+#define PbMpi_FLOAT MPI::FLOAT
+#define PbMpi_DOUBLE MPI::DOUBLE
+#define PbMpi_COMM_NULL MPI::COMM_NULL
+
+namespace PbMpi
+{
+typedef MPI::Intracomm Comm;
+typedef MPI::Group Group;
+typedef MPI::Request Request;
+typedef MPI::Status Status;
+
+inline void Init()
+{
+    MPI::Init();
+    MPI::COMM_WORLD.Set_errhandler(MPI::ERRORS_THROW_EXCEPTIONS);
+}
+inline void Init(int &argc, char **argv)
+{
+    MPI::Init(argc, argv);
+    MPI::COMM_WORLD.Set_errhandler(MPI::ERRORS_THROW_EXCEPTIONS);
+}
+inline void Finalize() { MPI::Finalize(); }
+
+inline int GetCommSize(const Comm &comm) { return comm.Get_size(); }
+inline int GetCommRank(const Comm &comm) { return comm.Get_rank(); }
+inline void Barrier(const Comm &comm) { comm.Barrier(); }
+
+inline double Wtime() { return MPI::Wtime(); }
+inline double Wtick() { return MPI::Wtick(); }
+
+inline void Wait(Request &request, Status *outStatus = NULL)
+{
+    if (outStatus)
+        request.Wait(*outStatus);
+    else
+        request.Wait();
+}
+
+inline Group GetCommGroup(Comm &comm) { return comm.Get_group(); }
+inline Group GetGroupIncl(Group &group, const int &n, int *ranks) { return group.Incl(n, ranks); }
+inline Comm CommCreateComm(Comm &comm, Group &group) { return comm.Create(group); }
+
+inline void Alltoall(Comm &comm, void *sendBuffer, const int &sn, const MPI_Datatype &sdatatype, void *recvBuffer,
+                     const int &rn, const MPI_Datatype &rdatatype)
+{
+    comm.Alltoall(sendBuffer, sn, sdatatype, recvBuffer, rn, rdatatype);
+}
+inline void Bcast(Comm &comm, void *data, const int &n, const MPI_Datatype &datatype, const int &srcRank)
+{
+    comm.Bcast(data, n, datatype, srcRank);
+}
+inline void Send(Comm &comm, const void *data, const int &length, const MPI_Datatype &dataType, const int &destRank,
+                 const int &tag)
+{
+    try {
+        comm.Send(data, length, dataType, destRank, tag);
+    } catch (MPI::Exception &e) {
+        std::stringstream ss;
+        ss << "MPI::Exception error_string=" << e.Get_error_string() << std::endl;
+        throw UbException(UB_EXARGS, "MPI:Exception catched\n" + ss.str());
+    } catch (...) {
+        throw UbException(UB_EXARGS, "unknown exception");
+    }
+}
+inline void Recv(Comm &comm, const void *data, const int &length, const MPI_Datatype &dataType, const int &srcRank,
+                 const int &tag)
+{
+    try {
+        comm.Recv(const_cast<void *>(data), length, dataType, srcRank, tag);
+    } catch (MPI::Exception &e) {
+        std::stringstream ss;
+        ss << "MPI::Exception error_string=" << e.Get_error_string() << std::endl;
+        throw UbException(UB_EXARGS, "MPI:Exception catched \n" + ss.str());
+    } catch (...) {
+        throw UbException(UB_EXARGS, "unknown exception");
+    }
+}
+
+inline void Irecv(Comm comm, const void *data, const int &length, const MPI_Datatype &dataType, const int &srcRank,
+                  const int &tag, Request &outRequest)
+{
+    outRequest = comm.Irecv(const_cast<void *>(data), length, dataType, srcRank, tag);
+}
+inline void Ssend(Comm &comm, const void *data, const int &length, const MPI_Datatype &dataType, const int &destRank,
+                  const int &tag)
+{
+    try {
+        comm.Ssend(data, length, dataType, destRank, tag);
+    } catch (MPI::Exception &e) {
+        std::stringstream ss;
+        ss << "MPI::Exception error_string=" << e.Get_error_string() << std::endl;
+        throw UbException(UB_EXARGS, "MPI:Exception catched\n" + ss.str());
+    } catch (...) {
+        throw UbException(UB_EXARGS, "unknown exception");
+    }
+}
+
+} // namespace PbMpi
+#else //////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+// C-Syntax
+//////////////////////////////////////////////////////////////////////////
+namespace PbMpi
+{
+using Comm    = MPI_Comm;
+using Group   = MPI_Group;
+using Request = MPI_Request;
+using Status  = MPI_Status;
+} // namespace PbMpi
+
+#define PbMpi_COMM_WORLD ((PbMpi::Comm)MPI_COMM_WORLD)
+#define PbMpi_INT MPI_INT
+#define PbMpi_CHAR MPI_CHAR
+#define PbMpi_SHORT MPI_SHORT
+#define PbMpi_FLOAT MPI_FLOAT
+#define PbMpi_DOUBLE MPI_DOUBLE
+#define PbMpi_COMM_NULL MPI_COMM_NULL
+
+namespace PbMpi
+{
+inline void Init()
+{
+    int argc    = 1;
+    char **argv = new char *[1];
+    argv[0]     = new char[1];
+    argv[0][0]  = 'n';
+    MPI_Init(&argc, &argv);
+}
+inline void Init(int &argc, char **argv) { MPI_Init(&argc, &argv); }
+inline void Finalize() { MPI_Finalize(); }
+inline int GetCommSize(Comm comm)
+{
+    int tmp;
+    MPI_Comm_size(comm, &tmp);
+    return tmp;
+}
+inline int GetCommRank(Comm comm)
+{
+    int tmp;
+    MPI_Comm_rank(comm, &tmp);
+    return tmp;
+}
+inline void Barrier(Comm comm) { MPI_Barrier(comm); }
+inline double Wtime() { return MPI_Wtime(); }
+inline double Wtick() { return MPI_Wtick(); }
+inline void Wait(Request &request, Status *outStatus = NULL) { MPI_Wait(&request, outStatus); }
+
+inline Group GetCommGroup(Comm comm)
+{
+    Group out;
+    MPI_Comm_group(comm, &out);
+    return out;
+}
+inline Group GetGroupIncl(Group group, const int &n, int *ranks)
+{
+    Group out;
+    MPI_Group_incl(group, n, ranks, &out);
+    return out;
+}
+inline Comm CommCreateComm(Comm comm, Group &group)
+{
+    Comm out;
+    MPI_Comm_create(comm, group, &out);
+    return out;
+}
+
+inline void Alltoall(Comm comm, void *sendBuffer, const int &sn, const MPI_Datatype &sdatatype, void *recvBuffer,
+                     const int &rn, const MPI_Datatype &rdatatype)
+{
+    MPI_Alltoall(sendBuffer, sn, sdatatype, recvBuffer, rn, rdatatype, comm);
+}
+inline void Bcast(Comm comm, void *data, const int &n, const MPI_Datatype &datatype, const int &srcRank)
+{
+    MPI_Bcast(data, n, datatype, srcRank, comm);
+}
+inline void Send(Comm comm, const void *data, const int &length, const MPI_Datatype &dataType, const int &destRank,
+                 const int &tag)
+{
+    MPI_Send(const_cast<void *>(data), length, dataType, destRank, tag, comm);
+}
+inline void Recv(Comm comm, const void *data, const int &length, const MPI_Datatype &dataType, const int &srcRank,
+                 const int &tag)
+{
+    MPI_Recv(const_cast<void *>(data), length, dataType, srcRank, tag, comm, MPI_STATUS_IGNORE);
+}
+inline void Ssend(Comm comm, const void *data, const int &length, const MPI_Datatype &dataType, const int &destRank,
+                  const int &tag)
+{
+    MPI_Ssend(const_cast<void *>(data), length, dataType, destRank, tag, comm);
+}
+inline void Irecv(Comm comm, const void *data, const int &length, const MPI_Datatype &dataType, const int &srcRank,
+                  const int &tag, Request &outRequest)
+{
+    MPI_Irecv(const_cast<void *>(data), length, dataType, srcRank, tag, comm, &outRequest);
+}
+
+} // namespace PbMpi
+#endif
+
+namespace PbMpi
+{
+/*======================================================================*/
+// send a single value "value" of MPI_Datatype
+template <class T>
+inline void sendSingleValue(const T &value, MPI_Datatype datatype, int dest, int tag, PbMpi::Comm comm);
+
+/*======================================================================*/
+// receives a single value "value" of MPI_Datatype
+template <class T>
+inline void receiveSingleValue(T &value, MPI_Datatype datatype, int source, int tag, PbMpi::Comm comm);
+
+/*======================================================================*/
+// receives and returns a single value of MPI_Datatype
+// expample: int value = PbMpi::receiveSingleValue<int>(MPI::INT,0,10,comm);
+template <class T>
+inline T receiveSingleValue(MPI_Datatype datatype, int source, int tag, PbMpi::Comm comm);
+
+/*======================================================================*/
+// sends bool value (doesn't work with template, why ever... stupid MPI)
+inline void sendBoolValue(const bool &value, int dest, int tag, PbMpi::Comm comm);
+
+/*======================================================================*/
+// receives bool value (doesn't work with template, why ever... stupid MPI)
+inline bool receiveBoolValue(int source, int tag, PbMpi::Comm comm);
+
+/*======================================================================*/
+// sends bool value (doesn't work with template, why ever... stupid MPI)
+inline void sendStringValue(const std::string &value, int dest, int tag, PbMpi::Comm comm);
+
+/*======================================================================*/
+// receives bool value (doesn't work with template, why ever... stupid MPI)
+inline std::string receiveStringValue(int source, int tag, PbMpi::Comm comm);
+
+/*======================================================================*/
+// send a vector of MPI_Datatype
+template <class T>
+inline void sendVector(const std::vector<T> &v, MPI_Datatype datatype, int dest, int tag, PbMpi::Comm comm);
+
+/*======================================================================*/
+// receive a std::vector of MPI_Datatype
+template <class T>
+inline void receiveVector(std::vector<T> &v, MPI_Datatype datatype, int source, int tag, PbMpi::Comm comm);
+
+/*======================================================================*/
+// receive a vector of MPI_Datatype and adds this vector to existing vector
+// ans returns number of received elements
+template <class T>
+inline int receiveVectorAndAddToVector(std::vector<T> &v, MPI_Datatype datatype, int source, int tag, PbMpi::Comm comm);
+
+/*======================================================================*/
+// send a std::vector of strings
+inline void sendStringVector(const std::vector<std::string> &v, int dest, int tag, PbMpi::Comm comm);
+
+/*======================================================================*/
+// send a vector of strings
+inline void receiveStringVector(std::vector<std::string> &v, int dest, int tag, PbMpi::Comm comm);
+} // namespace PbMpi
+
+/*======================================================================*/
+// send a single value of MPI_Datatype
+template <class T>
+void PbMpi::sendSingleValue(const T &value, MPI_Datatype datatype, int dest, int tag, PbMpi::Comm comm)
+{
+    PbMpi::Send(comm, &value, 1, datatype, dest, tag);
+    // comm.Send(&value, 1, datatype, dest, tag);
+}
+/*======================================================================*/
+template <class T>
+void PbMpi::receiveSingleValue(T &value, MPI_Datatype datatype, int source, int tag, PbMpi::Comm comm)
+{
+    PbMpi::Recv(comm, &value, 1, datatype, source, tag);
+    // comm.Recv(&value, 1, datatype, source, tag);
+}
+/*======================================================================*/
+template <class T>
+T PbMpi::receiveSingleValue(MPI_Datatype datatype, int source, int tag, PbMpi::Comm comm)
+{
+    T value;
+    PbMpi::Recv(comm, &value, 1, datatype, source, tag);
+    // comm.Recv(&value, 1, datatype, source, tag);
+
+    return value;
+}
+/*======================================================================*/
+// send a bool value (bool doesn't work with template, why ever)
+void PbMpi::sendBoolValue(const bool &value, int dest, int tag, PbMpi::Comm comm)
+{
+    short dummy;
+    if (value)
+        dummy = 1;
+    else
+        dummy = 0;
+
+    PbMpi::Send(comm, &dummy, 1, PbMpi_SHORT, dest, tag);
+    // comm.Send(&dummy, 1, MPI::SHORT, dest, tag);
+}
+/*======================================================================*/
+bool PbMpi::receiveBoolValue(int source, int tag, PbMpi::Comm comm)
+{
+    short dummy{ 0 };
+    PbMpi::Recv(comm, &dummy, 1, PbMpi_SHORT, source, tag);
+    // comm.Recv(&dummy, 1, MPI::SHORT, source, tag);
+
+    return (dummy == 1);
+}
+/*======================================================================*/
+// sends bool value (doesn't work with template, why ever... stupid MPI)
+void PbMpi::sendStringValue(const std::string &value, int dest, int tag, PbMpi::Comm comm)
+{
+    std::vector<char> vec;
+    for (char i : value)
+        vec.push_back(i);
+
+    PbMpi::sendVector(vec, PbMpi_CHAR, dest, tag, comm);
+}
+
+/*======================================================================*/
+// receives bool value (doesn't work with template, why ever... stupid MPI)
+std::string PbMpi::receiveStringValue(int source, int tag, PbMpi::Comm comm)
+{
+    std::vector<char> vec;
+    PbMpi::receiveVector(vec, PbMpi_CHAR, source, tag, comm);
+
+    std::string str;
+    for (char i : vec)
+        str += i;
+
+    return str;
+}
+/*======================================================================*/
+// send a vector of MPI_Datatype
+template <class T>
+void PbMpi::sendVector(const std::vector<T> &v, MPI_Datatype datatype, int dest, int tag, PbMpi::Comm comm)
+{
+    // send size
+    int size = (int)v.size();
+
+    PbMpi::Send(comm, &size, 1, PbMpi_INT, dest, tag);
+    // comm.Send(&size, 1, MPI::INT, dest, tag);
+
+    if (size > 0) {
+        PbMpi::Send(comm, &v[0], size, datatype, dest, tag);
+        // comm.Send(&v[0], size, datatype, dest, tag);
+    }
+}
+/*======================================================================*/
+// receive a vector of MPI_Datatype
+template <class T>
+void PbMpi::receiveVector(std::vector<T> &v, MPI_Datatype datatype, int source, int tag, PbMpi::Comm comm)
+{
+    int size{ 0 };
+
+    PbMpi::Recv(comm, &size, 1, PbMpi_INT, source, tag);
+    // comm.Recv(&size, 1, MPI::INT, source, tag);
+
+    v.resize(size);
+
+    if (size > 0) {
+        PbMpi::Recv(comm, &v[0], size, datatype, source, tag);
+        // comm.Recv(&v[0], size, datatype, source, tag);
+    }
+}
+/*======================================================================*/
+// receive a vector of MPI_Datatype and adds this vector to existing vector
+// return value is size of received elements
+template <class T>
+int PbMpi::receiveVectorAndAddToVector(std::vector<T> &v, MPI_Datatype datatype, int source, int tag, PbMpi::Comm comm)
+{
+    int incommingSize;
+
+    PbMpi::Recv(comm, &incommingSize, 1, PbMpi_INT, source, tag);
+    // comm.Recv(&incommingSize, 1, MPI::INT, source, tag);
+
+    int oldSize = (int)v.size();
+    v.resize(oldSize + incommingSize);
+
+    if (incommingSize > 0) {
+        PbMpi::Recv(comm, &v[oldSize], incommingSize, datatype, source, tag);
+        // comm.Recv(&v[oldSize], incommingSize, datatype, source, tag);
+    }
+
+    return incommingSize;
+}
+/*======================================================================*/
+// send a vector of strings
+void PbMpi::sendStringVector(const std::vector<std::string> &v, int dest, int tag, PbMpi::Comm comm)
+{
+    // send size
+    int stringVectorSize = (int)v.size();
+
+    PbMpi::Send(comm, &stringVectorSize, 1, PbMpi_INT, dest, tag);
+    // comm.Send(&stringVectorSize, 1, MPI::INT, dest, tag);
+
+    if (stringVectorSize > 0) {
+        std::vector<int> singleStringSizes(stringVectorSize + 1);
+        int nofChars = 0;
+        for (int i = 0; i < stringVectorSize; i++)
+            nofChars += singleStringSizes[i] = (int)v[i].length();
+        singleStringSizes[stringVectorSize] = nofChars;
+
+        PbMpi::Send(comm, &singleStringSizes[0], stringVectorSize + 1, PbMpi_INT, dest, tag);
+
+        std::vector<char> charVector(nofChars);
+        int pos = 0;
+        for (int i = 0; i < stringVectorSize; i++)
+            for (int j = 0; j < singleStringSizes[i]; j++)
+                charVector[pos++] = v[i][j];
+
+        PbMpi::Send(comm, &charVector[0], nofChars, PbMpi_CHAR, dest, tag);
+        // comm.Send(&charVector[0], nofChars, MPI::CHAR, dest, tag);
+    }
+}
+/*======================================================================*/
+// send a vector of strings
+void PbMpi::receiveStringVector(std::vector<std::string> &v, int source, int tag, PbMpi::Comm comm)
+{
+    // send size
+    int stringVectorSize{ 0 };
+    PbMpi::Recv(comm, &stringVectorSize, 1, PbMpi_INT, source, tag);
+    // comm.Recv(&stringVectorSize, 1, MPI::INT, source, tag);
+
+    v.clear();
+    v.resize(stringVectorSize);
+
+    if (stringVectorSize > 0) {
+        std::vector<int> singleStringSizes(stringVectorSize + 1);
+
+        PbMpi::Recv(comm, &singleStringSizes[0], stringVectorSize + 1, PbMpi_INT, source, tag);
+        // comm.Recv(&singleStringSizes[0], stringVectorSize+1, MPI::INT, source, tag);
+
+        int nofChars = singleStringSizes[stringVectorSize];
+        std::vector<char> charVector(nofChars);
+
+        PbMpi::Recv(comm, &charVector[0], nofChars, PbMpi_CHAR, source, tag);
+        // comm.Recv(&charVector[0], nofChars, MPI::CHAR, source, tag);
+
+        int pos = 0;
+        for (int i = 0; i < stringVectorSize; i++)
+            for (int j = 0; j < singleStringSizes[i]; j++)
+                v[i].push_back(charVector[pos++]);
+    }
+}
+
+#endif // PbMpi_H
diff --git a/src/basics/basics/transmitter/TbTransmitter.h b/src/basics/basics/transmitter/TbTransmitter.h
new file mode 100644
index 0000000000000000000000000000000000000000..22fff52a1d1a9d2219b78e933d63e3e1c208897f
--- /dev/null
+++ b/src/basics/basics/transmitter/TbTransmitter.h
@@ -0,0 +1,94 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file TbTransmitter.h
+//! \ingroup transmitter
+//! \author Soeren Freudiger, Sebastian Geller
+//=======================================================================================
+#ifndef TBTRANSMITTER_H
+#define TBTRANSMITTER_H
+
+#include <string>
+
+/*================================================================================*/
+/*  TbTransmitter                                                                 */
+/*                                                                                */
+/**
+This Class provides the base for sending and receiving of data.
+<BR><BR>
+@author <A HREF="mailto:muffmolch@gmx.de">S. Freudiger</A>
+@version 1.0 - 08.11.07
+*/
+
+/*
+usage: ...
+*/
+
+//////////////////////////////////////////////////////////////////////////
+// Transmitter
+// macht nichts ausser daten senden und empfangen
+template <typename T>
+class TbTransmitter
+{
+public:
+    using value_type = T;
+
+public:
+    TbTransmitter()          = default;
+    virtual ~TbTransmitter() = default;
+
+    virtual bool isLocalTransmitter() const  = 0;
+    virtual bool isRemoteTransmitter() const = 0;
+
+    // preprocess (e.g. synchronizing send-/receive-buffer)
+    virtual void sendDataSize()    = 0;
+    virtual void receiveDataSize() = 0;
+
+    // calculation
+    virtual void prepareForSend() {}
+    virtual void sendData() = 0;
+    virtual void prepareForReceive() {}
+    virtual value_type &receiveData() = 0;
+
+    // data-access
+    inline value_type &getData() { return this->data; }
+    inline const value_type &getData() const { return this->data; }
+
+    // info-section (usable for remote transmitter)
+    virtual int getSendToRank() const { return -1; }
+    virtual int getSendToTag() const { return -1; }
+    virtual int getRecvFromRank() const { return -1; }
+    virtual int getRecvFromTag() const { return -1; }
+
+    virtual std::string toString() const = 0;
+
+protected:
+    value_type data;
+};
+
+#endif // TBTRANSMITTER_H
diff --git a/src/basics/basics/transmitter/TbTransmitterLocal.h b/src/basics/basics/transmitter/TbTransmitterLocal.h
new file mode 100644
index 0000000000000000000000000000000000000000..39a2592c19cbb23d56c880ef501a89b506b974d7
--- /dev/null
+++ b/src/basics/basics/transmitter/TbTransmitterLocal.h
@@ -0,0 +1,148 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file TbTransmitterLocal.h
+//! \ingroup transmitter
+//! \author Soeren Freudiger, Sebastian Geller
+//=======================================================================================
+#ifndef TOTRANSMITTERLOCAL_H
+#define TOTRANSMITTERLOCAL_H
+
+#include <PointerDefinitions.h>
+#include <basics/transmitter/TbTransmitter.h>
+#include <basics/utilities/UbException.h>
+
+/*================================================================================*/
+/*   TbLocalTransmitter, TbVectorSenderLocal, TbVectorReceiverLocal               */
+/*                                                                                */
+/**
+This Class provides the base for exception handling.
+<BR><BR>
+@author <A HREF="mailto:muffmolch@gmx.de">S. Freudiger</A>
+@version 1.0 - 08.11.07
+*/
+
+/*
+usage: ...
+*/
+
+//////////////////////////////////////////////////////////////////////////
+// LocalTransmitter lokalen Datenaustausch
+// data = send- und zugleich receive-buffer
+template <typename T>
+class TbLocalTransmitter : public TbTransmitter<T>
+{
+public:
+    using TbLocalTransmitterPtr = SPtr<TbLocalTransmitter<T>>;
+
+    using value_type = T;
+
+public:
+    TbLocalTransmitter() : TbTransmitter<T>() {}
+
+    bool isLocalTransmitter() const override { return true; }
+    bool isRemoteTransmitter() const override { return !this->isLocalTransmitter(); }
+
+    // send buffer wird autom resized
+    void sendDataSize() override {}
+    // reiceive braucht nichts machen, da send==receive buffer ;-)
+    void receiveDataSize() override {}
+
+    void sendData() override {}
+    value_type &receiveData() override { return this->data; }
+
+    std::string toString() const override { return "TbLocalTransmitter" + (std::string) typeid(T).name(); }
+};
+
+//////////////////////////////////////////////////////////////////////////
+// TbVectorSender/ReceiverLocal lokalen Datenaustausch ueber ZWEI vektoren
+template <typename T>
+class TbVectorReceiverLocal : public TbTransmitter<T>
+{
+public:
+    using value_type = T;
+
+public:
+    TbVectorReceiverLocal() : TbTransmitter<value_type>() {}
+    // virtual ~TbVectorReceiverLocal() { std::cout<<typeid(*this).name()<<" tot"<<std::endl;   }
+
+    bool isLocalTransmitter() const { return true; }
+    bool isRemoteTransmitter() const { return !this->isLocalTransmitter(); }
+
+    // send buffer wird autom resized
+    void sendDataSize() { UB_THROW(UbException(UB_EXARGS, "empfaengt nur")); }
+    // reiceive braucht nichts machen, das macht der sender :-)
+    void receiveDataSize() {}
+
+    void sendData() { UB_THROW(UbException(UB_EXARGS, "empfaengt nur")); }
+    value_type &receiveData() { return this->data; }
+
+    std::string toString() const { return "TbVectorReceiverLocal<" + (std::string) typeid(T).name() + ">"; }
+};
+
+template <typename T>
+class TbVectorSenderLocal : public TbTransmitter<T>
+{
+public:
+    using value_type = T;
+
+public:
+    TbVectorSenderLocal(SPtr<TbVectorReceiverLocal<value_type>> receiver)
+        : TbTransmitter<value_type>(), receiver(receiver)
+    {
+    }
+    // virtual ~TbVectorSenderLocal() { std::cout<<typeid(*this).name()<<" tot"<<std::endl;   }
+
+    bool isLocalTransmitter() const { return true; }
+    bool isRemoteTransmitter() const { return !this->isLocalTransmitter(); }
+
+    // send buffer wird autom resized
+    void sendDataSize()
+    {
+        assert(receiver != NULL);
+        receiver->getData().resize(this->data.size());
+    }
+    // reiceive braucht nichts machen, da send==receive buffer ;-)
+    void receiveDataSize() { UB_THROW(UbException(UB_EXARGS, "sendet nur")); }
+
+    void sendData()
+    {
+        assert(this->data.size() == receiver->getData().size());
+        receiver->getData() = this->data;
+        //       for(int i=(int)this->data.size()-1; i>=0; --i)
+        //          receiver->getData()[i]= this->data[i];
+    }
+    value_type &receiveData() { UB_THROW(UbException(UB_EXARGS, "sendet nur")); }
+
+    std::string toString() const { return "TbVectorSenderLocal<" + (std::string) typeid(T).name() + ">"; }
+
+protected:
+    SPtr<TbVectorReceiverLocal<value_type>> receiver;
+};
+
+#endif // TOTRANSMITTERLOCAL_H
diff --git a/src/basics/basics/transmitter/TbTransmitterMpiPool.h b/src/basics/basics/transmitter/TbTransmitterMpiPool.h
new file mode 100644
index 0000000000000000000000000000000000000000..83c0b1e396364840d4ec03a666f482791e098462
--- /dev/null
+++ b/src/basics/basics/transmitter/TbTransmitterMpiPool.h
@@ -0,0 +1,574 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file TbTransmitterMpiPool.h
+//! \ingroup transmitter
+//! \author Soeren Freudiger, Sebastian Geller
+//=======================================================================================
+#ifndef TBTRANSMITTERMPIPOOL_H
+#define TBTRANSMITTERMPIPOOL_H
+
+#ifdef VF_MPI
+
+#include <iomanip>
+#include <iostream>
+#include <map>
+#include <sstream>
+#include <vector>
+
+#include <mpi.h>
+
+#include <basics/container/CbVector.h>
+#include <basics/container/CbVectorPool.h>
+#include <basics/transmitter/TbTransmitter.h>
+
+#include <PointerDefinitions.h>
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+// TbCbVectorMpiPoolSender/Receiver
+// diese verschicken immer einen VectorPool. Letztlich einen langen vector,
+// der eigentlich aus vielen kleinen besteht
+// jeder MpiPoolVector hat einen pointer auf die startadresse in diesem vector
+// die informationen werden im TbMpiVectorPool verwaltet
+// MpiPoolVector verhaelt sich nach aussen hin mit einschraenkungen wie ein std::vector
+// und kann somit bei den vector connector verwendet werden
+// man kann die klassen theoretisch verallgemeinern.
+
+template <typename T>
+class TbCbVectorSenderMpiPool;
+template <typename T>
+class TbCbVectorReceiverMpiPool;
+
+/*==================================================================*/
+template <typename T>
+class TbCbVectorMpiPool : public CbVectorPool<T>
+{
+public:
+    using MpiPoolPtr = SPtr<TbCbVectorMpiPool<T>>;
+
+    //////////////////////////////////////////////////////////////////////////
+    using MpiPoolPtrMap     = std::map<std::string, MpiPoolPtr>;
+    using MpiPoolPtrMapIter = typename MpiPoolPtrMap::iterator;
+
+    // da BasisKlasse templateKlasse ist MUSS man hier die typedefs nochmal wiederholen!
+    using value_type = typename CbVector<T>::value_type;
+    using size_type  = typename CbVector<T>::size_type;
+    using Pool       = std::vector<value_type>;
+
+    using CbVectorKey     = std::string;
+    using CbVectorMap     = std::map<CbVectorKey, CbVector<value_type> *>;
+    using CbVectorMapIter = typename CbVectorMap::iterator;
+
+    //////////////////////////////////////////////////////////////////////////
+    friend class TbCbVectorSenderMpiPool<T>;
+    friend class TbCbVectorReceiverMpiPool<T>;
+
+protected:
+    //////////////////////////////////////////////////////////////////////////
+    static MpiPoolPtrMap poolMap;
+
+public:
+    //////////////////////////////////////////////////////////////////////////
+    // STATIC MEMBERS
+    //////////////////////////////////////////////////////////////////////////
+    // createTbCbVectorMpiPool:
+    // poolKey      : Schluessel fuer eindeutige Indizierung in Map
+    // mpiRemoteRank: mpi-rank des Empfaengers/Senders
+    // mpiTag       : mpi-tag mit dem empfangen/gesendet wird
+    static MpiPoolPtr createTbCbVectorMpiPool(CbVectorKey poolKey, int mpiRemoteRank, int mpiTag, MPI_Comm comm,
+                                              size_type startPoolSize = 20000) // startPoolSize*sizeof(T)/1024/1024 [MB]
+
+    {
+        if (poolMap.find(poolKey) != poolMap.end()) {
+            throw UbException(UB_EXARGS, "es ist bereits ein Pool mit dem key vorhanden!!!");
+        }
+
+        // pool erstellen
+        MpiPoolPtr mpiPool(new TbCbVectorMpiPool<T>(poolKey, mpiRemoteRank, mpiTag, comm, startPoolSize));
+
+        // pool "speichern"
+        TbCbVectorMpiPool<value_type>::poolMap[poolKey] = mpiPool;
+
+        return mpiPool;
+    }
+    static void deleteTbCbVectorMpiPool(CbVectorKey poolKey)
+    {
+        MpiPoolPtrMapIter it = TbCbVectorMpiPool<value_type>::poolMap.find(poolKey);
+        if (it == poolMap.end()) {
+            throw UbException(UB_EXARGS, "kein Pool mit dem key vorhanden");
+        }
+        TbCbVectorMpiPool<value_type>::poolMap.erase(it);
+    }
+    /*==================================================================*/
+    static MpiPoolPtr getTbCbVectorMpiPool(CbVectorKey poolKey)
+    {
+        MpiPoolPtrMapIter it;
+        if ((it = TbCbVectorMpiPool<T>::poolMap.find(poolKey)) != TbCbVectorMpiPool<T>::poolMap.end()) {
+            return it->second;
+        }
+        return MpiPoolPtr();
+    }
+    /*==================================================================*/
+    static std::string getInfoString()
+    {
+        std::stringstream out;
+        out << "TbCbVectorMpiPool<" << typeid(T).name() << ") - Info:" << std::endl;
+        for (MpiPoolPtrMapIter it = poolMap.begin(); it != poolMap.end(); ++it)
+            out << "pool with key(" << std::setw(15) << it->first << ") "
+                << "stores " << std::setw(12) << it->second->getNofStoredVectors() << " vectors "
+                << ", elements to transfer = " << std::setw(15) << it->second->getPoolSize() << " ( "
+                << it->second->getPoolSize() * sizeof(T) / (1024.0 * 1024.0) << " MB )" << std::endl;
+        return out.str();
+    }
+    /*==================================================================*/
+    // checks if all vectors have one to one pool-entries
+    static bool consistencyCheck()
+    {
+        for (MpiPoolPtrMapIter it = poolMap.begin(); it != poolMap.end(); ++it) {
+            if (!it->second->CbVectorPool<T>::consistencyCheck()) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+    //////////////////////////////////////////////////////////////////////////
+    static void eraseMap() { poolMap.clear(); }
+
+protected:
+    //////////////////////////////////////////////////////////////////////////
+    TbCbVectorMpiPool(CbVectorKey poolKey, int mpiRemoteRank, int mpiTag, MPI_Comm comm, size_type startPoolSize)
+        : CbVectorPool<value_type>(startPoolSize), poolKey(poolKey),
+          nofStoredVectors(0) //=Anzahl an Vectoren im Pool, wird bei send/receiveDataOrder gesetzt
+          ,
+          counterPrepareReceiveDataOrder(0), counterSendDataOrder(0), counterReceiveDataOrder(0),
+          counterPrepareForReceive(0), counterReceive(0), counterPrepareForSend(0), counterSend(0), comm(comm),
+          receiveRequest(MPI_REQUEST_NULL)
+          //, sendRequest(MPI_REQUEST_NULL)
+          ,
+          mpiRemoteRank(mpiRemoteRank), mpiTag(mpiTag)
+    {
+        if ((std::string) typeid(value_type).name() == (std::string) typeid(double).name())
+            mpiDataType = MPI_DOUBLE;
+        else if ((std::string) typeid(value_type).name() == (std::string) typeid(float).name())
+            mpiDataType = MPI_FLOAT;
+        else if ((std::string) typeid(value_type).name() == (std::string) typeid(int).name())
+            mpiDataType = MPI_INT;
+        else
+            throw UbException(UB_EXARGS, "no MpiDataType for T" + (std::string) typeid(T).name());
+
+        for (int i = 0; i < 3; i++) {
+            sendRequest[i] = MPI_REQUEST_NULL;
+        }
+    }
+
+public:
+    /*==================================================================*/
+    // returns key of Pool in MpiPoolMap
+    CbVectorKey getPoolKey() const { return this->poolKey; }
+    /*==================================================================*/
+    // returns rank of process pool data will be send to/received from
+    int getRemoteRank() const { return this->mpiRemoteRank; }
+    /*==================================================================*/
+    // returns tag of process pool data will be send to/received from
+    int getRemoteTag() const { return this->mpiTag; }
+
+protected:
+    /*==================================================================*/
+    void sendDataOrder()
+    {
+        counterSendDataOrder++;
+        if (counterSendDataOrder == this->cbVectorMap.size()) {
+            // allg.: bei MPI muss man darauf achten, dass bei unblocked operationen die puffer (aus dem oder in den
+            // geschrieben wird auch noch vorhanden sind!!! wuerde man hier z.B. einen lokalen vector mit Isend() los-
+            // schicken, dann wurde der scope verlassen werden und der vector evtl geloescht werden, bevor mpi den
+            // vorgang abgeschlossen hat!!! ->  tmpOrderVec ist class-member!!!
+            unsigned nofElements = (unsigned)this->cbVectorMap.size() * 3 + 1;
+            tmpSendOrderVec.resize(nofElements); // std::vector< unsigned > vec(nofElements);
+            unsigned index           = 0;
+            tmpSendOrderVec[index++] = (unsigned)this->pool.size(); //= laenge des vectors
+            if (this->nextCbVectorStartIndexInPool != this->pool.size())
+                throw UbException(UB_EXARGS,
+                                  "an dieser Stelle sollten nextStartIndex und pool.size() identisch sein!!!");
+            for (CbVectorMapIter it = this->cbVectorMap.begin(); it != this->cbVectorMap.end(); ++it) {
+                CbVectorKey vectorKey;
+                size_type dataSize = 0, startIndexInPool = 0;
+                this->getCbVectorData(*it->second /*vec*/, vectorKey, startIndexInPool, dataSize);
+                if (it->first != vectorKey)
+                    throw UbException(UB_EXARGS, "key mismatch!");
+
+                tmpSendOrderKeyVec += vectorKey; // vectorKey == allocator.getAllocatorKey()
+                tmpSendOrderVec[index++] = (unsigned)vectorKey.length();
+                tmpSendOrderVec[index++] = (unsigned)startIndexInPool; // startIndex in poolVector
+                tmpSendOrderVec[index++] = (unsigned)dataSize;         // dataSize
+            }
+
+            MPI_Isend(&tmpSendOrderVec[0], (int)tmpSendOrderVec.size(), MPI_UNSIGNED, mpiRemoteRank, mpiTag, comm,
+                      &sendRequest[0]);
+
+            tmpSendOrderKeyVecLength = (unsigned)tmpSendOrderKeyVec.length();
+            MPI_Isend(&tmpSendOrderKeyVecLength, 1, MPI_UNSIGNED, mpiRemoteRank, mpiTag, comm, &sendRequest[1]);
+            MPI_Isend((char *)tmpSendOrderKeyVec.c_str(), tmpSendOrderKeyVecLength, MPI_CHAR, mpiRemoteRank, mpiTag,
+                      comm, &sendRequest[2]);
+
+            counterSendDataOrder = 0;
+
+            nofStoredVectors = this->cbVectorMap.size();
+
+            UBLOG(logDEBUG5, "TbCbVectorMpiPool::sendDataOrder()"
+                                 << " mpiRemoteRank=" << mpiRemoteRank << " mpiTag=" << mpiTag);
+
+#ifdef _DEBUG
+            orgPoolVectorStartPointer = &this->pool[0];
+#endif
+        }
+    }
+    /*==================================================================*/
+    void receiveDataOrder()
+    {
+        counterReceiveDataOrder++;
+        if (counterReceiveDataOrder == this->cbVectorMap.size()) {
+            // receiveRequest.Wait();
+            unsigned nofElements =
+                (unsigned)this->cbVectorMap.size() * 3 +
+                1; // map MUSS auf beiden seiten gleich gross sein, sonst hat man ein grundsaetzliches problem ;-)
+
+            UBLOG(logDEBUG5, "TbCbVectorMpiPool::receiveDataOrder()"
+                                 << " mpiRemoteRank=" << mpiRemoteRank << " mpiTag=" << mpiTag);
+
+            std::vector<unsigned> tmpRecvOrderVec;
+            tmpRecvOrderVec.resize(nofElements);
+
+            std::vector<char> tmpRecvOrderKeyVec;
+
+            // MPI_Status status;
+            MPI_Recv(&tmpRecvOrderVec[0], nofElements, MPI_UNSIGNED, mpiRemoteRank, mpiTag, comm, MPI_STATUS_IGNORE);
+
+            unsigned rcount;
+            MPI_Recv(&rcount, 1, MPI_UNSIGNED, mpiRemoteRank, mpiTag, comm, MPI_STATUS_IGNORE);
+            tmpRecvOrderKeyVec.resize(rcount);
+            MPI_Recv(&tmpRecvOrderKeyVec[0], rcount, MPI_CHAR, mpiRemoteRank, mpiTag, comm, MPI_STATUS_IGNORE);
+
+            if (nofElements != (unsigned)tmpRecvOrderVec.size())
+                throw UbException(UB_EXARGS, "error... vec size stimmt nicht");
+
+            unsigned index                     = 0;
+            size_type index2                   = 0;
+            this->nextCbVectorStartIndexInPool = tmpRecvOrderVec[index++]; //= laenge des vectors
+            this->pool.resize(this->nextCbVectorStartIndexInPool);
+            CbVectorMapIter it = this->cbVectorMap.begin();
+            for (/*index*/; index < nofElements; index += 3, ++it) {
+                size_type vectorKeyLength  = (size_type)tmpRecvOrderVec.at(index);
+                size_type startIndexInPool = (size_type)tmpRecvOrderVec.at(index + 1);
+                size_type dataSize         = (size_type)tmpRecvOrderVec.at(index + 2);
+                CbVectorKey vectorKey      = CbVectorKey(&tmpRecvOrderKeyVec[index2], vectorKeyLength);
+                index2 += vectorKeyLength;
+
+                // if(it==this->cbVectorMap.end() || it->first != vectorKey )
+                // throw UbException(UB_EXARGS, "entweder hat map nicht die gleiche reihenfolge oder vectorKey =
+                // "+UbSystem::toString(vectorKey)+" nicht vorhanden");
+                if (it == this->cbVectorMap.end())
+                    throw UbException(UB_EXARGS, "map ist leer");
+                else if (it->first != vectorKey)
+                    throw UbException(UB_EXARGS, "vectorKey = " + UbSystem::toString(vectorKey) +
+                                                     " nicht vorhanden it->first =" + UbSystem::toString(it->first));
+
+                this->setCbVectorData(*it->second /*vec*/, vectorKey, startIndexInPool, dataSize);
+            }
+            if (it != this->cbVectorMap.end())
+                throw UbException(UB_EXARGS, "error... in der map sind scheinbar noch weiter elemente vorhanden, die "
+                                             "es auf der send seite nicht gibt...");
+
+            counterReceiveDataOrder = 0;
+            nofStoredVectors        = this->cbVectorMap.size();
+
+#ifdef _DEBUG
+            orgPoolVectorStartPointer = &this->pool[0];
+#endif
+        }
+    }
+    /*==================================================================*/
+    void prepareForSendData()
+    {
+        // da sendDataOrder einen request verwendet muss man hier immer abfragen
+        if (counterPrepareForSend == 0) {
+            UBLOG(logDEBUG5, "TbCbVectorMpiPool::prepareForSendData():start"
+                                 << " mpiRemoteRank=" << mpiRemoteRank << " mpiTag=" << mpiTag);
+            // if(sendRequest != MPI_REQUEST_NULL) MPI_Wait(&sendRequest, MPI_STATUS_IGNORE);
+            if (sendRequest[2] != MPI_REQUEST_NULL)
+                MPI_Waitall(3, sendRequest, MPI_STATUS_IGNORE);
+            UBLOG(logDEBUG5, "TbCbVectorMpiPool::prepareForSendData():end"
+                                 << " mpiRemoteRank=" << mpiRemoteRank << " mpiTag=" << mpiTag);
+        }
+
+        counterPrepareForSend++;
+
+        if (counterPrepareForSend == nofStoredVectors) {
+            counterPrepareForSend = 0;
+        }
+
+        // A - non blocking
+        ////der ERSTE is entscheidend
+        ////Grund: wenn man
+        //// for(all trans) { trans->prepare(); trans->fillBuffer(); }
+        //// aufruft, dann wuerde u.U. der Buffer neu beschrieben werden obwohl noch nicht versendet wurde!!!
+        // counterPrepareForSend++;
+        // if(counterPrepareForSend==1)
+        //{
+        //   if(sendRequest != MPI::REQUEST_NULL) sendRequest.Wait();
+        //}
+        //
+        // if(counterPrepareForSend==nofStoredVectors)
+        //   counterPrepareForSend=0;
+    }
+    /*==================================================================*/
+    void sendData()
+    {
+        // A - non blocking
+        // der LETZTE is entscheidend
+        // counterSend++;
+        // if(counterSend==nofStoredVectors)
+        //{
+        //   //std::cout<<"Isend von "<<(int)nextStartIndex<<"elementen von "<<mpiRemoteRank<<" mit
+        //   tag="<<mpiTag<<std::endl; sendRequest = comm.Isend(&pool[0],(int)nextCbVectorStartIndexInPool, mpiDataType,
+        //   mpiRemoteRank, mpiTag); counterSend=0;
+        //}
+        // B - blocking
+        // der LETZTE is entscheidend
+        counterSend++;
+        if (counterSend == nofStoredVectors) {
+            // std::cout<<"Isend von "<<(int)nextStartIndex<<"elementen von "<<mpiRemoteRank<<" mit
+            // tag="<<mpiTag<<std::endl;
+            UBLOG(logDEBUG5, "TbCbVectorMpiPool::sendData():start"
+                                 << " mpiRemoteRank=" << mpiRemoteRank << " mpiTag=" << mpiTag);
+
+            // synchronous send
+            // comm.Ssend(&this->pool[0],(int)this->nextCbVectorStartIndexInPool, mpiDataType, mpiRemoteRank, mpiTag);
+#ifdef _DEBUG
+            if (this->orgPoolVectorStartPointer != &this->pool[0])
+                throw UbException(UB_EXARGS, "ups, pool array adress changed - unknown behavoir");
+#endif
+
+            // standard send
+            MPI_Send(&this->pool[0], (int)this->nextCbVectorStartIndexInPool, mpiDataType, mpiRemoteRank, mpiTag, comm);
+            UBLOG(logDEBUG5, "TbCbVectorMpiPool::sendData():end"
+                                 << " mpiRemoteRank=" << mpiRemoteRank << " mpiTag=" << mpiTag);
+            ////////////////////////////////////////////////////////////////////////////////////////////
+            // DEBUG///////////////////////////////////////
+            // int irank;
+            // MPI_Comm_rank(MPI_COMM_WORLD, &irank);
+            // std::cout << "MPI_Send: " << irank <<  " "  << mpiRemoteRank << " "  <<mpiTag<<std::endl;
+            ///////////////////////////////////////////////////
+            counterSend = 0;
+        }
+    }
+    /*==================================================================*/
+    void prepareForReceiveData()
+    {
+        // A - non blocking
+        // sobald der Letzte kann man den den request holen.
+        // andernfalls kann nicht gewaehrleistet werden, dass evtl noch mit dem buffer gearbeitet wird!!!
+        counterPrepareForReceive++;
+        if (counterPrepareForReceive == this->nofStoredVectors) {
+            UBLOG(logDEBUG5, "TbCbVectorMpiPool::prepareForReceiveData():start"
+                                 << " mpiRemoteRank=" << mpiRemoteRank << " mpiTag=" << mpiTag);
+#ifdef _DEBUG
+            if (this->orgPoolVectorStartPointer != &this->pool[0])
+                throw UbException(UB_EXARGS, "ups, pool array adress changed - unknown behavoir");
+#endif
+            MPI_Irecv(&this->pool[0], (int)this->nextCbVectorStartIndexInPool, mpiDataType, mpiRemoteRank, mpiTag, comm,
+                      &receiveRequest);
+            UBLOG(logDEBUG5, "TbCbVectorMpiPool::prepareForReceiveData():end"
+                                 << " mpiRemoteRank=" << mpiRemoteRank << " mpiTag=" << mpiTag);
+            counterPrepareForReceive = 0;
+        }
+    }
+    /*==================================================================*/
+    void receiveData()
+    {
+        // A - non blocking
+        // sobald der ERSTE reinkommt muss man warten, bis received wurde!!!
+        // denn erst anschliessend stehen die empfangenen daten zur verfuegung
+        if (counterReceive == 0) {
+            UBLOG(logDEBUG5, "TbCbVectorMpiPool::receiveData():start"
+                                 << " mpiRemoteRank=" << mpiRemoteRank << " mpiTag=" << mpiTag);
+            MPI_Wait(&receiveRequest, MPI_STATUS_IGNORE);
+            UBLOG(logDEBUG5, "TbCbVectorMpiPool::receiveData():end"
+                                 << " mpiRemoteRank=" << mpiRemoteRank << " mpiTag=" << mpiTag);
+        }
+        counterReceive++;
+        if (counterReceive == this->nofStoredVectors) // alle receiver waren hier
+        {
+            counterReceive = 0;
+        }
+
+        ////B - blocking
+        ////sobald der ERSTE reinkommt muss man warten, bis received wurde!!!
+        ////denn erst anschliessend stehen die empfangenen daten zur verfuegung
+        // if(counterReceive==0)
+        //{
+        //   comm.Recv(&this->pool[0],(int)this->nextCbVectorStartIndexInPool, mpiDataType, mpiRemoteRank, mpiTag);
+        //}
+        // counterReceive++;
+        // if(counterReceive==this->nofStoredVectors) //alle receiver waren hier
+        //   counterReceive=0;
+    }
+
+protected:
+    CbVectorKey poolKey; // eindeutiger schluessel fuer pool
+    size_type nofStoredVectors;
+
+    size_type counterPrepareReceiveDataOrder;
+    size_type counterSendDataOrder;
+    size_type counterReceiveDataOrder;
+    size_type counterPrepareForReceive;
+    size_type counterReceive;
+    size_type counterPrepareForSend;
+    size_type counterSend;
+
+    std::vector<unsigned> tmpSendOrderVec; // wird zur temp speicherung der anordnung benoetigt
+    std::string tmpSendOrderKeyVec;
+    unsigned tmpSendOrderKeyVecLength;
+
+    MPI_Comm comm;
+    MPI_Request receiveRequest;
+    // MPI_Request  sendRequest;
+    MPI_Request sendRequest[3];
+    // MPI_Status   sendStatus;
+    // MPI_Status   receiveStatus;
+    MPI_Datatype mpiDataType;
+
+    int mpiRemoteRank, mpiTag;
+
+#ifdef _DEBUG
+    T *orgPoolVectorStartPointer;
+#endif
+};
+
+template <typename T>
+typename TbCbVectorMpiPool<T>::MpiPoolPtrMap TbCbVectorMpiPool<T>::poolMap;
+
+//////////////////////////////////////////////////////////////////////////
+//  TbSenderMpiPool
+//////////////////////////////////////////////////////////////////////////
+template <typename T>
+class TbCbVectorSenderMpiPool : public TbTransmitter<CbVector<T>>
+{
+public:
+    using value_type = CbVector<T>;
+
+public:
+    TbCbVectorSenderMpiPool(std::string cbVectorKey, TbCbVectorMpiPool<T> *mpiVectorPool) : mpiVectorPool(mpiVectorPool)
+    {
+        this->getData().setAllocator(new CbVectorAllocatorPool<T>(cbVectorKey, this->mpiVectorPool));
+    }
+    ~TbCbVectorSenderMpiPool() override
+    {
+        if (this->mpiVectorPool->getNofStoredVectors() == 1) // last entry!
+        {
+            TbCbVectorMpiPool<T>::deleteTbCbVectorMpiPool(this->mpiVectorPool->getPoolKey());
+        }
+    }
+
+    bool isLocalTransmitter() const override { return false; }
+    bool isRemoteTransmitter() const override { return !this->isLocalTransmitter(); }
+
+    void sendDataSize() override { this->mpiVectorPool->sendDataOrder(); }
+    void receiveDataSize() override { throw UbException(UB_EXARGS, "TbMpiPoolSender sends only"); }
+    CbVector<T> &receiveData() override { throw UbException(UB_EXARGS, "TbMpiPoolSender sends only"); }
+    void prepareForSend() override { this->mpiVectorPool->prepareForSendData(); }
+    void sendData() override { this->mpiVectorPool->sendData(); }
+
+    // info-section (usable for remote transmitter)
+    int getSendTbRank() const { return this->mpiVectorPool->getRemoteRank(); }
+    int getSendTbTag() const { return this->mpiVectorPool->getRemoteTag(); }
+    int getRecvFromRank() const override { throw UbException(UB_EXARGS, "TbCbVectorSenderMpiPool sends only"); }
+    int getRecvFromTag() const override { throw UbException(UB_EXARGS, "TbCbVectorSenderMpiPool sends only"); }
+
+    std::string toString() const override
+    {
+        return "TbCbVectorSenderMpiPool<" + (std::string) typeid(T).name() + " to rank (tag)" +
+               UbSystem::toString(getSendTbRank()) + "(" + UbSystem::toString(getSendTbTag()) + ")";
+    }
+
+protected:
+    TbCbVectorMpiPool<T> *mpiVectorPool;
+};
+
+/*==================================================================*/
+template <typename T>
+class TbCbVectorReceiverMpiPool : public TbTransmitter<CbVector<T>>
+{
+public:
+    using value_type = CbVector<T>;
+
+public:
+    TbCbVectorReceiverMpiPool(std::string cbVectorKey, TbCbVectorMpiPool<T> *mpiVectorPool)
+        : mpiVectorPool(mpiVectorPool)
+    {
+        this->getData().setAllocator(new CbVectorAllocatorPool<T>(cbVectorKey, this->mpiVectorPool));
+    }
+    ~TbCbVectorReceiverMpiPool() override
+    {
+        if (this->mpiVectorPool->getNofStoredVectors() == 1) // last entry!
+        {
+            TbCbVectorMpiPool<T>::deleteTbCbVectorMpiPool(this->mpiVectorPool->getPoolKey());
+        }
+    }
+    bool isLocalTransmitter() const override { return false; }
+    bool isRemoteTransmitter() const override { return !this->isLocalTransmitter(); }
+
+    void sendDataSize() override { throw UbException(UB_EXARGS, "TbCbVectorReceiverMpiPool receives only"); }
+    void receiveDataSize() override { this->mpiVectorPool->receiveDataOrder(); }
+    void sendData() override { throw UbException(UB_EXARGS, "TbCbVectorReceiverMpiPool receives only"); }
+    void prepareForReceive() override { this->mpiVectorPool->prepareForReceiveData(); }
+    CbVector<T> &receiveData() override
+    {
+        this->mpiVectorPool->receiveData();
+        return this->getData();
+    }
+
+    // info-section (usable for remote transmitter)
+    int getSendTbRank() const { throw UbException(UB_EXARGS, "TbCbVectorReceiverMpiPool receives only"); }
+    int getSendTbTag() const { throw UbException(UB_EXARGS, "TbCbVectorReceiverMpiPool receives only"); }
+    int getRecvFromRank() const override { return this->mpiVectorPool->getRemoteRank(); }
+    int getRecvFromTag() const override { return this->mpiVectorPool->getRemoteTag(); }
+
+    std::string toString() const override
+    {
+        return "TbCbVectorReceiverMpiPool<" + (std::string) typeid(T).name() + " to rank (tag)" +
+               UbSystem::toString(getRecvFromRank()) + "(" + UbSystem::toString(getRecvFromTag()) + ")";
+    }
+
+protected:
+    TbCbVectorMpiPool<T> *mpiVectorPool;
+};
+
+#endif // VF_MPI
+
+#endif // TBTRANSMITTERMPIPOOL_H
diff --git a/src/basics/basics/utilities/UbFileInput.h b/src/basics/basics/utilities/UbFileInput.h
new file mode 100644
index 0000000000000000000000000000000000000000..d1eac796f437a17b5519d12b096dc8b5d4263de4
--- /dev/null
+++ b/src/basics/basics/utilities/UbFileInput.h
@@ -0,0 +1,122 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file UbFileInput.h
+//! \ingroup utilities
+//! \author Soeren Freudiger, Sebastian Geller
+//=======================================================================================
+#ifndef UBFILEINPUT_H
+#define UBFILEINPUT_H
+
+#include <fstream>
+#include <iostream>
+#include <string>
+
+#include <cstdlib> //atoi
+#include <cstring> //strstr
+
+#include <basics/utilities/UbException.h>
+
+/*=========================================================================*/
+/*  UbFileInput                                                            */
+/*                                                                         */
+/**
+...
+<BR><BR>
+@author <A HREF="mailto:muffmolch@gmx.de">S. Freudiger</A>
+@version 1.0 - 23.11.04
+*/
+
+/*
+usage: ...
+*/
+
+class UbFileInput
+{
+public:
+    enum FILETYPE { ASCII, BINARY };
+
+public:
+    UbFileInput() : filename("") {}
+    virtual ~UbFileInput() = default;
+
+    virtual bool operator!() { return !(infile); }
+    virtual bool isOpen() { return !(!(infile)); }
+
+    virtual bool open(std::string filename) = 0;
+    virtual void close() { infile.close(); }
+    virtual int eof() { return infile.eof(); }
+
+    virtual void skipLine()                     = 0; // Springt zur naechsten Zeile
+    virtual void readLine()                     = 0;
+    virtual std::string readStringLine()        = 0;
+    virtual int readInteger()                   = 0; // Liest einen Int-Wert ein
+    virtual std::size_t readSize_t()            = 0;
+    virtual double readDouble()                 = 0; // Liest einen double-Wert ein
+    virtual float readFloat()                   = 0; // Liest einen float-Wert ein
+    virtual bool readBool()                     = 0; // Liest einen bool-Wert ein
+    virtual char readChar()                     = 0; // Liest einen char-Wert ein
+    virtual std::string readString()            = 0; // Liest ein Wort ein
+    virtual std::string readLineTill(char stop) = 0; // Liest gesamte Zeile ein bis zu einem bestimmten Zeichen
+    virtual std::string parseString()           = 0; // Liest
+
+    virtual void setCommentIndicator(char commentindicator) { this->commentindicator = commentindicator; }
+
+    virtual bool containsString(const std::string &var)               = 0;
+    virtual void setPosAfterLineWithString(const std::string &var)    = 0;
+    virtual int readIntegerAfterString(const std::string &var)        = 0;
+    virtual double readDoubleAfterString(const std::string &var)      = 0;
+    virtual bool readBoolAfterString(const std::string &var)          = 0;
+    virtual std::string readStringAfterString(const std::string &var) = 0;
+
+    virtual std::string getFileName() { return this->filename; }
+
+    // returns file extension:
+    // e.g. "./../test/ich.inp" -> "inp", "./../test/ich" -> ""
+    virtual std::string getFileExtension()
+    {
+        std::size_t pos1 = filename.rfind("/");
+        if (pos1 == std::string::npos)
+            pos1 = 0;
+        std::size_t pos2 = filename.rfind(".");
+        if (pos2 != std::string::npos && pos2 > pos1)
+            return filename.substr(pos2 + 1);
+
+        return "";
+    }
+
+    // returns "ASCII", "BINARY"
+    virtual FILETYPE getFileType() = 0;
+
+protected:
+    std::ifstream infile;
+    std::string filename;
+    char commentindicator{ 'C' };
+};
+
+#endif // UBFILEINPUT_H
diff --git a/src/basics/basics/utilities/UbFileInputASCII.cpp b/src/basics/basics/utilities/UbFileInputASCII.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2d73804f4d06df62e38b0180b9fb0a244eb13887
--- /dev/null
+++ b/src/basics/basics/utilities/UbFileInputASCII.cpp
@@ -0,0 +1,293 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file UbFileInputASCII.cpp
+//! \ingroup utilities
+//! \author Soeren Freudiger, Sebastian Geller
+//=======================================================================================
+#include <algorithm>
+#include <basics/utilities/UbFileInputASCII.h>
+#include <cstring>
+
+using namespace std;
+
+UbFileInputASCII::UbFileInputASCII(string filename)
+{
+    this->filename         = filename;
+    this->commentindicator = 'C';
+
+    infile.open(filename.c_str());
+
+    // if(!infile) UB_THROW( UbException((string)("UbFileInputASCII::UbFileInputASCII(string filename, int how) couldn't
+    // open file:\n "+filename)) );
+}
+/*==========================================================*/
+bool UbFileInputASCII::open(string filename)
+{
+    infile.close();
+    infile.clear(); // setzt flags zurueck
+
+    this->filename = filename;
+    infile.open(this->filename.c_str());
+
+    return infile.is_open();
+}
+/*==========================================================*/
+int UbFileInputASCII::readInteger()
+{
+    int dummy;
+    infile >> dummy;
+    return dummy;
+}
+/*==========================================================*/
+long long UbFileInputASCII::readLongLong()
+{
+    long long dummy;
+    infile >> dummy;
+    return dummy;
+}
+/*==========================================================*/
+string UbFileInputASCII::getFileName() { return this->filename; }
+
+/*==========================================================*/
+void UbFileInputASCII::skipLine()
+{
+    string dummy;
+    getline(infile, dummy);
+}
+/*==========================================================*/
+void UbFileInputASCII::readLine()
+{
+    string dummy;
+    getline(infile, dummy);
+}
+/*==========================================================*/
+string UbFileInputASCII::readStringLine()
+{
+    string dummy;
+    getline(infile, dummy);
+    return dummy;
+}
+/*==========================================================*/
+string UbFileInputASCII::readLineTill(char stop)
+{
+    string dummy;
+    getline(infile, dummy, stop);
+    return dummy;
+}
+/*==========================================================*/
+string UbFileInputASCII::parseString()
+{
+    string dummy;
+    getline(infile, dummy, ' ');
+    return dummy;
+}
+/*==========================================================*/
+double UbFileInputASCII::readDouble()
+{
+    double dummy;
+    infile >> dummy;
+    return dummy;
+}
+/*==========================================================*/
+float UbFileInputASCII::readFloat()
+{
+    float dummy;
+    infile >> dummy;
+    return dummy;
+}
+/*==========================================================*/
+string UbFileInputASCII::readString()
+{
+    string dummy;
+    infile >> dummy;
+    return dummy;
+}
+/*==========================================================*/
+char UbFileInputASCII::readChar()
+{
+    int dummy;
+    infile >> dummy;
+    return (char)dummy;
+}
+/*==========================================================*/
+std::size_t UbFileInputASCII::readSize_t()
+{
+    std::size_t dummy;
+    infile >> dummy;
+    return dummy;
+}
+/*==========================================================*/
+void UbFileInputASCII::setPosAfterLineWithString(const string &var)
+{
+    infile.seekg(0L, ios::beg); // Positionszeiger der Datei auf den Anfang setzen
+    char line[512];
+    do {
+        infile.getline(line, 512);
+        if (infile.eof())
+            UB_THROW(UbException(UB_EXARGS, "error at reading in file \"" + filename + "\" -> string " + var +
+                                                " wasn't found in " + this->filename));
+    } while (strstr(line, var.c_str()) != line); // Ende Schleife, wenn varname ganz in zeile vorkommt
+}
+/*==========================================================*/
+bool UbFileInputASCII::containsString(const string &var)
+{
+    infile.clear(); // setzt den EOF-Status zurueck (wird durch infile.seekg() NICHT getan!!!)
+
+    infile.seekg(0L, ios::beg); // Positionszeiger der Datei auf den Anfang setzen
+    char line[512];
+    do {
+        infile.getline(line, 512);
+        if (infile.eof())
+            return false;
+    } while (strstr(line, var.c_str()) != line); // Ende Schleife, wenn varname ganz in zeile vorkommt
+
+    return true;
+}
+/*==========================================================*/
+int UbFileInputASCII::readIntegerAfterString(const string &var)
+// last change [29.6.2021] at [13:52]
+// suchts in einer Datei nach varname und gibt den dahinter stehenden int-Wert zurueck
+// z.B. timesteps 9
+{
+    infile.clear(); // setzt den EOF-Status zurueck (wird durch infile.seekg() NICHT getan!!!)
+
+    infile.seekg(0L, ios::beg); // Positionszeiger der Datei auf den Anfang setzen
+
+    char line[512];
+    do {
+        infile.getline(line, 512);
+
+        if (infile.eof())
+            UB_THROW(UbException(UB_EXARGS, "error at reading in file \"" + filename + "\" -> " + var +
+                                                " wasn't found in " + this->filename));
+    } while (strstr(line, var.c_str()) != line); // Ende Schleife, wenn varname ganz in zeile vorkommt
+
+    std::string temp{ line };
+    temp = temp.substr(var.size()); // zeile um "varname" kuerzen
+
+    temp.erase(std::remove(temp.begin(), temp.end(), ' '), temp.end());  // remove whitespace
+    temp.erase(std::remove(temp.begin(), temp.end(), '\t'), temp.end()); // remove tabs
+
+    return std::stoi(temp);
+}
+/*==========================================================*/
+// last change [29.6.2021] at [13:52]
+// sucht in einer Datei nach varname und gibt den dahinter stehenden int-Wert zurueck
+// z.B. nue 9.5
+double UbFileInputASCII::readDoubleAfterString(const string &var)
+{
+    infile.clear(); // setzt den EOF-Status zurueck (wird durch infile.seekg() NICHT getan!!!)
+
+    infile.seekg(0L, ios::beg); // Positionszeiger der Datei auf den Anfang setzen
+
+    char line[512];
+
+    do {
+        infile.getline(line, 512);
+        if (infile.eof())
+            UB_THROW(UbException(UB_EXARGS, "error at reading in file \"" + filename + "\" -> " + var +
+                                                " wasn't found in " + this->filename));
+    } while (/*!strncmp(varname,line,sizeof(varname))==0*/ strstr(line, var.c_str()) !=
+             line); // Ende Schleife, wenn varname ganz in zeile vorkommt
+
+    std::string temp{ line };
+    temp = temp.substr(var.size()); // zeile um "varname" kuerzen
+
+    temp.erase(std::remove(temp.begin(), temp.end(), ' '), temp.end());  // remove whitespace
+    temp.erase(std::remove(temp.begin(), temp.end(), '\t'), temp.end()); // remove tabs
+
+    return std::stod(temp);
+}
+/*==========================================================*/
+// last change [29.6.2021] at [13:52]
+// liefert string-Wert der hinter dem uebergebenen char feld in der datei infile steht
+// zudem wird der wert in die uebergebene variable value uebertragen (falls man das ergebniss als char benoetig)
+string UbFileInputASCII::readStringAfterString(const string &var) //,char *value)
+{
+    infile.clear(); // setzt den EOF-Status zurueck (wird durch infile.seekg() NICHT getan!!!)
+
+    infile.seekg(0L, ios::beg); // Positionszeiger der Datei auf den Anfang setzen
+
+    char line[512];
+    // string line_copy[512];
+    do {
+        infile.getline(line, 512);
+        if (infile.eof())
+            UB_THROW(UbException(UB_EXARGS, "error at reading in file \"" + filename + "\" -> " + var +
+                                                " wasn't found in " + this->filename));
+    } while (strstr(line, var.c_str()) != line); // Ende Schleife, wenn varname ganz in zeile vorkommt
+
+    // std::string lineRead;
+    // while(getline(infile, lineRead))
+    // {
+    //     if(lineRead.find(toSearch, 0) < lineRead.length())
+    //     {
+    //         occurenceNumber++;
+    //         cout << counter << ":" << lineRead << endl;
+
+    //     }
+    // }
+
+    std::string temp{ line };
+    temp = temp.substr(var.size()); // zeile um "varname" kuerzen
+
+    temp.erase(std::remove(temp.begin(), temp.end(), ' '), temp.end());  // remove whitespace
+    temp.erase(std::remove(temp.begin(), temp.end(), '\t'), temp.end()); // remove tabs
+
+    return temp;
+}
+/*==========================================================*/
+// last change [10.3.2004] at [9:46]
+// sucht in einer Datei nach varname und gibt den dahinter stehenden int-Wert zurueck
+// z.B. nue 9.5
+bool UbFileInputASCII::readBoolAfterString(const string &var)
+{
+    if (this->readStringAfterString(var) == "true")
+        return true;
+    else if (this->readStringAfterString(var) == "false")
+        return false;
+    else
+        UB_THROW(UbException(UB_EXARGS, "error at reading in file \"" + filename + "\" -> expression after " + var +
+                                            " is not equal to 'true' or 'false' in " + this->filename));
+}
+/*==========================================================*/
+// last change [10.3.2004] at [9:46]
+// sucht in einer Datei nach varname und gibt den dahinter stehenden int-Wert zurueck
+// z.B. nue 9.5
+bool UbFileInputASCII::readBool()
+{
+    string tmp = this->readString();
+    if (tmp == "true")
+        return true;
+    else if (tmp == "false")
+        return false;
+    else
+        UB_THROW(UbException(UB_EXARGS, "error at reading in file \"" + filename + "\" -> expression=\"" + tmp +
+                                            "\" is not equal to 'true' or 'false' in " + this->filename));
+}
diff --git a/src/basics/basics/utilities/UbFileInputASCII.h b/src/basics/basics/utilities/UbFileInputASCII.h
new file mode 100644
index 0000000000000000000000000000000000000000..a86955bca511f194f5936a81dd9a542026f88f67
--- /dev/null
+++ b/src/basics/basics/utilities/UbFileInputASCII.h
@@ -0,0 +1,101 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file UbFileInputASCII.h
+//! \ingroup utilities
+//! \author Soeren Freudiger, Sebastian Geller
+//=======================================================================================
+#ifndef UBFILEINPUTASCII_H
+#define UBFILEINPUTASCII_H
+
+#include <fstream>
+#include <iostream>
+#include <string>
+
+#include "basics_export.h"
+
+#include <basics/utilities/UbException.h>
+#include <basics/utilities/UbFileInput.h>
+
+/*=========================================================================*/
+/*  UbFileInputASCII                                                       */
+/*                                                                         */
+/**
+...
+<BR><BR>
+@author <A HREF="mailto:muffmolch@gmx.de">S. Freudiger</A>
+@version 1.0 - 23.11.04
+*/
+
+/*
+usage: ...
+*/
+
+class BASICS_EXPORT UbFileInputASCII : public UbFileInput
+{
+public:
+    UbFileInputASCII() : UbFileInput() {}
+    UbFileInputASCII(std::string filename);
+
+    bool open(std::string filename) override;
+
+    std::string getFileName() override;
+    void skipLine() override; // Springt zur naechsten Zeile
+
+    void readLine() override;
+    std::string readStringLine() override;
+    int readInteger() override; // Liest einen Int-Wert ein
+    long long readLongLong();   // Liest einen long-Wert ein
+
+    std::size_t readSize_t() override;
+    double readDouble() override;                 // Liest einen double-Wert ein
+    float readFloat() override;                   // Liest einen float-Wert ein
+    bool readBool() override;                     // Liest einen bool-Wert ein
+    char readChar() override;                     // Liest einen char-Wert ein
+    std::string readString() override;            // Liest ein Wort ein
+    std::string readLineTill(char stop) override; // Liest gesamte Zeile ein bis zu einem bestimmten Zeichen
+    std::string parseString() override;
+
+    bool containsString(const std::string &var) override;
+    void setPosAfterLineWithString(const std::string &var) override;
+    int readIntegerAfterString(const std::string &var) override;
+    double readDoubleAfterString(const std::string &var) override;
+    bool readBoolAfterString(const std::string &var) override;
+    std::string readStringAfterString(const std::string &var) override;
+
+    FILETYPE getFileType() override { return ASCII; }
+
+    template <typename T>
+    friend inline UbFileInputASCII &operator>>(UbFileInputASCII &file, T &data)
+    {
+        file.infile >> data;
+        return file;
+    }
+};
+
+#endif // UBFILEINPUTASCII_H
diff --git a/src/basics/basics/utilities/UbFileInputASCIITest.cfg b/src/basics/basics/utilities/UbFileInputASCIITest.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..294d58cd2eae2819366e4f9cb2e49195e4fd518a
--- /dev/null
+++ b/src/basics/basics/utilities/UbFileInputASCIITest.cfg
@@ -0,0 +1 @@
+test = 1
diff --git a/src/basics/basics/utilities/UbFileInputASCIITest.cpp b/src/basics/basics/utilities/UbFileInputASCIITest.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f22c385841d3b516d93650b505a0bf93c9ae85a6
--- /dev/null
+++ b/src/basics/basics/utilities/UbFileInputASCIITest.cpp
@@ -0,0 +1,18 @@
+#include <gmock/gmock.h>
+#include <filesystem>
+
+#include <basics/utilities/UbFileInputASCII.h>
+
+
+TEST(DISABLED_UbFileInputASCIITest, readIntegerAfterString)
+{
+    // assuming that the config files is stored parallel to this file.
+    std::filesystem::path filePath = __FILE__;
+    filePath.replace_filename("UbFileInputASCIITest.cfg");
+
+    UbFileInputASCII sut {filePath.string()};
+
+    const int actual = sut.readIntegerAfterString("test =");
+
+    EXPECT_THAT(actual, testing::Eq(1));
+}
diff --git a/src/basics/basics/utilities/UbFileInputBinary.cpp b/src/basics/basics/utilities/UbFileInputBinary.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b77327f6d8c195f93ba34510a3b691e6cd6c52b2
--- /dev/null
+++ b/src/basics/basics/utilities/UbFileInputBinary.cpp
@@ -0,0 +1,182 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file UbFileInputBinary.cpp
+//! \ingroup utilities
+//! \author Soeren Freudiger, Sebastian Geller
+//=======================================================================================
+#include <basics/utilities/UbFileInputBinary.h>
+#include <cstring>
+
+using namespace std;
+
+/*==========================================================*/
+UbFileInputBinary::UbFileInputBinary(string filename)
+{
+    this->filename = filename;
+    infile.open(filename.c_str(), ios::in | ios::binary);
+}
+/*==========================================================*/
+bool UbFileInputBinary::open(string filename)
+{
+    infile.close();
+    infile.clear(); // setzt flags zurueck
+
+    this->filename = filename;
+    infile.open(this->filename.c_str(), ios::in | ios::binary);
+
+    return infile.is_open();
+}
+/*==========================================================*/
+int UbFileInputBinary::readInteger()
+{
+    int dummy;
+    infile.read((char *)&dummy, sizeof(int));
+    return dummy;
+}
+/*==========================================================*/
+std::size_t UbFileInputBinary::readSize_t()
+{
+    std::size_t dummy;
+    infile.read((char *)&dummy, sizeof(std::size_t));
+    return dummy;
+}
+/*==========================================================*/
+double UbFileInputBinary::readDouble()
+{
+    double dummy;
+    infile.read((char *)&dummy, sizeof(double));
+    return dummy;
+}
+/*==========================================================*/
+float UbFileInputBinary::readFloat()
+{
+    float dummy;
+    infile.read((char *)&dummy, sizeof(float));
+    return dummy;
+}
+/*==========================================================*/
+char UbFileInputBinary::readChar()
+{
+    char dummy;
+    infile.read((char *)&dummy, sizeof(char));
+    return dummy;
+}
+/*==========================================================*/
+string UbFileInputBinary::readString()
+{
+    char c;
+    infile.read(&c, sizeof(char));
+    while (c == ' ' || c == '\t')
+        infile.read(&c, sizeof(char));
+
+    string dummy;
+    dummy += c;
+
+    infile.read(&c, sizeof(char));
+    while (c != '\0' && c != ' ' && c != '\t' && c != '\n') {
+        dummy += c;
+        infile.read(&c, sizeof(char));
+    }
+    return dummy;
+}
+/*==========================================================*/
+bool UbFileInputBinary::readBool()
+{
+    bool dummy;
+    infile.read((char *)&dummy, sizeof(bool));
+    return dummy;
+}
+/*==========================================================*/
+void UbFileInputBinary::skipLine()
+{
+    char c;
+    do {
+        infile.read(&c, sizeof(char));
+    } while (c != '\n');
+}
+/*==========================================================*/
+void UbFileInputBinary::readLine()
+{
+    char c;
+    infile.read(&c, sizeof(char));
+    while (c != '\n')
+        infile.read(&c, sizeof(char));
+}
+/*==========================================================*/
+string UbFileInputBinary::readStringLine()
+{
+    char c;
+    string dummy;
+    infile.read(&c, sizeof(char));
+    while (c != '\n') {
+        dummy += c;
+        infile.read(&c, sizeof(char));
+    }
+    return dummy;
+}
+/*==========================================================*/
+string UbFileInputBinary::readLineTill(char /*stop*/)
+{
+    UB_THROW(UbException(UB_EXARGS, "method makes no sense for binary streams"));
+}
+/*==========================================================*/
+string UbFileInputBinary::parseString()
+{
+    UB_THROW(UbException(UB_EXARGS, "method makes no sense for binary streams"));
+}
+/*==========================================================*/
+bool UbFileInputBinary::containsString(const string & /*var*/)
+{
+    UB_THROW(UbException(UB_EXARGS, "method makes no sense for binary streams"));
+}
+/*==========================================================*/
+void UbFileInputBinary::setPosAfterLineWithString(const string & /*var*/)
+{
+    UB_THROW(UbException(UB_EXARGS, "method makes no sense for binary streams"));
+}
+/*==========================================================*/
+int UbFileInputBinary::readIntegerAfterString(const string & /*var*/)
+{
+    UB_THROW(UbException(UB_EXARGS, "method makes no sense for binary streams"));
+}
+/*==========================================================*/
+double UbFileInputBinary::readDoubleAfterString(const string & /*var*/)
+{
+    UB_THROW(UbException(UB_EXARGS, "method makes no sense for binary streams"));
+}
+/*==========================================================*/
+string UbFileInputBinary::readStringAfterString(const string & /*var*/)
+{
+    UB_THROW(UbException(UB_EXARGS, "method makes no sense for binary streams"));
+}
+/*==========================================================*/
+bool UbFileInputBinary::readBoolAfterString(const string & /*var*/)
+{
+    UB_THROW(UbException(UB_EXARGS, "method makes no sense for binary streams"));
+}
diff --git a/src/basics/basics/utilities/UbFileInputBinary.h b/src/basics/basics/utilities/UbFileInputBinary.h
new file mode 100644
index 0000000000000000000000000000000000000000..9e477c3a24df2c78b5696688354d5dcba747d486
--- /dev/null
+++ b/src/basics/basics/utilities/UbFileInputBinary.h
@@ -0,0 +1,104 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file UbFileInputBinary.h
+//! \ingroup utilities
+//! \author Soeren Freudiger, Sebastian Geller
+//=======================================================================================
+#ifndef UBFILEINPUTBINARY_H
+#define UBFILEINPUTBINARY_H
+
+#include <fstream>
+#include <iostream>
+#include <string>
+
+#include <basics/utilities/UbException.h>
+#include <basics/utilities/UbFileInput.h>
+
+/*=========================================================================*/
+/*  UbFileInputBinary                                                      */
+/*                                                                         */
+/**
+...
+<BR><BR>
+@author <A HREF="mailto:muffmolch@gmx.de">S. Freudiger</A>
+@version 1.0 - 23.11.04
+*/
+
+/*
+usage: ...
+*/
+
+class UbFileInputBinary : public UbFileInput
+{
+public:
+    UbFileInputBinary() : UbFileInput() {}
+    UbFileInputBinary(std::string filename);
+
+    bool open(std::string filename) override;
+
+    void skipLine() override; // Springt zur naechsten Zeile
+    void readLine() override;
+    std::string readStringLine() override;
+    std::size_t readSize_t() override;
+    int readInteger() override;                   // Liest einen Int-Wert ein
+    double readDouble() override;                 // Liest einen double-Wert ein
+    float readFloat() override;                   // Liest einen float-Wert ein
+    bool readBool() override;                     // Liest einen bool-Wert ein
+    char readChar() override;                     // Liest einen char-Wert ein
+    std::string readString() override;            // Liest ein Wort ein
+    std::string readLineTill(char stop) override; // Liest gesamte Zeile ein bis zu einem bestimmten Zeichen
+    std::string parseString() override;           // Liest
+
+    bool containsString(const std::string &var) override;
+    void setPosAfterLineWithString(const std::string &var) override;
+    int readIntegerAfterString(const std::string &var) override;
+    double readDoubleAfterString(const std::string &var) override;
+    bool readBoolAfterString(const std::string &var) override;
+    std::string readStringAfterString(const std::string &var) override;
+
+    FILETYPE getFileType() override { return BINARY; }
+
+    template <typename T>
+    friend inline UbFileInputBinary &operator>>(UbFileInputBinary &file, T &data)
+    {
+        file.infile.read((char *)&data, sizeof(T));
+        return file;
+    }
+
+    template <typename T>
+    void readVector(std::vector<T> &v)
+    {
+        size_t size = v.size();
+        if (size > 0) {
+            infile.read((char *)&v[0], sizeof(T) * size);
+        }
+    }
+};
+
+#endif
diff --git a/src/basics/basics/utilities/UbFileOutput.h b/src/basics/basics/utilities/UbFileOutput.h
new file mode 100644
index 0000000000000000000000000000000000000000..877b96fc5c6a1d31ee7f6e724df134dd42373760
--- /dev/null
+++ b/src/basics/basics/utilities/UbFileOutput.h
@@ -0,0 +1,121 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file UbFileOutput.h
+//! \ingroup utilities
+//! \author Soeren Freudiger, Sebastian Geller
+//=======================================================================================
+#ifndef UBFILEOUTPUT_H
+#define UBFILEOUTPUT_H
+
+#include <fstream>
+#include <iomanip>
+#include <iostream>
+#include <string>
+
+#include <basics/utilities/UbException.h>
+
+/*=========================================================================*/
+/*  UbFileOutput                                                             */
+/*                                                                         */
+/**
+...
+<BR><BR>
+@author <A HREF="mailto:muffmolch@gmx.de">S. Freudiger</A>
+@version 1.0 - 23.11.04
+*/
+
+/*
+usage: ...
+*/
+
+class UbFileOutput
+{
+public:
+    enum CREATEOPTION { OUTFILE = 0, INANDOUTFILE = 1, APPENDFILE = 2 };
+    enum FILETYPE { ASCII, BINARY };
+
+public:
+    UbFileOutput() : filename("") {}
+    UbFileOutput(const std::string &filename) : filename(filename) {}
+    virtual ~UbFileOutput() { outfile.flush(); }
+
+    virtual bool open(const std::string &filename, CREATEOPTION opt = OUTFILE) = 0;
+
+    virtual bool operator!() { return !(outfile); }
+    virtual bool isOpen() { return !(!(outfile)); }
+
+    virtual void flush() { outfile.flush(); }
+    virtual void close() { outfile.close(); }
+
+    virtual void writeInteger(const int &value, const int &width = 0)        = 0;
+    virtual void writeDouble(const double &value, const int &width = 0)      = 0;
+    virtual void writeFloat(const float &value, const int &width = 0)        = 0;
+    virtual void writeBool(const bool &value, const int &width = 0)          = 0;
+    virtual void writeSize_t(const std::size_t &value, const int &width = 0) = 0;
+    virtual void writeChar(const char &value, const int &width = 0)          = 0;
+    virtual void writeString(const std::string &value, const int &width = 0) = 0;
+    virtual void writeStringOnly(const std::string &value)                   = 0;
+    virtual void writeLine(const std::string &value, const int &width = 0)   = 0;
+    virtual void writeLine()                                                 = 0;
+
+    virtual void writeCommentLine(const std::string &line)                 = 0;
+    virtual void writeCommentLine(char indicator, const std::string &line) = 0;
+    virtual void writeCopyOfFile(const std::string &filename)              = 0;
+
+    virtual void setCommentIndicator(char commentindicator) { this->commentindicator = commentindicator; }
+
+    virtual void setPrecision(const int &precision) = 0;
+    virtual int getPrecision()                      = 0;
+
+    // returns "ASCII", "BINARY"
+    virtual FILETYPE getFileType() = 0;
+
+    // returns file extension:
+    // e.g. "./../test/ich.inp" -> "inp", "./../test/ich" -> ""
+    virtual std::string getFileExtension()
+    {
+        std::size_t pos1 = filename.rfind("/");
+        if (pos1 == std::string::npos)
+            pos1 = 0;
+        std::size_t pos2 = filename.rfind(".");
+        if (pos2 != std::string::npos && pos2 > pos1)
+            return filename.substr(pos2 + 1);
+
+        return "";
+    }
+
+    virtual std::string getFileName() { return this->filename; }
+
+protected:
+    std::ofstream outfile;
+    std::string filename;
+    char commentindicator{ 'C' };
+};
+
+#endif // UBFILEOUTPUT_H
diff --git a/src/basics/basics/utilities/UbFileOutputASCII.cpp b/src/basics/basics/utilities/UbFileOutputASCII.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..56edaf919a9d3f058fff9f5d74e646679f5010f0
--- /dev/null
+++ b/src/basics/basics/utilities/UbFileOutputASCII.cpp
@@ -0,0 +1,203 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file UbFileOutputASCII.cpp
+//! \ingroup utilities
+//! \author Soeren Freudiger, Sebastian Geller
+//=======================================================================================
+#include <basics/utilities/UbFileOutputASCII.h>
+#include <basics/utilities/UbInfinity.h>
+#include <basics/utilities/UbMath.h>
+#include <basics/utilities/UbSystem.h>
+#include <cstring>
+
+using namespace std;
+
+UbFileOutputASCII::UbFileOutputASCII(const string &filename, const bool &createPath, const int & /*precision*/)
+    : UbFileOutput(filename)
+{
+    this->commentindicator = 'C';
+    this->setPrecision(20);
+
+    outfile.open(filename.c_str(), ios::out);
+
+    if (!outfile && createPath) {
+        outfile.clear(); // flags ruecksetzen (ansonsten liefert utern if(!outfile) weiterhin true!!!
+        string path = UbSystem::getPathFromString(filename);
+        if (path.size() > 0) {
+            UbSystem::makeDirectory(path);
+            outfile.open(filename.c_str(), ios::out);
+        }
+    }
+
+    if (!outfile)
+        UB_THROW(UbException(UB_EXARGS, "couldn't open file:\n " + filename));
+}
+/*==========================================================*/
+UbFileOutputASCII::UbFileOutputASCII(const std::string &filename, CREATEOPTION opt, const bool &createPath,
+                                     const int &precision)
+    : UbFileOutput(filename)
+{
+    this->commentindicator = 'C';
+    this->setPrecision(precision);
+
+    if (!this->open(filename, opt) && createPath) {
+        outfile.clear(); // flags ruecksetzen (ansonsten liefert utern if(!outfile) weiterhin true!!!
+        string path = UbSystem::getPathFromString(filename);
+        if (path.size() > 0)
+            UbSystem::makeDirectory(path);
+
+        this->open(filename, opt);
+    }
+
+    if (!outfile)
+        UB_THROW(UbException(UB_EXARGS, "couldn't open file:\n " + filename));
+}
+/*==========================================================*/
+bool UbFileOutputASCII::open(const std::string &filename, CREATEOPTION opt)
+{
+    outfile.close();
+    outfile.clear(); // setzt flags zurueck
+    this->filename = filename;
+
+    if (opt == UbFileOutput::OUTFILE)
+        outfile.open(this->filename.c_str(), ios::out);
+    else if (opt == UbFileOutput::INANDOUTFILE)
+        outfile.open(this->filename.c_str(), ios::out | ios::in);
+    else if (opt == UbFileOutput::APPENDFILE)
+        outfile.open(this->filename.c_str(), ios::app);
+    else
+        UB_THROW(UbException(UB_EXARGS, "undefined CREATEOPTION"));
+
+    return outfile.is_open();
+}
+/*==========================================================*/
+void UbFileOutputASCII::writeBool(const bool &value, const int &width)
+{
+    outfile.width(width);
+    if (value)
+        outfile << "true ";
+    else
+        outfile << "false ";
+}
+/*==========================================================*/
+void UbFileOutputASCII::writeDouble(const double &value, const int &width)
+{
+    outfile.width(width);
+    // Problem: Ub::inf wird gerundet
+    //         -> beim Einlesen ist der Wert evtl zu gross und es kommt murks raus
+    //         -> max Laenge darstellen und gut ist
+    if (UbMath::equal(value, (double)Ub::inf)) {
+        ios_base::fmtflags flags = outfile.flags();
+        outfile << setprecision(std::numeric_limits<double>::digits10 + 2);
+        outfile << value << " ";
+        outfile.flags(flags);
+        return;
+    }
+    outfile << value << " ";
+}
+/*==========================================================*/
+void UbFileOutputASCII::writeFloat(const float &value, const int &width)
+{
+    outfile.width(width);
+    // Problem: Ub::inf wird gerundet
+    //         -> beim Einlesen ist der Wert evtl zu gross und es kommt murks raus
+    //         -> max Laenge darstellen und gut ist
+    if (UbMath::equal(value, (float)Ub::inf)) {
+        ios_base::fmtflags flags = outfile.flags();
+        outfile << setprecision(std::numeric_limits<float>::digits10 + 2);
+        outfile << value << " ";
+        outfile.flags(flags);
+        return;
+    }
+    outfile << value << " ";
+}
+/*==========================================================*/
+void UbFileOutputASCII::setPrecision(const int &precision) { outfile << setprecision(precision); }
+/*==========================================================*/
+void UbFileOutputASCII::writeInteger(const int &value, const int &width)
+{
+    outfile.width(width);
+    outfile << value << " ";
+}
+/*==========================================================*/
+void UbFileOutputASCII::writeSize_t(const std::size_t &value, const int &width)
+{
+    outfile.width(width);
+    outfile << value << " ";
+}
+/*==========================================================*/
+void UbFileOutputASCII::writeChar(const char &value, const int &width)
+{
+    outfile.width(width);
+    outfile << (int)value << " ";
+}
+/*==========================================================*/
+void UbFileOutputASCII::writeString(const string &value, const int &width)
+{
+    outfile.width(width);
+    outfile << value.c_str() << " ";
+}
+/*==========================================================*/
+void UbFileOutputASCII::writeStringOnly(const string &value) { outfile << value.c_str(); }
+
+/*==========================================================*/
+void UbFileOutputASCII::writeLine(const string &value, const int &width)
+{
+    outfile.width(width);
+    outfile << value.c_str() << endl;
+}
+/*==========================================================*/
+void UbFileOutputASCII::writeLine() { outfile << endl; }
+/*==========================================================*/
+void UbFileOutputASCII::writeCommentLine(const string &line) { this->writeCommentLine(this->commentindicator, line); }
+/*==========================================================*/
+void UbFileOutputASCII::writeCommentLine(char indicator, const string &line)
+{
+    this->outfile << indicator << line << endl;
+}
+/*==========================================================*/
+void UbFileOutputASCII::writeCopyOfFile(const string &filename)
+{
+    ifstream infile(filename.c_str());
+    if (!infile)
+        UB_THROW(UbException(UB_EXARGS, "couldn't open file:\n " + filename));
+
+    try {
+        char c;
+        while (infile.get(c)) {
+            outfile.put(c); //=out<<c;
+        }
+        outfile.flush();
+        infile.close();
+    } catch (std::exception &e) {
+        UB_THROW(UbException(UB_EXARGS, "catched std::exception, error: " + (std::string)e.what()));
+    } catch (...) {
+        UB_THROW(UbException(UB_EXARGS, "unknown error"));
+    }
+}
diff --git a/src/basics/basics/utilities/UbFileOutputASCII.h b/src/basics/basics/utilities/UbFileOutputASCII.h
new file mode 100644
index 0000000000000000000000000000000000000000..24efd507a0b94266cd95e6b3113cef5bf498b076
--- /dev/null
+++ b/src/basics/basics/utilities/UbFileOutputASCII.h
@@ -0,0 +1,99 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file UbFileOutputASCII.h
+//! \ingroup utilities
+//! \author Soeren Freudiger, Sebastian Geller
+//=======================================================================================
+#ifndef UBFILEOUTPUTASCII_H
+#define UBFILEOUTPUTASCII_H
+
+#include <fstream>
+#include <iomanip>
+#include <iostream>
+
+#include "basics_export.h"
+
+#include <basics/utilities/UbException.h>
+#include <basics/utilities/UbFileOutput.h>
+
+/*=========================================================================*/
+/*  UbFileOutputASCII                                                             */
+/*                                                                         */
+/**
+...
+<BR><BR>
+@author <A HREF="mailto:muffmolch@gmx.de">S. Freudiger</A>
+@version 1.0 - 23.11.04
+*/
+
+/*
+usage: ...
+*/
+
+class BASICS_EXPORT UbFileOutputASCII : public UbFileOutput
+{
+public:
+    UbFileOutputASCII() : UbFileOutput() {}
+    UbFileOutputASCII(const std::string &filename, const bool &createPath = true, const int &precision = 15);
+    UbFileOutputASCII(const std::string &filename, CREATEOPTION opt, const bool &createPath = true,
+                      const int &precision = 15);
+
+    bool open(const std::string &filename, CREATEOPTION opt = OUTFILE) override;
+
+    void writeBool(const bool &value, const int &width = 0) override;
+    void writeDouble(const double &value, const int &width = 0) override;
+    void writeFloat(const float &value, const int &width = 0) override;
+    void writeInteger(const int &value, const int &width = 0) override;
+    void writeSize_t(const std::size_t &value, const int &width = 0) override;
+    void writeChar(const char &value, const int &width = 0) override;
+    void writeString(const std::string &value, const int &width = 0) override;
+    void writeStringOnly(const std::string &value) override;
+    void writeLine(const std::string &value, const int &width = 0) override;
+    void writeLine() override;
+
+    void setPrecision(const int &precision) override;
+    int getPrecision() override { return (int)outfile.precision(); }
+
+    void setCommentIndicator(char commentindicator) override { this->commentindicator = commentindicator; }
+
+    void writeCommentLine(const std::string &line) override;
+    void writeCommentLine(char indicator, const std::string &line) override;
+    void writeCopyOfFile(const std::string &filename) override;
+
+    FILETYPE getFileType() override { return ASCII; }
+
+    template <typename T>
+    friend inline UbFileOutputASCII &operator<<(UbFileOutputASCII &file, const T &data)
+    {
+        file.outfile << data;
+        return file;
+    }
+};
+
+#endif
diff --git a/src/basics/basics/utilities/UbFileOutputBinary.cpp b/src/basics/basics/utilities/UbFileOutputBinary.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ce9fca58f7eddd8d0ec3cc4a7d0ecf48fb2f4691
--- /dev/null
+++ b/src/basics/basics/utilities/UbFileOutputBinary.cpp
@@ -0,0 +1,208 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file UbFileOutputBinary.cpp
+//! \ingroup utilities
+//! \author Soeren Freudiger, Sebastian Geller
+//=======================================================================================
+#include <basics/utilities/UbFileOutputBinary.h>
+#include <basics/utilities/UbSystem.h>
+#include <cstring>
+
+using namespace std;
+
+/*==========================================================*/
+UbFileOutputBinary::UbFileOutputBinary(const string &filename, const bool &createPath)
+{
+    this->filename         = filename;
+    this->commentindicator = 'C';
+
+    outfile.open(filename.c_str(), ios::out | ios::binary);
+
+    if (!outfile && createPath) {
+        string path = UbSystem::getPathFromString(filename);
+        if (path.size() > 0) {
+            outfile.clear(); // flags ruecksetzen (ansonsten liefert utern if(!outfile) weiterhin true!!!
+            UbSystem::makeDirectory(path);
+            outfile.open(filename.c_str(), ios::out | ios::binary);
+        }
+    }
+
+    if (!outfile)
+        UB_THROW(UbException(UB_EXARGS, "couldn't open file:\n " + filename));
+}
+/*==========================================================*/
+UbFileOutputBinary::UbFileOutputBinary(const string &filename, UbFileOutput::CREATEOPTION opt, const bool &createPath)
+{
+    this->filename         = filename;
+    this->commentindicator = 'C';
+
+    this->open(filename, opt);
+
+    if (!this->open(filename, opt) && createPath) {
+        string path = UbSystem::getPathFromString(filename);
+        if (path.size() > 0) {
+            outfile.clear(); // flags ruecksetzen (ansonsten liefert utern if(!outfile) weiterhin true!!!
+            UbSystem::makeDirectory(path, 20);
+
+            this->open(filename, opt);
+        }
+    }
+
+    if (!outfile)
+        UB_THROW(UbException(UB_EXARGS, "couldn't open file:\n " + filename));
+}
+/*==========================================================*/
+bool UbFileOutputBinary::open(const string &filename, UbFileOutput::CREATEOPTION opt)
+{
+    outfile.close();
+    outfile.clear(); // setzt flags zurueck
+
+    this->filename = filename;
+
+    if (opt == UbFileOutput::OUTFILE)
+        outfile.open(this->filename.c_str(), ios::out | ios::binary);
+    else if (opt == UbFileOutput::APPENDFILE)
+        outfile.open(this->filename.c_str(), ios::app | ios::binary);
+    else if (opt == UbFileOutput::INANDOUTFILE)
+        UB_THROW(UbException(UB_EXARGS, "undefined CREATEOPTION - INANDOUTFILE not possible for BINARY files"));
+    else
+        UB_THROW(UbException(UB_EXARGS, "undefined CREATEOPTION"));
+
+    return outfile.is_open();
+}
+/*==========================================================*/
+void UbFileOutputBinary::writeBool(const bool &value, const int & /*width*/)
+{
+    outfile.write((char *)&value, sizeof(bool));
+}
+/*==========================================================*/
+void UbFileOutputBinary::writeDouble(const double &value, const int & /*width*/)
+{
+    outfile.write((char *)&value, sizeof(double));
+}
+/*==========================================================*/
+void UbFileOutputBinary::writeFloat(const float &value, const int & /*width*/)
+{
+    outfile.write((char *)&value, sizeof(float));
+}
+/*==========================================================*/
+void UbFileOutputBinary::setPrecision(const int & /*precision*/) { UB_THROW(UbException(UB_EXARGS, "no way")); }
+/*==========================================================*/
+int UbFileOutputBinary::getPrecision() { UB_THROW(UbException(UB_EXARGS, "no way")); }
+/*==========================================================*/
+void UbFileOutputBinary::writeInteger(const int &value, const int & /*width*/)
+{
+    outfile.write((char *)&value, sizeof(value));
+}
+/*==========================================================*/
+void UbFileOutputBinary::writeSize_t(const std::size_t &value, const int & /*width*/)
+{
+    outfile.write((char *)&value, sizeof(value));
+}
+/*==========================================================*/
+void UbFileOutputBinary::writeChar(const char &value, const int & /*width*/)
+{
+    outfile.write((char *)&value, sizeof(value));
+}
+/*==========================================================*/
+void UbFileOutputBinary::writeString(const string &value, const int & /*width*/)
+{
+    char c              = '\0';
+    unsigned int length = (unsigned)value.length();
+
+    unsigned pos;
+    // whitespaces und tabs am stringanfang uebergehen
+    for (pos = 0; pos < length; pos++)
+        if (value[pos] != ' ' && value[pos] != '\t')
+            break;
+
+    while (pos < length) {
+        while (pos < length && value[pos] != ' ' && value[pos] != '\t' && value[pos] != '\0') {
+            outfile.write((char *)&(value[pos++]), sizeof(char));
+        }
+
+        outfile.write(&c, sizeof(char));
+        pos++;
+
+        while (pos < length && (value[pos] == ' ' || value[pos] == '\t' || value[pos] == '\0')) {
+            pos++;
+        }
+    }
+}
+/*==========================================================*/
+void UbFileOutputBinary::writeStringOnly(const string & /*value*/)
+{
+    throw UbException(UB_EXARGS, "no way... causes to many errors"); // TODO: WTF?
+}
+/*==========================================================*/
+void UbFileOutputBinary::writeLine(const std::string &value, const int & /*width*/)
+{
+    this->writeString(value);
+    char c = '\n';
+    outfile.write(&c, sizeof(char));
+}
+/*==========================================================*/
+void UbFileOutputBinary::writeLine()
+{
+    char c = '\n';
+    outfile.write(&c, sizeof(char));
+}
+/*==========================================================*/
+void UbFileOutputBinary::writeCommentLine(const string &line)
+{
+    try {
+        this->writeCommentLine(this->commentindicator, line);
+    } catch (...) {
+        UB_THROW(UbException(UB_EXARGS, "unknown error"));
+    }
+}
+/*==========================================================*/
+void UbFileOutputBinary::writeCommentLine(char indicator, const string &line)
+{
+    string dummy = indicator + line;
+    this->writeLine(dummy);
+}
+/*==========================================================*/
+void UbFileOutputBinary::writeCopyOfFile(const string &filename)
+{
+    ifstream infile(filename.c_str(), ios::in | ios::binary);
+    if (!infile)
+        UB_THROW(UbException(UB_EXARGS, "couldn't open file:\n " + filename));
+
+    try {
+        char c;
+        while (infile.get(c)) {
+            outfile.put(c); //=out<<c;
+        }
+        outfile.flush();
+        infile.close();
+    } catch (...) {
+        UB_THROW(UbException(UB_EXARGS, "unknown error"));
+    }
+}
diff --git a/src/basics/basics/utilities/UbFileOutputBinary.h b/src/basics/basics/utilities/UbFileOutputBinary.h
new file mode 100644
index 0000000000000000000000000000000000000000..630df58b8a3ed47d9a3e8adc033db282ce5e80ef
--- /dev/null
+++ b/src/basics/basics/utilities/UbFileOutputBinary.h
@@ -0,0 +1,102 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file UbFileOutputBinary.h
+//! \ingroup utilities
+//! \author Soeren Freudiger, Sebastian Geller
+//=======================================================================================
+#ifndef UBFILEOUTPUTBINARY_H
+#define UBFILEOUTPUTBINARY_H
+
+#include <fstream>
+#include <iomanip>
+#include <iostream>
+
+#include <basics/utilities/UbException.h>
+#include <basics/utilities/UbFileOutput.h>
+
+/*=========================================================================*/
+/*  UbFileOutputBinary                                                             */
+/*                                                                         */
+/**
+...
+<BR><BR>
+@author <A HREF="mailto:muffmolch@gmx.de">S. Freudiger</A>
+@version 1.0 - 23.11.04
+*/
+
+/*
+usage: ...
+*/
+
+class UbFileOutputBinary : public UbFileOutput
+{
+public:
+    UbFileOutputBinary() : UbFileOutput() {}
+    UbFileOutputBinary(const std::string &filename, const bool &createPath = true);
+    UbFileOutputBinary(const std::string &filename, UbFileOutput::CREATEOPTION opt, const bool &createPath);
+
+    bool open(const std::string &filename, UbFileOutput::CREATEOPTION opt = OUTFILE) override;
+
+    void writeInteger(const int &value, const int &width = 0) override;
+    void writeDouble(const double &value, const int &width = 0) override;
+    void writeFloat(const float &value, const int &width = 0) override;
+    void writeBool(const bool &value, const int &width = 0) override;
+    void writeChar(const char &value, const int &width = 0) override;
+    void writeSize_t(const std::size_t &value, const int &width = 0) override;
+    void writeString(const std::string &value, const int &width = 0) override;
+    void writeStringOnly(const std::string &value) override;
+    void writeLine(const std::string &value, const int &width = 0) override;
+    void writeLine() override;
+    void writeCommentLine(const std::string &line) override;
+    void writeCommentLine(char indicator, const std::string &line) override;
+    void writeCopyOfFile(const std::string &filename) override;
+
+    void setPrecision(const int &precision) override;
+    int getPrecision() override;
+
+    FILETYPE getFileType() override { return BINARY; }
+
+    template <typename T>
+    friend inline UbFileOutputBinary &operator<<(UbFileOutputBinary &file, const T &data)
+    {
+        file.outfile.write((char *)&data, sizeof(T));
+        return file;
+    }
+
+    template <typename T>
+    void writeVector(std::vector<T> &v)
+    {
+        size_t size = v.size();
+        if (size > 0) {
+            outfile.write((char *)&v[0], sizeof(T) * size);
+        }
+    }
+};
+
+#endif
diff --git a/src/basics/basics/utilities/UbNupsTimer.h b/src/basics/basics/utilities/UbNupsTimer.h
new file mode 100644
index 0000000000000000000000000000000000000000..1545b5b694a57d112b485cf766ce26e22f30d939
--- /dev/null
+++ b/src/basics/basics/utilities/UbNupsTimer.h
@@ -0,0 +1,125 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file UbNupsTimer.h
+//! \ingroup utilities
+//! \author Soeren Freudiger, Sebastian Geller
+//=======================================================================================
+#ifndef UBNUPSTIMER_H
+#define UBNUPSTIMER_H
+
+#include <basics/utilities/UbTiming.h>
+#include <sstream>
+#include <vector>
+
+/*=========================================================================*/
+/*  UbNupsTimer                                                             */
+/*                                                                         */
+/**
+This Class provides the base for ...
+<BR><BR>
+@author <A HREF="mailto:muffmolch@gmx.de">S. Freudiger</A>
+@version 1.0 - 01.11.04
+*/
+class UbNupsTimer : public UbTiming
+{
+public:
+    UbNupsTimer() : UbTiming()
+    {
+        mTempNodes = 0.0;
+        mNofNodes.resize(0);
+        mDurations.resize(0);
+    }
+    /*==========================================================*/
+    UbNupsTimer(std::string name) : UbTiming(name)
+    {
+        mNofNodes.resize(0);
+        mDurations.resize(0);
+        mTempNodes = 0.0;
+    }
+    /*==========================================================*/
+    void initTiming() override
+    {
+        UbTiming::initTiming();
+        mNofNodes.resize(0);
+        mDurations.resize(0);
+        mTempNodes = 0.0;
+    }
+    /*==========================================================*/
+    void startNUPSTiming(double nofNodes)
+    {
+        mTempNodes = nofNodes;
+        UbTiming::startTiming();
+    }
+    /*==========================================================*/
+    void endTiming() override
+    {
+        UbTiming::endTiming();
+        // save #node and time informations
+        mNofNodes.push_back(mTempNodes);
+        mDurations.push_back(UbTiming::getDuration());
+        // reset internal timecounter
+        UbTiming::initTiming();
+    }
+    /*==========================================================*/
+    double getAverageNups()
+    {
+        double averageNups = 0.0;
+        for (int i = 0; i < (int)mNofNodes.size(); i++)
+            averageNups += mNofNodes.at(i) / mDurations.at(i);
+
+        return averageNups / (double)mNofNodes.size();
+    }
+    /*==========================================================*/
+    double getSumOfDuration()
+    {
+        double duration = 0.0;
+        for (int i = 0; i < (int)mDurations.size(); i++)
+            duration += mDurations.at(i);
+        return duration;
+    }
+    /*==========================================================*/
+    std::string getNupsString()
+    {
+        std::stringstream ss;
+        ss << "saved nups informations" << std::endl;
+        for (int i = 0; i < (int)mNofNodes.size(); i++)
+            ss << mNofNodes.at(i) << "nodes/" << mDurations.at(i) << "sec=" << mNofNodes.at(i) / mDurations.at(i)
+               << "nups\n";
+        return ss.str();
+    }
+
+protected:
+private:
+    std::vector<double> mNofNodes;
+    std::vector<double> mDurations;
+
+    double mTempNodes;
+};
+
+#endif
diff --git a/src/basics/basics/utilities/UbRandom.h b/src/basics/basics/utilities/UbRandom.h
new file mode 100644
index 0000000000000000000000000000000000000000..9026f600734f971923ec5b69f42ea7caddc1ddd2
--- /dev/null
+++ b/src/basics/basics/utilities/UbRandom.h
@@ -0,0 +1,86 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file UbRandom.h
+//! \ingroup utilities
+//! \author Soeren Freudiger, Sebastian Geller
+//=======================================================================================
+#ifndef UBRANDOM_H
+#define UBRANDOM_H
+
+#include <cassert>
+#include <cmath>
+#include <cstdlib>
+#include <ctime>
+
+/*=========================================================================*/
+/*  UbRandom                                                             */
+/*                                                                         */
+/**
+generates a random number
+<BR><BR>
+@author <A HREF="mailto:muffmolch@gmx.de">S. Freudiger</A>
+@version 1.0 - 04.10.2007
+*/
+/*
+usage:
+   int main()
+   {
+      char* hand[] = {"Schere", "Stein", "Papier"};
+      for (unsigned u = 0; u < 20; u++)
+      {
+         cout << hand[UbRandom::rand(0, 2, 1)] << endl;
+      }
+
+      return 0;
+   }
+*/
+
+class UbRandom
+{
+private:
+    UbRandom() { std::srand(static_cast<int>(std::time(NULL))); }
+
+public:
+    // returns arbitrary int value element of [min ; max]
+    static inline int rand(const int &min, const int &max)
+    {
+        static UbRandom dummy;
+        assert(max - min < RAND_MAX);
+        return (min + std::rand() % (max - min + 1));
+    }
+    // returns arbitrary float value element of "( (max - min) / gran ) * [min ; max]"
+    // with other words: val = min+n*(max-min)/gran, n=0..gran-1
+    static inline double rand(const double &min, const double &max, const double &gran)
+    {
+        static UbRandom dummy;
+        return (min + std::floor(std::rand() / (1.0 + RAND_MAX) * gran) * (max - min) / gran);
+    }
+};
+
+#endif // UBRANDOM_H
diff --git a/src/basics/basics/utilities/UbStringInputASCII.cpp b/src/basics/basics/utilities/UbStringInputASCII.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6a04f86aeb8d5b7be9e96ca39d1808b987c1f711
--- /dev/null
+++ b/src/basics/basics/utilities/UbStringInputASCII.cpp
@@ -0,0 +1,212 @@
+//#include <basics/utilities/UbStringInputASCII.h>
+//#include <cstring>
+//
+// using namespace std;
+//
+//
+// UbStringInputASCII::UbStringInputASCII(string inputString) : UbFileInputASCII("")
+//{
+//	instream.str(inputString);
+//
+//
+////	this->filename         = filename;
+////   this->commentindicator = 'C';
+////
+////   infile.open(filename.c_str());
+//
+//}
+///*==========================================================*/
+// int UbStringInputASCII::readInteger()
+//{
+//	int dummy;
+//	instream>>dummy;
+//	return dummy;
+//}
+///*==========================================================*/
+// std::size_t UbStringInputASCII::readSize_t()
+//{
+//   std::size_t dummy;
+//   instream>>dummy;
+//   return dummy;
+//}
+///*==========================================================*/
+// string UbStringInputASCII::getFileName()
+//{
+//	return this->filename;
+//}
+//
+///*==========================================================*/
+// void UbStringInputASCII::skipLine()
+//{
+//	string dummy;
+//	getline(instream, dummy);
+//}
+///*==========================================================*/
+// void UbStringInputASCII::readLine()
+//{
+//	string dummy;
+//	getline(instream, dummy);
+//}
+///*==========================================================*/
+// string UbStringInputASCII::readStringLine()
+//{
+//   string dummy;
+//   getline(instream, dummy);
+//   return dummy;
+//}
+///*==========================================================*/
+// string UbStringInputASCII::readLineTill(char stop)
+//{
+//	string dummy;
+//	getline(instream, dummy, stop);
+//	return dummy;
+//}
+///*==========================================================*/
+// string UbStringInputASCII::parseString()
+//{
+//	string dummy;
+//	getline(instream, dummy, ' ');
+//	return dummy;
+//}
+///*==========================================================*/
+// double UbStringInputASCII::readDouble()
+//{
+//   double dummy;
+//   instream>>dummy;
+//   return dummy;
+//}
+///*==========================================================*/
+// float UbStringInputASCII::readFloat()
+//{
+//   float dummy;
+//   instream>>dummy;
+//   return dummy;
+//}
+///*==========================================================*/
+// char UbStringInputASCII::readChar()
+//{
+//   char dummy;
+//   instream>>dummy;
+//   return dummy;
+//}
+///*==========================================================*/
+// string UbStringInputASCII::readString()
+//{
+//	string dummy;
+//	instream>>dummy;
+//	return dummy;
+//}
+///*==========================================================*/
+// bool UbStringInputASCII::containsString(string var)
+//{
+//   instream.seekg(0L, ios::beg); //Positionszeiger der Datei auf den Anfang setzen
+//   char line[512];
+//   do
+//   {
+//      instream.getline(line,512);
+//      if(instream.eof()) return false;
+//   }while (strstr(line,var.c_str()) != line);		// Ende Schleife, wenn varname ganz in zeile vorkommt
+//
+//   return true;
+//}
+///*==========================================================*/
+// void UbStringInputASCII::setPosAfterLineWithString(string var)
+//{
+//   instream.seekg(0L, ios::beg); //Positionszeiger der Datei auf den Anfang setzen
+//   char line[512];
+//   do
+//   {
+//      instream.getline(line,512);
+//      if(instream.eof()) UB_THROW( UbException(UB_EXARGS,var+" wasn't found in "+this->filename) );
+//   }while (strstr(line,var.c_str()) != line);		// Ende Schleife, wenn varname ganz in zeile vorkommt
+//}
+///*==========================================================*/
+// int UbStringInputASCII::readIntegerAfterString(string var)
+//// last change [10.3.2004] at [9:46]
+////suchts in einer Datei nach varname und gibt den dahinter stehenden int-Wert zurueck
+////z.B. timesteps 9
+//{
+//   instream.seekg(0L, ios::beg); //Positionszeiger der Datei auf den Anfang setzen
+//
+//   char line[512];
+//
+//   do
+//   {
+//      instream.getline(line,512);
+//      if(instream.eof()) UB_THROW( UbException(UB_EXARGS,var+" wasn't found in "+this->filename) );
+//   }while (strstr(line,var.c_str()) != line);		// Ende Schleife, wenn varname ganz in zeile vorkommt
+//
+//   strcpy (line, (line+strlen(var.c_str())));	    // zeile um "varname" kuerzen
+//   while ((line[0] == ' ') || (line[0] == '\t')) strcpy (line, (line+1));	// Whitespaces entfernen
+//
+//   return(atoi(line));						// Umwandlung in int
+//}
+///*==========================================================*/
+//// last change [10.3.2004] at [9:46]
+////sucht in einer Datei nach varname und gibt den dahinter stehenden int-Wert zurueck
+////z.B. nue 9.5
+// double UbStringInputASCII::readDoubleAfterString(string var)
+//{
+//   instream.seekg(0L, ios::beg); //Positionszeiger der Datei auf den Anfang setzen
+//
+//   char line[512];
+//
+//   do
+//   {
+//      instream.getline(line,512);
+//      if(instream.eof()) UB_THROW( UbException(UB_EXARGS,var+" wasn't found in "+this->filename) );
+//   }while (/*!strncmp(varname,line,sizeof(varname))==0*/strstr(line,var.c_str()) != line);		// Ende Schleife, wenn
+//   varname ganz in zeile vorkommt
+//
+//
+//   strcpy (line, (line+strlen(var.c_str())));	    // zeile um "varname" kuerzen
+//   while ((line[0] == ' ') || (line[0] == '\t')) strcpy (line, (line+1));	// Whitespaces entfernen
+//
+//   return (atof(line));			// Umwandlung in double
+//}
+///*==========================================================*/
+////  [9.9.2002]
+//// liefert sring-Wert der hinter dem uebergebenen char feld in der datei instream steht
+//// zudem wird der wert in die uebergebene variable value uebertragen (falls man das ergebniss als char benoetig)
+// string UbStringInputASCII::readStringAfterString(string var)
+//{
+//   instream.seekg(0L, ios::beg); //Positionszeiger der Datei auf den Anfang setzen
+//
+//   char line[512];
+//   //string line_copy[512];
+//
+//   do{
+//      instream.getline(line,512);
+//      if(instream.eof()) UB_THROW( UbException(UB_EXARGS,var+" wasn't found in "+this->filename) );
+//   }while (strstr(line,var.c_str()) != line);		// Ende Schleife, wenn varname ganz in zeile vorkommt
+//
+//   strcpy (line, (line+strlen(var.c_str())));										// zeile um "varname" kuerzen
+//   while ((line[0] == ' ') || (line[0] == '\t')) strcpy (line, (line+1));	// Whitespaces entfernen
+//
+//   char *p;
+//   p=strtok(line," "); //schneidet alles "ab und inklusive space " nach namen ab
+//   p=strtok(line,"\t");//schneidet alles "ab und inklusive tab   " nach namen ab
+//
+//   return (string)p;			// Umwandlung in string
+//}
+///*==========================================================*/
+//// last change [10.3.2004] at [9:46]
+////sucht in einer Datei nach varname und gibt den dahinter stehenden int-Wert zurueck
+////z.B. nue 9.5
+// bool UbStringInputASCII::readBoolAfterString(string var)
+//{
+//   if(this->readStringAfterString(var.c_str())      == "true" ) return true;
+//   else if(this->readStringAfterString(var.c_str()) == "false") return false;
+//   else UB_THROW( UbException(UB_EXARGS,var+" is not equal to 'true' or 'false' in "+this->filename) );
+//}
+///*==========================================================*/
+//// last change [10.3.2004] at [9:46]
+////sucht in einer Datei nach varname und gibt den dahinter stehenden int-Wert zurueck
+////z.B. nue 9.5
+// bool UbStringInputASCII::readBool()
+//{
+//   string tmp = this->readString();
+//   if(     tmp == "true" ) return true;
+//   else if(tmp == "false") return false;
+//   else UB_THROW( UbException(UB_EXARGS,"expression is not equal to 'true' or 'false' in "+this->filename) );
+//}
diff --git a/src/basics/basics/utilities/UbStringInputASCII.h b/src/basics/basics/utilities/UbStringInputASCII.h
new file mode 100644
index 0000000000000000000000000000000000000000..d83adde4dee62f703a6a6070b7a2c0eb6c66360f
--- /dev/null
+++ b/src/basics/basics/utilities/UbStringInputASCII.h
@@ -0,0 +1,55 @@
+////  _    ___      __              __________      _     __
+//// | |  / (_)____/ /___  ______ _/ / ____/ /_  __(_)___/ /____
+//// | | / / / ___/ __/ / / / __ `/ / /_  / / / / / / __  / ___/
+//// | |/ / / /  / /_/ /_/ / /_/ / / __/ / / /_/ / / /_/ (__  )
+//// |___/_/_/   \__/\__,_/\__,_/_/_/   /_/\__,_/_/\__,_/____/
+////
+//#ifndef UBSTRINGINPUTASCII_H
+//#define UBSTRINGINPUTASCII_H
+//
+//#include <fstream>
+//#include <iostream>
+//#include <string>
+//
+//#include <basics/utilities/UbException.h>
+//#include <basics/utilities/UbFileInput.h>
+//
+//#include <basics/utilities/UbFileInputASCII.h>
+//
+// class UbStringInputASCII : public UbFileInputASCII
+//{
+// public:
+//	UbStringInputASCII(std::string inputString);
+//
+//	std::string getFileName();
+//	void	      skipLine();					   // Springt zur naechsten Zeile
+//
+//   void        readLine();
+//   std::string readStringLine();
+//   std::size_t readSize_t();
+//   int		   readInteger();				   // Liest einen Int-Wert ein
+//   double	   readDouble();				   // Liest einen double-Wert ein
+//	float 	   readFloat();				   // Liest einen float-Wert ein
+//	bool  	   readBool();				      // Liest einen bool-Wert ein
+//   char        readChar();                // Liest einen char-Wert ein
+//   std::string	readString();				   // Liest ein Wort ein
+//	std::string	readLineTill(char stop);	// Liest gesamte Zeile ein bis zu einem bestimmten Zeichen
+//	std::string	parseString();
+//
+//   bool        containsString(std::string var);
+//   void        setPosAfterLineWithString(std::string var);
+//   int		   readIntegerAfterString(std::string var);
+//   double	   readDoubleAfterString(std::string var);
+//   bool        readBoolAfterString(std::string var);
+//   std::string readStringAfterString(std::string var);
+//
+//   FILETYPE getFileType() { return ASCII; }
+//
+// private:
+//	std::istringstream instream;
+//};
+//
+//
+//#endif
+//
+//
diff --git a/src/basics/basics/utilities/Vector3D.cpp b/src/basics/basics/utilities/Vector3D.cpp
index 6ff9dc8738f869d75e7fc9870bb5bb7468d83468..a97e8bfdcd64a717b556d7f02e4450ee56977ea0 100644
--- a/src/basics/basics/utilities/Vector3D.cpp
+++ b/src/basics/basics/utilities/Vector3D.cpp
@@ -26,7 +26,7 @@
 //  You should have received a copy of the GNU General Public License along
 //  with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
 //
-//! \file UbVector3D.cpp
+//! \file Vector3D.cpp
 //! \ingroup utilities
 //! \author Soeren Freudiger, Sebastian Geller
 //=======================================================================================
diff --git a/src/basics/basics/utilities/Vector3D.h b/src/basics/basics/utilities/Vector3D.h
index b278a80d732115a9b1183547e61ff1fe6e82d057..ab02dbeea18264a305564d995055744a15c1c7cb 100644
--- a/src/basics/basics/utilities/Vector3D.h
+++ b/src/basics/basics/utilities/Vector3D.h
@@ -26,7 +26,7 @@
 //  You should have received a copy of the GNU General Public License along
 //  with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
 //
-//! \file UbVector3D.h
+//! \file Vector3D.h
 //! \ingroup utilities
 //! \author Soeren Freudiger, Sebastian Geller
 //=======================================================================================
diff --git a/src/basics/basics/utilities/Vector3DTest.cpp b/src/basics/basics/utilities/Vector3DTest.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0aaf474569b4baf58d8166a94ed37c394053eca4
--- /dev/null
+++ b/src/basics/basics/utilities/Vector3DTest.cpp
@@ -0,0 +1,157 @@
+#include "Vector3D.h"
+#include "gmock/gmock.h"
+
+#include <cmath>
+
+using namespace testing;
+
+class Vector3DTest : public Test
+{
+public:
+    Vector3D vec1;
+    Vector3D vec2;
+
+    void SetUp() override
+    {
+        vec1[0] = vec1[1] = vec1[2] = 4.0f;
+        vec2[0]                     = 0.0f;
+        vec2[0]                     = 2.4f;
+        vec2[0]                     = -1.3f;
+    }
+};
+
+TEST_F(Vector3DTest, overloadMinusOperator)
+{
+    Vector3D vec3;
+    vec3[0] = vec2[0] - vec1[0];
+    vec3[1] = vec2[1] - vec1[1];
+    vec3[2] = vec2[2] - vec1[2];
+
+    Vector3D v4 = vec2 - vec1;
+    ASSERT_THAT((double)v4[0], DoubleEq(vec3[0]));
+    ASSERT_THAT((double)v4[1], DoubleEq(vec3[1]));
+    ASSERT_THAT((double)v4[2], DoubleEq(vec3[2]));
+}
+
+TEST_F(Vector3DTest, overloadPlusOperator)
+{
+    Vector3D vec3;
+    vec3[0] = vec2[0] + vec1[0];
+    vec3[1] = vec2[1] + vec1[1];
+    vec3[2] = vec2[2] + vec1[2];
+
+    Vector3D v4 = vec2 + vec1;
+    ASSERT_THAT((double)v4[0], DoubleEq(vec3[0]));
+    ASSERT_THAT((double)v4[1], DoubleEq(vec3[1]));
+    ASSERT_THAT((double)v4[2], DoubleEq(vec3[2]));
+}
+
+TEST_F(Vector3DTest, overloadTimesOperatorWithSkalarProduct)
+{
+    double skalar = vec1[0] * vec2[0] + vec1[1] * vec2[1] + vec1[2] * vec2[2];
+    ASSERT_THAT(vec1.Dot(vec2), DoubleEq(skalar));
+}
+
+TEST_F(Vector3DTest, overloadTimesOperatorWithSkalarMultiplication)
+{
+    double skalar = 1.0f / 3.0f;
+    Vector3D vec3;
+    vec3[0] = skalar * vec1[0];
+    vec3[1] = skalar * vec1[1];
+    vec3[2] = skalar * vec1[2];
+
+    Vector3D v4 = vec1 * skalar;
+
+    ASSERT_THAT((double)v4[0], DoubleEq(vec3[0]));
+    ASSERT_THAT((double)v4[1], DoubleEq(vec3[1]));
+    ASSERT_THAT((double)v4[2], DoubleEq(vec3[2]));
+}
+
+TEST_F(Vector3DTest, getLengthFromVector)
+{
+    Vector3D v;
+    v[0] = 4.0;
+    v[1] = 3.0;
+    v[2] = -1.0;
+
+    double expected = std::sqrt(16.0 + 9.0 + 1.0);
+    ASSERT_THAT(v.Length(), testing::DoubleEq(expected));
+}
+
+TEST_F(Vector3DTest, compareTwoVectors)
+{
+    Vector3D v;
+    v[0] = vec1[0];
+    v[1] = vec1[1];
+    v[2] = vec1[2];
+    ASSERT_TRUE(v == vec1);
+}
+//
+// TEST_F(Vector3DTest, checkEuclideanDistance)
+//{
+//    Vector3D v = Vector3D(3, 3, 3);
+//
+//    ASSERT_FLOAT_EQ(v.getEuclideanDistanceTo(vec1), (float)sqrt(3));
+//}
+//
+// TEST_F(Vector3DTest, checkEuclideanDistanceWithNullVector_ExpectNull)
+//{
+//    Vector3D v1 = Vector3D(0.0, 0.0, 0.0);
+//    Vector3D v2 = Vector3D(0.0, 0.0, 0.0);
+//
+//    ASSERT_THAT((double)v1.getEuclideanDistanceTo(v2), DoubleEq(0.0));
+//}
+//
+// TEST(Vector3DAngleTest, checkInnerAngleBetweenToVectors_ExpectRightAngle)
+//{
+//    Vector3D v1 = Vector3D(1.0, 4.0, -2.0);
+//    Vector3D v2 = Vector3D(-3.0, 3.0, 1);
+//
+//    ASSERT_THAT((int)floor(v1.getInnerAngle(v2)), Eq(69));
+//}
+//
+// TEST(Vector3DAngleTest, checkInnerAngleBetweenSameVectors_ExpectNull)
+//{
+//    Vector3D v1 = Vector3D(1.0, 4.0, -2.0);
+//    Vector3D v2 = Vector3D(1.0, 4.0, -2.0);
+//
+//    ASSERT_THAT((int)floor(v1.getInnerAngle(v2)), Eq(0.0));
+//}
+//
+// TEST(Vector3DAngleTest, checkInnerAngleBetweenNullVectors_ExpectNull)
+//{
+//    Vector3D v1 = Vector3D(0.0, 0.0, 0.0);
+//    Vector3D v2 = Vector3D(0.0, 0.0, 0.0);
+//
+//    ASSERT_THAT((int)floor(v1.getInnerAngle(v2)), Eq(0.0));
+//}
+//
+//
+// TEST(Vector3DAngleTest, checkInnerAngleBetweenSecondNullVectors_ExpectNull)
+//{
+//    Vector3D v1 = Vector3D(1.0, 0.0, 0.0);
+//    Vector3D v2 = Vector3D(0.0, 0.0, 0.0);
+//
+//    ASSERT_THAT((int)floor(v1.getInnerAngle(v2)), Eq(0.0));
+//}
+//
+// TEST(Vector3DAngleTest, checkInnerAngleBetweenFirstNullVectors_ExpectNull)
+//{
+//    Vector3D v1 = Vector3D(0.0, 0.0, 0.0);
+//    Vector3D v2 = Vector3D(2.0, 0.0, 0.0);
+//
+//    ASSERT_THAT((int)floor(v1.getInnerAngle(v2)), Eq(0.0));
+//}
+
+TEST_F(Vector3DTest, crossProductBetweenTwoVectors)
+{
+    Vector3D v1 = Vector3D(-5.0, -5.0, 0.0);
+    Vector3D v2 = Vector3D(5.0, 0.0, 10);
+
+    Vector3D crossProd        = Vector3D(-50.0, 50.0, 25.0);
+    Vector3D testCrossProduct = v1.Cross(v2);
+
+    EXPECT_THAT(testCrossProduct[0], DoubleEq(crossProd[0]));
+    EXPECT_THAT(testCrossProduct[1], DoubleEq(crossProd[1]));
+    EXPECT_THAT(testCrossProduct[2], DoubleEq(crossProd[2]));
+}
diff --git a/src/basics/basics/writer/WbWriterAvsASCII.cpp b/src/basics/basics/writer/WbWriterAvsASCII.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3f17db89a1aa1893d156b9142991bf6ce15806c5
--- /dev/null
+++ b/src/basics/basics/writer/WbWriterAvsASCII.cpp
@@ -0,0 +1,1158 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file WbWriterAvsASCII.cpp
+//! \ingroup writer
+//! \author Soeren Freudiger, Sebastian Geller
+//=======================================================================================
+#include <basics/utilities/UbLogger.h>
+#include <basics/utilities/UbSystem.h>
+#include <basics/writer/WbWriterAvsASCII.h>
+#include <cstring>
+
+using namespace std;
+
+std::string WbWriterAvsASCII::writeQuads(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                                         std::vector<UbTupleInt4> &cells)
+{
+    string avsfilename = filename + getFileExtension();
+    UBLOG(logDEBUG1, "WbWriterAvsASCII::writeQuads to " << avsfilename << " - start");
+
+    ofstream out(avsfilename.c_str(), ios::out | ios::binary);
+    if (!out) {
+        out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!outfile) weiterhin true!!!
+        string path = UbSystem::getPathFromString(avsfilename);
+        if (path.size() > 0) {
+            UbSystem::makeDirectory(path);
+            out.open(avsfilename.c_str(), ios::out | ios::binary);
+        }
+        if (!out)
+            throw UbException(UB_EXARGS, "couldn't open file " + avsfilename);
+    }
+    char magic = (char)7;
+    int idummy;
+    float fdummy;
+
+    int nofNodes = (int)nodes.size();
+    int nofCells = (int)cells.size();
+
+    int nofNodeData     = 0;
+    int nofCellData     = 0;
+    int nofModelData    = 0;
+    int cellType        = 3; //=quad
+    int nofNodesPerCell = 4;
+
+    out.write((char *)&magic, sizeof(char));
+    out.write((char *)&nofNodes, sizeof(int));
+    out.write((char *)&nofCells, sizeof(int));
+    out.write((char *)&nofNodeData, sizeof(int));
+    out.write((char *)&nofCellData, sizeof(int));
+    out.write((char *)&nofModelData, sizeof(int));
+
+    idummy = (int)nofCells * nofNodesPerCell;
+    out.write((char *)&idummy, sizeof(int)); //(nof nodes) * (nodes per cell)
+    for (int c = 0; c < nofCells; c++) {
+        idummy = c + 1;
+        out.write((char *)&idummy, sizeof(int)); // cell id
+        idummy = 1;
+        out.write((char *)&idummy, sizeof(int)); // mat
+        idummy = nofNodesPerCell;
+        out.write((char *)&idummy, sizeof(int)); // nodes per cell
+        idummy = cellType;
+        out.write((char *)&idummy, sizeof(int)); // cell type
+    }
+    // knotennummern der einzelnen zellen
+    for (int c = 0; c < nofCells; c++) {
+        idummy = val<1>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<2>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<3>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<4>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+    }
+
+    // coords
+    // x1-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<1>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // x2-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<2>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // x3-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<3>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // out<<"\n";
+
+    out.close();
+    UBLOG(logDEBUG1, "WbWriterAvsASCII::writeQuads to " << avsfilename << " - end");
+
+    return avsfilename;
+}
+/*===============================================================================*/
+std::string WbWriterAvsASCII::writeOcts(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                                        std::vector<UbTupleInt8> &cells)
+{
+    string avsfilename = filename + getFileExtension();
+    UBLOG(logDEBUG1, "WbWriterAvsASCII::writeOcts to " << avsfilename << " - start");
+
+    ofstream out(avsfilename.c_str(), ios::out | ios::binary);
+    if (!out) {
+        out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!outfile) weiterhin true!!!
+        string path = UbSystem::getPathFromString(avsfilename);
+        if (path.size() > 0) {
+            UbSystem::makeDirectory(path);
+            out.open(avsfilename.c_str(), ios::out | ios::binary);
+        }
+        if (!out)
+            throw UbException(UB_EXARGS, "file konnte nicht geschrieben werden " + avsfilename);
+    }
+
+    char magic = (char)7;
+    int idummy;
+    float fdummy;
+
+    int nofNodes = (int)nodes.size();
+    int nofCells = (int)cells.size();
+
+    int nofNodeData     = 0;
+    int nofCellData     = 0;
+    int nofModelData    = 0;
+    int cellType        = 7; //=hex
+    int nofNodesPerCell = 8;
+
+    out.write((char *)&magic, sizeof(char));
+    out.write((char *)&nofNodes, sizeof(int));
+    out.write((char *)&nofCells, sizeof(int));
+    out.write((char *)&nofNodeData, sizeof(int));
+    out.write((char *)&nofCellData, sizeof(int));
+    out.write((char *)&nofModelData, sizeof(int));
+
+    idummy = (int)nofCells * nofNodesPerCell;
+    out.write((char *)&idummy, sizeof(int)); //(nof nodes) * (nodes per cell)
+    for (int c = 0; c < nofCells; c++) {
+        idummy = c + 1;
+        out.write((char *)&idummy, sizeof(int)); // cell id
+        idummy = 1;
+        out.write((char *)&idummy, sizeof(int)); // mat
+        idummy = nofNodesPerCell;
+        out.write((char *)&idummy, sizeof(int)); // nodes per cell
+        idummy = cellType;
+        out.write((char *)&idummy, sizeof(int)); // cell type
+    }
+    // knotennummern der einzelnen zellen
+    for (int c = 0; c < nofCells; c++) {
+        idummy = val<1>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<2>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<3>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<4>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<5>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<6>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<7>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<8>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+    }
+
+    // coords
+    // x1-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<1>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // x2-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<2>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // x3-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<3>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // out<<"\n";
+
+    out.close();
+    UBLOG(logDEBUG1, "WbWriterAvsASCII::writeOcts to " << avsfilename << " - end");
+
+    return avsfilename;
+}
+/*===============================================================================*/
+std::string WbWriterAvsASCII::writeQuadsWithNodeData(const string &filename, vector<UbTupleFloat3> &nodes,
+                                                     vector<UbTupleInt4> &cells, vector<string> &datanames,
+                                                     vector<vector<double>> &nodedata)
+{
+    string avsfilename = filename + getFileExtension();
+    UBLOG(logDEBUG1, "WbWriterAvsASCII::writeQuadsWithNodeData to " << avsfilename << " - start");
+
+    ofstream out(avsfilename.c_str(), ios::out | ios::binary);
+    if (!out) {
+        out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!outfile) weiterhin true!!!
+        string path = UbSystem::getPathFromString(avsfilename);
+        if (path.size() > 0) {
+            UbSystem::makeDirectory(path);
+            out.open(avsfilename.c_str(), ios::out | ios::binary);
+        }
+        if (!out)
+            throw UbException(UB_EXARGS, "write UCD File " + avsfilename + " konnte nicht geschrieben werden");
+    }
+    char magic = (char)7;
+    int idummy;
+    float fdummy;
+
+    int nofNodes = (int)nodes.size();
+    int nofCells = (int)cells.size();
+
+    int nofNodeData     = (int)datanames.size();
+    int nofCellData     = 0;
+    int nofModelData    = 0;
+    int cellType        = 3; //=quad
+    int nofNodesPerCell = 4;
+
+    out.write((char *)&magic, sizeof(char));
+    out.write((char *)&nofNodes, sizeof(int));
+    out.write((char *)&nofCells, sizeof(int));
+    out.write((char *)&nofNodeData, sizeof(int));
+    out.write((char *)&nofCellData, sizeof(int));
+    out.write((char *)&nofModelData, sizeof(int));
+
+    idummy = (int)nofCells * nofNodesPerCell;
+    out.write((char *)&idummy, sizeof(int)); //(nof nodes) * (nodes per cell)
+    for (int c = 0; c < nofCells; c++) {
+        idummy = c + 1;
+        out.write((char *)&idummy, sizeof(int)); // cell id
+        idummy = 1;
+        out.write((char *)&idummy, sizeof(int)); // mat
+        idummy = nofNodesPerCell;
+        out.write((char *)&idummy, sizeof(int)); // nodes per cell
+        idummy = cellType;
+        out.write((char *)&idummy, sizeof(int)); // cell type
+    }
+    // knotennummern der einzelnen zellen
+    for (int c = 0; c < nofCells; c++) {
+        idummy = val<1>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<2>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<3>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<4>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+    }
+
+    // coords
+    // x1-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<1>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // x2-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<2>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // x3-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<3>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // out<<"\n";
+
+    // NODE DATA
+    char labels[1024];
+    char units[1024];
+    strcpy(labels, "");
+    strcpy(units, "");
+
+    for (int d = 0; d < nofNodeData - 1; ++d) {
+        strcat(labels, datanames[d].c_str());
+        strcat(labels, ".");
+    }
+    strcat(labels, datanames[nofNodeData - 1].c_str());
+
+    for (int i = 0; i < (nofNodeData - 1); i++)
+        strcat(units, "no_unit.");
+    strcat(units, "no_unit");
+
+    out.write((char *)&labels, sizeof(labels));
+    out.write((char *)&units, sizeof(units));
+
+    // nof and type of data
+    idummy = nofNodeData;
+    out.write((char *)&idummy, sizeof(int)); // Datentypen pro knoten (hier = nof_node_data, da NUR skalare)
+
+    idummy = 1;
+    for (int i = 0; i < nofNodeData; i++)
+        out.write((char *)&idummy, sizeof(int)); // jeder Datentyp ist ein skalarer Wert
+
+    // min and max of data
+    fdummy = 0.0;
+    for (int i = 0; i < nofNodeData; i++)
+        out.write((char *)&fdummy, sizeof(float)); // min Wert pro Datentyp
+    fdummy = 1.0;
+    for (int i = 0; i < nofNodeData; i++)
+        out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp
+
+    // daten ins file schreiben
+    for (int d = 0; d < nofNodeData; ++d)
+        for (int n = 0; n < (int)nodedata[d].size(); n++) {
+            fdummy = (float)nodedata[d][n];
+            out.write((char *)&fdummy, sizeof(float));
+        }
+
+    fdummy = 1.;
+    for (int i = 0; i < nofNodeData; i++)
+        out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp
+
+    out.close();
+    UBLOG(logDEBUG1, "WbWriterAvsASCII::writeQuadsWithNodeData to " << avsfilename << " - end");
+
+    return avsfilename;
+}
+/*===============================================================================*/
+std::string WbWriterAvsASCII::writeQuadsWithCellData(const string &filename, vector<UbTupleFloat3> &nodes,
+                                                     vector<UbTupleInt4> &cells, vector<string> &datanames,
+                                                     vector<vector<double>> &celldata)
+{
+    string avsfilename = filename + getFileExtension();
+    UBLOG(logDEBUG1, "WbWriterAvsASCII::writeQuadsWithCellData to " << avsfilename << " - start");
+
+    ofstream out(avsfilename.c_str(), ios::out | ios::binary);
+    if (!out) {
+        out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!outfile) weiterhin true!!!
+        string path = UbSystem::getPathFromString(avsfilename);
+        if (path.size() > 0) {
+            UbSystem::makeDirectory(path);
+            out.open(avsfilename.c_str(), ios::out | ios::binary);
+        }
+        if (!out)
+            throw UbException(UB_EXARGS,
+                              "write_OutputFile-UCD File  " + avsfilename + " konnte nicht geschrieben werden");
+    }
+
+    char magic = (char)7;
+    int idummy;
+    float fdummy;
+
+    int nofNodes = (int)nodes.size();
+    int nofCells = (int)cells.size();
+
+    int nofNodeData     = 0;
+    int nofCellData     = (int)datanames.size();
+    int nofModelData    = 0;
+    int cellType        = 3; //=quad
+    int nofNodesPerCell = 4;
+
+    out.write((char *)&magic, sizeof(char));
+    out.write((char *)&nofNodes, sizeof(int));
+    out.write((char *)&nofCells, sizeof(int));
+    out.write((char *)&nofNodeData, sizeof(int));
+    out.write((char *)&nofCellData, sizeof(int));
+    out.write((char *)&nofModelData, sizeof(int));
+
+    idummy = (int)nofCells * nofNodesPerCell;
+    out.write((char *)&idummy, sizeof(int)); //(nof nodes) * (nodes per cell)
+    for (int c = 0; c < nofCells; c++) {
+        idummy = c + 1;
+        out.write((char *)&idummy, sizeof(int)); // cell id
+        idummy = 1;
+        out.write((char *)&idummy, sizeof(int)); // mat
+        idummy = nofNodesPerCell;
+        out.write((char *)&idummy, sizeof(int)); // nodes per cell
+        idummy = cellType;
+        out.write((char *)&idummy, sizeof(int)); // cell type
+    }
+    // knotennummern der einzelnen zellen
+    for (int c = 0; c < nofCells; c++) {
+        idummy = val<1>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<2>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<3>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<4>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+    }
+
+    // coords
+    // x1-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<1>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // x2-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<2>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // x3-coords
+    fdummy = 0.0;
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<3>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // out<<"\n";
+
+    // CELL DATA
+    char labels[1024];
+    char units[1024];
+    strcpy(labels, "");
+    strcpy(units, "");
+
+    for (int d = 0; d < nofCellData - 1; ++d) {
+        strcat(labels, datanames[d].c_str());
+        strcat(labels, ".");
+    }
+    strcat(labels, datanames[nofCellData - 1].c_str());
+
+    for (int d = 0; d < nofCellData - 1; ++d)
+        strcat(units, "no_unit.");
+    strcat(units, "no_unit");
+
+    out.write((char *)&labels, sizeof(labels));
+    out.write((char *)&units, sizeof(units));
+
+    // nof and type of data
+    idummy = nofCellData;
+    out.write((char *)&idummy, sizeof(int)); // Datentypen pro knoten (hier = nof_node_data, da NUR skalare)
+
+    idummy = 1;
+    for (int i = 0; i < nofCellData; i++)
+        out.write((char *)&idummy, sizeof(int)); // jeder Datentyp ist ein skalarer Wert
+
+    // min and max of data
+    fdummy = 0.0;
+    for (int i = 0; i < nofCellData; i++)
+        out.write((char *)&fdummy, sizeof(float)); // min Wert pro Datentyp
+    fdummy = 1.0;
+    for (int i = 0; i < nofCellData; i++)
+        out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp
+
+    // daten ins file schreiben
+    for (int d = 0; d < nofCellData; ++d)
+        for (int n = 0; n < (int)celldata[d].size(); n++) {
+            fdummy = (float)celldata[d][n];
+            out.write((char *)&fdummy, sizeof(float));
+        }
+
+    fdummy = 1.;
+    for (int i = 0; i < nofCellData; i++)
+        out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp
+
+    out.close();
+    UBLOG(logDEBUG1, "WbWriterAvsASCII::writeQuadsWithCellData to " << avsfilename << " - end");
+
+    return avsfilename;
+}
+/*===============================================================================*/
+std::string WbWriterAvsASCII::writeQuadsWithNodeAndCellData(const string &filename, vector<UbTupleFloat3> &nodes,
+                                                            vector<UbTupleInt4> &cells, vector<string> &nodedatanames,
+                                                            vector<vector<double>> &nodedata,
+                                                            vector<string> &celldatanames,
+                                                            vector<vector<double>> &celldata)
+{
+    string avsfilename = filename + getFileExtension();
+    UBLOG(logDEBUG1, "WbWriterAvsASCII::writeQuadsWithNodeAndCellData to " << avsfilename << " - start");
+
+    ofstream out(avsfilename.c_str(), ios::out | ios::binary);
+    if (!out) {
+        out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!outfile) weiterhin true!!!
+        string path = UbSystem::getPathFromString(avsfilename);
+        if (path.size() > 0) {
+            UbSystem::makeDirectory(path);
+            out.open(avsfilename.c_str(), ios::out | ios::binary);
+        }
+        if (!out)
+            throw UbException(UB_EXARGS,
+                              "write_OutputFile-UCD File  " + avsfilename + " konnte nicht geschrieben werden");
+    }
+
+    char magic = (char)7;
+    int idummy;
+    float fdummy;
+
+    int nofNodes = (int)nodes.size();
+    int nofCells = (int)cells.size();
+
+    int nofNodeData     = (int)nodedatanames.size();
+    int nofCellData     = (int)celldatanames.size();
+    int nofModelData    = 0;
+    int cellType        = 3; //=quad
+    int nofNodesPerCell = 4;
+
+    out.write((char *)&magic, sizeof(char));
+    out.write((char *)&nofNodes, sizeof(int));
+    out.write((char *)&nofCells, sizeof(int));
+    out.write((char *)&nofNodeData, sizeof(int));
+    out.write((char *)&nofCellData, sizeof(int));
+    out.write((char *)&nofModelData, sizeof(int));
+
+    idummy = (int)nofCells * nofNodesPerCell;
+    out.write((char *)&idummy, sizeof(int)); //(nof nodes) * (nodes per cell)
+    for (int c = 0; c < nofCells; c++) {
+        idummy = c + 1;
+        out.write((char *)&idummy, sizeof(int)); // cell id
+        idummy = 1;
+        out.write((char *)&idummy, sizeof(int)); // mat
+        idummy = nofNodesPerCell;
+        out.write((char *)&idummy, sizeof(int)); // nodes per cell
+        idummy = cellType;
+        out.write((char *)&idummy, sizeof(int)); // cell type
+    }
+    // knotennummern der einzelnen zellen
+    for (int c = 0; c < nofCells; c++) {
+        idummy = val<1>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<2>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<3>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<4>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+    }
+
+    // coords
+    // x1-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<1>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // x2-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<2>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // x3-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<3>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // out<<"\n";
+
+    // NODE DATA
+    char nodelabels[1024];
+    char nodeunits[1024];
+    strcpy(nodelabels, "");
+    strcpy(nodeunits, "");
+
+    for (int d = 0; d < nofNodeData - 1; ++d) {
+        strcat(nodelabels, nodedatanames[d].c_str());
+        strcat(nodelabels, ".");
+    }
+    strcat(nodelabels, nodedatanames[nofNodeData - 1].c_str());
+
+    for (int i = 0; i < (nofNodeData - 1); i++)
+        strcat(nodeunits, "no_unit.");
+    strcat(nodeunits, "no_unit");
+
+    out.write((char *)&nodelabels, sizeof(nodelabels));
+    out.write((char *)&nodeunits, sizeof(nodeunits));
+
+    // nof and type of data
+    idummy = nofNodeData;
+    out.write((char *)&idummy, sizeof(int)); // Datentypen pro knoten (hier = nof_node_data, da NUR skalare)
+
+    idummy = 1;
+    for (int i = 0; i < nofNodeData; i++)
+        out.write((char *)&idummy, sizeof(int)); // jeder Datentyp ist ein skalarer Wert
+
+    // min and max of data
+    fdummy = 0.0;
+    for (int i = 0; i < nofNodeData; i++)
+        out.write((char *)&fdummy, sizeof(float)); // min Wert pro Datentyp
+    fdummy = 1.0;
+    for (int i = 0; i < nofNodeData; i++)
+        out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp
+
+    // daten ins file schreiben
+    for (int d = 0; d < nofNodeData; ++d)
+        for (int n = 0; n < (int)nodedata[d].size(); n++) {
+            fdummy = (float)nodedata[d][n];
+            out.write((char *)&fdummy, sizeof(float));
+        }
+
+    fdummy = 1.;
+    for (int i = 0; i < nofNodeData; i++)
+        out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp
+
+    // CELL DATA
+    char celllabels[1024];
+    char cellunits[1024];
+    strcpy(celllabels, "");
+    strcpy(cellunits, "");
+
+    for (int d = 0; d < nofCellData - 1; ++d) {
+        strcat(celllabels, celldatanames[d].c_str());
+        strcat(celllabels, ".");
+    }
+    strcat(celllabels, celldatanames[nofCellData - 1].c_str());
+
+    for (int d = 0; d < nofCellData - 1; ++d)
+        strcat(cellunits, "no_unit.");
+    strcat(cellunits, "no_unit");
+
+    out.write((char *)&celllabels, sizeof(celllabels));
+    out.write((char *)&cellunits, sizeof(cellunits));
+
+    // nof and type of data
+    idummy = nofCellData;
+    out.write((char *)&idummy, sizeof(int)); // Datentypen pro knoten (hier = nof_node_data, da NUR skalare)
+
+    idummy = 1;
+    for (int i = 0; i < nofCellData; i++)
+        out.write((char *)&idummy, sizeof(int)); // jeder Datentyp ist ein skalarer Wert
+
+    // min and max of data
+    fdummy = 0.0;
+    for (int i = 0; i < nofCellData; i++)
+        out.write((char *)&fdummy, sizeof(float)); // min Wert pro Datentyp
+    fdummy = 1.0;
+    for (int i = 0; i < nofCellData; i++)
+        out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp
+
+    // daten ins file schreiben
+    for (int d = 0; d < nofCellData; ++d)
+        for (int n = 0; n < (int)celldata[d].size(); n++) {
+            fdummy = (float)celldata[d][n];
+            out.write((char *)&fdummy, sizeof(float));
+        }
+
+    fdummy = 1.;
+    for (int i = 0; i < nofCellData; i++)
+        out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp
+
+    out.close();
+    UBLOG(logDEBUG1, "WbWriterAvsASCII::writeQuadsWithNodeAndCellData to " << avsfilename << " - end");
+
+    return avsfilename;
+}
+/*===============================================================================*/
+std::string WbWriterAvsASCII::writeLines(const string &filename, vector<UbTupleFloat3> &nodes,
+                                         vector<UbTupleInt2> &lines)
+{
+    string avsfilename = filename + getFileExtension();
+    UBLOG(logDEBUG1, "WbWriterAvsASCII::writeLines to " << avsfilename << " - start");
+
+    ofstream out(avsfilename.c_str(), ios::out);
+    if (!out) {
+        out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!outfile) weiterhin true!!!
+        string path = UbSystem::getPathFromString(avsfilename);
+        if (path.size() > 0) {
+            UbSystem::makeDirectory(path);
+            out.open(avsfilename.c_str(), ios::out);
+        }
+        if (!out)
+            throw UbException(UB_EXARGS, avsfilename + " konnte nicht geschrieben werden");
+    }
+
+    int nofNodes = (int)nodes.size();
+    int nofLines = (int)lines.size();
+
+    out << "# UCD-File created by WbWriterAvsASCII\n";
+    out << nofNodes << " " << nofLines << " 0 0 0 " << endl;
+
+    for (int n = 0; n < nofNodes; n++)
+        out << n + 1 << " " << val<1>(nodes[n]) << " " << val<2>(nodes[n]) << " " << val<3>(nodes[n]) << " \n";
+
+    for (int l = 0; l < nofLines; l++)
+        out << l + 1 << " 2 line " << val<1>(lines[l]) + 1 << " " << val<2>(lines[l]) + 1 << " " << endl;
+
+    out.close();
+    UBLOG(logDEBUG1, "WbWriterAvsASCII::writeLines to " << avsfilename << " - end");
+
+    return avsfilename;
+}
+/*===============================================================================*/
+std::string WbWriterAvsASCII::writeTriangles(const string &filename, vector<UbTupleFloat3> &nodes,
+                                             vector<UbTupleInt3> &triangles)
+{
+    string avsfilename = filename + getFileExtension();
+    UBLOG(logDEBUG1, "WbWriterAvsASCII::writeTriangles to " << avsfilename << " - start");
+
+    ofstream out(avsfilename.c_str(), ios::out);
+    if (!out) {
+        out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!outfile) weiterhin true!!!
+        string path = UbSystem::getPathFromString(avsfilename);
+        if (path.size() > 0) {
+            UbSystem::makeDirectory(path);
+            out.open(avsfilename.c_str(), ios::out);
+        }
+        if (!out)
+            throw UbException(UB_EXARGS, "file konnte nicht geschrieben werden " + avsfilename);
+    }
+
+    int nofNodes = (int)nodes.size();
+    int nofTrian = (int)triangles.size();
+
+    out << "# UCD-File created by WbWriterAvsASCII\n";
+    out << nofNodes << " " << nofTrian << " 0 0 0 " << endl;
+
+    for (int n = 0; n < nofNodes; n++)
+        out << n + 1 << " " << val<1>(nodes[n]) << " " << val<2>(nodes[n]) << " " << val<3>(nodes[n]) << " \n";
+
+    for (int l = 0; l < nofTrian; l++)
+        out << l + 1 << " 2 tri " << val<1>(triangles[l]) + 1 << " " << val<2>(triangles[l]) + 1 << " "
+            << val<3>(triangles[l]) + 1 << " " << endl;
+
+    out.close();
+    UBLOG(logDEBUG1, "WbWriterAvsASCII::writeTriangles to " << avsfilename << " - end");
+
+    return avsfilename;
+}
+/*===============================================================================*/
+std::string WbWriterAvsASCII::writeTrianglesWithNodeData(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                                                         std::vector<UbTupleInt3> &cells,
+                                                         std::vector<std::string> &datanames,
+                                                         std::vector<std::vector<double>> &nodedata)
+{
+    string avsfilename = filename + getFileExtension();
+    UBLOG(logDEBUG1, "WbWriterAvsASCII::writeTrianglesWithNodeData to " << avsfilename << " - end");
+
+    ofstream out(avsfilename.c_str(), ios::out | ios::binary);
+    if (!out) {
+        out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!outfile) weiterhin true!!!
+        string path = UbSystem::getPathFromString(avsfilename);
+        if (path.size() > 0) {
+            UbSystem::makeDirectory(path);
+            out.open(avsfilename.c_str(), ios::out | ios::binary);
+        }
+        if (!out)
+            throw UbException(UB_EXARGS,
+                              "write_OutputFile-UCD File " + avsfilename + " konnte nicht geschrieben werden");
+    }
+    char magic = (char)7;
+    int idummy;
+    float fdummy;
+
+    int nofNodes = (int)nodes.size();
+    int nofCells = (int)cells.size();
+
+    int nofNodeData     = (int)datanames.size();
+    int nofCellData     = 0;
+    int nofModelData    = 0;
+    int cellType        = 2; // triangle
+    int nofNodesPerCell = 3;
+
+    out.write((char *)&magic, sizeof(char));
+    out.write((char *)&nofNodes, sizeof(int));
+    out.write((char *)&nofCells, sizeof(int));
+    out.write((char *)&nofNodeData, sizeof(int));
+    out.write((char *)&nofCellData, sizeof(int));
+    out.write((char *)&nofModelData, sizeof(int));
+
+    idummy = (int)nofCells * nofNodesPerCell;
+    out.write((char *)&idummy, sizeof(int)); //(nof nodes) * (nodes per cell)
+    for (int c = 0; c < nofCells; c++) {
+        idummy = c + 1;
+        out.write((char *)&idummy, sizeof(int)); // cell id
+        idummy = 1;
+        out.write((char *)&idummy, sizeof(int)); // mat
+        idummy = nofNodesPerCell;
+        out.write((char *)&idummy, sizeof(int)); // nodes per cell
+        idummy = cellType;
+        out.write((char *)&idummy, sizeof(int)); // cell type
+    }
+    // knotennummern der einzelnen zellen
+    for (int c = 0; c < nofCells; c++) {
+        idummy = val<1>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<2>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<3>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+    }
+
+    // coords
+    // x1-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<1>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // x2-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<2>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // x3-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<3>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // out<<"\n";
+
+    // NODE DATA
+    char labels[1024];
+    char units[1024];
+    strcpy(labels, "");
+    strcpy(units, "");
+
+    for (int d = 0; d < nofNodeData - 1; ++d) {
+        strcat(labels, datanames[d].c_str());
+        strcat(labels, ".");
+    }
+    strcat(labels, datanames[nofNodeData - 1].c_str());
+
+    for (int i = 0; i < (nofNodeData - 1); i++)
+        strcat(units, "no_unit.");
+    strcat(units, "no_unit");
+
+    out.write((char *)&labels, sizeof(labels));
+    out.write((char *)&units, sizeof(units));
+
+    // nof and type of data
+    idummy = nofNodeData;
+    out.write((char *)&idummy, sizeof(int)); // Datentypen pro knoten (hier = nof_node_data, da NUR skalare)
+
+    idummy = 1;
+    for (int i = 0; i < nofNodeData; i++)
+        out.write((char *)&idummy, sizeof(int)); // jeder Datentyp ist ein skalarer Wert
+
+    // min and max of data
+    fdummy = 0.0;
+    for (int i = 0; i < nofNodeData; i++)
+        out.write((char *)&fdummy, sizeof(float)); // min Wert pro Datentyp
+    fdummy = 1.0;
+    for (int i = 0; i < nofNodeData; i++)
+        out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp
+
+    // daten ins file schreiben
+    for (int d = 0; d < nofNodeData; ++d) {
+        for (int n = 0; n < (int)nodedata[d].size(); n++) {
+            fdummy = (float)nodedata[d][n];
+            out.write((char *)&fdummy, sizeof(float));
+        }
+    }
+
+    fdummy = 1.;
+    for (int i = 0; i < nofNodeData; i++)
+        out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp
+
+    out.close();
+    UBLOG(logDEBUG1, "WbWriterAvsASCII::writeTrianglesWithNodeData to " << avsfilename << " - end");
+
+    return avsfilename;
+}
+/*===============================================================================*/
+std::string WbWriterAvsASCII::writeOctsWithCellData(const string &filename, vector<UbTupleFloat3> &nodes,
+                                                    vector<UbTupleInt8> &cells, vector<string> &datanames,
+                                                    vector<vector<double>> &celldata)
+{
+    string avsfilename = filename + getFileExtension();
+    UBLOG(logDEBUG1, "WbWriterAvsASCII::writeOctsWithCellData to " << avsfilename << " - start");
+
+    ofstream out(avsfilename.c_str(), ios::out | ios::binary);
+    if (!out) {
+        out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!outfile) weiterhin true!!!
+        string path = UbSystem::getPathFromString(avsfilename);
+        if (path.size() > 0) {
+            UbSystem::makeDirectory(path);
+            out.open(avsfilename.c_str(), ios::out | ios::binary);
+        }
+        if (!out)
+            throw UbException(UB_EXARGS, "file konnte nicht geschrieben werden " + avsfilename);
+    }
+
+    char magic = (char)7;
+    int idummy;
+    float fdummy;
+
+    int nofNodes = (int)nodes.size();
+    int nofCells = (int)cells.size();
+
+    int nofNodeData     = 0;
+    int nofCellData     = (int)datanames.size();
+    int nofModelData    = 0;
+    int cellType        = 7; //=hex
+    int nofNodesPerCell = 8;
+
+    out.write((char *)&magic, sizeof(char));
+    out.write((char *)&nofNodes, sizeof(int));
+    out.write((char *)&nofCells, sizeof(int));
+    out.write((char *)&nofNodeData, sizeof(int));
+    out.write((char *)&nofCellData, sizeof(int));
+    out.write((char *)&nofModelData, sizeof(int));
+
+    idummy = (int)nofCells * nofNodesPerCell;
+    out.write((char *)&idummy, sizeof(int)); //(nof nodes) * (nodes per cell)
+    for (int c = 0; c < nofCells; c++) {
+        idummy = c + 1;
+        out.write((char *)&idummy, sizeof(int)); // cell id
+        idummy = 1;
+        out.write((char *)&idummy, sizeof(int)); // mat
+        idummy = nofNodesPerCell;
+        out.write((char *)&idummy, sizeof(int)); // nodes per cell
+        idummy = cellType;
+        out.write((char *)&idummy, sizeof(int)); // cell type
+    }
+    // knotennummern der einzelnen zellen
+    for (int c = 0; c < nofCells; c++) {
+        idummy = val<1>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<2>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<3>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<4>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<5>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<6>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<7>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<8>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+    }
+
+    // coords
+    // x1-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<1>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // x2-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<2>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // x3-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<3>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // out<<"\n";
+
+    // CELL DATA
+    char labels[1024];
+    char units[1024];
+    strcpy(labels, "");
+    strcpy(units, "");
+
+    for (int d = 0; d < nofCellData - 1; ++d) {
+        strcat(labels, datanames[d].c_str());
+        strcat(labels, ".");
+    }
+    strcat(labels, datanames[nofCellData - 1].c_str());
+
+    for (int d = 0; d < nofCellData - 1; ++d)
+        strcat(units, "no_unit.");
+    strcat(units, "no_unit");
+
+    out.write((char *)&labels, sizeof(labels));
+    out.write((char *)&units, sizeof(units));
+
+    // nof and type of data
+    idummy = nofCellData;
+    out.write((char *)&idummy, sizeof(int)); // Datentypen pro knoten (hier = nof_node_data, da NUR skalare)
+
+    idummy = 1;
+    for (int i = 0; i < nofCellData; i++)
+        out.write((char *)&idummy, sizeof(int)); // jeder Datentyp ist ein skalarer Wert
+
+    // min and max of data
+    fdummy = 0.0;
+    for (int i = 0; i < nofCellData; i++)
+        out.write((char *)&fdummy, sizeof(float)); // min Wert pro Datentyp
+    fdummy = 1.0;
+    for (int i = 0; i < nofCellData; i++)
+        out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp
+
+    // daten ins file schreiben
+    for (int d = 0; d < nofCellData; ++d)
+        for (int n = 0; n < (int)celldata[d].size(); n++) {
+            fdummy = (float)celldata[d][n];
+            out.write((char *)&fdummy, sizeof(float));
+        }
+
+    fdummy = 1.;
+    for (int i = 0; i < nofCellData; i++)
+        out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp
+
+    out.close();
+    UBLOG(logDEBUG1, "WbWriterAvsASCII::writeOctsWithCellData to " << avsfilename << " - end");
+
+    return avsfilename;
+}
+/*===============================================================================*/
+std::string WbWriterAvsASCII::writeOctsWithNodeData(const string &filename, vector<UbTupleFloat3> &nodes,
+                                                    vector<UbTupleUInt8> &cells, vector<string> &datanames,
+                                                    vector<vector<double>> &nodedata)
+{
+    string avsfilename = filename + getFileExtension();
+    UBLOG(logDEBUG1, "WbWriterAvsASCII::writeOctsWithNodeData to " << avsfilename << " - start");
+
+    ofstream out(avsfilename.c_str(), ios::out | ios::binary);
+    if (!out) {
+        out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!outfile) weiterhin true!!!
+        string path = UbSystem::getPathFromString(avsfilename);
+        if (path.size() > 0) {
+            UbSystem::makeDirectory(path);
+            out.open(avsfilename.c_str(), ios::out | ios::binary);
+        }
+        if (!out)
+            throw UbException(UB_EXARGS, "file konnte nicht geschrieben werden " + avsfilename);
+    }
+
+    if ((int)nodedata.size() == 0)
+        throw UbException(UB_EXARGS, "no nodedata!!!");
+    if (nodes.size() != nodedata[0].size())
+        throw UbException(UB_EXARGS, "nodedata != nofNodes!!!");
+
+    char magic = (char)7;
+    int idummy;
+    float fdummy;
+
+    int nofNodes = (int)nodes.size();
+    int nofCells = (int)cells.size();
+
+    int nofNodeData     = (int)datanames.size();
+    int nofCellData     = 0;
+    int nofModelData    = 0;
+    int cellType        = 7; //=hex
+    int nofNodesPerCell = 8;
+
+    out.write((char *)&magic, sizeof(char));
+    out.write((char *)&nofNodes, sizeof(int));
+    out.write((char *)&nofCells, sizeof(int));
+    out.write((char *)&nofNodeData, sizeof(int));
+    out.write((char *)&nofCellData, sizeof(int));
+    out.write((char *)&nofModelData, sizeof(int));
+
+    idummy = (int)nofCells * nofNodesPerCell;
+    out.write((char *)&idummy, sizeof(int)); //(nof nodes) * (nodes per cell)
+    for (int c = 0; c < nofCells; c++) {
+        idummy = c + 1;
+        out.write((char *)&idummy, sizeof(int)); // cell id
+        idummy = 1;
+        out.write((char *)&idummy, sizeof(int)); // mat
+        idummy = nofNodesPerCell;
+        out.write((char *)&idummy, sizeof(int)); // nodes per cell
+        idummy = cellType;
+        out.write((char *)&idummy, sizeof(int)); // cell type
+    }
+    // knotennummern der einzelnen zellen
+    for (int c = 0; c < nofCells; c++) {
+        idummy = val<1>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<2>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<3>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<4>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<5>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<6>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<7>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<8>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+    }
+
+    // coords
+    // x1-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<1>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // x2-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<2>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // x3-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<3>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+
+    // NODE DATA
+    char labels[1024];
+    char units[1024];
+    strcpy(labels, "");
+    strcpy(units, "");
+
+    for (int d = 0; d < nofNodeData - 1; ++d) {
+        strcat(labels, datanames[d].c_str());
+        strcat(labels, ".");
+    }
+    strcat(labels, datanames[nofNodeData - 1].c_str());
+
+    for (int i = 0; i < (nofNodeData - 1); i++)
+        strcat(units, "no_unit.");
+    strcat(units, "no_unit");
+
+    out.write((char *)&labels, sizeof(labels));
+    out.write((char *)&units, sizeof(units));
+
+    // nof and type of data
+    idummy = nofNodeData;
+    out.write((char *)&idummy, sizeof(int)); // Datentypen pro knoten (hier = nof_node_data, da NUR skalare)
+
+    idummy = 1;
+    for (int i = 0; i < nofNodeData; i++)
+        out.write((char *)&idummy, sizeof(int)); // jeder Datentyp ist ein skalarer Wert
+
+    // min and max of data
+    fdummy = 0.0;
+    for (int i = 0; i < nofNodeData; i++)
+        out.write((char *)&fdummy, sizeof(float)); // min Wert pro Datentyp
+    fdummy = 1.0;
+    for (int i = 0; i < nofNodeData; i++)
+        out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp
+
+    // daten ins file schreiben
+    for (int d = 0; d < nofNodeData; ++d)
+        for (int n = 0; n < (int)nodedata[d].size(); n++) {
+            fdummy = (float)nodedata[d][n];
+            out.write((char *)&fdummy, sizeof(float));
+        }
+
+    fdummy = 1.;
+    for (int i = 0; i < nofNodeData; i++)
+        out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp
+
+    out.close();
+    UBLOG(logDEBUG1, "WbWriterAvsASCII::writeOctsWithNodeData to " << avsfilename << " - end");
+
+    return avsfilename;
+}
diff --git a/src/basics/basics/writer/WbWriterAvsASCII.h b/src/basics/basics/writer/WbWriterAvsASCII.h
new file mode 100644
index 0000000000000000000000000000000000000000..f5a462c70f11ddd7b1e4b76ab935b9ad1f988523
--- /dev/null
+++ b/src/basics/basics/writer/WbWriterAvsASCII.h
@@ -0,0 +1,118 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file WbWriterAvsASCII.h
+//! \ingroup writer
+//! \author Soeren Freudiger, Sebastian Geller
+//=======================================================================================
+#ifndef WBWRITERAVSASCII_H
+#define WBWRITERAVSASCII_H
+
+#include <basics/writer/WbWriter.h>
+
+class WbWriterAvsASCII : public WbWriter
+{
+public:
+    static WbWriterAvsASCII *getInstance()
+    {
+        static WbWriterAvsASCII instance;
+        return &instance;
+    }
+
+    WbWriterAvsASCII(const WbWriterAvsASCII &) = delete;
+    const WbWriterAvsASCII &operator=(const WbWriterAvsASCII &) = delete;
+
+private:
+    WbWriterAvsASCII() = default;
+
+public:
+    std::string getFileExtension() override { return ".ascii.inp"; }
+
+    ///////////////////virtual std::string writeOcts(const std::string& filename,std::vector< UbTupleFloat3 >& nodes,
+    ///std::vector< UbTupleInt8 >& cells) = 0;
+    ///////////////////////////////////////////////////////
+    // lines
+    //     0 ---- 1
+    // nodenumbering must start with 0!
+    std::string writeLines(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                           std::vector<UbTupleInt2> &lines) override;
+
+    //////////////////////////////////////////////////////////////////////////
+    // triangles
+    // cell numbering:
+    //                    2
+    //
+    //                  0---1
+    // nodenumbering must start with 0!
+    std::string writeTriangles(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                               std::vector<UbTuple<int, int, int>> &triangles) override;
+    std::string writeTrianglesWithNodeData(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                                           std::vector<UbTupleInt3> &cells, std::vector<std::string> &datanames,
+                                           std::vector<std::vector<double>> &nodedata) override;
+
+    //////////////////////////////////////////////////////////////////////////
+    // quads
+    // cell numbering:
+    //                  3---2
+    //                  |   |
+    //                  0---1
+    // nodenumbering must start with 0!
+    std::string writeQuads(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                           std::vector<UbTupleInt4> &cells) override;
+    std::string writeQuadsWithNodeData(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                                       std::vector<UbTupleInt4> &cells, std::vector<std::string> &datanames,
+                                       std::vector<std::vector<double>> &nodedata) override;
+    std::string writeQuadsWithCellData(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                                       std::vector<UbTupleInt4> &cells, std::vector<std::string> &datanames,
+                                       std::vector<std::vector<double>> &celldata) override;
+    std::string writeQuadsWithNodeAndCellData(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                                              std::vector<UbTupleInt4> &cells, std::vector<std::string> &nodedatanames,
+                                              std::vector<std::vector<double>> &nodedata,
+                                              std::vector<std::string> &celldatanames,
+                                              std::vector<std::vector<double>> &celldata) override;
+
+    //////////////////////////////////////////////////////////////////////////
+    // octs
+    //     7 ---- 6
+    //    /|     /|
+    //   4 +--- 5 |
+    //   | |    | |
+    //   | 3 ---+ 2
+    //   |/     |/
+    //   0 ---- 1
+    std::string writeOcts(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                          std::vector<UbTupleInt8> &cells) override;
+    std::string writeOctsWithCellData(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                                      std::vector<UbTupleInt8> &cells, std::vector<std::string> &datanames,
+                                      std::vector<std::vector<double>> &celldata) override;
+    std::string writeOctsWithNodeData(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                                      std::vector<UbTupleUInt8> &cells, std::vector<std::string> &datanames,
+                                      std::vector<std::vector<double>> &nodedata) override;
+};
+
+#endif // WBWRITERAVSASCII_H
diff --git a/src/basics/basics/writer/WbWriterAvsBinary.cpp b/src/basics/basics/writer/WbWriterAvsBinary.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8ce19629448cff4ebbb33a61eaead0bca119a998
--- /dev/null
+++ b/src/basics/basics/writer/WbWriterAvsBinary.cpp
@@ -0,0 +1,1254 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file WbWriterAvsBinary.cpp
+//! \ingroup writer
+//! \author Soeren Freudiger, Sebastian Geller
+//=======================================================================================
+#include <basics/utilities/UbLogger.h>
+#include <basics/utilities/UbSystem.h>
+#include <basics/writer/WbWriterAvsASCII.h>
+#include <basics/writer/WbWriterAvsBinary.h>
+
+#include <cstring>
+
+using namespace std;
+
+std::string WbWriterAvsBinary::writeLines(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                                          std::vector<UbTupleInt2> &lines)
+{
+    string avsfilename = filename + getFileExtension();
+    UBLOG(logDEBUG1, "WbWriterAvsBinary::writeLines to " << avsfilename << " - start");
+
+    ofstream out(avsfilename.c_str(), ios::out | ios::binary);
+    if (!out) {
+        out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!outfile) weiterhin true!!!
+        string path = UbSystem::getPathFromString(avsfilename);
+        if (path.size() > 0) {
+            UbSystem::makeDirectory(path);
+            out.open(avsfilename.c_str(), ios::out | ios::binary);
+        }
+        if (!out)
+            throw UbException(UB_EXARGS, avsfilename + " konnte nicht geschrieben werden");
+    }
+
+    char magic = (char)7;
+    int idummy;
+    float fdummy;
+
+    int nofNodes = (int)nodes.size();
+    int nofCells = (int)lines.size();
+
+    int nofNodeData     = 0;
+    int nofCellData     = 0;
+    int nofModelData    = 0;
+    int cellType        = 1; // line
+    int nofNodesPerCell = 2;
+
+    out.write((char *)&magic, sizeof(char));
+    out.write((char *)&nofNodes, sizeof(int));
+    out.write((char *)&nofCells, sizeof(int));
+    out.write((char *)&nofNodeData, sizeof(int));
+    out.write((char *)&nofCellData, sizeof(int));
+    out.write((char *)&nofModelData, sizeof(int));
+
+    idummy = (int)nofCells * nofNodesPerCell;
+    out.write((char *)&idummy, sizeof(int)); //(nof nodes) * (nodes per cell)
+    for (int c = 0; c < nofCells; c++) {
+        idummy = c + 1;
+        out.write((char *)&idummy, sizeof(int)); // cell id
+        idummy = 1;
+        out.write((char *)&idummy, sizeof(int)); // mat
+        idummy = nofNodesPerCell;
+        out.write((char *)&idummy, sizeof(int)); // nodes per cell
+        idummy = cellType;
+        out.write((char *)&idummy, sizeof(int)); // cell type
+    }
+    // knotennummern der einzelnen zellen
+    for (int c = 0; c < nofCells; c++) {
+        idummy = val<1>(lines[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<2>(lines[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+    }
+
+    // coords
+    // x1-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<1>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // x2-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<2>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // x3-coords
+    fdummy = 0.0;
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<3>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // out<<"\n";
+
+    out.close();
+    UBLOG(logDEBUG1, "WbWriterAvsBinary::writeLines to " << avsfilename << " - end");
+
+    return avsfilename;
+}
+/*===============================================================================*/
+std::string WbWriterAvsBinary::writeTriangles(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                                              std::vector<UbTuple<int, int, int>> &triangles)
+{
+    string avsfilename = filename + getFileExtension();
+    UBLOG(logDEBUG1, "WbWriterAvsBinary::writeTriangles to " << avsfilename << " - start");
+
+    ofstream out(avsfilename.c_str(), ios::out | ios::binary);
+    if (!out) {
+        out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!outfile) weiterhin true!!!
+        string path = UbSystem::getPathFromString(avsfilename);
+        if (path.size() > 0) {
+            UbSystem::makeDirectory(path);
+            out.open(avsfilename.c_str(), ios::out | ios::binary);
+        }
+        if (!out)
+            throw UbException(UB_EXARGS, avsfilename + " konnte nicht geschrieben werden");
+    }
+
+    char magic = (char)7;
+    int idummy;
+    float fdummy;
+
+    int nofNodes = (int)nodes.size();
+    int nofCells = (int)triangles.size();
+
+    int nofNodeData     = 0;
+    int nofCellData     = 0;
+    int nofModelData    = 0;
+    int cellType        = 2; // triangle
+    int nofNodesPerCell = 3;
+
+    out.write((char *)&magic, sizeof(char));
+    out.write((char *)&nofNodes, sizeof(int));
+    out.write((char *)&nofCells, sizeof(int));
+    out.write((char *)&nofNodeData, sizeof(int));
+    out.write((char *)&nofCellData, sizeof(int));
+    out.write((char *)&nofModelData, sizeof(int));
+
+    idummy = (int)nofCells * nofNodesPerCell;
+    out.write((char *)&idummy, sizeof(int)); //(nof nodes) * (nodes per cell)
+    for (int c = 0; c < nofCells; c++) {
+        idummy = c + 1;
+        out.write((char *)&idummy, sizeof(int)); // cell id
+        idummy = 1;
+        out.write((char *)&idummy, sizeof(int)); // mat
+        idummy = nofNodesPerCell;
+        out.write((char *)&idummy, sizeof(int)); // nodes per cell
+        idummy = cellType;
+        out.write((char *)&idummy, sizeof(int)); // cell type
+    }
+    // knotennummern der einzelnen zellen
+    for (int c = 0; c < nofCells; c++) {
+        idummy = val<1>(triangles[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<2>(triangles[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<3>(triangles[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+    }
+
+    // coords
+    // x1-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<1>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // x2-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<2>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // x3-coords
+    fdummy = 0.0;
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<3>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // out<<"\n";
+
+    out.close();
+    UBLOG(logDEBUG1, "WbWriterAvsBinary::writeTriangles to " << avsfilename << " - end");
+
+    return avsfilename;
+}
+/*===============================================================================*/
+std::string WbWriterAvsBinary::writeQuads(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                                          std::vector<UbTupleInt4> &cells)
+{
+    string avsfilename = filename + getFileExtension();
+    UBLOG(logDEBUG1, "WbWriterAvsBinary::writeQuads to " << avsfilename << " - start");
+
+    ofstream out(avsfilename.c_str(), ios::out | ios::binary);
+    if (!out) {
+        out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!outfile) weiterhin true!!!
+        string path = UbSystem::getPathFromString(avsfilename);
+        if (path.size() > 0) {
+            UbSystem::makeDirectory(path);
+            out.open(avsfilename.c_str(), ios::out | ios::binary);
+        }
+        if (!out)
+            throw UbException(UB_EXARGS, avsfilename + " konnte nicht geschrieben werden");
+    }
+    char magic = (char)7;
+    int idummy;
+    float fdummy;
+
+    int nofNodes = (int)nodes.size();
+    int nofCells = (int)cells.size();
+
+    int nofNodeData     = 0;
+    int nofCellData     = 0;
+    int nofModelData    = 0;
+    int cellType        = 3; //=quad
+    int nofNodesPerCell = 4;
+
+    out.write((char *)&magic, sizeof(char));
+    out.write((char *)&nofNodes, sizeof(int));
+    out.write((char *)&nofCells, sizeof(int));
+    out.write((char *)&nofNodeData, sizeof(int));
+    out.write((char *)&nofCellData, sizeof(int));
+    out.write((char *)&nofModelData, sizeof(int));
+
+    idummy = (int)nofCells * nofNodesPerCell;
+    out.write((char *)&idummy, sizeof(int)); //(nof nodes) * (nodes per cell)
+    for (int c = 0; c < nofCells; c++) {
+        idummy = c + 1;
+        out.write((char *)&idummy, sizeof(int)); // cell id
+        idummy = 1;
+        out.write((char *)&idummy, sizeof(int)); // mat
+        idummy = nofNodesPerCell;
+        out.write((char *)&idummy, sizeof(int)); // nodes per cell
+        idummy = cellType;
+        out.write((char *)&idummy, sizeof(int)); // cell type
+    }
+    // knotennummern der einzelnen zellen
+    for (int c = 0; c < nofCells; c++) {
+        idummy = val<1>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<2>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<3>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<4>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+    }
+
+    // coords
+    // x1-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<1>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // x2-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<2>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // x3-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<3>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // out<<"\n";
+
+    out.close();
+    UBLOG(logDEBUG1, "WbWriterAvsBinary::writeQuads to " << avsfilename << " - end");
+
+    return avsfilename;
+}
+/*===============================================================================*/
+std::string WbWriterAvsBinary::writeOcts(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                                         std::vector<UbTupleInt8> &cells)
+{
+    string avsfilename = filename + getFileExtension();
+    UBLOG(logDEBUG1, "WbWriterAvsBinary::writeOcts to " << avsfilename << " - start");
+
+    ofstream out(avsfilename.c_str(), ios::out | ios::binary);
+    if (!out) {
+        out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!outfile) weiterhin true!!!
+        string path = UbSystem::getPathFromString(avsfilename);
+        if (path.size() > 0) {
+            UbSystem::makeDirectory(path);
+            out.open(avsfilename.c_str(), ios::out | ios::binary);
+        }
+        if (!out)
+            throw UbException(UB_EXARGS, "file konnte nicht geschrieben werden");
+    }
+
+    char magic = (char)7;
+    int idummy;
+    float fdummy;
+
+    int nofNodes = (int)nodes.size();
+    int nofCells = (int)cells.size();
+
+    int nofNodeData     = 0;
+    int nofCellData     = 0;
+    int nofModelData    = 0;
+    int cellType        = 7; //=hex
+    int nofNodesPerCell = 8;
+
+    out.write((char *)&magic, sizeof(char));
+    out.write((char *)&nofNodes, sizeof(int));
+    out.write((char *)&nofCells, sizeof(int));
+    out.write((char *)&nofNodeData, sizeof(int));
+    out.write((char *)&nofCellData, sizeof(int));
+    out.write((char *)&nofModelData, sizeof(int));
+
+    idummy = (int)nofCells * nofNodesPerCell;
+    out.write((char *)&idummy, sizeof(int)); //(nof nodes) * (nodes per cell)
+    for (int c = 0; c < nofCells; c++) {
+        idummy = c + 1;
+        out.write((char *)&idummy, sizeof(int)); // cell id
+        idummy = 1;
+        out.write((char *)&idummy, sizeof(int)); // mat
+        idummy = nofNodesPerCell;
+        out.write((char *)&idummy, sizeof(int)); // nodes per cell
+        idummy = cellType;
+        out.write((char *)&idummy, sizeof(int)); // cell type
+    }
+    // knotennummern der einzelnen zellen
+    for (int c = 0; c < nofCells; c++) {
+        idummy = val<1>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<2>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<3>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<4>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<5>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<6>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<7>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<8>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+    }
+
+    // coords
+    // x1-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<1>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // x2-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<2>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // x3-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<3>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // out<<"\n";
+
+    out.close();
+    UBLOG(logDEBUG1, "WbWriterAvsBinary::writeOcts to " << avsfilename << " - end");
+
+    return avsfilename;
+}
+/*===============================================================================*/
+std::string WbWriterAvsBinary::writeTrianglesWithNodeData(const std::string &filename,
+                                                          std::vector<UbTupleFloat3> &nodes,
+                                                          std::vector<UbTupleInt3> &cells,
+                                                          std::vector<std::string> &datanames,
+                                                          std::vector<std::vector<double>> &nodedata)
+{
+    string avsfilename = filename + getFileExtension();
+    UBLOG(logDEBUG1, "WbWriterAvsBinary::writeTrianglesWithNodeData to " << avsfilename << " - start");
+
+    ofstream out(avsfilename.c_str(), ios::out | ios::binary);
+    if (!out) {
+        out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!outfile) weiterhin true!!!
+        string path = UbSystem::getPathFromString(avsfilename);
+        if (path.size() > 0) {
+            UbSystem::makeDirectory(path);
+            out.open(avsfilename.c_str(), ios::out | ios::binary);
+        }
+        if (!out)
+            throw UbException(UB_EXARGS,
+                              "write_OutputFile-UCD File " + avsfilename + " konnte nicht geschrieben werden");
+    }
+    char magic = (char)7;
+    int idummy;
+    float fdummy;
+
+    int nofNodes = (int)nodes.size();
+    int nofCells = (int)cells.size();
+
+    int nofNodeData     = (int)datanames.size();
+    int nofCellData     = 0;
+    int nofModelData    = 0;
+    int cellType        = 2; // triangle
+    int nofNodesPerCell = 3;
+
+    out.write((char *)&magic, sizeof(char));
+    out.write((char *)&nofNodes, sizeof(int));
+    out.write((char *)&nofCells, sizeof(int));
+    out.write((char *)&nofNodeData, sizeof(int));
+    out.write((char *)&nofCellData, sizeof(int));
+    out.write((char *)&nofModelData, sizeof(int));
+
+    idummy = (int)nofCells * nofNodesPerCell;
+    out.write((char *)&idummy, sizeof(int)); //(nof nodes) * (nodes per cell)
+    for (int c = 0; c < nofCells; c++) {
+        idummy = c + 1;
+        out.write((char *)&idummy, sizeof(int)); // cell id
+        idummy = 1;
+        out.write((char *)&idummy, sizeof(int)); // mat
+        idummy = nofNodesPerCell;
+        out.write((char *)&idummy, sizeof(int)); // nodes per cell
+        idummy = cellType;
+        out.write((char *)&idummy, sizeof(int)); // cell type
+    }
+    // knotennummern der einzelnen zellen
+    for (int c = 0; c < nofCells; c++) {
+        idummy = val<1>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<2>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<3>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+    }
+
+    // coords
+    // x1-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<1>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // x2-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<2>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // x3-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<3>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // out<<"\n";
+
+    // NODE DATA
+    char labels[1024];
+    char units[1024];
+    strcpy(labels, "");
+    strcpy(units, "");
+
+    for (int d = 0; d < nofNodeData - 1; ++d) {
+        strcat(labels, datanames[d].c_str());
+        strcat(labels, ".");
+    }
+    strcat(labels, datanames[nofNodeData - 1].c_str());
+
+    for (int i = 0; i < (nofNodeData - 1); i++)
+        strcat(units, "no_unit.");
+    strcat(units, "no_unit");
+
+    out.write((char *)&labels, sizeof(labels));
+    out.write((char *)&units, sizeof(units));
+
+    // nof and type of data
+    idummy = nofNodeData;
+    out.write((char *)&idummy, sizeof(int)); // Datentypen pro knoten (hier = nof_node_data, da NUR skalare)
+
+    idummy = 1;
+    for (int i = 0; i < nofNodeData; i++)
+        out.write((char *)&idummy, sizeof(int)); // jeder Datentyp ist ein skalarer Wert
+
+    // min and max of data
+    fdummy = 0.0;
+    for (int i = 0; i < nofNodeData; i++)
+        out.write((char *)&fdummy, sizeof(float)); // min Wert pro Datentyp
+    fdummy = 1.0;
+    for (int i = 0; i < nofNodeData; i++)
+        out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp
+
+    // daten ins file schreiben
+    for (int d = 0; d < nofNodeData; ++d)
+        for (int n = 0; n < (int)nodedata[d].size(); n++) {
+            fdummy = (float)nodedata[d][n];
+            out.write((char *)&fdummy, sizeof(float));
+        }
+
+    fdummy = 1.;
+    for (int i = 0; i < nofNodeData; i++)
+        out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp
+
+    out.close();
+    UBLOG(logDEBUG1, "WbWriterAvsBinary::writeTrianglesWithNodeData to " << avsfilename << " - end");
+
+    return avsfilename;
+}
+/*===============================================================================*/
+std::string WbWriterAvsBinary::writeQuadsWithNodeData(const string &filename, vector<UbTupleFloat3> &nodes,
+                                                      vector<UbTupleInt4> &cells, vector<string> &datanames,
+                                                      vector<vector<double>> &nodedata)
+{
+    string avsfilename = filename + getFileExtension();
+    UBLOG(logDEBUG1, "WbWriterAvsBinary::writeQuadsWithNodeData to " << avsfilename << " - start");
+
+    ofstream out(avsfilename.c_str(), ios::out | ios::binary);
+    if (!out) {
+        out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!outfile) weiterhin true!!!
+        string path = UbSystem::getPathFromString(avsfilename);
+        if (path.size() > 0) {
+            UbSystem::makeDirectory(path);
+            out.open(avsfilename.c_str(), ios::out | ios::binary);
+        }
+        if (!out)
+            throw UbException(UB_EXARGS,
+                              "write_OutputFile-UCD File " + avsfilename + " konnte nicht geschrieben werden");
+    }
+    char magic = (char)7;
+    int idummy;
+    float fdummy;
+
+    int nofNodes = (int)nodes.size();
+    int nofCells = (int)cells.size();
+
+    int nofNodeData     = (int)datanames.size();
+    int nofCellData     = 0;
+    int nofModelData    = 0;
+    int cellType        = 3; //=quad
+    int nofNodesPerCell = 4;
+
+    out.write((char *)&magic, sizeof(char));
+    out.write((char *)&nofNodes, sizeof(int));
+    out.write((char *)&nofCells, sizeof(int));
+    out.write((char *)&nofNodeData, sizeof(int));
+    out.write((char *)&nofCellData, sizeof(int));
+    out.write((char *)&nofModelData, sizeof(int));
+
+    idummy = (int)nofCells * nofNodesPerCell;
+    out.write((char *)&idummy, sizeof(int)); //(nof nodes) * (nodes per cell)
+    for (int c = 0; c < nofCells; c++) {
+        idummy = c + 1;
+        out.write((char *)&idummy, sizeof(int)); // cell id
+        idummy = 1;
+        out.write((char *)&idummy, sizeof(int)); // mat
+        idummy = nofNodesPerCell;
+        out.write((char *)&idummy, sizeof(int)); // nodes per cell
+        idummy = cellType;
+        out.write((char *)&idummy, sizeof(int)); // cell type
+    }
+    // knotennummern der einzelnen zellen
+    for (int c = 0; c < nofCells; c++) {
+        idummy = val<1>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<2>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<3>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<4>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+    }
+
+    // coords
+    // x1-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<1>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // x2-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<2>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // x3-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<3>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // out<<"\n";
+
+    // NODE DATA
+    char labels[1024];
+    char units[1024];
+    strcpy(labels, "");
+    strcpy(units, "");
+
+    for (int d = 0; d < nofNodeData - 1; ++d) {
+        strcat(labels, datanames[d].c_str());
+        strcat(labels, ".");
+    }
+    strcat(labels, datanames[nofNodeData - 1].c_str());
+
+    for (int i = 0; i < (nofNodeData - 1); i++)
+        strcat(units, "no_unit.");
+    strcat(units, "no_unit");
+
+    out.write((char *)&labels, sizeof(labels));
+    out.write((char *)&units, sizeof(units));
+
+    // nof and type of data
+    idummy = nofNodeData;
+    out.write((char *)&idummy, sizeof(int)); // Datentypen pro knoten (hier = nof_node_data, da NUR skalare)
+
+    idummy = 1;
+    for (int i = 0; i < nofNodeData; i++)
+        out.write((char *)&idummy, sizeof(int)); // jeder Datentyp ist ein skalarer Wert
+
+    // min and max of data
+    fdummy = 0.0;
+    for (int i = 0; i < nofNodeData; i++)
+        out.write((char *)&fdummy, sizeof(float)); // min Wert pro Datentyp
+    fdummy = 1.0;
+    for (int i = 0; i < nofNodeData; i++)
+        out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp
+
+    // daten ins file schreiben
+    for (int d = 0; d < nofNodeData; ++d)
+        for (int n = 0; n < (int)nodedata[d].size(); n++) {
+            fdummy = (float)nodedata[d][n];
+            out.write((char *)&fdummy, sizeof(float));
+        }
+
+    fdummy = 1.;
+    for (int i = 0; i < nofNodeData; i++)
+        out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp
+
+    out.close();
+    UBLOG(logDEBUG1, "WbWriterAvsBinary::writeQuadsWithNodeData to " << avsfilename << " - end");
+
+    return avsfilename;
+}
+/*===============================================================================*/
+std::string WbWriterAvsBinary::writeQuadsWithCellData(const string &filename, vector<UbTupleFloat3> &nodes,
+                                                      vector<UbTupleInt4> &cells, vector<string> &datanames,
+                                                      vector<vector<double>> &celldata)
+{
+    string avsfilename = filename + getFileExtension();
+    UBLOG(logDEBUG1, "WbWriterAvsBinary::writeQuadsWithCellData to " << avsfilename << " - start");
+
+    ofstream out(avsfilename.c_str(), ios::out | ios::binary);
+    if (!out) {
+        out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!outfile) weiterhin true!!!
+        string path = UbSystem::getPathFromString(avsfilename);
+        if (path.size() > 0) {
+            UbSystem::makeDirectory(path);
+            out.open(avsfilename.c_str(), ios::out | ios::binary);
+        }
+        if (!out)
+            throw UbException(UB_EXARGS, avsfilename + " konnte nicht geschrieben werden");
+    }
+
+    char magic = (char)7;
+    int idummy;
+    float fdummy;
+
+    int nofNodes = (int)nodes.size();
+    int nofCells = (int)cells.size();
+
+    int nofNodeData     = 0;
+    int nofCellData     = (int)datanames.size();
+    int nofModelData    = 0;
+    int cellType        = 3; //=quad
+    int nofNodesPerCell = 4;
+
+    out.write((char *)&magic, sizeof(char));
+    out.write((char *)&nofNodes, sizeof(int));
+    out.write((char *)&nofCells, sizeof(int));
+    out.write((char *)&nofNodeData, sizeof(int));
+    out.write((char *)&nofCellData, sizeof(int));
+    out.write((char *)&nofModelData, sizeof(int));
+
+    idummy = (int)nofCells * nofNodesPerCell;
+    out.write((char *)&idummy, sizeof(int)); //(nof nodes) * (nodes per cell)
+    for (int c = 0; c < nofCells; c++) {
+        idummy = c + 1;
+        out.write((char *)&idummy, sizeof(int)); // cell id
+        idummy = 1;
+        out.write((char *)&idummy, sizeof(int)); // mat
+        idummy = nofNodesPerCell;
+        out.write((char *)&idummy, sizeof(int)); // nodes per cell
+        idummy = cellType;
+        out.write((char *)&idummy, sizeof(int)); // cell type
+    }
+    // knotennummern der einzelnen zellen
+    for (int c = 0; c < nofCells; c++) {
+        idummy = val<1>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<2>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<3>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<4>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+    }
+
+    // coords
+    // x1-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<1>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // x2-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<2>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // x3-coords
+    fdummy = 0.0;
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<3>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // out<<"\n";
+
+    // CELL DATA
+    char labels[1024];
+    char units[1024];
+    strcpy(labels, "");
+    strcpy(units, "");
+
+    for (int d = 0; d < nofCellData - 1; ++d) {
+        strcat(labels, datanames[d].c_str());
+        strcat(labels, ".");
+    }
+    strcat(labels, datanames[nofCellData - 1].c_str());
+
+    for (int d = 0; d < nofCellData - 1; ++d)
+        strcat(units, "no_unit.");
+    strcat(units, "no_unit");
+
+    out.write((char *)&labels, sizeof(labels));
+    out.write((char *)&units, sizeof(units));
+
+    // nof and type of data
+    idummy = nofCellData;
+    out.write((char *)&idummy, sizeof(int)); // Datentypen pro knoten (hier = nof_node_data, da NUR skalare)
+
+    idummy = 1;
+    for (int i = 0; i < nofCellData; i++)
+        out.write((char *)&idummy, sizeof(int)); // jeder Datentyp ist ein skalarer Wert
+
+    // min and max of data
+    fdummy = 0.0;
+    for (int i = 0; i < nofCellData; i++)
+        out.write((char *)&fdummy, sizeof(float)); // min Wert pro Datentyp
+    fdummy = 1.0;
+    for (int i = 0; i < nofCellData; i++)
+        out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp
+
+    // daten ins file schreiben
+    for (int d = 0; d < nofCellData; ++d)
+        for (int n = 0; n < (int)celldata[d].size(); n++) {
+            fdummy = (float)celldata[d][n];
+            out.write((char *)&fdummy, sizeof(float));
+        }
+
+    fdummy = 1.;
+    for (int i = 0; i < nofCellData; i++)
+        out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp
+
+    out.close();
+    UBLOG(logDEBUG1, "WbWriterAvsBinary::writeQuadsWithCellData to " << avsfilename << " - end");
+
+    return avsfilename;
+}
+/*===============================================================================*/
+std::string WbWriterAvsBinary::writeQuadsWithNodeAndCellData(const string &filename, vector<UbTupleFloat3> &nodes,
+                                                             vector<UbTupleInt4> &cells, vector<string> &nodedatanames,
+                                                             vector<vector<double>> &nodedata,
+                                                             vector<string> &celldatanames,
+                                                             vector<vector<double>> &celldata)
+{
+    string avsfilename = filename + getFileExtension();
+    UBLOG(logDEBUG1, "WbWriterAvsBinary::writeQuadsWithNodeAndCellData to " << avsfilename << " - start");
+
+    ofstream out(avsfilename.c_str(), ios::out | ios::binary);
+    if (!out) {
+        out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!outfile) weiterhin true!!!
+        string path = UbSystem::getPathFromString(avsfilename);
+        if (path.size() > 0) {
+            UbSystem::makeDirectory(path);
+            out.open(avsfilename.c_str(), ios::out | ios::binary);
+        }
+        if (!out)
+            throw UbException(UB_EXARGS, avsfilename + " konnte nicht geschrieben werden");
+    }
+
+    char magic = (char)7;
+    int idummy;
+    float fdummy;
+
+    int nofNodes = (int)nodes.size();
+    int nofCells = (int)cells.size();
+
+    int nofNodeData     = (int)nodedatanames.size();
+    int nofCellData     = (int)celldatanames.size();
+    int nofModelData    = 0;
+    int cellType        = 3; //=quad
+    int nofNodesPerCell = 4;
+
+    out.write((char *)&magic, sizeof(char));
+    out.write((char *)&nofNodes, sizeof(int));
+    out.write((char *)&nofCells, sizeof(int));
+    out.write((char *)&nofNodeData, sizeof(int));
+    out.write((char *)&nofCellData, sizeof(int));
+    out.write((char *)&nofModelData, sizeof(int));
+
+    idummy = (int)nofCells * nofNodesPerCell;
+    out.write((char *)&idummy, sizeof(int)); //(nof nodes) * (nodes per cell)
+    for (int c = 0; c < nofCells; c++) {
+        idummy = c + 1;
+        out.write((char *)&idummy, sizeof(int)); // cell id
+        idummy = 1;
+        out.write((char *)&idummy, sizeof(int)); // mat
+        idummy = nofNodesPerCell;
+        out.write((char *)&idummy, sizeof(int)); // nodes per cell
+        idummy = cellType;
+        out.write((char *)&idummy, sizeof(int)); // cell type
+    }
+    // knotennummern der einzelnen zellen
+    for (int c = 0; c < nofCells; c++) {
+        idummy = val<1>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<2>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<3>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<4>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+    }
+
+    // coords
+    // x1-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<1>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // x2-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<2>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // x3-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<3>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // out<<"\n";
+
+    // NODE DATA
+    char nodelabels[1024];
+    char nodeunits[1024];
+    strcpy(nodelabels, "");
+    strcpy(nodeunits, "");
+
+    for (int d = 0; d < nofNodeData - 1; ++d) {
+        strcat(nodelabels, nodedatanames[d].c_str());
+        strcat(nodelabels, ".");
+    }
+    strcat(nodelabels, nodedatanames[nofNodeData - 1].c_str());
+
+    for (int i = 0; i < (nofNodeData - 1); i++)
+        strcat(nodeunits, "no_unit.");
+    strcat(nodeunits, "no_unit");
+
+    out.write((char *)&nodelabels, sizeof(nodelabels));
+    out.write((char *)&nodeunits, sizeof(nodeunits));
+
+    // nof and type of data
+    idummy = nofNodeData;
+    out.write((char *)&idummy, sizeof(int)); // Datentypen pro knoten (hier = nof_node_data, da NUR skalare)
+
+    idummy = 1;
+    for (int i = 0; i < nofNodeData; i++)
+        out.write((char *)&idummy, sizeof(int)); // jeder Datentyp ist ein skalarer Wert
+
+    // min and max of data
+    fdummy = 0.0;
+    for (int i = 0; i < nofNodeData; i++)
+        out.write((char *)&fdummy, sizeof(float)); // min Wert pro Datentyp
+    fdummy = 1.0;
+    for (int i = 0; i < nofNodeData; i++)
+        out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp
+
+    // daten ins file schreiben
+    for (int d = 0; d < nofNodeData; ++d)
+        for (int n = 0; n < (int)nodedata[d].size(); n++) {
+            fdummy = (float)nodedata[d][n];
+            out.write((char *)&fdummy, sizeof(float));
+        }
+
+    fdummy = 1.;
+    for (int i = 0; i < nofNodeData; i++)
+        out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp
+
+    // CELL DATA
+    char celllabels[1024];
+    char cellunits[1024];
+    strcpy(celllabels, "");
+    strcpy(cellunits, "");
+
+    for (int d = 0; d < nofCellData - 1; ++d) {
+        strcat(celllabels, celldatanames[d].c_str());
+        strcat(celllabels, ".");
+    }
+    strcat(celllabels, celldatanames[nofCellData - 1].c_str());
+
+    for (int d = 0; d < nofCellData - 1; ++d)
+        strcat(cellunits, "no_unit.");
+    strcat(cellunits, "no_unit");
+
+    out.write((char *)&celllabels, sizeof(celllabels));
+    out.write((char *)&cellunits, sizeof(cellunits));
+
+    // nof and type of data
+    idummy = nofCellData;
+    out.write((char *)&idummy, sizeof(int)); // Datentypen pro knoten (hier = nof_node_data, da NUR skalare)
+
+    idummy = 1;
+    for (int i = 0; i < nofCellData; i++)
+        out.write((char *)&idummy, sizeof(int)); // jeder Datentyp ist ein skalarer Wert
+
+    // min and max of data
+    fdummy = 0.0;
+    for (int i = 0; i < nofCellData; i++)
+        out.write((char *)&fdummy, sizeof(float)); // min Wert pro Datentyp
+    fdummy = 1.0;
+    for (int i = 0; i < nofCellData; i++)
+        out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp
+
+    // daten ins file schreiben
+    for (int d = 0; d < nofCellData; ++d)
+        for (int n = 0; n < (int)celldata[d].size(); n++) {
+            fdummy = (float)celldata[d][n];
+            out.write((char *)&fdummy, sizeof(float));
+        }
+
+    fdummy = 1.;
+    for (int i = 0; i < nofCellData; i++)
+        out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp
+
+    out.close();
+    UBLOG(logDEBUG1, "WbWriterAvsBinary::writeQuadsWithNodeAndCellData to " << avsfilename << " - end");
+
+    return avsfilename;
+}
+/*===============================================================================*/
+std::string WbWriterAvsBinary::writeOctsWithCellData(const string &filename, vector<UbTupleFloat3> &nodes,
+                                                     vector<UbTupleInt8> &cells, vector<string> &datanames,
+                                                     vector<vector<double>> &celldata)
+{
+    string avsfilename = filename + getFileExtension();
+    UBLOG(logDEBUG1, "WbWriterAvsBinary::writeOctsWithCellData to " << avsfilename << " - start");
+
+    ofstream out(avsfilename.c_str(), ios::out | ios::binary);
+    if (!out) {
+        out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!outfile) weiterhin true!!!
+        string path = UbSystem::getPathFromString(avsfilename);
+        if (path.size() > 0) {
+            UbSystem::makeDirectory(path);
+            out.open(avsfilename.c_str(), ios::out | ios::binary);
+        }
+        if (!out)
+            throw UbException(UB_EXARGS, "file konnte nicht geschrieben werden");
+    }
+
+    char magic = (char)7;
+    int idummy;
+    float fdummy;
+
+    int nofNodes = (int)nodes.size();
+    int nofCells = (int)cells.size();
+
+    int nofNodeData     = 0;
+    int nofCellData     = (int)datanames.size();
+    int nofModelData    = 0;
+    int cellType        = 7; //=hex
+    int nofNodesPerCell = 8;
+
+    out.write((char *)&magic, sizeof(char));
+    out.write((char *)&nofNodes, sizeof(int));
+    out.write((char *)&nofCells, sizeof(int));
+    out.write((char *)&nofNodeData, sizeof(int));
+    out.write((char *)&nofCellData, sizeof(int));
+    out.write((char *)&nofModelData, sizeof(int));
+
+    idummy = (int)nofCells * nofNodesPerCell;
+    out.write((char *)&idummy, sizeof(int)); //(nof nodes) * (nodes per cell)
+    for (int c = 0; c < nofCells; c++) {
+        idummy = c + 1;
+        out.write((char *)&idummy, sizeof(int)); // cell id
+        idummy = 1;
+        out.write((char *)&idummy, sizeof(int)); // mat
+        idummy = nofNodesPerCell;
+        out.write((char *)&idummy, sizeof(int)); // nodes per cell
+        idummy = cellType;
+        out.write((char *)&idummy, sizeof(int)); // cell type
+    }
+    // knotennummern der einzelnen zellen
+    for (int c = 0; c < nofCells; c++) {
+        idummy = val<1>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<2>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<3>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<4>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<5>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<6>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<7>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<8>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+    }
+
+    // coords
+    // x1-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<1>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // x2-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<2>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // x3-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<3>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // out<<"\n";
+
+    // CELL DATA
+    char labels[1024];
+    char units[1024];
+    strcpy(labels, "");
+    strcpy(units, "");
+
+    for (int d = 0; d < nofCellData - 1; ++d) {
+        strcat(labels, datanames[d].c_str());
+        strcat(labels, ".");
+    }
+    strcat(labels, datanames[nofCellData - 1].c_str());
+
+    for (int d = 0; d < nofCellData - 1; ++d)
+        strcat(units, "no_unit.");
+    strcat(units, "no_unit");
+
+    out.write((char *)&labels, sizeof(labels));
+    out.write((char *)&units, sizeof(units));
+
+    // nof and type of data
+    idummy = nofCellData;
+    out.write((char *)&idummy, sizeof(int)); // Datentypen pro knoten (hier = nof_node_data, da NUR skalare)
+
+    idummy = 1;
+    for (int i = 0; i < nofCellData; i++)
+        out.write((char *)&idummy, sizeof(int)); // jeder Datentyp ist ein skalarer Wert
+
+    // min and max of data
+    fdummy = 0.0;
+    for (int i = 0; i < nofCellData; i++)
+        out.write((char *)&fdummy, sizeof(float)); // min Wert pro Datentyp
+    fdummy = 1.0;
+    for (int i = 0; i < nofCellData; i++)
+        out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp
+
+    // daten ins file schreiben
+    for (int d = 0; d < nofCellData; ++d)
+        for (int n = 0; n < (int)celldata[d].size(); n++) {
+            fdummy = (float)celldata[d][n];
+            out.write((char *)&fdummy, sizeof(float));
+        }
+
+    fdummy = 1.;
+    for (int i = 0; i < nofCellData; i++)
+        out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp
+
+    out.close();
+    UBLOG(logDEBUG1, "WbWriterAvsBinary::writeOctsWithCellData to " << avsfilename << " - end");
+
+    return avsfilename;
+}
+/*===============================================================================*/
+std::string WbWriterAvsBinary::writeOctsWithNodeData(const string &filename, vector<UbTupleFloat3> &nodes,
+                                                     vector<UbTupleUInt8> &cells, vector<string> &datanames,
+                                                     vector<vector<double>> &nodedata)
+{
+    string avsfilename = filename + getFileExtension();
+    UBLOG(logDEBUG1, "WbWriterAvsBinary::writeOctsWithNodeData to " << avsfilename << " - start");
+
+    ofstream out(avsfilename.c_str(), ios::out | ios::binary);
+    if (!out) {
+        out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!outfile) weiterhin true!!!
+        string path = UbSystem::getPathFromString(avsfilename);
+        if (path.size() > 0) {
+            UbSystem::makeDirectory(path);
+            out.open(avsfilename.c_str(), ios::out | ios::binary);
+        }
+        if (!out)
+            throw UbException(UB_EXARGS, "file konnte nicht geschrieben werden");
+    }
+
+    if ((int)nodedata.size() == 0)
+        throw UbException(UB_EXARGS, "no nodedata!!!");
+    if (nodes.size() != nodedata[0].size())
+        throw UbException(UB_EXARGS, "nodedata != nofNodes!!!");
+
+    char magic = (char)7;
+    int idummy;
+    float fdummy;
+
+    int nofNodes = (int)nodes.size();
+    int nofCells = (int)cells.size();
+
+    int nofNodeData     = (int)datanames.size();
+    int nofCellData     = 0;
+    int nofModelData    = 0;
+    int cellType        = 7; //=hex
+    int nofNodesPerCell = 8;
+
+    out.write((char *)&magic, sizeof(char));
+    out.write((char *)&nofNodes, sizeof(int));
+    out.write((char *)&nofCells, sizeof(int));
+    out.write((char *)&nofNodeData, sizeof(int));
+    out.write((char *)&nofCellData, sizeof(int));
+    out.write((char *)&nofModelData, sizeof(int));
+
+    idummy = (int)nofCells * nofNodesPerCell;
+    out.write((char *)&idummy, sizeof(int)); //(nof nodes) * (nodes per cell)
+    for (int c = 0; c < nofCells; c++) {
+        idummy = c + 1;
+        out.write((char *)&idummy, sizeof(int)); // cell id
+        idummy = 1;
+        out.write((char *)&idummy, sizeof(int)); // mat
+        idummy = nofNodesPerCell;
+        out.write((char *)&idummy, sizeof(int)); // nodes per cell
+        idummy = cellType;
+        out.write((char *)&idummy, sizeof(int)); // cell type
+    }
+    // knotennummern der einzelnen zellen
+    for (int c = 0; c < nofCells; c++) {
+        idummy = val<1>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<2>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<3>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<4>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<5>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<6>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<7>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+        idummy = val<8>(cells[c]) + 1;
+        out.write((char *)&idummy, sizeof(int));
+    }
+
+    // coords
+    // x1-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<1>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // x2-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<2>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+    // x3-coords
+    for (int n = 0; n < nofNodes; n++) {
+        fdummy = (float)(val<3>(nodes[n]));
+        out.write((char *)&fdummy, sizeof(float));
+    }
+
+    // NODE DATA
+    char labels[1024];
+    char units[1024];
+    strcpy(labels, "");
+    strcpy(units, "");
+
+    for (int d = 0; d < nofNodeData - 1; ++d) {
+        strcat(labels, datanames[d].c_str());
+        strcat(labels, ".");
+    }
+    strcat(labels, datanames[nofNodeData - 1].c_str());
+
+    for (int i = 0; i < (nofNodeData - 1); i++)
+        strcat(units, "no_unit.");
+    strcat(units, "no_unit");
+
+    out.write((char *)&labels, sizeof(labels));
+    out.write((char *)&units, sizeof(units));
+
+    // nof and type of data
+    idummy = nofNodeData;
+    out.write((char *)&idummy, sizeof(int)); // Datentypen pro knoten (hier = nof_node_data, da NUR skalare)
+
+    idummy = 1;
+    for (int i = 0; i < nofNodeData; i++)
+        out.write((char *)&idummy, sizeof(int)); // jeder Datentyp ist ein skalarer Wert
+
+    // min and max of data
+    fdummy = 0.0;
+    for (int i = 0; i < nofNodeData; i++)
+        out.write((char *)&fdummy, sizeof(float)); // min Wert pro Datentyp
+    fdummy = 1.0;
+    for (int i = 0; i < nofNodeData; i++)
+        out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp
+
+    // daten ins file schreiben
+    for (int d = 0; d < nofNodeData; ++d)
+        for (int n = 0; n < (int)nodedata[d].size(); n++) {
+            fdummy = (float)nodedata[d][n];
+            out.write((char *)&fdummy, sizeof(float));
+        }
+
+    fdummy = 1.;
+    for (int i = 0; i < nofNodeData; i++)
+        out.write((char *)&fdummy, sizeof(float)); // max Wert pro Datentyp
+
+    out.close();
+    UBLOG(logDEBUG1, "WbWriterAvsBinary::writeOctsWithNodeData to " << avsfilename << " - end");
+
+    return avsfilename;
+}
diff --git a/src/basics/basics/writer/WbWriterAvsBinary.h b/src/basics/basics/writer/WbWriterAvsBinary.h
new file mode 100644
index 0000000000000000000000000000000000000000..ef6c73cacbfdac1d8ad500022ec2e3cafe0d373e
--- /dev/null
+++ b/src/basics/basics/writer/WbWriterAvsBinary.h
@@ -0,0 +1,116 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file WbWriterAvsBinary.h
+//! \ingroup writer
+//! \author Soeren Freudiger, Sebastian Geller
+//=======================================================================================
+#ifndef WBWRITERAVSBINARY_H
+#define WBWRITERAVSBINARY_H
+
+#include <basics/writer/WbWriter.h>
+
+class WbWriterAvsBinary : public WbWriter
+{
+public:
+    static WbWriterAvsBinary *getInstance()
+    {
+        static WbWriterAvsBinary instance;
+        return &instance;
+    }
+
+    WbWriterAvsBinary(const WbWriterAvsBinary &) = delete;
+    const WbWriterAvsBinary &operator=(const WbWriterAvsBinary &) = delete;
+
+private:
+    WbWriterAvsBinary() = default;
+
+public:
+    std::string getFileExtension() override { return ".bin.inp"; }
+
+    //////////////////////////////////////////////////////////////////////////
+    // lines
+    //     0 ---- 1
+    // nodenumbering must start with 0!
+    std::string writeLines(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                           std::vector<UbTupleInt2> &lines) override;
+
+    //////////////////////////////////////////////////////////////////////////
+    // triangles
+    // cell numbering:
+    //                    2
+    //
+    //                  0---1
+    // nodenumbering must start with 0!
+    std::string writeTriangles(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                               std::vector<UbTuple<int, int, int>> &triangles) override;
+    std::string writeTrianglesWithNodeData(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                                           std::vector<UbTupleInt3> &cells, std::vector<std::string> &datanames,
+                                           std::vector<std::vector<double>> &nodedata) override;
+
+    //////////////////////////////////////////////////////////////////////////
+    // quads
+    // cell numbering:
+    //                  3---2
+    //                  |   |
+    //                  0---1
+    // nodenumbering must start with 0!
+    std::string writeQuads(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                           std::vector<UbTupleInt4> &cells) override;
+    std::string writeQuadsWithNodeData(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                                       std::vector<UbTupleInt4> &cells, std::vector<std::string> &datanames,
+                                       std::vector<std::vector<double>> &nodedata) override;
+    std::string writeQuadsWithCellData(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                                       std::vector<UbTupleInt4> &cells, std::vector<std::string> &datanames,
+                                       std::vector<std::vector<double>> &celldata) override;
+    std::string writeQuadsWithNodeAndCellData(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                                              std::vector<UbTupleInt4> &cells, std::vector<std::string> &nodedatanames,
+                                              std::vector<std::vector<double>> &nodedata,
+                                              std::vector<std::string> &celldatanames,
+                                              std::vector<std::vector<double>> &celldata) override;
+
+    //////////////////////////////////////////////////////////////////////////
+    // octs
+    //     7 ---- 6
+    //    /|     /|
+    //   4 +--- 5 |
+    //   | |    | |
+    //   | 3 ---+ 2
+    //   |/     |/
+    //   0 ---- 1
+    std::string writeOcts(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                          std::vector<UbTupleInt8> &cells) override;
+    std::string writeOctsWithCellData(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                                      std::vector<UbTupleInt8> &cells, std::vector<std::string> &datanames,
+                                      std::vector<std::vector<double>> &celldata) override;
+    std::string writeOctsWithNodeData(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                                      std::vector<UbTupleUInt8> &cells, std::vector<std::string> &datanames,
+                                      std::vector<std::vector<double>> &nodedata) override;
+};
+
+#endif // WBWRITERAVSBINARY_H
diff --git a/src/basics/basics/writer/WbWriterBOBJ.cpp b/src/basics/basics/writer/WbWriterBOBJ.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..59ea865efc1a21f017a0804b40c8e6cb0089ff32
--- /dev/null
+++ b/src/basics/basics/writer/WbWriterBOBJ.cpp
@@ -0,0 +1,113 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file WbWriterBOBJ.cpp
+//! \ingroup writer
+//! \author Soeren Freudiger, Sebastian Geller
+//=======================================================================================
+#ifdef CAB_ZLIB
+#include <basics/utilities/UbLogger.h>
+#include <basics/writer/WbWriterBOBJ.h>
+#include <cstring>
+
+#include <zlib.h>
+
+using namespace std;
+/*===============================================================================*/
+std::string WbWriterBOBJ::writeTriangles(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                                         std::vector<UbTupleInt3> &triangles)
+{
+    string bobjFilename = filename + getFileExtension();
+    UBLOG(logDEBUG1, "WbWriterBOBJ::writeTriangles to " << bobjFilename << " - start");
+
+    gzFile gzf = gzopen(bobjFilename.c_str(), "wb1");
+
+    size_t nofNodes     = nodes.size();
+    size_t nofTriangles = triangles.size();
+
+    // write to file
+    size_t numVerts;
+    // double v[3];
+    if (sizeof(numVerts) != 4) {
+        throw UbException(UB_EXARGS, "danger...");
+    }
+    numVerts = nofNodes;
+    gzwrite(gzf, &numVerts, sizeof(numVerts));
+
+    for (size_t k = 0; k < nofNodes; k++) {
+        float vertp = val<1>(nodes[k]);
+        gzwrite(gzf, &vertp, sizeof(vertp));
+        vertp = val<2>(nodes[k]);
+        gzwrite(gzf, &vertp, sizeof(vertp));
+        vertp = val<3>(nodes[k]);
+        gzwrite(gzf, &vertp, sizeof(vertp));
+    }
+
+    // NORMAL VECTOR
+    // double n[3];
+    gzwrite(gzf, &numVerts, sizeof(numVerts));
+    for (size_t k = 0; k < nofNodes; k++) {
+        // poly->GetPointData()->GetNormals()->GetTuple(k, n);
+        float normp = 0.0; // n[0];
+        gzwrite(gzf, &normp, sizeof(normp));
+        normp = 0.0; // n[1];
+        gzwrite(gzf, &normp, sizeof(normp));
+        normp = 0.0; // n[2];
+        gzwrite(gzf, &normp, sizeof(normp));
+    }
+
+    // vtkIdType npts = 3;
+    // vtkIdType* pts;
+    size_t numTris = nofTriangles;
+    gzwrite(gzf, &numTris, sizeof(numTris));
+    for (size_t k = 0; k < nofTriangles /*(size_t)poly->GetNumberOfPolys()*/; k++) {
+        // poly->GetPolys()->GetNextCell(npts, pts);
+        // int triIndex = *pts;
+        // gzwrite(gzf, &triIndex, sizeof(triIndex));
+        // triIndex = *(pts+1);
+        // gzwrite(gzf, &triIndex, sizeof(triIndex));
+        // triIndex = *(pts+2);
+        // gzwrite(gzf, &triIndex, sizeof(triIndex));
+        // poly->GetPolys()->GetNextCell(npts, pts);
+        int triIndex = val<1>(triangles[k]); //*pts;
+        gzwrite(gzf, &triIndex, sizeof(triIndex));
+        triIndex = val<2>(triangles[k]); //*(pts+1);
+        gzwrite(gzf, &triIndex, sizeof(triIndex));
+        triIndex = val<3>(triangles[k]); //*(pts+2);
+        gzwrite(gzf, &triIndex, sizeof(triIndex));
+    }
+
+    gzclose(gzf);
+
+    UBLOG(logDEBUG1, "WbWriterBOBJ::writeTriangles to " << bobjFilename << " - end");
+
+    return bobjFilename;
+}
+/*===============================================================================*/
+
+#endif // CAB_ZLIB
diff --git a/src/basics/basics/writer/WbWriterBOBJ.h b/src/basics/basics/writer/WbWriterBOBJ.h
new file mode 100644
index 0000000000000000000000000000000000000000..591357ac6f861b39af617b3d4c8380de6be7dff6
--- /dev/null
+++ b/src/basics/basics/writer/WbWriterBOBJ.h
@@ -0,0 +1,79 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file WbWriterBOBJ.h
+//! \ingroup writer
+//! \author Soeren Freudiger, Sebastian Geller
+//=======================================================================================
+#ifdef CAB_ZLIB
+#ifndef WBWRITERBOBJ_H
+#define WBWRITERBOBJ_H
+
+#include <basics/writer/WbWriter.h>
+#include <string>
+
+class WbWriterBOBJ : public WbWriter
+{
+public:
+    OBCREATOR_EXT(WbWriterBOBJ)
+
+    static WbWriterBOBJ *getInstance()
+    {
+        static WbWriterBOBJ instance;
+        return &instance;
+    }
+
+private:
+    WbWriterBOBJ() : WbWriter()
+    {
+        if (sizeof(unsigned char) != 1)
+            throw UbException(UB_EXARGS, "error char  type mismatch");
+        if (sizeof(int) != 4)
+            throw UbException(UB_EXARGS, "error int   type mismatch");
+        if (sizeof(float) != 4)
+            throw UbException(UB_EXARGS, "error float type mismatch");
+    }
+    WbWriterBOBJ(const WbWriterBOBJ &);                  // no copy allowed
+    const WbWriterBOBJ &operator=(const WbWriterBOBJ &); // no copy allowed
+
+    static std::string pvdEndTag;
+
+public:
+    std::string getFileExtension() { return "BOBJ.gz"; }
+
+    std::string writeTriangles(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                               std::vector<UbTupleInt3> &triangles);
+};
+
+UB_AUTO_RUN_NAMED(
+    ObFactory<WbWriter>::getInstance()->addObCreator(ObSingletonCreatorImpl<WbWriterBOBJ, WbWriter>::getInstance()),
+    CAB_WbWriterVtkXmlASCII);
+
+#endif // WBWRITERBOBJ_H
+
+#endif // CAB_ZLIB
diff --git a/src/basics/basics/writer/WbWriterSunflow.cpp b/src/basics/basics/writer/WbWriterSunflow.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..61ecc8e567aa546b6c92c0a0f662714bee0a1746
--- /dev/null
+++ b/src/basics/basics/writer/WbWriterSunflow.cpp
@@ -0,0 +1,147 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file WbWriterSunflow.cpp
+//! \ingroup writer
+//! \author Soeren Freudiger, Sebastian Geller
+//=======================================================================================
+#include <basics/utilities/UbLogger.h>
+#include <basics/writer/WbWriterSunflow.h>
+#include <cstring>
+
+using namespace std;
+
+/*===============================================================================*/
+std::string WbWriterSunflow::writeTriangles(const string &filename, vector<UbTupleFloat3> &nodes,
+                                            vector<UbTupleInt3> &triangles)
+{
+    string sunflowFilename = filename + getFileExtension();
+    UBLOG(logDEBUG1, "WbWriterSunflow::writeTriangles to " << sunflowFilename << " - start");
+
+    std::ofstream out(sunflowFilename.c_str());
+    if (!out) {
+        out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!out) weiterhin true!!!
+        string path = UbSystem::getPathFromString(sunflowFilename);
+        if (path.size() > 0) {
+            UbSystem::makeDirectory(path);
+            out.open(sunflowFilename.c_str());
+        }
+        if (!out)
+            throw UbException(UB_EXARGS, "couldn't open file " + sunflowFilename);
+    }
+
+    // General part
+
+    // Image details
+    out << "image {" << endl;
+    out << "   resolution 640 480" << endl;
+    out << "   aa 0 1" << endl;
+    out << "   filter mitchell" << endl;
+    out << "}" << endl << endl;
+
+    // Camera position
+    out << "camera {" << endl;
+    out << "   type pinhole" << endl;
+    out << "   eye    -0.25 -0.3 0.13" << endl;
+    out << "   target -0.1 0.1 0.13" << endl;
+    out << "   up     0 0 1" << endl;
+    out << "   fov    60" << endl;
+    out << "   aspect 1.333333" << endl;
+    out << "}" << endl << endl;
+
+    // Light
+    out << "light {" << endl;
+    out << "   type ibl" << endl;
+    out << "   image sky_small.hdr" << endl;
+    out << "   center 0 -1 0" << endl;
+    out << "   up 0 0 1" << endl;
+    out << "   lock true" << endl;
+    out << "   samples 200" << endl;
+    out << "}" << endl << endl;
+
+    // Shaders
+    out << "shader {" << endl;
+    out << "   name default-shader" << endl;
+    out << "   type diffuse" << endl;
+    out << "   diff 0.25 0.25 0.25" << endl;
+    out << "}" << endl << endl;
+
+    out << "shader {" << endl;
+    out << "   name Glass" << endl;
+    out << "   type glass" << endl;
+    out << "   eta 1.333" << endl;
+    out << "   color 0.1 0.3 0.8" << endl;
+    out << "}" << endl << endl;
+
+    out << "shader {" << endl;
+    out << "   name Mirror" << endl;
+    out << "   type mirror" << endl;
+    out << "   refl 0.7 0.7 0.7" << endl;
+    out << "}" << endl << endl;
+
+    // Objects
+    // a) Ground plane
+    out << "object {" << endl;
+    out << "   shader default-shader" << endl;
+    out << "   type plane" << endl;
+    out << "   p 0 0 0" << endl;
+    out << "   n 0 0 1" << endl;
+    out << "}" << endl << endl;
+
+    // b) Mesh
+    out << "object {" << endl;
+    out << "   shader Glass" << endl;
+    out << "   transform {" << endl;
+    out << "      rotatey 270.0" << endl;
+    out << "   }" << endl;
+    out << "   type generic-mesh" << endl;
+    out << "      name polySurfac" << endl << endl;
+
+    // POINTS SECTION
+    int nofNodes = (int)nodes.size();
+    out << "   points " << nofNodes << endl;
+    for (int n = 0; n < nofNodes; n++)
+        out << "      " << val<1>(nodes[n]) << " " << val<2>(nodes[n]) << " " << val<3>(nodes[n]) << endl;
+
+    // TRIANGLES SECTION
+    int nofTriangles = (int)triangles.size();
+    out << "   triangles " << nofTriangles << endl;
+    for (int c = 0; c < nofTriangles; c++)
+        out << "      " << val<1>(triangles[c]) << " " << val<2>(triangles[c]) << " " << val<3>(triangles[c]) << endl;
+
+    // FOOTER
+    out << "   normals none" << endl;
+    out << "   uvs none" << endl;
+    out << "}" << endl;
+
+    out.close();
+    UBLOG(logDEBUG1, "WbWriterSunflow::writeTriangles to " << sunflowFilename << " - end");
+
+    return sunflowFilename;
+}
+/*===============================================================================*/
diff --git a/src/basics/basics/writer/WbWriterSunflow.h b/src/basics/basics/writer/WbWriterSunflow.h
new file mode 100644
index 0000000000000000000000000000000000000000..519a932f9088b535fb49e77770accd8364226096
--- /dev/null
+++ b/src/basics/basics/writer/WbWriterSunflow.h
@@ -0,0 +1,72 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file WbWriterSunflow.h
+//! \ingroup writer
+//! \author Soeren Freudiger, Sebastian Geller
+//=======================================================================================
+#ifndef WbWriterSunflow_H
+#define WbWriterSunflow_H
+
+#include <string>
+
+#include <basics/writer/WbWriter.h>
+
+class WbWriterSunflow : public WbWriter
+{
+public:
+    static WbWriterSunflow *getInstance()
+    {
+        static WbWriterSunflow instance;
+        return &instance;
+    }
+
+    WbWriterSunflow(const WbWriterSunflow &) = delete;
+    const WbWriterSunflow &operator=(const WbWriterSunflow &) = delete;
+
+private:
+    WbWriterSunflow() : WbWriter()
+    {
+        if (sizeof(unsigned char) != 1)
+            throw UbException(UB_EXARGS, "error char  type mismatch");
+        if (sizeof(int) != 4)
+            throw UbException(UB_EXARGS, "error int   type mismatch");
+        if (sizeof(float) != 4)
+            throw UbException(UB_EXARGS, "error float type mismatch");
+    }
+
+    static std::string pvdEndTag;
+
+public:
+    std::string getFileExtension() override { return "ascii.sunflow"; }
+
+    std::string writeTriangles(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                               std::vector<UbTupleInt3> &triangles) override;
+};
+
+#endif // WbWriterSunflow_H
diff --git a/src/basics/basics/writer/WbWriterTecPlotASCII.cpp b/src/basics/basics/writer/WbWriterTecPlotASCII.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ec7748d35ecea52b645a6cc654d52a6bb93fc874
--- /dev/null
+++ b/src/basics/basics/writer/WbWriterTecPlotASCII.cpp
@@ -0,0 +1,96 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file WbWriterTechPlotASCII.cpp
+//! \ingroup writer
+//! \author Soeren Freudiger, Sebastian Geller
+//=======================================================================================
+#include <basics/utilities/UbLogger.h>
+#include <basics/writer/WbWriterTecPlotASCII.h>
+
+using namespace std;
+
+/*===============================================================================*/
+string WbWriterTecPlotASCII::writeOctsWithNodeData(const string &filename, vector<UbTupleFloat3> &nodes,
+                                                   vector<UbTupleUInt8> &cells, vector<string> &datanames,
+                                                   vector<vector<double>> &nodedata)
+{
+    string tecplotfilename = filename + getFileExtension();
+    UBLOG(logDEBUG1, "WbWriterTecPlotASCII::writeOctsWithNodeData to " << tecplotfilename << " - start");
+
+    ofstream out(tecplotfilename.c_str());
+    if (!out) {
+        out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!out) weiterhin true!!!
+        string path = UbSystem::getPathFromString(tecplotfilename);
+        if (path.size() > 0) {
+            UbSystem::makeDirectory(path);
+            out.open(tecplotfilename.c_str());
+        }
+        if (!out)
+            throw UbException(UB_EXARGS, "couldn't open file " + tecplotfilename);
+    }
+
+    int nofNodes = (int)nodes.size();
+    int nofCells = (int)cells.size();
+
+    out << "TITLE = VirtualFluids OctGrid from " << UbSystem::getTimeStamp() << endl;
+
+    out << "VARIABLES = \"X\", \"Y\", \"Z\"";
+    for (size_t d = 0; d < datanames.size(); d++)
+        out << ", \"" << datanames[d] << "\"";
+    out << endl;
+
+    out << "ZONE NODES=" << nofNodes << ", ELEMENTS=" << nofCells << ", DATAPACKING=POINT, ZONETYPE=FEBRICK" << endl;
+    for (size_t n = 0; n < nodes.size(); n++) {
+        UbTupleFloat3 &coords = nodes[n];
+        out << val<1>(coords) << " " << val<2>(coords) << " " << val<3>(coords);
+        for (size_t d = 0; d < datanames.size(); d++)
+            out << " " << nodedata[d][n];
+        out << endl;
+    }
+
+    for (size_t c = 0; c < cells.size(); c++) {
+        UbTupleUInt8 &cell = cells[c];
+        out << val<1>(cell) << " " << val<2>(cell) << " " << val<3>(cell) << " " << val<4>(cell) << " " << val<5>(cell)
+            << " " << val<6>(cell) << " " << val<7>(cell) << " " << val<8>(cell) << endl;
+    }
+
+    out.close();
+    UBLOG(logDEBUG1, "WbWriterTecPlotASCII::writeOctsWithNodeData to " << tecplotfilename << " - end");
+
+    return tecplotfilename;
+}
+/*===============================================================================*/
+string WbWriterTecPlotASCII::writeOctsU(const string &filename, vector<UbTupleFloat3> &nodes,
+                                        vector<UbTupleUInt8> &cells)
+{
+    vector<string> datanames;
+    vector<vector<double>> nodedata;
+    return writeOctsWithNodeData(filename, nodes, cells, datanames, nodedata);
+}
+/*===============================================================================*/
diff --git a/src/basics/basics/writer/WbWriterTecPlotASCII.h b/src/basics/basics/writer/WbWriterTecPlotASCII.h
new file mode 100644
index 0000000000000000000000000000000000000000..31cac3cc49b60d66f932530eb4f36c1b8029304d
--- /dev/null
+++ b/src/basics/basics/writer/WbWriterTecPlotASCII.h
@@ -0,0 +1,139 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file WbWriterTechPlotASCII.h
+//! \ingroup writer
+//! \author Soeren Freudiger, Sebastian Geller
+//=======================================================================================
+#ifndef WBWRITERTECPLOTASCII_H
+#define WBWRITERTECPLOTASCII_H
+
+#include <string>
+
+#include <basics/writer/WbWriter.h>
+
+class WbWriterTecPlotASCII : public WbWriter
+{
+public:
+    static WbWriterTecPlotASCII *getInstance()
+    {
+        static WbWriterTecPlotASCII instance;
+        return &instance;
+    }
+
+    WbWriterTecPlotASCII(const WbWriterTecPlotASCII &) = delete;
+    const WbWriterTecPlotASCII &operator=(const WbWriterTecPlotASCII &) = delete;
+
+private:
+    WbWriterTecPlotASCII() : WbWriter()
+    {
+        if (sizeof(unsigned char) != 1)
+            throw UbException(UB_EXARGS, "machine error char  type mismatch");
+        if (sizeof(int) != 4)
+            throw UbException(UB_EXARGS, "machine error int   type mismatch");
+        if (sizeof(float) != 4)
+            throw UbException(UB_EXARGS, "machine error float type mismatch");
+    }
+
+    static std::string pvdEndTag;
+
+public:
+    std::string getFileExtension() override { return ".ascii.dat"; }
+
+    // write a metafile
+    //    std::string writeCollection(const std::string& filename, const std::vector<std::string>& filenames, const
+    //    double& timestep, const bool& sepGroups); std::string addFilesToCollection(const std::string& filename, const
+    //    std::vector<std::string>& filenames, const double& timestep, const bool& sepGroups); std::string
+    //    writeParallelFile(const std::string& filename,std::vector<std::string>& pieceSources,
+    //    std::vector<std::string>& pointDataNames, std::vector<std::string>& cellDataNames);
+
+    //////////////////////////////////////////////////////////////////////////
+    // nodes
+    //    std::string writeNodes(const std::string& filename,std::vector< UbTupleFloat3 >& nodes);
+    //    std::string writeNodesWithNodeData(const std::string& filename,std::vector< UbTupleFloat3 >& nodes,
+    //    std::vector<std::string >& datanames, std::vector<std::vector<double > >& nodedata);
+
+    //////////////////////////////////////////////////////////////////////////
+    // lines
+    //     0 ---- 1
+    // nodenumbering must start with 0!
+    //    std::string writeLines(const std::string& filename,std::vector<UbTupleFloat3 >& nodes, std::vector<UbTupleInt2
+    //    >& lines); std::string writeLinesWithNodeData(const std::string& filename,std::vector<UbTupleFloat3 >& nodes,
+    //    std::vector<UbTupleInt2 >& lines, std::vector< std::string >& datanames, std::vector< std::vector< double > >&
+    //    nodedata);
+    //
+    //////////////////////////////////////////////////////////////////////////
+    // triangles
+    //                    2
+    //
+    //                  0---1
+    // nodenumbering must start with 0!
+    //    std::string writeTriangles(const std::string& filename,std::vector<UbTupleFloat3 >& nodes,
+    //    std::vector<UbTupleInt3 >& triangles); std::string writeTrianglesWithNodeData(const std::string&
+    //    filename,std::vector< UbTupleFloat3 >& nodes, std::vector< UbTupleInt3 >& cells, std::vector<std::string >&
+    //    datanames, std::vector<std::vector<double > >& nodedata);
+
+    //////////////////////////////////////////////////////////////////////////
+    // 2D
+    // cell numbering:
+    //                  3---2
+    //                  |   |
+    //                  0---1
+    // nodenumbering must start with 0!
+
+    //    std::string writeQuads(const std::string& filename,std::vector< UbTupleFloat3 >& nodes, std::vector<
+    //    UbTupleInt4 >& cells); std::string writeQuadsWithNodeData(const std::string& filename,std::vector<
+    //    UbTupleFloat3 >& nodes, std::vector< UbTupleInt4 >& cells, std::vector< std::string >& datanames, std::vector<
+    //    std::vector< double > >& nodedata); std::string writeQuadsWithCellData(const std::string&
+    //    filename,std::vector< UbTupleFloat3 >& nodes, std::vector< UbTupleInt4 >& cells, std::vector< std::string >&
+    //    datanames, std::vector< std::vector< double > >& celldata); std::string writeQuadsWithNodeAndCellData(const
+    //    std::string& filename,std::vector< UbTupleFloat3 >& nodes, std::vector< UbTupleInt4 >& cells,
+    //                                              std::vector< std::string >& nodedatanames, std::vector< std::vector<
+    //                                              double > >& nodedata, std::vector< std::string >& celldatanames,
+    //                                              std::vector< std::vector< double > >& celldata );
+
+    //////////////////////////////////////////////////////////////////////////
+    // octs
+    //     7 ---- 6
+    //    /|     /|
+    //   4 +--- 5 |
+    //   | |    | |
+    //   | 3 ---+ 2
+    //   |/     |/
+    //   0 ---- 1
+    std::string writeOctsU(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                           std::vector<UbTupleUInt8> &cells);
+    // std::string writeOctsWithCellData(const std::string& filename,std::vector<UbTupleFloat3 >& nodes,
+    // std::vector<UbTupleInt8 >& cells, std::vector<std::string >& datanames, std::vector<std::vector<double > >&
+    // celldata);
+    std::string writeOctsWithNodeData(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                                      std::vector<UbTupleUInt8> &cells, std::vector<std::string> &datanames,
+                                      std::vector<std::vector<double>> &nodedata) override;
+};
+
+#endif // WBWRITERTECPLOTASCII_H
diff --git a/src/basics/basics/writer/WbWriterVtkASCII.cpp b/src/basics/basics/writer/WbWriterVtkASCII.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..dcd94f8203b1388e974fdcc3638dc3abff10cb67
--- /dev/null
+++ b/src/basics/basics/writer/WbWriterVtkASCII.cpp
@@ -0,0 +1,699 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file WbWriterVtkASCII.cpp
+//! \ingroup writer
+//! \author Soeren Freudiger, Sebastian Geller
+//=======================================================================================
+#include <basics/utilities/UbLogger.h>
+#include <basics/writer/WbWriterVtkASCII.h>
+#include <cstring>
+
+using namespace std;
+
+std::string WbWriterVtkASCII::writeQuads(const string &filename, vector<UbTupleFloat3> &nodes,
+                                         vector<UbTupleInt4> &cells)
+{
+    string vtkfilename = filename + getFileExtension();
+    UBLOG(logDEBUG1, "WbWriterVtkASCII::writeQuads to " << vtkfilename << " - start");
+
+    std::ofstream out(vtkfilename.c_str());
+    if (!out) {
+        out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!out) weiterhin true!!!
+        string path = UbSystem::getPathFromString(vtkfilename);
+        if (path.size() > 0) {
+            UbSystem::makeDirectory(path);
+            out.open(vtkfilename.c_str());
+        }
+        if (!out)
+            throw UbException(UB_EXARGS, "couldn't open file " + vtkfilename);
+    }
+
+    int nofNodes = (int)nodes.size();
+    int nofCells = (int)cells.size();
+
+    // VtkASCII FILE
+    out << "# vtk DataFile Version 4.0"
+        << "\n";
+    out << "GeoFile"
+        << "\n";
+    out << "ASCII"
+        << "\n";
+
+    // POINTS SECTION
+    out << "DATASET UNSTRUCTURED_GRID"
+        << "\n";
+    out << "POINTS " << nofNodes << " float"
+        << "\n";
+    for (int n = 0; n < nofNodes; n++)
+        out << val<1>(nodes[n]) << " " << val<2>(nodes[n]) << " " << val<3>(nodes[n]) << " \n";
+
+    out << "\n";
+
+    // CELLS SECTION
+    out << "CELLS " << nofCells << " " << 5 * nofCells << "\n";
+    for (int c = 0; c < (int)cells.size(); c++)
+        out << "4 " << val<1>(cells[c]) << " " << val<2>(cells[c]) << " " << val<4>(cells[c]) << " " << val<3>(cells[c])
+            << " \n";
+    out << "\n";
+
+    out << "CELL_TYPES " << nofCells << "\n";
+    for (int i = 0; i < nofCells; i++)
+        out << "8" << endl;
+    out << endl;
+
+    out.close();
+
+    UBLOG(logDEBUG1, "WbWriterVtkASCII::writeQuads to " << vtkfilename << " - end");
+
+    return vtkfilename;
+}
+/*===============================================================================*/
+std::string WbWriterVtkASCII::writeQuadsWithNodeData(const string &filename, vector<UbTupleFloat3> &nodes,
+                                                     vector<UbTupleInt4> &cells, vector<string> &datanames,
+                                                     vector<vector<double>> &nodedata)
+{
+    string vtkfilename = filename + getFileExtension();
+    UBLOG(logDEBUG1, "WbWriterVtkASCII::writeQuadsWithNodeData to " << vtkfilename << " - start");
+
+    std::ofstream out(vtkfilename.c_str());
+    if (!out) {
+        out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!out) weiterhin true!!!
+        string path = UbSystem::getPathFromString(vtkfilename);
+        if (path.size() > 0) {
+            UbSystem::makeDirectory(path);
+            out.open(vtkfilename.c_str());
+        }
+        if (!out)
+            throw UbException(UB_EXARGS, "couldn't open file " + vtkfilename);
+    }
+
+    // write geo
+    int nofNodes = (int)nodes.size();
+    int nofCells = (int)cells.size();
+
+    // VtkASCII FILE
+    out << "# vtk DataFile Version 4.0"
+        << "\n";
+    out << "GeoFile"
+        << "\n";
+    out << "ASCII"
+        << "\n";
+
+    // POINTS SECTION
+    out << "DATASET UNSTRUCTURED_GRID"
+        << "\n";
+    out << "POINTS " << nofNodes << " float"
+        << "\n";
+    for (int n = 0; n < nofNodes; n++)
+        out << val<1>(nodes[n]) << " " << val<2>(nodes[n]) << " " << val<3>(nodes[n]) << " \n";
+
+    out << "\n";
+
+    // CELLS SECTION
+    out << "CELLS " << nofCells << " " << 5 * nofCells << "\n";
+    for (int c = 0; c < (int)cells.size(); c++)
+        out << "4 " << val<1>(cells[c]) << " " << val<2>(cells[c]) << " " << val<4>(cells[c]) << " " << val<3>(cells[c])
+            << " \n";
+    out << "\n";
+
+    out << "CELL_TYPES " << nofCells << "\n";
+    for (int i = 0; i < nofCells; i++)
+        out << "8" << endl;
+    out << endl;
+
+    // write data section
+    out << "POINT_DATA " << nofNodes << "\n";
+    for (int s = 0; s < (int)datanames.size(); ++s) {
+        out << "SCALARS " << datanames[s] << " float 1 \n LOOKUP_TABLE default \n";
+        for (int d = 0; d < (int)nodedata[s].size(); d++)
+            out << nodedata[s][d] << "\n";
+
+        out << endl;
+    }
+
+    out.close();
+    UBLOG(logDEBUG1, "WbWriterVtkASCII::writeQuadsWithNodeData to " << vtkfilename << " - end");
+    return vtkfilename;
+}
+/*===============================================================================*/
+std::string WbWriterVtkASCII::writeQuadsWithCellData(const string &filename, vector<UbTupleFloat3> &nodes,
+                                                     vector<UbTupleInt4> &cells, vector<string> &datanames,
+                                                     vector<vector<double>> &celldata)
+{
+    string vtkfilename = filename + getFileExtension();
+    UBLOG(logDEBUG1, "WbWriterVtkASCII::writeQuadsWithCellData to " << vtkfilename << " - start");
+
+    std::ofstream out(vtkfilename.c_str());
+    if (!out) {
+        out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!out) weiterhin true!!!
+        string path = UbSystem::getPathFromString(vtkfilename);
+        if (path.size() > 0) {
+            UbSystem::makeDirectory(path);
+            out.open(vtkfilename.c_str());
+        }
+        if (!out)
+            throw UbException(UB_EXARGS, "couldn't open file " + vtkfilename);
+    }
+
+    // write geo
+    int nofNodes = (int)nodes.size();
+    int nofCells = (int)cells.size();
+
+    // VtkASCII FILE
+    out << "# vtk DataFile Version 4.0"
+        << "\n";
+    out << "GeoFile"
+        << "\n";
+    out << "ASCII"
+        << "\n";
+
+    // POINTS SECTION
+    out << "DATASET UNSTRUCTURED_GRID"
+        << "\n";
+    out << "POINTS " << nofNodes << " float"
+        << "\n";
+    for (int n = 0; n < nofNodes; n++)
+        out << val<1>(nodes[n]) << " " << val<2>(nodes[n]) << " " << val<3>(nodes[n]) << " \n";
+
+    out << "\n";
+
+    // CELLS SECTION
+    out << "CELLS " << nofCells << " " << 5 * nofCells << "\n";
+    for (int c = 0; c < (int)cells.size(); c++)
+        out << "4 " << val<1>(cells[c]) << " " << val<2>(cells[c]) << " " << val<4>(cells[c]) << " " << val<3>(cells[c])
+            << " \n";
+    out << "\n";
+
+    out << "CELL_TYPES " << nofCells << "\n";
+    for (int i = 0; i < nofCells; i++)
+        out << "8" << endl;
+    out << endl;
+
+    // write data section
+    out << "CELL_DATA " << nofCells << "\n";
+    for (int s = 0; s < (int)datanames.size(); ++s) {
+        out << "SCALARS " << datanames[s] << " float 1 \n LOOKUP_TABLE default \n";
+        for (int d = 0; d < (int)celldata[s].size(); d++)
+            out << celldata[s][d] << "\n";
+
+        out << endl;
+    }
+
+    out.close();
+    UBLOG(logDEBUG1, "WbWriterVtkASCII::writeQuadsWithCellData to " << vtkfilename << " - end");
+    return vtkfilename;
+}
+/*===============================================================================*/
+std::string WbWriterVtkASCII::writeQuadsWithNodeAndCellData(const string &filename, vector<UbTupleFloat3> &nodes,
+                                                            vector<UbTupleInt4> &cells, vector<string> &nodedatanames,
+                                                            vector<vector<double>> &nodedata,
+                                                            vector<string> &celldatanames,
+                                                            vector<vector<double>> &celldata)
+{
+    string vtkfilename = filename + getFileExtension();
+    UBLOG(logDEBUG1, "WbWriterVtkASCII::writeQuadsWithNodeAndCellData to " << vtkfilename << " - start");
+
+    std::ofstream out(vtkfilename.c_str());
+    if (!out) {
+        out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!out) weiterhin true!!!
+        string path = UbSystem::getPathFromString(vtkfilename);
+        if (path.size() > 0) {
+            UbSystem::makeDirectory(path);
+            out.open(vtkfilename.c_str());
+        }
+        if (!out)
+            throw UbException(UB_EXARGS, "couldn't open file " + vtkfilename);
+    }
+
+    // write geo
+    int nofNodes = (int)nodes.size();
+    int nofCells = (int)cells.size();
+
+    // VtkASCII FILE
+    out << "# vtk DataFile Version 4.0"
+        << "\n";
+    out << "GeoFile"
+        << "\n";
+    out << "ASCII"
+        << "\n";
+
+    // POINTS SECTION
+    out << "DATASET UNSTRUCTURED_GRID"
+        << "\n";
+    out << "POINTS " << nofNodes << " float"
+        << "\n";
+    for (int n = 0; n < nofNodes; n++)
+        out << val<1>(nodes[n]) << " " << val<2>(nodes[n]) << " " << val<3>(nodes[n]) << " \n";
+
+    out << "\n";
+
+    // CELLS SECTION
+    out << "CELLS " << nofCells << " " << 5 * nofCells << "\n";
+    for (int c = 0; c < (int)cells.size(); c++)
+        out << "4 " << val<1>(cells[c]) << " " << val<2>(cells[c]) << " " << val<4>(cells[c]) << " " << val<3>(cells[c])
+            << " \n";
+    out << "\n";
+
+    out << "CELL_TYPES " << nofCells << "\n";
+    for (int i = 0; i < nofCells; i++)
+        out << "8" << endl;
+    out << endl;
+
+    // write node data section
+    out << "POINT_DATA " << nofNodes << "\n";
+    for (int s = 0; s < (int)nodedatanames.size(); ++s) {
+        out << "SCALARS " << nodedatanames[s] << " float 1 \n LOOKUP_TABLE default \n";
+        for (int d = 0; d < (int)nodedata[s].size(); d++)
+            out << nodedata[s][d] << "\n";
+
+        out << endl;
+    }
+
+    // write cell data section
+    out << "CELL_DATA " << nofCells << "\n";
+    for (int s = 0; s < (int)celldatanames.size(); ++s) {
+        out << "SCALARS " << celldatanames[s] << " float 1 \n LOOKUP_TABLE default \n";
+        for (int d = 0; d < (int)celldata[s].size(); d++)
+            out << celldata[s][d] << "\n";
+
+        out << endl;
+    }
+
+    out.close();
+    UBLOG(logDEBUG1, "WbWriterVtkASCII::writeQuadsWithNodeAndCellData to " << vtkfilename << " - end");
+    return vtkfilename;
+}
+/*===============================================================================*/
+std::string WbWriterVtkASCII::writeLines(const string &filename, vector<UbTupleFloat3> &nodes,
+                                         vector<UbTupleInt2> &lines)
+{
+    string vtkfilename = filename + getFileExtension();
+    UBLOG(logDEBUG1, "WbWriterVtkASCII::writeLines to " << vtkfilename << " - start");
+
+    std::ofstream out(vtkfilename.c_str());
+    if (!out) {
+        out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!out) weiterhin true!!!
+        string path = UbSystem::getPathFromString(vtkfilename);
+        if (path.size() > 0) {
+            UbSystem::makeDirectory(path);
+            out.open(vtkfilename.c_str());
+        }
+        if (!out)
+            throw UbException(UB_EXARGS, "couldn't open file " + vtkfilename);
+    }
+
+    int nofNodes = (int)nodes.size();
+    int nofLines = (int)lines.size();
+
+    // VtkASCII FILE
+    out << "# vtk DataFile Version 4.0"
+        << "\n";
+    out << "GeoFile"
+        << "\n";
+    out << "ASCII"
+        << "\n";
+
+    // POINTS SECTION
+    out << "DATASET UNSTRUCTURED_GRID"
+        << "\n";
+    out << "POINTS " << nofNodes << " float"
+        << "\n";
+    for (int n = 0; n < nofNodes; n++) {
+        out << val<1>(nodes[n]) << " " << val<2>(nodes[n]) << " " << val<3>(nodes[n]) << " \n";
+    }
+    out << "\n";
+
+    // CELLS SECTION
+    out << "CELLS " << nofLines << " " << 3 * nofLines << "\n";
+    int nr = 0;
+    for (int l = 0; l < nofLines; l++) {
+        int el = nr + 1;
+        out << "2 " << val<1>(lines[l]) << " " << val<2>(lines[l]) << " " << endl;
+        nr = el + 1;
+    }
+    out << "\n";
+
+    out << "CELL_TYPES " << nofLines << "\n";
+    for (int l = 0; l < nofLines; l++)
+        out << "3" << endl;
+    out << endl;
+
+    out.close();
+
+    UBLOG(logDEBUG1, "WbWriterVtkASCII::writeLines to " << vtkfilename << " - end");
+    return vtkfilename;
+}
+/*===============================================================================*/
+std::string WbWriterVtkASCII::writeTriangles(const string &filename, vector<UbTupleFloat3> &nodes,
+                                             vector<UbTupleInt3> &triangles)
+{
+    string vtkfilename = filename + getFileExtension();
+    UBLOG(logDEBUG1, "WbWriterVtkASCII::writeTriangles to " << vtkfilename << " - start");
+
+    std::ofstream out(vtkfilename.c_str());
+    if (!out) {
+        out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!out) weiterhin true!!!
+        string path = UbSystem::getPathFromString(vtkfilename);
+        if (path.size() > 0) {
+            UbSystem::makeDirectory(path);
+            out.open(vtkfilename.c_str());
+        }
+        if (!out)
+            throw UbException(UB_EXARGS, "couldn't open file " + vtkfilename);
+    }
+
+    int nofNodes     = (int)nodes.size();
+    int nofTriangles = (int)triangles.size();
+
+    // VtkASCII FILE
+    out << "# vtk DataFile Version 4.0"
+        << "\n";
+    out << "GeoFile"
+        << "\n";
+    out << "ASCII"
+        << "\n";
+
+    // POINTS SECTION
+    out << "DATASET UNSTRUCTURED_GRID"
+        << "\n";
+    out << "POINTS " << nofNodes << " float"
+        << "\n";
+    for (int n = 0; n < nofNodes; n++) {
+        out << val<1>(nodes[n]) << " " << val<2>(nodes[n]) << " " << val<3>(nodes[n]) << " \n";
+    }
+    out << "\n";
+
+    // CELLS SECTION
+    out << "CELLS " << nofTriangles << " " << 4 * nofTriangles << "\n";
+    int nr = 0;
+    for (int t = 0; t < nofTriangles; t++) {
+        int el = nr + 1;
+        out << "3 " << val<1>(triangles[t]) << " " << val<2>(triangles[t]) << " " << val<3>(triangles[t]) << " "
+            << endl;
+        nr = el + 1;
+    }
+    out << "\n";
+
+    out << "CELL_TYPES " << nofTriangles << "\n";
+    for (int l = 0; l < nofTriangles; l++)
+        out << "5" << endl;
+    out << endl;
+
+    out.close();
+
+    UBLOG(logDEBUG1, "WbWriterVtkASCII::writeTriangles to " << vtkfilename << " - end");
+    return vtkfilename;
+}
+/*===============================================================================*/
+std::string WbWriterVtkASCII::writeTrianglesWithNodeData(const string &filename, vector<UbTupleFloat3> &nodes,
+                                                         vector<UbTupleInt3> &cells, vector<string> &datanames,
+                                                         vector<vector<double>> &nodedata)
+{
+    string vtkfilename = filename + getFileExtension();
+    UBLOG(logDEBUG1, "WbWriterVtkASCII::writeTrianglesWithNodeData to " << vtkfilename << " - start");
+
+    std::ofstream out(vtkfilename.c_str());
+    if (!out) {
+        out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!out) weiterhin true!!!
+        string path = UbSystem::getPathFromString(vtkfilename);
+        if (path.size() > 0) {
+            UbSystem::makeDirectory(path);
+            out.open(vtkfilename.c_str());
+        }
+        if (!out)
+            throw UbException(UB_EXARGS, "couldn't open file " + vtkfilename);
+    }
+
+    // write geo
+    int nofNodes = (int)nodes.size();
+    int nofCells = (int)cells.size();
+
+    // VtkASCII FILE
+    out << "# vtk DataFile Version 4.0"
+        << "\n";
+    out << "GeoFile"
+        << "\n";
+    out << "ASCII"
+        << "\n";
+
+    // POINTS SECTION
+    out << "DATASET UNSTRUCTURED_GRID"
+        << "\n";
+    out << "POINTS " << nofNodes << " float"
+        << "\n";
+    for (int n = 0; n < nofNodes; n++)
+        out << val<1>(nodes[n]) << " " << val<2>(nodes[n]) << " " << val<3>(nodes[n]) << " \n";
+
+    out << "\n";
+
+    // CELLS SECTION
+    out << "CELLS " << nofCells << " " << 4 * nofCells << "\n";
+    for (int c = 0; c < (int)cells.size(); c++)
+        out << "3 " << val<1>(cells[c]) << " " << val<2>(cells[c]) << " " << val<3>(cells[c]) << " \n";
+    out << "\n";
+
+    out << "CELL_TYPES " << nofCells << "\n";
+    for (int i = 0; i < nofCells; i++)
+        out << "5" << endl;
+    out << endl;
+
+    // write data section
+    out << "POINT_DATA " << nofNodes << "\n";
+    for (int s = 0; s < (int)datanames.size(); ++s) {
+        out << "SCALARS " << datanames[s] << " float 1 \n LOOKUP_TABLE default \n";
+        for (int d = 0; d < (int)nodedata[s].size(); d++)
+            out << nodedata[s][d] << "\n";
+
+        out << endl;
+    }
+
+    out.close();
+    UBLOG(logDEBUG1, "WbWriterVtkASCII::writeTrianglesWithNodeData to " << vtkfilename << " - end");
+    return vtkfilename;
+}
+/*===============================================================================*/
+std::string WbWriterVtkASCII::writeOctsWithCellData(const string &filename, vector<UbTupleFloat3> &nodes,
+                                                    vector<UbTupleInt8> &cells, vector<string> &datanames,
+                                                    vector<vector<double>> &celldata)
+{
+    string vtkfilename = filename + getFileExtension();
+    UBLOG(logDEBUG1, "WbWriterVtkASCII::writeOctsWithCellData to " << vtkfilename << " - start");
+
+    std::ofstream out(vtkfilename.c_str());
+    if (!out) {
+        out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!out) weiterhin true!!!
+        string path = UbSystem::getPathFromString(vtkfilename);
+        if (path.size() > 0) {
+            UbSystem::makeDirectory(path);
+            out.open(vtkfilename.c_str());
+        }
+        if (!out)
+            throw UbException(UB_EXARGS, "couldn't open file " + vtkfilename);
+    }
+
+    // write geo
+    int nofNodes = (int)nodes.size();
+    int nofCells = (int)cells.size();
+
+    // VtkASCII FILE
+    out << "# vtk DataFile Version 4.0"
+        << "\n";
+    out << "GeoFile"
+        << "\n";
+    out << "ASCII"
+        << "\n";
+
+    // POINTS SECTION
+    out << "DATASET UNSTRUCTURED_GRID"
+        << "\n";
+    out << "POINTS " << nofNodes << " float"
+        << "\n";
+    for (int n = 0; n < nofNodes; n++)
+        out << val<1>(nodes[n]) << " " << val<2>(nodes[n]) << " " << val<3>(nodes[n]) << " \n";
+
+    out << "\n";
+
+    // CELLS SECTION
+    out << "CELLS " << nofCells << " " << 9 * nofCells << "\n";
+    for (int c = 0; c < (int)cells.size(); c++) {
+        out << "8 " << val<1>(cells[c]) << " " << val<2>(cells[c]) << " " << val<4>(cells[c]) << " " << val<3>(cells[c])
+            << " " << val<5>(cells[c]) << " " << val<6>(cells[c]) << " " << val<8>(cells[c]) << " " << val<7>(cells[c])
+            << " \n";
+    }
+
+    out << "\n";
+
+    out << "CELL_TYPES " << nofCells << "\n";
+    for (int i = 0; i < nofCells; i++)
+        out << "11 " << endl;
+    out << endl;
+
+    // write data section
+    out << "CELL_DATA " << nofCells << "\n";
+    for (int s = 0; s < (int)datanames.size(); ++s) {
+        out << "SCALARS " << datanames[s] << " float 1 \n LOOKUP_TABLE default \n";
+        for (int d = 0; d < (int)celldata[s].size(); d++)
+            out << celldata[s][d] << "\n";
+
+        out << endl;
+    }
+
+    out.close();
+    UBLOG(logDEBUG1, "WbWriterVtkASCII::writeOctsWithCellData to " << vtkfilename << " - end");
+
+    return vtkfilename;
+}
+/*===============================================================================*/
+std::string WbWriterVtkASCII::writeOctsWithNodeData(const string &filename, vector<UbTupleFloat3> &nodes,
+                                                    vector<UbTupleUInt8> &cells, vector<string> &datanames,
+                                                    vector<vector<double>> &nodedata)
+{
+    string vtkfilename = filename + getFileExtension();
+    UBLOG(logDEBUG1, "WbWriterVtkASCII::writeOctsWithNodeData to " << vtkfilename << " - start");
+
+    std::ofstream out(vtkfilename.c_str());
+    if (!out) {
+        out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!out) weiterhin true!!!
+        string path = UbSystem::getPathFromString(vtkfilename);
+        if (path.size() > 0) {
+            UbSystem::makeDirectory(path);
+            out.open(vtkfilename.c_str());
+        }
+        if (!out)
+            throw UbException(UB_EXARGS, "couldn't open file " + vtkfilename);
+    }
+
+    // write geo
+    int nofNodes = (int)nodes.size();
+    int nofCells = (int)cells.size();
+
+    // VtkASCII FILE
+    out << "# vtk DataFile Version 4.0"
+        << "\n";
+    out << "GeoFile"
+        << "\n";
+    out << "ASCII"
+        << "\n";
+
+    // POINTS SECTION
+    out << "DATASET UNSTRUCTURED_GRID"
+        << "\n";
+    out << "POINTS " << nofNodes << " float"
+        << "\n";
+    for (int n = 0; n < nofNodes; n++)
+        out << val<1>(nodes[n]) << " " << val<2>(nodes[n]) << " " << val<3>(nodes[n]) << " \n";
+
+    out << "\n";
+
+    // CELLS SECTION
+    out << "CELLS " << nofCells << " " << 9 * nofCells << "\n";
+    for (int c = 0; c < (int)cells.size(); c++) {
+        out << "8 " << val<1>(cells[c]) << " " << val<2>(cells[c]) << " " << val<4>(cells[c]) << " " << val<3>(cells[c])
+            << " " << val<5>(cells[c]) << " " << val<6>(cells[c]) << " " << val<8>(cells[c]) << " " << val<7>(cells[c])
+            << " \n";
+    }
+    out << "\n";
+
+    out << "CELL_TYPES " << nofCells << "\n";
+    for (int i = 0; i < nofCells; i++)
+        out << "11" << endl;
+    out << endl;
+
+    // write data section
+    out << "POINT_DATA " << nofNodes << "\n";
+    for (int s = 0; s < (int)datanames.size(); ++s) {
+        out << "SCALARS " << datanames[s] << " float 1 \n LOOKUP_TABLE default \n";
+        for (int d = 0; d < (int)nodedata[s].size(); d++)
+            out << nodedata[s][d] << "\n";
+
+        out << endl;
+    }
+
+    out.close();
+    UBLOG(logDEBUG1, "WbWriterVtkASCII::writeOctsWithNodeData to " << vtkfilename << " - end");
+    return vtkfilename;
+}
+/*===============================================================================*/
+std::string WbWriterVtkASCII::writeOcts(const string &filename, vector<UbTupleFloat3> &nodes,
+                                        vector<UbTupleInt8> &cells)
+{
+    string vtkfilename = filename + getFileExtension();
+    UBLOG(logDEBUG1, "WbWriterVtkASCII::writeOcts to " << vtkfilename << " - start");
+
+    std::ofstream out(vtkfilename.c_str());
+    if (!out) {
+        out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!out) weiterhin true!!!
+        string path = UbSystem::getPathFromString(vtkfilename);
+        if (path.size() > 0) {
+            UbSystem::makeDirectory(path);
+            out.open(vtkfilename.c_str());
+        }
+        if (!out)
+            throw UbException(UB_EXARGS, "couldn't open file " + vtkfilename);
+    }
+
+    int nofNodes = (int)nodes.size();
+    int nofCells = (int)cells.size();
+
+    // VtkASCII FILE
+    out << "# vtk DataFile Version 4.0"
+        << "\n";
+    out << "GeoFile"
+        << "\n";
+    out << "ASCII"
+        << "\n";
+
+    // POINTS SECTION
+    out << "DATASET UNSTRUCTURED_GRID"
+        << "\n";
+    out << "POINTS " << nofNodes << " float"
+        << "\n";
+    for (int n = 0; n < nofNodes; n++)
+        out << val<1>(nodes[n]) << " " << val<2>(nodes[n]) << " " << val<3>(nodes[n]) << " \n";
+
+    out << "\n";
+
+    // CELLS SECTION
+    out << "CELLS " << nofCells << " " << 9 * nofCells << "\n";
+    for (int c = 0; c < (int)cells.size(); c++)
+        out << "8 " << val<1>(cells[c]) << " " << val<2>(cells[c]) << " " << val<4>(cells[c]) << " " << val<3>(cells[c])
+            << " " << val<5>(cells[c]) << " " << val<6>(cells[c]) << " " << val<8>(cells[c]) << " " << val<7>(cells[c])
+            << " \n";
+    out << "\n";
+
+    out << "CELL_TYPES " << nofCells << "\n";
+    for (int i = 0; i < nofCells; i++)
+        out << "11" << endl;
+    out << endl;
+
+    out.close();
+
+    UBLOG(logDEBUG1, "WbWriterVtkASCII::writeOcts to " << vtkfilename << " - end");
+    return vtkfilename;
+}
diff --git a/src/basics/basics/writer/WbWriterVtkASCII.h b/src/basics/basics/writer/WbWriterVtkASCII.h
new file mode 100644
index 0000000000000000000000000000000000000000..f041a45eba07e32af59b490b11ca2c041a822339
--- /dev/null
+++ b/src/basics/basics/writer/WbWriterVtkASCII.h
@@ -0,0 +1,117 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file WbWriterVtkASCII.h
+//! \ingroup writer
+//! \author Soeren Freudiger, Sebastian Geller
+//=======================================================================================
+#ifndef WBWRITERVTKASCII_H
+#define WBWRITERVTKASCII_H
+
+#include <basics/writer/WbWriter.h>
+
+class WbWriterVtkASCII : public WbWriter
+{
+public:
+    static WbWriterVtkASCII *getInstance()
+    {
+        static WbWriterVtkASCII instance;
+        return &instance;
+    }
+
+private:
+    WbWriterVtkASCII() : WbWriter() {}
+    WbWriterVtkASCII(const WbWriterVtkASCII &);                  // no copy allowed
+    const WbWriterVtkASCII &operator=(const WbWriterVtkASCII &); // no copy allowed
+
+public:
+    std::string getFileExtension() override { return ".ascii.vtk"; }
+
+    //////////////////////////////////////////////////////////////////////////
+    // lines
+    //     0 ---- 1
+    // nodenumbering must start with 0!
+    std::string writeLines(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                           std::vector<UbTupleInt2> &lines) override;
+
+    //////////////////////////////////////////////////////////////////////////
+    // triangles
+    // cell numbering:
+    //                    2
+    //
+    //                  0---1
+    // nodenumbering must start with 0!
+    std::string writeTriangles(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                               std::vector<UbTupleInt3> &cells) override;
+    std::string writeTrianglesWithNodeData(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                                           std::vector<UbTupleInt3> &cells, std::vector<std::string> &datanames,
+                                           std::vector<std::vector<double>> &nodedata) override;
+
+    //////////////////////////////////////////////////////////////////////////
+    // 2D
+    // cell numbering:
+    //                  3---2
+    //                  |   |
+    //                  0---1
+    // nodenumbering must start with 0!
+    std::string writeQuads(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                           std::vector<UbTupleInt4> &cells) override;
+    std::string writeQuadsWithNodeData(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                                       std::vector<UbTupleInt4> &cells, std::vector<std::string> &datanames,
+                                       std::vector<std::vector<double>> &nodedata) override;
+    std::string writeQuadsWithCellData(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                                       std::vector<UbTupleInt4> &cells, std::vector<std::string> &datanames,
+                                       std::vector<std::vector<double>> &celldata) override;
+    std::string writeQuadsWithNodeAndCellData(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                                              std::vector<UbTupleInt4> &cells, std::vector<std::string> &nodedatanames,
+                                              std::vector<std::vector<double>> &nodedata,
+                                              std::vector<std::string> &celldatanames,
+                                              std::vector<std::vector<double>> &celldata) override;
+
+    //////////////////////////////////////////////////////////////////////////
+    // octs
+    //     7 ---- 6
+    //    /|     /|
+    //   4 +--- 5 |
+    //   | |    | |
+    //   | 3 ---+ 2
+    //   |/     |/
+    //   0 ---- 1
+    std::string writeOcts(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                          std::vector<UbTupleInt8> &cells) override;
+    std::string writeOctsBinary(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                                std::vector<UbTupleInt8> &cells);
+    std::string writeOctsWithCellData(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                                      std::vector<UbTupleInt8> &cells, std::vector<std::string> &datanames,
+                                      std::vector<std::vector<double>> &celldata) override;
+    std::string writeOctsWithNodeData(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                                      std::vector<UbTupleUInt8> &cells, std::vector<std::string> &datanames,
+                                      std::vector<std::vector<double>> &nodedata) override;
+};
+
+#endif // WBWRITERVTKASCII_H
diff --git a/src/basics/basics/writer/WbWriterVtkBinary.cpp b/src/basics/basics/writer/WbWriterVtkBinary.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0b1507e7a5f2c9cb22128c06dd9112541c642504
--- /dev/null
+++ b/src/basics/basics/writer/WbWriterVtkBinary.cpp
@@ -0,0 +1,850 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file WbWriterVtkBinary.cpp
+//! \ingroup writer
+//! \author Soeren Freudiger, Sebastian Geller
+//=======================================================================================
+#include <basics/utilities/UbLogger.h>
+#include <basics/writer/WbWriterVtkASCII.h>
+#include <basics/writer/WbWriterVtkBinary.h>
+#include <cstring>
+
+using namespace std;
+
+std::string WbWriterVtkBinary::writeLines(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                                          std::vector<UbTupleInt2> &lines)
+{
+    return WbWriterVtkASCII::getInstance()->writeLines(filename, nodes, lines);
+}
+/*===============================================================================*/
+std::string WbWriterVtkBinary::writeTriangles(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                                              std::vector<UbTupleInt3> &cells)
+{
+    return WbWriterVtkASCII::getInstance()->writeTriangles(filename, nodes, cells);
+}
+/*===============================================================================*/
+std::string WbWriterVtkBinary::writeTrianglesWithNodeData(const std::string &filename,
+                                                          std::vector<UbTupleFloat3> &nodes,
+                                                          std::vector<UbTupleInt3> &cells,
+                                                          std::vector<std::string> &datanames,
+                                                          std::vector<std::vector<double>> &nodedata)
+{
+    return WbWriterVtkASCII::getInstance()->writeTrianglesWithNodeData(filename, nodes, cells, datanames, nodedata);
+}
+/*===============================================================================*/
+std::string WbWriterVtkBinary::writeQuads(const string &filename, vector<UbTupleFloat3> &nodes,
+                                          vector<UbTupleInt4> &cells)
+{
+    string vtkfilename = filename + getFileExtension();
+    UBLOG(logDEBUG1, "WbWriterVtkBinary::writeQuads to " << vtkfilename << " - start");
+
+    ofstream out(vtkfilename.c_str(), ofstream::out | ofstream::binary);
+    if (!out) {
+        out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!out) weiterhin true!!!
+        string path = UbSystem::getPathFromString(vtkfilename);
+        if (path.size() > 0) {
+            UbSystem::makeDirectory(path);
+            out.open(vtkfilename.c_str(), ios::out | ios::binary);
+        }
+        if (!out)
+            throw UbException(UB_EXARGS, "couldn't open file " + vtkfilename);
+    }
+
+    // HEADER-SECTION
+    // WRITE BIGENDIAN VtkBinary FILE
+    bool swapByte = UbSystem::isLittleEndian();
+    int nofNodes  = (int)nodes.size();
+    int nofCells  = (int)cells.size();
+
+    out << "# vtk DataFile Version 4.0"
+        << "\n";
+    out << "D3Q19MasterNodeGrid"
+        << "\n";
+    out << ""
+        << "\n";
+
+    // POINTS SECTION
+    out << "DATASET UNSTRUCTURED_GRID"
+        << "\n";
+    out << "POINTS " << nofNodes << " float"
+        << "\n";
+    for (int n = 0; n < nofNodes; n++) {
+        float x1 = (float)val<1>(nodes[n]);
+        float x2 = (float)val<2>(nodes[n]);
+        float x3 = (float)val<3>(nodes[n]);
+
+        if (swapByte) {
+            UbSystem::swapByteOrder((unsigned char *)&x1, sizeof(float));
+            UbSystem::swapByteOrder((unsigned char *)&x2, sizeof(float));
+            UbSystem::swapByteOrder((unsigned char *)&x3, sizeof(float));
+        }
+
+        out.write((char *)&x1, sizeof(float));
+        out.write((char *)&x2, sizeof(float));
+        out.write((char *)&x3, sizeof(float));
+    }
+    out << "\n";
+
+    // CELLS SECTION
+    out << "CELLS " << nofCells << " " << nofCells * 5 << "\n";
+
+    int nodesPerCellDummy = 4; // nofNodesPerCell
+    if (swapByte)
+        UbSystem::swapByteOrder((unsigned char *)&nodesPerCellDummy, sizeof(int));
+    for (int c = 0; c < (int)cells.size(); c++) {
+        int SW = val<1>(cells[c]);
+        int SE = val<2>(cells[c]);
+        int NE = val<3>(cells[c]);
+        int NW = val<4>(cells[c]);
+        if (swapByte) {
+            UbSystem::swapByteOrder((unsigned char *)&SW, sizeof(int));
+            UbSystem::swapByteOrder((unsigned char *)&SE, sizeof(int));
+            UbSystem::swapByteOrder((unsigned char *)&NW, sizeof(int));
+            UbSystem::swapByteOrder((unsigned char *)&NE, sizeof(int));
+        }
+
+        out.write((char *)&nodesPerCellDummy, sizeof(int));
+        out.write((char *)&SW, sizeof(int));
+        out.write((char *)&SE, sizeof(int));
+        out.write((char *)&NW, sizeof(int));
+        out.write((char *)&NE, sizeof(int));
+    }
+    out << "\n";
+
+    out << "CELL_TYPES " << (int)cells.size() << "\n";
+    int celltype = 8;
+    if (swapByte)
+        UbSystem::swapByteOrder((unsigned char *)&celltype, sizeof(int));
+    for (int c = 0; c < nofCells; c++)
+        out.write((char *)&celltype, sizeof(int));
+
+    out << endl;
+    out.close();
+
+    UBLOG(logDEBUG1, "WbWriterVtkBinary::writeQuads to " << vtkfilename << " - end");
+    return vtkfilename;
+}
+/*===============================================================================*/
+std::string WbWriterVtkBinary::writeQuadsWithNodeData(const string &filename, vector<UbTupleFloat3> &nodes,
+                                                      vector<UbTupleInt4> &cells, vector<string> &datanames,
+                                                      vector<vector<double>> &nodedata)
+{
+    string vtkfilename = filename + getFileExtension();
+    UBLOG(logDEBUG1, "WbWriterVtkBinary::writeQuadsWithNodeData to " << vtkfilename << " - start");
+
+    ofstream out(vtkfilename.c_str(), ofstream::out | ofstream::binary);
+    if (!out) {
+        out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!out) weiterhin true!!!
+        string path = UbSystem::getPathFromString(vtkfilename);
+        if (path.size() > 0) {
+            UbSystem::makeDirectory(path);
+            out.open(vtkfilename.c_str(), ios::out | ios::binary);
+        }
+        if (!out)
+            throw UbException(UB_EXARGS, "couldn't open file " + vtkfilename);
+    }
+
+    // WRITE BIGENDIAN VtkBinary FILE
+    bool swapByte = UbSystem::isLittleEndian();
+    int nofNodes  = (int)nodes.size();
+    int nofCells  = (int)cells.size();
+
+    out << "# vtk DataFile Version 4.0"
+        << "\n";
+    out << "D3Q19MasterNodeGrid"
+        << "\n";
+    out << ""
+        << "\n";
+
+    // POINTS SECTION
+    out << "DATASET UNSTRUCTURED_GRID"
+        << "\n";
+    out << "POINTS " << nofNodes << " float"
+        << "\n";
+    for (int n = 0; n < nofNodes; n++) {
+        float x1 = (float)val<1>(nodes[n]);
+        float x2 = (float)val<2>(nodes[n]);
+        float x3 = (float)val<3>(nodes[n]);
+
+        if (swapByte) {
+            UbSystem::swapByteOrder((unsigned char *)&x1, sizeof(float));
+            UbSystem::swapByteOrder((unsigned char *)&x2, sizeof(float));
+            UbSystem::swapByteOrder((unsigned char *)&x3, sizeof(float));
+        }
+
+        out.write((char *)&x1, sizeof(float));
+        out.write((char *)&x2, sizeof(float));
+        out.write((char *)&x3, sizeof(float));
+    }
+    out << "\n";
+
+    // CELLS SECTION
+    out << "CELLS " << nofCells << " " << nofCells * 5 << "\n";
+
+    int nodesPerCellDummy = 4; // nofNodesPerCell
+    if (swapByte)
+        UbSystem::swapByteOrder((unsigned char *)&nodesPerCellDummy, sizeof(int));
+    for (int c = 0; c < (int)cells.size(); c++) {
+        int SW = val<1>(cells[c]);
+        int SE = val<2>(cells[c]);
+        int NE = val<3>(cells[c]);
+        int NW = val<4>(cells[c]);
+        if (swapByte) {
+            UbSystem::swapByteOrder((unsigned char *)&SW, sizeof(int));
+            UbSystem::swapByteOrder((unsigned char *)&SE, sizeof(int));
+            UbSystem::swapByteOrder((unsigned char *)&NW, sizeof(int));
+            UbSystem::swapByteOrder((unsigned char *)&NE, sizeof(int));
+        }
+
+        out.write((char *)&nodesPerCellDummy, sizeof(int));
+        out.write((char *)&SW, sizeof(int));
+        out.write((char *)&SE, sizeof(int));
+        out.write((char *)&NW, sizeof(int));
+        out.write((char *)&NE, sizeof(int));
+    }
+    out << "\n";
+
+    out << "CELL_TYPES " << (int)cells.size() << "\n";
+    int celltype = 8;
+    if (swapByte)
+        UbSystem::swapByteOrder((unsigned char *)&celltype, sizeof(int));
+    for (int c = 0; c < nofCells; c++)
+        out.write((char *)&celltype, sizeof(int));
+
+    out << endl;
+
+    // DATA SECTION
+    // write data section
+    out << "POINT_DATA " << nofNodes << "\n";
+    for (int s = 0; s < (int)datanames.size(); ++s) {
+        if ((int)nodedata[s].size() != nofNodes)
+            throw UbException(UB_EXARGS, "datasetsize must be equal to nofNodes");
+        out << "SCALARS " << datanames[s] << " float 1 \n LOOKUP_TABLE default \n";
+        for (int d = 0; d < (int)nodedata[s].size(); d++) {
+            float dummy = (float)nodedata[s][d];
+            if (swapByte)
+                UbSystem::swapByteOrder((unsigned char *)&dummy, sizeof(float));
+            out.write((const char *)&dummy, sizeof(float));
+        }
+        out << endl;
+    }
+    out.close();
+
+    UBLOG(logDEBUG1, "WbWriterVtkBinary::writeQuadsWithNodeData to " << vtkfilename << " - end");
+    return vtkfilename;
+}
+/*===============================================================================*/
+std::string WbWriterVtkBinary::writeQuadsWithCellData(const string &filename, vector<UbTupleFloat3> &nodes,
+                                                      vector<UbTupleInt4> &cells, vector<string> &datanames,
+                                                      vector<vector<double>> &celldata)
+{
+    // HEADER-SECTION
+    string vtkfilename = filename + getFileExtension();
+    UBLOG(logDEBUG1, "WbWriterVtkBinary::writeQuadsWithCellData to " << vtkfilename << " - start");
+
+    ofstream out(vtkfilename.c_str(), ofstream::out | ofstream::binary);
+    if (!out) {
+        out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!out) weiterhin true!!!
+        string path = UbSystem::getPathFromString(vtkfilename);
+        if (path.size() > 0) {
+            UbSystem::makeDirectory(path);
+            out.open(vtkfilename.c_str(), ios::out | ios::binary);
+        }
+        if (!out)
+            throw UbException(UB_EXARGS, "couldn't open file " + vtkfilename);
+    }
+
+    // WRITE BIGENDIAN VtkBinary FILE
+    bool swapByte = UbSystem::isLittleEndian();
+    int nofNodes  = (int)nodes.size();
+    int nofCells  = (int)cells.size();
+
+    out << "# vtk DataFile Version 4.0"
+        << "\n";
+    out << "D3Q19MasterNodeGrid"
+        << "\n";
+    out << ""
+        << "\n";
+
+    // POINTS SECTION
+    out << "DATASET UNSTRUCTURED_GRID"
+        << "\n";
+    out << "POINTS " << nofNodes << " float"
+        << "\n";
+    for (int n = 0; n < nofNodes; n++) {
+        float x1 = (float)val<1>(nodes[n]);
+        float x2 = (float)val<2>(nodes[n]);
+        float x3 = (float)val<3>(nodes[n]);
+
+        if (swapByte) {
+            UbSystem::swapByteOrder((unsigned char *)&x1, sizeof(float));
+            UbSystem::swapByteOrder((unsigned char *)&x2, sizeof(float));
+            UbSystem::swapByteOrder((unsigned char *)&x3, sizeof(float));
+        }
+
+        out.write((char *)&x1, sizeof(float));
+        out.write((char *)&x2, sizeof(float));
+        out.write((char *)&x3, sizeof(float));
+    }
+    out << "\n";
+
+    // CELLS SECTION
+    out << "CELLS " << nofCells << " " << nofCells * 5 << "\n";
+
+    int nodesPerCellDummy = 4; // nofNodesPerCell
+    if (swapByte)
+        UbSystem::swapByteOrder((unsigned char *)&nodesPerCellDummy, sizeof(int));
+    for (int c = 0; c < (int)cells.size(); c++) {
+        int SW = val<1>(cells[c]);
+        int SE = val<2>(cells[c]);
+        int NE = val<3>(cells[c]);
+        int NW = val<4>(cells[c]);
+        if (swapByte) {
+            UbSystem::swapByteOrder((unsigned char *)&SW, sizeof(int));
+            UbSystem::swapByteOrder((unsigned char *)&SE, sizeof(int));
+            UbSystem::swapByteOrder((unsigned char *)&NW, sizeof(int));
+            UbSystem::swapByteOrder((unsigned char *)&NE, sizeof(int));
+        }
+
+        out.write((char *)&nodesPerCellDummy, sizeof(int));
+        out.write((char *)&SW, sizeof(int));
+        out.write((char *)&SE, sizeof(int));
+        out.write((char *)&NW, sizeof(int));
+        out.write((char *)&NE, sizeof(int));
+    }
+    out << "\n";
+
+    out << "CELL_TYPES " << (int)cells.size() << "\n";
+    int celltype = 8;
+    if (swapByte)
+        UbSystem::swapByteOrder((unsigned char *)&celltype, sizeof(int));
+    for (int c = 0; c < nofCells; c++)
+        out.write((char *)&celltype, sizeof(int));
+
+    out << endl;
+
+    // DATA SECTION
+    // write data section
+    out << "CELL_DATA " << nofCells << "\n";
+    for (int s = 0; s < (int)datanames.size(); ++s) {
+        if ((int)celldata[s].size() != nofCells)
+            throw UbException(UB_EXARGS, "datasetsize must be equal to nofNodes");
+        out << "SCALARS " << datanames[s] << " float 1 \n LOOKUP_TABLE default \n";
+        for (int d = 0; d < (int)celldata[s].size(); d++) {
+            float dummy = (float)celldata[s][d];
+            if (swapByte)
+                UbSystem::swapByteOrder((unsigned char *)&dummy, sizeof(float));
+            out.write((const char *)&dummy, sizeof(float));
+        }
+        out << endl;
+    }
+    out.close();
+
+    UBLOG(logDEBUG1, "WbWriterVtkBinary::writeQuadsWithCellData to " << vtkfilename << " - end");
+    return vtkfilename;
+}
+/*===============================================================================*/
+std::string WbWriterVtkBinary::writeQuadsWithNodeAndCellData(const string &filename, vector<UbTupleFloat3> &nodes,
+                                                             vector<UbTupleInt4> &cells, vector<string> &nodedatanames,
+                                                             vector<vector<double>> &nodedata,
+                                                             vector<string> &celldatanames,
+                                                             vector<vector<double>> &celldata)
+{
+    string vtkfilename = filename + getFileExtension();
+    UBLOG(logDEBUG1, "WbWriterVtkBinary::writeQuadsWithNodeAndCellData to " << vtkfilename << " - start");
+
+    ofstream out(vtkfilename.c_str(), ofstream::out | ofstream::binary);
+    if (!out) {
+        out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!out) weiterhin true!!!
+        string path = UbSystem::getPathFromString(vtkfilename);
+        if (path.size() > 0) {
+            UbSystem::makeDirectory(path);
+            out.open(vtkfilename.c_str(), ios::out | ios::binary);
+        }
+        if (!out)
+            throw UbException(UB_EXARGS, "couldn't open file " + vtkfilename);
+    }
+
+    // HEADER-SECTION
+    // WRITE BIGENDIAN VtkBinary FILE
+    bool swapByte = UbSystem::isLittleEndian();
+    int nofNodes  = (int)nodes.size();
+    int nofCells  = (int)cells.size();
+
+    out << "# vtk DataFile Version 4.0"
+        << "\n";
+    out << "D3Q19MasterNodeGrid"
+        << "\n";
+    out << ""
+        << "\n";
+
+    // POINTS SECTION
+    out << "DATASET UNSTRUCTURED_GRID"
+        << "\n";
+    out << "POINTS " << nofNodes << " float"
+        << "\n";
+    for (int n = 0; n < nofNodes; n++) {
+        float x1 = (float)val<1>(nodes[n]);
+        float x2 = (float)val<2>(nodes[n]);
+        float x3 = (float)val<3>(nodes[n]);
+
+        if (swapByte) {
+            UbSystem::swapByteOrder((unsigned char *)&x1, sizeof(float));
+            UbSystem::swapByteOrder((unsigned char *)&x2, sizeof(float));
+            UbSystem::swapByteOrder((unsigned char *)&x3, sizeof(float));
+        }
+
+        out.write((char *)&x1, sizeof(float));
+        out.write((char *)&x2, sizeof(float));
+        out.write((char *)&x3, sizeof(float));
+    }
+    out << "\n";
+
+    // CELLS SECTION
+    out << "CELLS " << nofCells << " " << nofCells * 5 << "\n";
+
+    int nodesPerCellDummy = 4; // nofNodesPerCell
+    if (swapByte)
+        UbSystem::swapByteOrder((unsigned char *)&nodesPerCellDummy, sizeof(int));
+    for (int c = 0; c < (int)cells.size(); c++) {
+        int SW = val<1>(cells[c]);
+        int SE = val<2>(cells[c]);
+        int NE = val<3>(cells[c]);
+        int NW = val<4>(cells[c]);
+        if (swapByte) {
+            UbSystem::swapByteOrder((unsigned char *)&SW, sizeof(int));
+            UbSystem::swapByteOrder((unsigned char *)&SE, sizeof(int));
+            UbSystem::swapByteOrder((unsigned char *)&NW, sizeof(int));
+            UbSystem::swapByteOrder((unsigned char *)&NE, sizeof(int));
+        }
+
+        out.write((char *)&nodesPerCellDummy, sizeof(int));
+        out.write((char *)&SW, sizeof(int));
+        out.write((char *)&SE, sizeof(int));
+        out.write((char *)&NW, sizeof(int));
+        out.write((char *)&NE, sizeof(int));
+    }
+    out << "\n";
+
+    out << "CELL_TYPES " << (int)cells.size() << "\n";
+    int celltype = 8;
+    if (swapByte)
+        UbSystem::swapByteOrder((unsigned char *)&celltype, sizeof(int));
+    for (int c = 0; c < nofCells; c++)
+        out.write((char *)&celltype, sizeof(int));
+
+    out << endl;
+
+    // NODE DATA SECTION
+    // write data section
+    out << "POINT_DATA " << nofNodes << "\n";
+    for (int s = 0; s < (int)nodedatanames.size(); ++s) {
+        if ((int)nodedata[s].size() != nofNodes)
+            throw UbException(UB_EXARGS, "datasetsize must be equal to nofNodes");
+        out << "SCALARS " << nodedatanames[s] << " float 1 \n LOOKUP_TABLE default \n";
+        for (int d = 0; d < (int)nodedata[s].size(); d++) {
+            float dummy = (float)nodedata[s][d];
+            if (swapByte)
+                UbSystem::swapByteOrder((unsigned char *)&dummy, sizeof(float));
+            out.write((const char *)&dummy, sizeof(float));
+        }
+        out << endl;
+    }
+
+    // CELL DATA SECTION
+    // write data section
+    out << "CELL_DATA " << nofCells << "\n";
+    for (int s = 0; s < (int)celldatanames.size(); ++s) {
+        if ((int)celldata[s].size() != nofCells)
+            throw UbException(UB_EXARGS, "datasetsize must be equal to nofNodes");
+        out << "SCALARS " << celldatanames[s] << " float 1 \n LOOKUP_TABLE default \n";
+        for (int d = 0; d < (int)celldata[s].size(); d++) {
+            float dummy = (float)celldata[s][d];
+            if (swapByte)
+                UbSystem::swapByteOrder((unsigned char *)&dummy, sizeof(float));
+            out.write((const char *)&dummy, sizeof(float));
+        }
+        out << endl;
+    }
+
+    out.close();
+
+    UBLOG(logDEBUG1, "WbWriterVtkBinary::writeQuadsWithNodeAndCellData to " << vtkfilename << " - end");
+    return vtkfilename;
+}
+/*===============================================================================*/
+std::string WbWriterVtkBinary::writeOctsWithCellData(const string &filename, vector<UbTupleFloat3> &nodes,
+                                                     vector<UbTupleInt8> &cells, vector<string> &datanames,
+                                                     vector<vector<double>> &celldata)
+{
+    string vtkfilename = filename + getFileExtension();
+    UBLOG(logDEBUG1, "WbWriterVtkBinary::writeOctsWithCellData to " << vtkfilename << " - start");
+
+    ofstream out(vtkfilename.c_str(), ofstream::out | ofstream::binary);
+    if (!out) {
+        out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!out) weiterhin true!!!
+        string path = UbSystem::getPathFromString(vtkfilename);
+        if (path.size() > 0) {
+            UbSystem::makeDirectory(path);
+            out.open(vtkfilename.c_str(), ios::out | ios::binary);
+        }
+        if (!out)
+            throw UbException(UB_EXARGS, "couldn't open file " + vtkfilename);
+    }
+
+    // HEADER-SECTION
+    // WRITE BIGENDIAN VtkBinary FILE
+    bool swapByte = UbSystem::isLittleEndian();
+    int nofNodes  = (int)nodes.size();
+    int nofCells  = (int)cells.size();
+
+    out << "# vtk DataFile Version 4.0"
+        << "\n";
+    out << "D3Q19MasterNodeGrid"
+        << "\n";
+    out << ""
+        << "\n";
+
+    // POINTS SECTION
+    out << "DATASET UNSTRUCTURED_GRID"
+        << "\n";
+    out << "POINTS " << nofNodes << " float"
+        << "\n";
+    for (int n = 0; n < nofNodes; n++) {
+        float x1 = (float)val<1>(nodes[n]);
+        float x2 = (float)val<2>(nodes[n]);
+        float x3 = (float)val<3>(nodes[n]);
+
+        if (swapByte) {
+            UbSystem::swapByteOrder((unsigned char *)&x1, sizeof(float));
+            UbSystem::swapByteOrder((unsigned char *)&x2, sizeof(float));
+            UbSystem::swapByteOrder((unsigned char *)&x3, sizeof(float));
+        }
+
+        out.write((char *)&x1, sizeof(float));
+        out.write((char *)&x2, sizeof(float));
+        out.write((char *)&x3, sizeof(float));
+    }
+    out << "\n";
+
+    // CELLS SECTION
+    out << "CELLS " << nofCells << " " << nofCells * 9 << "\n";
+
+    int nodesPerCellDummy = 8; // nofNodesPerCell
+    if (swapByte)
+        UbSystem::swapByteOrder((unsigned char *)&nodesPerCellDummy, sizeof(int));
+    for (int c = 0; c < (int)cells.size(); c++) {
+        int BSW = val<1>(cells[c]);
+        int TSW = val<5>(cells[c]);
+        int BSE = val<2>(cells[c]);
+        int TSE = val<6>(cells[c]);
+        int BNW = val<3>(cells[c]);
+        int TNW = val<7>(cells[c]);
+        int BNE = val<4>(cells[c]);
+        int TNE = val<8>(cells[c]);
+        if (swapByte) {
+            UbSystem::swapByteOrder((unsigned char *)&BSW, sizeof(int));
+            UbSystem::swapByteOrder((unsigned char *)&BSE, sizeof(int));
+            UbSystem::swapByteOrder((unsigned char *)&BNW, sizeof(int));
+            UbSystem::swapByteOrder((unsigned char *)&BNE, sizeof(int));
+            UbSystem::swapByteOrder((unsigned char *)&TSW, sizeof(int));
+            UbSystem::swapByteOrder((unsigned char *)&TSE, sizeof(int));
+            UbSystem::swapByteOrder((unsigned char *)&TNW, sizeof(int));
+            UbSystem::swapByteOrder((unsigned char *)&TNE, sizeof(int));
+        }
+
+        out.write((char *)&nodesPerCellDummy, sizeof(int));
+        out.write((char *)&BSW, sizeof(int));
+        out.write((char *)&BSE, sizeof(int));
+        out.write((char *)&BNE, sizeof(int));
+        out.write((char *)&BNW, sizeof(int));
+        out.write((char *)&TSW, sizeof(int));
+        out.write((char *)&TSE, sizeof(int));
+        out.write((char *)&TNE, sizeof(int));
+        out.write((char *)&TNW, sizeof(int));
+    }
+    out << "\n";
+
+    out << "CELL_TYPES " << (int)cells.size() << "\n";
+    int celltype = 11;
+    if (swapByte)
+        UbSystem::swapByteOrder((unsigned char *)&celltype, sizeof(int));
+    for (int c = 0; c < nofCells; c++)
+        out.write((char *)&celltype, sizeof(int));
+
+    out << endl;
+
+    // CELL DATA SECTION
+    // write data section
+    out << "CELL_DATA " << nofCells << "\n";
+    for (int s = 0; s < (int)datanames.size(); ++s) {
+        if ((int)celldata[s].size() != nofCells)
+            throw UbException(UB_EXARGS, "datasetsize must be equal to nofNodes");
+        out << "SCALARS " << datanames[s] << " float 1 \n LOOKUP_TABLE default \n";
+        for (int d = 0; d < (int)celldata[s].size(); d++) {
+            float dummy = (float)celldata[s][d];
+            if (swapByte)
+                UbSystem::swapByteOrder((unsigned char *)&dummy, sizeof(float));
+            out.write((const char *)&dummy, sizeof(float));
+        }
+        out << endl;
+    }
+    out.close();
+
+    UBLOG(logDEBUG1, "WbWriterVtkBinary::writeOctsWithCellData to " << vtkfilename << " - end");
+    return vtkfilename;
+}
+/*===============================================================================*/
+std::string WbWriterVtkBinary::writeOctsWithNodeData(const string &filename, vector<UbTupleFloat3> &nodes,
+                                                     vector<UbTupleUInt8> &cells, vector<string> &datanames,
+                                                     vector<vector<double>> &nodedata)
+{
+    // HEADER-SECTION
+    string vtkfilename = filename + getFileExtension();
+    UBLOG(logDEBUG1, "WbWriterVtkBinary::writeOctsWithNodeData to " << vtkfilename << " - start");
+
+    ofstream out(vtkfilename.c_str(), ofstream::out | ofstream::binary);
+    if (!out) {
+        out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!out) weiterhin true!!!
+        string path = UbSystem::getPathFromString(vtkfilename);
+        if (path.size() > 0) {
+            UbSystem::makeDirectory(path);
+            out.open(vtkfilename.c_str(), ios::out | ios::binary);
+        }
+        if (!out)
+            throw UbException(UB_EXARGS, "couldn't open file " + vtkfilename);
+    }
+
+    // WRITE BIGENDIAN VtkBinary FILE
+    bool swapByte = UbSystem::isLittleEndian();
+    int nofNodes  = (int)nodes.size();
+    int nofCells  = (int)cells.size();
+
+    out << "# vtk DataFile Version 4.0"
+        << "\n";
+    out << "D3Q19MasterNodeGrid"
+        << "\n";
+    out << ""
+        << "\n";
+
+    // POINTS SECTION
+    out << "DATASET UNSTRUCTURED_GRID"
+        << "\n";
+    out << "POINTS " << nofNodes << " float"
+        << "\n";
+    for (int n = 0; n < nofNodes; n++) {
+        float x1 = val<1>(nodes[n]);
+        float x2 = val<2>(nodes[n]);
+        float x3 = val<3>(nodes[n]);
+
+        if (swapByte) {
+            UbSystem::swapByteOrder((unsigned char *)&x1, sizeof(float));
+            UbSystem::swapByteOrder((unsigned char *)&x2, sizeof(float));
+            UbSystem::swapByteOrder((unsigned char *)&x3, sizeof(float));
+        }
+
+        out.write((char *)&x1, sizeof(float));
+        out.write((char *)&x2, sizeof(float));
+        out.write((char *)&x3, sizeof(float));
+    }
+    out << "\n";
+
+    // CELLS SECTION
+    out << "CELLS " << nofCells << " " << nofCells * 9 << "\n";
+
+    int nodesPerCellDummy = 8; // nofNodesPerCell
+    if (swapByte)
+        UbSystem::swapByteOrder((unsigned char *)&nodesPerCellDummy, sizeof(int));
+    for (int c = 0; c < (int)cells.size(); c++) {
+        int BSW = val<1>(cells[c]);
+        int TSW = val<5>(cells[c]);
+        int BSE = val<2>(cells[c]);
+        int TSE = val<6>(cells[c]);
+        int BNW = val<3>(cells[c]);
+        int TNW = val<7>(cells[c]);
+        int BNE = val<4>(cells[c]);
+        int TNE = val<8>(cells[c]);
+        if (swapByte) {
+            UbSystem::swapByteOrder((unsigned char *)&BSW, sizeof(int));
+            UbSystem::swapByteOrder((unsigned char *)&BSE, sizeof(int));
+            UbSystem::swapByteOrder((unsigned char *)&BNW, sizeof(int));
+            UbSystem::swapByteOrder((unsigned char *)&BNE, sizeof(int));
+            UbSystem::swapByteOrder((unsigned char *)&TSW, sizeof(int));
+            UbSystem::swapByteOrder((unsigned char *)&TSE, sizeof(int));
+            UbSystem::swapByteOrder((unsigned char *)&TNW, sizeof(int));
+            UbSystem::swapByteOrder((unsigned char *)&TNE, sizeof(int));
+        }
+
+        out.write((char *)&nodesPerCellDummy, sizeof(int));
+        out.write((char *)&BSW, sizeof(int));
+        out.write((char *)&BSE, sizeof(int));
+        out.write((char *)&BNE, sizeof(int));
+        out.write((char *)&BNW, sizeof(int));
+        out.write((char *)&TSW, sizeof(int));
+        out.write((char *)&TSE, sizeof(int));
+        out.write((char *)&TNE, sizeof(int));
+        out.write((char *)&TNW, sizeof(int));
+    }
+    out << "\n";
+
+    out << "CELL_TYPES " << (int)cells.size() << "\n";
+    int celltype = 11;
+    if (swapByte)
+        UbSystem::swapByteOrder((unsigned char *)&celltype, sizeof(int));
+    for (int c = 0; c < nofCells; c++)
+        out.write((char *)&celltype, sizeof(int));
+
+    out << endl;
+
+    // NODE DATA SECTION
+    // write data section
+    out << "POINT_DATA " << nofNodes << "\n";
+    for (int s = 0; s < (int)datanames.size(); ++s) {
+        if ((int)nodedata[s].size() != nofNodes)
+            throw UbException(UB_EXARGS, "datasetsize must be equal to nofNodes");
+        out << "SCALARS " << datanames[s] << " float 1 \n LOOKUP_TABLE default \n";
+        for (int d = 0; d < (int)nodedata[s].size(); d++) {
+            float dummy = (float)nodedata[s][d];
+            if (swapByte)
+                UbSystem::swapByteOrder((unsigned char *)&dummy, sizeof(float));
+            out.write((const char *)&dummy, sizeof(float));
+        }
+        out << endl;
+    }
+
+    out.close();
+
+    UBLOG(logDEBUG1, "WbWriterVtkBinary::writeOctsWithNodeData to " << vtkfilename << " - end");
+    return vtkfilename;
+}
+/*===============================================================================*/
+std::string WbWriterVtkBinary::writeOcts(const string &filename, vector<UbTupleFloat3> &nodes,
+                                         vector<UbTupleInt8> &cells)
+{
+    string vtkfilename = filename + getFileExtension();
+    UBLOG(logDEBUG1, "WbWriterVtkBinary::writeOcts to " << vtkfilename << " - start");
+
+    ofstream out(vtkfilename.c_str(), ofstream::out | ofstream::binary);
+    if (!out) {
+        out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!out) weiterhin true!!!
+        string path = UbSystem::getPathFromString(vtkfilename);
+        if (path.size() > 0) {
+            UbSystem::makeDirectory(path);
+            out.open(vtkfilename.c_str(), ios::out | ios::binary);
+        }
+        if (!out)
+            throw UbException(UB_EXARGS, "couldn't open file " + vtkfilename);
+    }
+
+    // HEADER-SECTION
+    // WRITE BIGENDIAN VtkBinary FILE
+    bool swapByte = UbSystem::isLittleEndian();
+    int nofNodes  = (int)nodes.size();
+    int nofCells  = (int)cells.size();
+
+    out << "# vtk DataFile Version 4.0"
+        << "\n";
+    out << "D3Q19MasterNodeGrid"
+        << "\n";
+    out << ""
+        << "\n";
+
+    // POINTS SECTION
+    out << "DATASET UNSTRUCTURED_GRID"
+        << "\n";
+    out << "POINTS " << nofNodes << " float"
+        << "\n";
+    for (int n = 0; n < nofNodes; n++) {
+        float x1 = val<1>(nodes[n]);
+        float x2 = val<2>(nodes[n]);
+        float x3 = val<3>(nodes[n]);
+
+        if (swapByte) {
+            UbSystem::swapByteOrder((unsigned char *)&x1, sizeof(float));
+            UbSystem::swapByteOrder((unsigned char *)&x2, sizeof(float));
+            UbSystem::swapByteOrder((unsigned char *)&x3, sizeof(float));
+        }
+
+        out.write((char *)&x1, sizeof(float));
+        out.write((char *)&x2, sizeof(float));
+        out.write((char *)&x3, sizeof(float));
+    }
+    out << "\n";
+
+    // CELLS SECTION
+    out << "CELLS " << nofCells << " " << nofCells * 9 << "\n";
+
+    int nodesPerCellDummy = 8; // nofNodesPerCell
+    if (swapByte)
+        UbSystem::swapByteOrder((unsigned char *)&nodesPerCellDummy, sizeof(int));
+    for (int c = 0; c < (int)cells.size(); c++) {
+        int BSW = val<1>(cells[c]);
+        int TSW = val<5>(cells[c]);
+        int BSE = val<2>(cells[c]);
+        int TSE = val<6>(cells[c]);
+        int BNW = val<3>(cells[c]);
+        int TNW = val<7>(cells[c]);
+        int BNE = val<4>(cells[c]);
+        int TNE = val<8>(cells[c]);
+        if (swapByte) {
+            UbSystem::swapByteOrder((unsigned char *)&BSW, sizeof(int));
+            UbSystem::swapByteOrder((unsigned char *)&BSE, sizeof(int));
+            UbSystem::swapByteOrder((unsigned char *)&BNW, sizeof(int));
+            UbSystem::swapByteOrder((unsigned char *)&BNE, sizeof(int));
+            UbSystem::swapByteOrder((unsigned char *)&TSW, sizeof(int));
+            UbSystem::swapByteOrder((unsigned char *)&TSE, sizeof(int));
+            UbSystem::swapByteOrder((unsigned char *)&TNW, sizeof(int));
+            UbSystem::swapByteOrder((unsigned char *)&TNE, sizeof(int));
+        }
+
+        out.write((char *)&nodesPerCellDummy, sizeof(int));
+        out.write((char *)&BSW, sizeof(int));
+        out.write((char *)&BSE, sizeof(int));
+        out.write((char *)&BNE, sizeof(int));
+        out.write((char *)&BNW, sizeof(int));
+        out.write((char *)&TSW, sizeof(int));
+        out.write((char *)&TSE, sizeof(int));
+        out.write((char *)&TNE, sizeof(int));
+        out.write((char *)&TNW, sizeof(int));
+    }
+    out << "\n";
+
+    out << "CELL_TYPES " << (int)cells.size() << "\n";
+    int celltype = 11;
+    if (swapByte)
+        UbSystem::swapByteOrder((unsigned char *)&celltype, sizeof(int));
+    for (int c = 0; c < nofCells; c++)
+        out.write((char *)&celltype, sizeof(int));
+
+    out << endl;
+    out.close();
+
+    UBLOG(logDEBUG1, "WbWriterVtkBinary::writeOcts to " << vtkfilename << " - end");
+    return vtkfilename;
+}
diff --git a/src/basics/basics/writer/WbWriterVtkBinary.h b/src/basics/basics/writer/WbWriterVtkBinary.h
new file mode 100644
index 0000000000000000000000000000000000000000..8d5485a58db22c60124b931a878e12acce16bd09
--- /dev/null
+++ b/src/basics/basics/writer/WbWriterVtkBinary.h
@@ -0,0 +1,116 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file WbWriterVtkBinary.h
+//! \ingroup writer
+//! \author Soeren Freudiger, Sebastian Geller
+//=======================================================================================
+#ifndef WBWRITERVTKBINARY_H
+#define WBWRITERVTKBINARY_H
+
+#include <basics/writer/WbWriter.h>
+
+class WbWriterVtkBinary : public WbWriter
+{
+public:
+    static WbWriterVtkBinary *getInstance()
+    {
+        static WbWriterVtkBinary instance;
+        return &instance;
+    }
+
+    WbWriterVtkBinary(const WbWriterVtkBinary &) = delete;
+    const WbWriterVtkBinary &operator=(const WbWriterVtkBinary &) = delete;
+
+private:
+    WbWriterVtkBinary() = default;
+
+public:
+    std::string getFileExtension() override { return ".bin.vtk"; }
+
+    //////////////////////////////////////////////////////////////////////////
+    // lines
+    //     0 ---- 1
+    // nodenumbering must start with 0!
+    std::string writeLines(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                           std::vector<UbTupleInt2> &lines) override;
+
+    //////////////////////////////////////////////////////////////////////////
+    // triangles
+    // cell numbering:
+    //                    2
+    //
+    //                  0---1
+    // nodenumbering must start with 0!
+    std::string writeTriangles(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                               std::vector<UbTupleInt3> &cells) override;
+    std::string writeTrianglesWithNodeData(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                                           std::vector<UbTupleInt3> &cells, std::vector<std::string> &datanames,
+                                           std::vector<std::vector<double>> &nodedata) override;
+
+    //////////////////////////////////////////////////////////////////////////
+    // 2D
+    // cell numbering:
+    //                  3---2
+    //                  |   |
+    //                  0---1
+    // nodenumbering must start with 0!
+    std::string writeQuads(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                           std::vector<UbTupleInt4> &cells) override;
+    std::string writeQuadsWithNodeData(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                                       std::vector<UbTupleInt4> &cells, std::vector<std::string> &datanames,
+                                       std::vector<std::vector<double>> &nodedata) override;
+    std::string writeQuadsWithCellData(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                                       std::vector<UbTupleInt4> &cells, std::vector<std::string> &datanames,
+                                       std::vector<std::vector<double>> &celldata) override;
+    std::string writeQuadsWithNodeAndCellData(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                                              std::vector<UbTupleInt4> &cells, std::vector<std::string> &nodedatanames,
+                                              std::vector<std::vector<double>> &nodedata,
+                                              std::vector<std::string> &celldatanames,
+                                              std::vector<std::vector<double>> &celldata) override;
+
+    //////////////////////////////////////////////////////////////////////////
+    // octs
+    //     7 ---- 6
+    //    /|     /|
+    //   4 +--- 5 |
+    //   | |    | |
+    //   | 3 ---+ 2
+    //   |/     |/
+    //   0 ---- 1
+    std::string writeOcts(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                          std::vector<UbTupleInt8> &cells) override;
+    std::string writeOctsWithCellData(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                                      std::vector<UbTupleInt8> &cells, std::vector<std::string> &datanames,
+                                      std::vector<std::vector<double>> &celldata) override;
+    std::string writeOctsWithNodeData(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                                      std::vector<UbTupleUInt8> &cells, std::vector<std::string> &datanames,
+                                      std::vector<std::vector<double>> &nodedata) override;
+};
+
+#endif // WBWRITERVTKBINARY_H
diff --git a/src/basics/basics/writer/WbWriterX3D.cpp b/src/basics/basics/writer/WbWriterX3D.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..fd8ab6174b0b948718b0d7fbc8ca74d4054b2d2b
--- /dev/null
+++ b/src/basics/basics/writer/WbWriterX3D.cpp
@@ -0,0 +1,191 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file WbWriterX3D.cpp
+//! \ingroup writer
+//! \author Soeren Freudiger, Sebastian Geller
+//=======================================================================================
+#include <basics/utilities/UbLogger.h>
+#include <basics/writer/WbWriterX3D.h>
+
+using namespace std;
+
+/*===============================================================================*/
+std::string WbWriterX3D::writeTriangles(const string &filename, vector<UbTupleFloat3> &nodes,
+                                        vector<UbTupleInt3> &triangles)
+{
+    string X3DFilename = filename + getFileExtension();
+    UBLOG(logDEBUG1, "WbWriterX3D::writeTriangles to " << X3DFilename << " - start");
+
+    std::ofstream out(X3DFilename.c_str());
+    if (!out) {
+        out.clear(); // flags ruecksetzen (ansonsten liefert utern if(!out) weiterhin true!!!
+        string path = UbSystem::getPathFromString(X3DFilename);
+        if (path.size() > 0) {
+            UbSystem::makeDirectory(path);
+            out.open(X3DFilename.c_str());
+        }
+        if (!out)
+            throw UbException(UB_EXARGS, "couldn't open file " + X3DFilename);
+    }
+
+    // General part
+
+    // Root Element
+    out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << endl;
+    out << "<!DOCTYPE X3D PUBLIC \"ISO//Web3D//DTD X3D 3.1//EN\"   \"http://www.web3d.org/specifications/x3d-3.1.dtd\">"
+        << endl;
+    out << "<X3D profile='Interchange' version='3.1' xmlns:xsd='http://www.w3.org/2001/XMLSchema-instance' "
+           "xsd:noNamespaceSchemaLocation=' http://www.web3d.org/specifications/x3d-3.1.xsd '>"
+        << endl
+        << endl;
+
+    // Head
+    out << "<head>" << endl;
+    out << "<meta content='Simple X3D Writer for blender'/>" << endl;
+    out << "</head>" << endl << endl;
+
+    // Scene, Shape beginn
+    out << "<Scene>" << endl;
+    out << "<Shape>" << endl;
+
+    // IndexedFaceSet => Polylinien der Dreiecke
+    out << "<IndexedFaceSet  coordIndex=\"" << endl;
+
+    // TRIANGLES Ponits SECTION
+    int nofTriangles = (int)triangles.size();
+    // out<<"   triangles "<<nofTriangles<<endl;
+    for (int c = 0; c < nofTriangles; c++)
+        out << "      " << val<1>(triangles[c]) << " " << val<2>(triangles[c]) << " " << val<3>(triangles[c]) << " -1"
+            << endl;
+    out << "\">" << endl;
+
+    // Coordinates
+    out << "<Coordinate  point=\"" << endl;
+
+    // Coordinates SECTION
+    int nofNodes = (int)nodes.size();
+    // out<<"   points "<<nofNodes<<endl;
+    for (int n = 0; n < nofNodes; n++)
+        out << "      " << val<1>(nodes[n]) << ", " << val<2>(nodes[n]) << ", " << val<3>(nodes[n]) << ", " << endl;
+    out << "\"/>" << endl;
+
+    // Footer
+    out << "</IndexedFaceSet>" << endl;
+    out << "</Shape>" << endl;
+    out << "</Scene>" << endl;
+    out << "</X3D>" << endl;
+
+    //// Image details
+    // out<<"image {"              <<endl;
+    // out<<"   resolution 640 480"<<endl;
+    // out<<"   aa 0 1"            <<endl;
+    // out<<"   filter mitchell"   <<endl;
+    // out<<"}"                    <<endl<<endl;
+
+    //// Camera position
+    // out<<"camera {"                 <<endl;
+    // out<<"   type pinhole"          <<endl;
+    // out<<"   eye    -0.25 -0.3 0.13"<<endl;
+    // out<<"   target -0.1 0.1 0.13"  <<endl;
+    // out<<"   up     0 0 1"          <<endl;
+    // out<<"   fov    60"             <<endl;
+    // out<<"   aspect 1.333333"       <<endl;
+    // out<<"}"                        <<endl<<endl;
+
+    //// Light
+    // out<<"light {"                  <<endl;
+    // out<<"   type ibl"              <<endl;
+    // out<<"   image sky_small.hdr"   <<endl;
+    // out<<"   center 0 -1 0"         <<endl;
+    // out<<"   up 0 0 1"              <<endl;
+    // out<<"   lock true"             <<endl;
+    // out<<"   samples 200"           <<endl;
+    // out<<"}"                        <<endl<<endl;
+
+    //// Shaders
+    // out<<"shader {"                 <<endl;
+    // out<<"   name default-shader"   <<endl;
+    // out<<"   type diffuse"          <<endl;
+    // out<<"   diff 0.25 0.25 0.25"   <<endl;
+    // out<<"}"                        <<endl<<endl;
+
+    // out<<"shader {"                 <<endl;
+    // out<<"   name Glass"            <<endl;
+    // out<<"   type glass"            <<endl;
+    // out<<"   eta 1.333"             <<endl;
+    // out<<"   color 0.1 0.3 0.8"     <<endl;
+    // out<<"}"                        <<endl<<endl;
+    //
+    // out<<"shader {"                 <<endl;
+    // out<<"   name Mirror"           <<endl;
+    // out<<"   type mirror"           <<endl;
+    // out<<"   refl 0.7 0.7 0.7"      <<endl;
+    // out<<"}"                        <<endl<<endl;
+
+    //// Objects
+    //// a) Ground plane
+    // out<<"object {"                 <<endl;
+    // out<<"   shader default-shader" <<endl;
+    // out<<"   type plane"            <<endl;
+    // out<<"   p 0 0 0"               <<endl;
+    // out<<"   n 0 0 1"               <<endl;
+    // out<<"}"                        <<endl<<endl;
+
+    //// b) Mesh
+    // out<<"object {"                 <<endl;
+    // out<<"   shader Glass"          <<endl;
+    // out<<"   transform {"           <<endl;
+    // out<<"      rotatey 270.0"      <<endl;
+    // out<<"   }"                     <<endl;
+    // out<<"   type generic-mesh"     <<endl;
+    // out<<"      name polySurfac"    <<endl<<endl;
+
+    //// POINTS SECTION
+    // int nofNodes = (int)nodes.size();
+    // out<<"   points "<<nofNodes<<endl;
+    // for(int n=0; n<nofNodes; n++)
+    //   out<<"      "<< val<1>(nodes[n]) <<" "<< val<2>(nodes[n]) <<" "<< val<3>(nodes[n]) <<endl;
+
+    //// TRIANGLES SECTION
+    // int nofTriangles= (int)triangles.size();
+    // out<<"   triangles "<<nofTriangles<<endl;
+    // for(int c=0; c<nofTriangles; c++)
+    //   out<<"      "<<val<1>(triangles[c]) <<" "<< val<2>(triangles[c])<<" "<< val<3>(triangles[c])<<endl;
+
+    //// FOOTER
+    // out<<"   normals none" << endl;
+    // out<<"   uvs none"     << endl;
+    // out<<"}"               << endl;
+
+    out.close();
+    UBLOG(logDEBUG1, "WbWriterX3D::writeTriangles to " << X3DFilename << " - end");
+
+    return X3DFilename;
+}
+/*===============================================================================*/
diff --git a/src/basics/basics/writer/WbWriterX3D.h b/src/basics/basics/writer/WbWriterX3D.h
new file mode 100644
index 0000000000000000000000000000000000000000..4884d828c8f17a4c0ec270fbbe6fa42e69adb69e
--- /dev/null
+++ b/src/basics/basics/writer/WbWriterX3D.h
@@ -0,0 +1,72 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file WbWriterX3D.h
+//! \ingroup writer
+//! \author Soeren Freudiger, Sebastian Geller
+//=======================================================================================
+#ifndef WBWRITERX3D_H
+#define WBWRITERX3D_H
+
+#include <string>
+
+#include <basics/writer/WbWriter.h>
+
+class WbWriterX3D : public WbWriter
+{
+public:
+    static WbWriterX3D *getInstance()
+    {
+        static WbWriterX3D instance;
+        return &instance;
+    }
+
+    WbWriterX3D(const WbWriterX3D &) = delete;
+    const WbWriterX3D &operator=(const WbWriterX3D &) = delete;
+
+private:
+    WbWriterX3D() : WbWriter()
+    {
+        if (sizeof(unsigned char) != 1)
+            throw UbException(UB_EXARGS, "error char  type mismatch");
+        if (sizeof(int) != 4)
+            throw UbException(UB_EXARGS, "error int   type mismatch");
+        if (sizeof(float) != 4)
+            throw UbException(UB_EXARGS, "error float type mismatch");
+    }
+
+    static std::string pvdEndTag;
+
+public:
+    std::string getFileExtension() override { return "ascii.X3D"; }
+
+    std::string writeTriangles(const std::string &filename, std::vector<UbTupleFloat3> &nodes,
+                               std::vector<UbTupleInt3> &triangles) override;
+};
+
+#endif // WBWRITERX3D_H
diff --git a/src/basics/config/ConfigurationFile.cpp b/src/basics/config/ConfigurationFile.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..026d13e15486c46a7056e061ea075a03c9c06f9f
--- /dev/null
+++ b/src/basics/config/ConfigurationFile.cpp
@@ -0,0 +1,133 @@
+#include "ConfigurationFile.h"
+
+
+#include <map>
+#include <vector>
+#include <sstream>
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <stdlib.h>
+
+#include <basics/basics/utilities/UbException.h>
+
+
+namespace vf::basics
+{
+
+void ConfigurationFile::clear()
+{
+   data.clear();
+}
+//////////////////////////////////////////////////////////////////////////
+bool ConfigurationFile::load(const std::string& file)
+{
+   std::ifstream inFile(file.c_str());
+
+   if (!inFile.good())
+   {
+      UB_THROW(UbException(UB_EXARGS, "Cannot read configuration file "+file+"!"));
+   }
+
+   while (inFile.good() && ! inFile.eof())
+   {
+      std::string line;
+      getline(inFile, line);
+
+      // filter out comments
+      if (!line.empty())
+      {
+         size_t pos = line.find('#');
+
+         if (pos != std::string::npos)
+         {
+            line = line.substr(0, pos);
+         }
+      }
+
+      // split line into key and value
+      if (!line.empty())
+      {
+         size_t pos = line.find('=');
+
+         if (pos != std::string::npos)
+         {
+            std::string key = trim(line.substr(0, pos));
+            std::string value = trim(line.substr(pos + 1));
+
+            if (!key.empty() && !value.empty())
+            {
+               data[key] = value;
+            }
+         }
+      }
+   }
+
+   return true;
+}
+
+//////////////////////////////////////////////////////////////////////////
+template<>
+bool ConfigurationFile::fromString<bool>(const std::string& str) const
+{
+   return str == "true";
+}
+
+//////////////////////////////////////////////////////////////////////////
+bool ConfigurationFile::contains(const std::string& key) const
+{
+   return data.find(key) != data.end();
+}
+//////////////////////////////////////////////////////////////////////////
+std::string ConfigurationFile::getString(const std::string& key) const
+{
+   std::map<std::string, std::string>::const_iterator iter = data.find(key);
+
+   if (iter != data.end())
+   {
+      std::string value = iter->second;
+      return value;
+   }
+   else
+   {
+      UB_THROW(UbException(UB_EXARGS, "The parameter \"" + key + "\" is missing!"));
+   }
+}
+//////////////////////////////////////////////////////////////////////////
+std::string ConfigurationFile::trim(const std::string& str)
+{
+   size_t first = str.find_first_not_of(" \t\n\r");
+
+   if (first != std::string::npos)
+   {
+      size_t last = str.find_last_not_of(" \t\n\r");
+
+      return str.substr(first, last - first + 1);
+   }
+   else
+   {
+      return "";
+   }
+}
+//////////////////////////////////////////////////////////////////////////
+void ConfigurationFile::split(std::vector<std::string>& lst, const std::string& input, const std::string& separators, bool remove_empty) const
+{
+   std::ostringstream word;
+   for (size_t n = 0; n < input.size(); ++n)
+   {
+      if (std::string::npos == separators.find(input[n]))
+         word << input[n];
+      else
+      {
+         if (!word.str().empty() || !remove_empty)
+            lst.push_back(word.str());
+         word.str("");
+      }
+   }
+   if (!word.str().empty() || !remove_empty)
+      lst.push_back(word.str());
+}
+//////////////////////////////////////////////////////////////////////////
+
+
+}
diff --git a/src/basics/config/ConfigurationFile.h b/src/basics/config/ConfigurationFile.h
new file mode 100644
index 0000000000000000000000000000000000000000..ef7e7c9f06f94cabb3ba9cbefe95c8ee75736958
--- /dev/null
+++ b/src/basics/config/ConfigurationFile.h
@@ -0,0 +1,143 @@
+#ifndef BASICS_CONFIGURATIONFILE_H
+#define BASICS_CONFIGURATIONFILE_H
+
+#include <map>
+#include <vector>
+#include <sstream>
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <stdlib.h>
+
+#include <basics/basics/utilities/UbException.h>
+
+//! \brief  Simple configuration file
+//! \details The Configuration class presented here can read and keep values of any configuration file written in a format like this:
+//!#
+//!# Simulation parameters
+//!#
+//!
+//!nbDimensions    = 2
+//!temperature     = 25.001
+//!epsilon         = 1.013e-14
+//!writeLogFile    = false      # NOTE: Set to "true" in debug mode only.
+//!                             #       Logging slows down the program.
+//!errorMessage    = the simulation failed
+//!origin          = 0.0 0.0 0.0 # x, y, z of origin
+//!
+//!Example how to use it:
+//!
+//!ConfigurationFile   config;
+//!config.load(configname);
+//!
+//!int            nbDimensions = config.getValue<int>("nbDimensions");
+//!float          temperature  = config.getValue<float>("temperature");
+//!double         epsilon      = config.getValue<double>("epsilon");
+//!bool           writeLogFile = config.getValue<bool>("writeLogFile");
+//!string         errorMessage = config.getValue<string>("errorMessage");
+//!vector<double> origin       = config.getVector<double>("origin");
+//!            
+//! \author  Konstantin Kutscher
+
+
+namespace vf::basics
+{
+
+
+class ConfigurationFile
+{
+public:
+   //! clear all values
+   void clear();
+
+   //! load a configuration file
+   bool load(const std::string& File);
+
+   //! check if value associated with given key exists
+   bool contains(const std::string& key) const;
+
+   //! get vector with key
+   template<class T>
+   std::vector<T> getVector(const std::string& key) const;
+
+   //! get value with key
+   template<class T>
+   T getValue(const std::string& key) const;
+
+private:
+   //! the container
+   std::map<std::string, std::string> data;
+
+   //! get string with key
+   std::string  getString(const std::string& key) const;
+
+   //! remove leading and trailing tabs and spaces
+   static std::string trim(const std::string& str);
+
+   //! convert string to data type T
+   template<class T>
+   T fromString(const std::string& str) const;
+
+   void split(std::vector<std::string>& lst, const std::string& input, const std::string& separators, bool remove_empty = true) const;
+};
+
+
+//////////////////////////////////////////////////////////////////////////
+template<class T>
+std::vector<T> ConfigurationFile::getVector(const std::string& key) const
+{
+   std::string str = getString(key);
+   std::vector<T> v;
+   std::vector<std::string> strings;
+   split(strings, str, "\t\n\r;, ");
+   for (std::vector<std::string>::iterator it = strings.begin(); it != strings.end(); ++it)
+   {
+      if (*it != "")
+      {
+         v.push_back(fromString<T>(*it));
+      }
+   }
+   return v;
+}
+//////////////////////////////////////////////////////////////////////////
+template<class T>
+T ConfigurationFile::fromString(const std::string& str) const
+{
+   std::istringstream stream(str);
+   T t;
+   stream >> t;
+   return t;
+}
+
+template<>
+bool ConfigurationFile::fromString<bool>(const std::string& str) const;
+
+//////////////////////////////////////////////////////////////////////////
+template<class T>
+T ConfigurationFile::getValue(const std::string& key) const
+{
+   std::string str = getString(key);
+   bool bFlag = false;
+   if ((std::string)typeid(T).name() == (std::string)typeid(bool).name()) 
+   {
+      bFlag = true;
+   }
+
+   std::istringstream iss(str);
+   T x;
+   iss >> x;
+   if (!iss && !bFlag)
+      UB_THROW(UbException(UB_EXARGS, " cannot convert \"" + str + "\" to type <" + static_cast<std::string>(typeid(x).name()) + ">"));
+
+   if (bFlag)
+   {
+      bool value = (str == "true");
+      x = value;
+   }
+
+   return x;
+}
+
+}
+
+#endif
diff --git a/src/basics/geometry3d/GbCylinder3D.cpp b/src/basics/geometry3d/GbCylinder3D.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..562eb70c85acd87b405cf0c05f646ce22a40b3de
--- /dev/null
+++ b/src/basics/geometry3d/GbCylinder3D.cpp
@@ -0,0 +1,1344 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file GbCylinder3D.cpp
+//! \ingroup geometry3D
+//! \author Konstantin Kutscher, Soeren Textor, Sebastian Geller
+//=======================================================================================
+#include <basics/utilities/UbInfinity.h>
+#include <geometry3d/GbCylinder3D.h>
+#include <geometry3d/GbPoint3D.h>
+#include <geometry3d/GbSystem3D.h>
+#include <geometry3d/GbTriangle3D.h>
+
+using namespace std;
+
+// Konstruktor
+/*==========================================================*/
+GbCylinder3D::GbCylinder3D()
+
+{
+    this->setName("cylinder");
+    GbPoint3D *p1 = new GbPoint3D();
+    GbPoint3D *p2 = new GbPoint3D();
+    mLine         = new GbLine3D(p1, p2);
+    this->mLine->addObserver(this);
+    mRad         = 0.0;
+    cylinderType = GbCylinder3D::NOTPARALLELTOAXIS;
+    this->mLine->addObserver(this);
+    this->calculateValues();
+}
+/*=======================================================*/
+GbCylinder3D::GbCylinder3D(GbCylinder3D *cylinder)
+{
+    this->setName("cylinder");
+    mRad         = cylinder->getRadius();
+    cylinderType = cylinder->cylinderType;
+    mLine        = cylinder->getLine()->clone();
+
+    this->mLine->addObserver(this);
+    this->calculateValues();
+}
+/*==========================================================*/
+GbCylinder3D::GbCylinder3D(const double &x1a, const double &x2a, const double &x3a, const double &x1b,
+                           const double &x2b, const double &x3b, const double &rad)
+{
+    this->setName("cylinder");
+    mLine = new GbLine3D;
+    // Min/Max, damit gewaehrleistet ist, dass Startpunkt immer der "Achs-Minimale" ist
+    // Anm.: bin nich tsicher ob weiter unten irgendwelche Algos drauf beruhen...
+    //      geht nat nur solange, zylinder achs-parallel, aber das ist erzeit so!!!
+    mLine->setPoints(new GbPoint3D(min(x1a, x1b), min(x2a, x2b), min(x3a, x3b)),
+                     new GbPoint3D(max(x1a, x1b), max(x2a, x2b), max(x3a, x3b)));
+    // mLine->setPoints( new GbPoint3D(x1a,x2a,x3a),new GbPoint3D(x1b, x2b ,x3b ));
+    this->mLine->addObserver(this);
+    mRad = fabs(rad);
+
+    this->calculateValues();
+}
+/*==========================================================*/
+GbCylinder3D::GbCylinder3D(GbPoint3D *p1, GbPoint3D *p2, const double &rad)
+{
+    this->setName("cylinder");
+    mRad = rad;
+
+    mLine = new GbLine3D(p1, p2);
+    this->mLine->addObserver(this);
+    this->calculateValues();
+}
+/*==========================================================*/
+GbCylinder3D::GbCylinder3D(GbLine3D *line, const double &rad)
+{
+    this->setName("cylinder");
+    mRad = rad;
+
+    this->mLine = line;
+    this->mLine->addObserver(this);
+
+    this->calculateValues();
+}
+/*==========================================================*/
+// Destruktor
+GbCylinder3D::~GbCylinder3D()
+{
+    if (mLine)
+        this->mLine->removeObserver(this);
+    mLine = NULL;
+}
+/*=======================================================*/
+void GbCylinder3D::calculateValues()
+{
+    double x1a = mLine->getPoint1()->x1;
+    double x1b = mLine->getPoint2()->x1;
+    double x2a = mLine->getPoint1()->x2;
+    double x2b = mLine->getPoint2()->x2;
+    double x3a = mLine->getPoint1()->x3;
+    double x3b = mLine->getPoint2()->x3;
+
+    if (x1a != x1b && x2a == x2b && x3a == x3b)
+        this->cylinderType = X1PARALLEL;
+    else if (x2a != x2b && x1a == x1b && x3a == x3b)
+        this->cylinderType = X2PARALLEL;
+    else if (x3a != x3b && x1a == x1b && x2a == x2b)
+        this->cylinderType = X3PARALLEL;
+    // nach dem serialisieren ruft er den Standardkonstruktor auf wo alles 0 ist und bricht sonst hier ab
+    else if (x3a == x3b && x1a == x1b && x2a == x2b)
+        this->cylinderType = X1PARALLEL;
+    else
+        this->cylinderType = NOTPARALLELTOAXIS;
+
+    if ((this->cylinderType & NOTPARALLELTOAXIS) == NOTPARALLELTOAXIS)
+        throw UbException(UB_EXARGS,
+                          "derzeit nur zu Achsen orthogonale Zylinder erlaubt... isPointInObject3D funzt sonst ned");
+
+    if (this->isParallelToX1Axis()) {
+        minX1 = mLine->getX1Minimum();
+        maxX1 = mLine->getX1Maximum();
+        minX2 = mLine->getX2Centroid() - mRad;
+        maxX2 = mLine->getX2Centroid() + mRad;
+        minX3 = mLine->getX3Centroid() - mRad;
+        maxX3 = mLine->getX3Centroid() + mRad;
+    } else if (this->isParallelToX2Axis()) {
+        minX1 = mLine->getX1Centroid() - mRad;
+        maxX1 = mLine->getX1Centroid() + mRad;
+        minX2 = mLine->getX2Minimum();
+        maxX2 = mLine->getX2Maximum();
+        minX3 = mLine->getX3Centroid() - mRad;
+        maxX3 = mLine->getX3Centroid() + mRad;
+    } else if (this->isParallelToX3Axis()) {
+        minX1 = mLine->getX1Centroid() - mRad;
+        maxX1 = mLine->getX1Centroid() + mRad;
+        minX2 = mLine->getX2Centroid() - mRad;
+        maxX2 = mLine->getX2Centroid() + mRad;
+        minX3 = mLine->getX3Minimum();
+        maxX3 = mLine->getX3Maximum();
+    }
+
+    centerX1 = mLine->getX1Centroid();
+    centerX2 = mLine->getX2Centroid();
+    centerX3 = mLine->getX3Centroid();
+}
+
+/*=======================================================*/
+void GbCylinder3D::finalize()
+{
+    if (this->mLine) {
+        mLine->finalize();
+        delete mLine;
+        mLine = NULL;
+    }
+}
+/*=======================================================*/
+double GbCylinder3D::getHeight()
+{
+    if (mLine)
+        return mLine->getLength();
+
+    return 0.0;
+}
+/*=======================================================*/
+GbPoint3D *GbCylinder3D::getPoint1()
+{
+    if (this->mLine)
+        return this->mLine->getPoint1();
+    return NULL;
+}
+/*=======================================================*/
+GbPoint3D *GbCylinder3D::getPoint2()
+{
+    if (this->mLine)
+        return this->mLine->getPoint2();
+    return NULL;
+}
+/*=======================================================*/
+void GbCylinder3D::setRadius(const double &radius)
+{
+    this->mRad = std::fabs(radius);
+    this->notifyObserversObjectChanged();
+}
+/*=======================================================*/
+void GbCylinder3D::setLine(GbLine3D *line)
+{
+    if (this->mLine)
+        this->mLine->removeObserver(this);
+    this->mLine = line;
+    this->mLine->addObserver(this);
+    this->calculateValues();
+
+    this->notifyObserversObjectChanged();
+}
+/*=======================================================*/
+void GbCylinder3D::setPoint1(const double &x1, const double &x2, const double &x3)
+{
+    if (!mLine->getPoint1())
+        throw UbException(UB_EXARGS, "line has no point1");
+    mLine->getPoint1()->setCoordinates(x1, x2, x3);
+    this->calculateValues();
+
+    // this->notifyObserversObjectChanged(); //wird automatisch aufgerufen, da der point (this) benachrichtigt...
+}
+/*=======================================================*/
+void GbCylinder3D::setPoint2(const double &x1, const double &x2, const double &x3)
+{
+    if (!mLine->getPoint2())
+        throw UbException(UB_EXARGS, "line has no point2");
+    mLine->getPoint2()->setCoordinates(x1, x2, x3);
+    this->calculateValues();
+
+    // this->notifyObserversObjectChanged(); //wird automatisch aufgerufen, da der point (this) benachrichtigt...
+}
+/*==========================================================*/
+bool GbCylinder3D::isPointInGbObject3D(const double &x1p, const double &x2p, const double &x3p)
+{
+    // true, wenn 'in Object' oder 'auf Boundary'!
+    if (this->isParallelToX1Axis() && (UbMath::less(x1p, minX1) || UbMath::greater(x1p, maxX1)))
+        return false;
+    else if (this->isParallelToX2Axis() && (UbMath::less(x2p, minX2) || UbMath::greater(x2p, maxX2)))
+        return false;
+    else if (this->isParallelToX3Axis() && (UbMath::less(x3p, minX3) || UbMath::greater(x3p, maxX3)))
+        return false;
+    else if (this->isNotParallelToAxis())
+        throw UbException(UB_EXARGS,
+                          "derzeit nur zu Achsen orthogonale Zylinder erlaubt... isPointInObject3D funzt sonst ned");
+
+    return UbMath::lessEqual(fabs(mLine->getDistance(x1p, x2p, x3p)), fabs(mRad));
+}
+/*==========================================================*/
+bool GbCylinder3D::isPointInGbObject3D(const double &x1p, const double &x2p, const double &x3p, bool &pointIsOnBoundary)
+{
+    // funzt derzeit nur bei achsparallelen cylindern
+    pointIsOnBoundary = false;
+
+    if (this->isParallelToX1Axis() && (UbMath::less(x1p, minX1) || UbMath::greater(x1p, maxX1)))
+        return false;
+    else if (this->isParallelToX2Axis() && (UbMath::less(x2p, minX2) || UbMath::greater(x2p, maxX2)))
+        return false;
+    else if (this->isParallelToX3Axis() && (UbMath::less(x3p, minX3) || UbMath::greater(x3p, maxX3)))
+        return false;
+    else if (this->isNotParallelToAxis())
+        throw UbException(UB_EXARGS,
+                          "derzeit nur zu Achsen orthogonale Zylinder erlaubt... isPointInObject3D funzt sonst ned");
+
+    // true, wenn 'in Object' oder 'auf Boundary'!
+
+    double dis = mLine->getDistance(x1p, x2p, x3p);
+
+    if (UbMath::equal(dis, mRad))
+        pointIsOnBoundary = true;
+
+    if (this->isParallelToX1Axis() && (UbMath::equal(x1p, minX1) || UbMath::equal(x1p, maxX1)))
+        pointIsOnBoundary = true;
+    else if (this->isParallelToX2Axis() && (UbMath::equal(x2p, minX2) || UbMath::equal(x2p, maxX2)))
+        pointIsOnBoundary = true;
+    else if (this->isParallelToX3Axis() && (UbMath::equal(x3p, minX3) || UbMath::equal(x3p, maxX3)))
+        pointIsOnBoundary = true;
+
+    return UbMath::lessEqual(dis, mRad);
+}
+/*==========================================================*/
+string GbCylinder3D::toString()
+{
+    stringstream ss;
+    ss << "GbCylinder3D[";
+    ss << "line=" << this->mLine->toString();
+    ss << ", r=" << this->mRad;
+    ss << "]";
+    return (ss.str());
+}
+/*=======================================================*/
+bool GbCylinder3D::isCellInsideGbObject3D(const double &x1a, const double &x2a, const double &x3a, const double &x1b,
+                                          const double &x2b, const double &x3b)
+{
+    if (this->isPointInGbObject3D(x1a, x2a, x3a) && this->isPointInGbObject3D(x1b, x2a, x3a) &&
+        this->isPointInGbObject3D(x1b, x2b, x3a) && this->isPointInGbObject3D(x1a, x2b, x3a) &&
+        this->isPointInGbObject3D(x1a, x2a, x3b) && this->isPointInGbObject3D(x1b, x2a, x3b) &&
+        this->isPointInGbObject3D(x1b, x2b, x3b) && this->isPointInGbObject3D(x1a, x2b, x3b)) {
+        return true;
+    }
+    return false;
+}
+/*==========================================================*/
+bool GbCylinder3D::isCellCuttingGbObject3D(const double &x1a, const double &x2a, const double &x3a, const double &x1b,
+                                           const double &x2b, const double &x3b)
+// Merksatz: cell oder deren Volumen schneidet oder beinhaltet komplette oder Teile der CuboidUmrandung
+// returns true:
+//  - cell cuts  cylinder3D
+//  - cell boxes cylinder3D
+// returns false:
+//  - cell completely inside cylinder3D ( = cylinder3D boxes cell)
+//  - cell und cylinder3D haben kein gemeinsames Volumen
+{
+    // erstmal wieder die dumm Loesung
+    if (this->isCellInsideOrCuttingGbObject3D(x1a, x2a, x3a, x1b, x2b, x3b) &&
+        !this->isCellInsideGbObject3D(x1a, x2a, x3a, x1b, x2b, x3b)) {
+        return true;
+    }
+
+    return false;
+}
+/*==========================================================*/
+bool GbCylinder3D::isCellInsideOrCuttingGbObject3D(const double &x1a, const double &x2a, const double &x3a,
+                                                   const double &x1b, const double &x2b, const double &x3b)
+// returns true:
+//  - cell completely inside cylinder3D ( = cylinder3D boxes cell)
+//  - cell cuts  cylinder3D
+//  - cell boxes cylinder3D
+// returns false:
+//  - cell und cylinder3D haben kein gemeinsames Volumen
+{
+    double dmin = 0.0;
+
+    if (this->isParallelToX1Axis()) {
+        // check liegt Cell komplett !x1-ausserhalb"?
+        if (UbMath::less(x1a, minX1) && UbMath::less(x1b, minX1))
+            return false;
+        if (UbMath::greater(x1a, maxX1) && UbMath::greater(x1b, maxX1))
+            return false;
+
+        // mittelpunkt kreis-querschnitt
+        double &midX2 = mLine->getPoint1()->x2;
+        double &midX3 = mLine->getPoint1()->x3;
+        if (UbMath::less(midX2, x2a))
+            dmin += std::pow(midX2 - x2a, 2.0);
+        else if (UbMath::greater(midX2, x2b))
+            dmin += std::pow(midX2 - x2b, 2.0);
+        if (UbMath::less(midX3, x3a))
+            dmin += std::pow(midX3 - x3a, 2.0);
+        else if (UbMath::greater(midX3, x3b))
+            dmin += std::pow(midX3 - x3b, 2.0);
+        if (UbMath::lessEqual(dmin, mRad * mRad))
+            return true;
+
+        return false;
+    } else if (this->isParallelToX2Axis()) {
+        // check liegt Cell komplett !x2-ausserhalb"?
+        if (UbMath::less(x2a, minX2) && UbMath::less(x2b, minX2))
+            return false;
+        if (UbMath::greater(x2a, maxX2) && UbMath::greater(x2b, maxX2))
+            return false;
+
+        // mittelpunkt kreis-querschnitt
+        double &midX1 = mLine->getPoint1()->x1;
+        double &midX3 = mLine->getPoint1()->x3;
+        if (UbMath::less(midX1, x1a))
+            dmin += std::pow(midX1 - x1a, 2.0);
+        else if (UbMath::greater(midX1, x1b))
+            dmin += std::pow(midX1 - x1b, 2.0);
+        if (UbMath::less(midX3, x3a))
+            dmin += std::pow(midX3 - x3a, 2.0);
+        else if (UbMath::greater(midX3, x3b))
+            dmin += std::pow(midX3 - x3b, 2.0);
+        if (UbMath::lessEqual(dmin, mRad * mRad))
+            return true;
+
+    } else if (this->isParallelToX3Axis()) {
+        // check liegt Cell komplett !x3-ausserhalb"?
+        if (UbMath::less(x3a, minX3) && UbMath::less(x3b, minX3))
+            return false;
+        if (UbMath::greater(x3a, maxX3) && UbMath::greater(x3b, maxX3))
+            return false;
+
+        // mittelpunkt kreis-querschnitt
+        double &midX1 = mLine->getPoint1()->x1;
+        double &midX2 = mLine->getPoint1()->x2;
+        if (UbMath::less(midX1, x1a))
+            dmin += std::pow(midX1 - x1a, 2.0);
+        else if (UbMath::greater(midX1, x1b))
+            dmin += std::pow(midX1 - x1b, 2.0);
+        if (UbMath::less(midX2, x2a))
+            dmin += std::pow(midX2 - x2a, 2.0);
+        else if (UbMath::greater(midX2, x2b))
+            dmin += std::pow(midX2 - x2b, 2.0);
+        if (UbMath::lessEqual(dmin, mRad * mRad))
+            return true;
+    }
+
+    return false;
+}
+/*==========================================================*/
+GbLine3D *GbCylinder3D::createClippedLine3D(GbPoint3D &point1, GbPoint3D &point2)
+{
+    // liefert immer "innere" linie, also der teil, der vom Zylinder "abgeschnitten" wurde!
+    // funktioniert derzeit nur mit achsenparallelen Zylindern!
+    vector<GbPoint3D *> schnittpunkte;
+
+    double xa, ya, za, xb, yb, zb, xm, ym, zStart, zEnd, t1, t2;
+
+    if (this->isParallelToX1Axis()) {
+        xa     = point1.getX2Coordinate();
+        ya     = point1.getX3Coordinate();
+        za     = point1.getX1Coordinate();
+        xb     = point2.getX2Coordinate();
+        yb     = point2.getX3Coordinate();
+        zb     = point2.getX1Coordinate();
+        xm     = mLine->getPoint1()->getX2Coordinate();
+        ym     = mLine->getPoint1()->getX3Coordinate();
+        zStart = mLine->getPoint1()->getX1Coordinate();
+        zEnd   = mLine->getPoint2()->getX1Coordinate();
+    } else if (this->isParallelToX2Axis()) {
+        xa     = point1.getX1Coordinate();
+        ya     = point1.getX3Coordinate();
+        za     = point1.getX2Coordinate();
+        xb     = point2.getX1Coordinate();
+        yb     = point2.getX3Coordinate();
+        zb     = point2.getX2Coordinate();
+        xm     = mLine->getPoint1()->getX1Coordinate();
+        ym     = mLine->getPoint1()->getX3Coordinate();
+        zStart = mLine->getPoint1()->getX2Coordinate();
+        zEnd   = mLine->getPoint2()->getX2Coordinate();
+    } else if (this->isParallelToX3Axis()) {
+        xa     = point1.getX1Coordinate();
+        ya     = point1.getX2Coordinate();
+        za     = point1.getX3Coordinate();
+        xb     = point2.getX1Coordinate();
+        yb     = point2.getX2Coordinate();
+        zb     = point2.getX3Coordinate();
+        xm     = mLine->getPoint1()->getX1Coordinate();
+        ym     = mLine->getPoint1()->getX2Coordinate();
+        zStart = mLine->getPoint1()->getX3Coordinate();
+        zEnd   = mLine->getPoint2()->getX3Coordinate();
+    } else
+        throw UbException(UB_EXARGS, "funktioniert derzeit nur mit achsenparallelen Zylindern");
+
+    // Bestimmung des Schnittpunktes mit unendlich ausgedehntem Zylinder
+    double r   = mRad;
+    double r2  = r * r;
+    double xa2 = xa * xa;
+    double xb2 = xb * xb;
+    double ya2 = ya * ya;
+    double yb2 = yb * yb;
+    double xm2 = xm * xm;
+    double ym2 = ym * ym;
+
+    double wurzel = 2.0 * xa * xm * yb2 + 2.0 * ya * ym * xb2 - 2.0 * xa * xb * r2 + 2.0 * xa * xb * ym2 -
+                    2.0 * ya * yb * r2 + 2.0 * xa2 * yb * ym + 2.0 * xa * xm * ya * ym - 2.0 * xa * xm * yb * ym -
+                    2.0 * ya * ym * xb * xm + 2.0 * xb * xm * yb * ym + 2.0 * ya * yb * xa * xb -
+                    2.0 * ya * yb * xa * xm - 2.0 * ya * yb * xb * xm - 2.0 * xa * xb * ya * ym -
+                    2.0 * xa * xb * yb * ym + 2.0 * xb * xm * ya2 + 2.0 * ya * yb * xm2 - xa2 * yb2 - xb2 * ya2 +
+                    xa2 * r2 - xa2 * ym2 + xb2 * r2 - xb2 * ym2 + ya2 * r2 - ya2 * xm2 + yb2 * r2 - yb2 * xm2;
+    double nenner  = -2.0 * (ya * yb + xa * xb) + xa2 + xb2 + ya2 + yb2;
+    double zaehler = 2.0 * (-xa * xm + xb * xm - ya * ym + yb * ym) + xa2 - xb2 + ya2 - yb2;
+
+    if (UbMath::greaterEqual(wurzel, 0.0) && !UbMath::zero(nenner)) // fabs(nenner)>1.E-13)
+    {
+        t1 = (zaehler + 2.0 * sqrt(wurzel)) / nenner;
+        t2 = (zaehler - 2.0 * sqrt(wurzel)) / nenner;
+
+        if (UbMath::inClosedInterval(t1, -1.0, 1.0)) // Schnittpunkt innerhalb der Strecke
+        {
+            double x = xa * (0.5 - 0.5 * t1) + xb * (0.5 + 0.5 * t1);
+            double y = ya * (0.5 - 0.5 * t1) + yb * (0.5 + 0.5 * t1);
+            double z = za * (0.5 - 0.5 * t1) + zb * (0.5 + 0.5 * t1);
+
+            if (UbMath::inClosedInterval(z, zStart, zEnd)) // zWert muss sich innerhal der cylinderlaenge befinden
+            {
+                if (this->isParallelToX1Axis())
+                    schnittpunkte.push_back(new GbPoint3D(z, x, y));
+                else if (this->isParallelToX2Axis())
+                    schnittpunkte.push_back(new GbPoint3D(x, z, y));
+                else if (this->isParallelToX3Axis())
+                    schnittpunkte.push_back(new GbPoint3D(x, y, z));
+            }
+        }
+        if (fabs(t2 - t1) > 1.E-13 && UbMath::inClosedInterval(t2, -1.0, 1.0)) // Schnittpunkt innerhalb der Strecke
+        {
+            double x = xa * (0.5 - 0.5 * t2) + xb * (0.5 + 0.5 * t2);
+            double y = ya * (0.5 - 0.5 * t2) + yb * (0.5 + 0.5 * t2);
+            double z = za * (0.5 - 0.5 * t2) + zb * (0.5 + 0.5 * t2);
+
+            if (UbMath::inClosedInterval(z, zStart, zEnd)) // zWert muss sich innerhal der cylinderlaenge befinden
+            {
+                if (this->isParallelToX1Axis())
+                    schnittpunkte.push_back(new GbPoint3D(z, x, y));
+                else if (this->isParallelToX2Axis())
+                    schnittpunkte.push_back(new GbPoint3D(x, z, y));
+                else if (this->isParallelToX3Axis())
+                    schnittpunkte.push_back(new GbPoint3D(x, y, z));
+            }
+        }
+    }
+    // wenn nenner==0 -> Strecke parallel zu Zylinder! Es muss noch auf Schnittpunkt mit "Deckeln" geprueft werden
+
+    // Schnittpunkt mit Seitenflaechen bestimmen
+    // hierzu wird der schnittpunkt der gegebnen strecke mit den seitenflaechenberechnet
+    // als erstes "schaut man seitlich auf den Zylinder" --> kreisflaechen wird als strecke darsgestellt
+    // mit diesen "strecken" berechnet man Schnittpunkte.
+    // anschliessend wird geprueft, ob der berechnete Schnittpunkt ueberhaupt im kreis liegt
+    // falls ja --> Schnittpunkt vorhanden
+
+    double x1a, y1a, z1a, x1b, y1b, z1b, // uebergebene Strecke
+        x2a, y2a, x2b, y2b,              // erste "Kreisstrecke"
+        x3a, y3a, x3b, y3b,              // zweite "Kreisstrecke"
+        y2m, /*z2m,*/ y3m, z3m;
+    double nenner1ab;
+
+    if (this->isParallelToX1Axis()) {
+        x1a = point1.getX1Coordinate();
+        y1a = point1.getX2Coordinate();
+        z1a = point1.getX3Coordinate();
+        x1b = point2.getX1Coordinate();
+        y1b = point2.getX2Coordinate();
+        z1b = point2.getX3Coordinate();
+
+        x2a = mLine->getPoint1()->getX1Coordinate();
+        y2m = mLine->getPoint1()->getX2Coordinate();
+        //      z2m=mLine->getPoint1()->getX3Coordinate();
+        y2a = y2m + mRad;
+        x2b = mLine->getPoint1()->getX1Coordinate();
+        y2b = y2m - mRad;
+
+        x3a = mLine->getPoint2()->getX1Coordinate(); //
+        y3m = mLine->getPoint2()->getX2Coordinate();
+        z3m = mLine->getPoint2()->getX3Coordinate();
+        y3a = y3m + mRad;
+        x3b = mLine->getPoint2()->getX1Coordinate();
+        y3b = y3m - mRad;
+    } else if (this->isParallelToX2Axis()) {
+        x1a = point1.getX2Coordinate();
+        y1a = point1.getX3Coordinate();
+        z1a = point1.getX1Coordinate();
+        x1b = point2.getX2Coordinate();
+        y1b = point2.getX3Coordinate();
+        z1b = point2.getX1Coordinate();
+
+        x2a = mLine->getPoint1()->getX2Coordinate();
+        y2m = mLine->getPoint1()->getX3Coordinate();
+        //      z2m=mLine->getPoint1()->getX1Coordinate();
+        y2a = y2m + mRad;
+        x2b = mLine->getPoint1()->getX2Coordinate();
+        y2b = y2m - mRad;
+
+        x3a = mLine->getPoint2()->getX2Coordinate(); //
+        y3m = mLine->getPoint2()->getX3Coordinate();
+        z3m = mLine->getPoint2()->getX1Coordinate();
+        y3a = y3m + mRad;
+        x3b = mLine->getPoint2()->getX2Coordinate();
+        y3b = y3m - mRad;
+    } else if (this->isParallelToX3Axis()) {
+        x1a = point1.getX3Coordinate();
+        y1a = point1.getX2Coordinate();
+        z1a = point1.getX1Coordinate();
+        x1b = point2.getX3Coordinate();
+        y1b = point2.getX2Coordinate();
+        z1b = point2.getX1Coordinate();
+
+        x2a = mLine->getPoint1()->getX3Coordinate();
+        y2m = mLine->getPoint1()->getX2Coordinate();
+        //      z2m=mLine->getPoint1()->getX1Coordinate();
+        y2a = y2m + mRad;
+        x2b = mLine->getPoint1()->getX3Coordinate();
+        y2b = y2m - mRad;
+
+        x3a = mLine->getPoint2()->getX3Coordinate(); //
+        y3m = mLine->getPoint2()->getX2Coordinate();
+        z3m = mLine->getPoint2()->getX1Coordinate();
+        y3a = y3m + mRad;
+        x3b = mLine->getPoint2()->getX3Coordinate();
+        y3b = y3m - mRad;
+    } else
+        throw UbException(UB_EXARGS, "funktioniert derzeit nur mit achsenparallelen Zylindern");
+
+    nenner1ab = -y1a * x2a + y1a * x2b + y1b * x2a - y1b * x2b + x1a * y2a - x1a * y2b - x1b * y2a + x1b * y2b;
+    // double nenner2 = x1a*y2a-x1a*y2b-x1b*y2a+x1b*y2b-y1a*x2a+y1a*x2b+y1b*x2a-y1b*x2b;
+    if (fabs(nenner1ab) > 1.E-13) // andernfalls sind die beiden Strecken parallel
+    {
+        // tStrecke ist fuer gegebene Strecke!
+        double t1ab = (-y1a * x2a + y1a * x2b - 2.0 * y2a * x2b + x1a * y2a - x1a * y2b - x1b * y2b + 2.0 * y2b * x2a +
+                       x1b * y2a - y1b * x2a + y1b * x2b) /
+                      nenner1ab;
+        // double tStrecke =
+        // -(-x1a*y2a+x1a*y2b+2.0*y2a*x2b+y1a*x2a-2.0*x2a*y2b-y1a*x2b+y1b*x2a-y1b*x2b-x1b*y2a+x1b*y2b)/nenner2; wenn -1
+        // <= t2 <= +1 -> SP mit strecke
+        if (UbMath::inClosedInterval(t1ab, -1.0, 1.0)) // Schnittpunkt innerhalb der Strecke
+        {
+            double x, y, z, abstand_ist;
+            if (this->isParallelToX1Axis()) {
+                x           = x1a * (0.5 - 0.5 * t1ab) + x1b * (0.5 + 0.5 * t1ab);
+                y           = y1a * (0.5 - 0.5 * t1ab) + y1b * (0.5 + 0.5 * t1ab);
+                z           = z1a * (0.5 - 0.5 * t1ab) + z1b * (0.5 + 0.5 * t1ab);
+                abstand_ist = sqrt((y3m - y) * (y3m - y) + (z3m - z) * (z3m - z));
+            } else if (this->isParallelToX2Axis()) {
+                y           = x1a * (0.5 - 0.5 * t1ab) + x1b * (0.5 + 0.5 * t1ab);
+                z           = y1a * (0.5 - 0.5 * t1ab) + y1b * (0.5 + 0.5 * t1ab);
+                x           = z1a * (0.5 - 0.5 * t1ab) + z1b * (0.5 + 0.5 * t1ab);
+                abstand_ist = sqrt((y3m - z) * (y3m - z) + (z3m - x) * (z3m - x));
+            } else if (this->isParallelToX3Axis()) {
+                z           = x1a * (0.5 - 0.5 * t1ab) + x1b * (0.5 + 0.5 * t1ab);
+                y           = y1a * (0.5 - 0.5 * t1ab) + y1b * (0.5 + 0.5 * t1ab);
+                x           = z1a * (0.5 - 0.5 * t1ab) + z1b * (0.5 + 0.5 * t1ab);
+                abstand_ist = sqrt((y3m - y) * (y3m - y) + (z3m - x) * (z3m - x));
+            } else
+                throw UbException(UB_EXARGS, "funktioniert derzeit nur mit achsenparallelen Zylindern");
+
+            // pruefen, ob Punkt Element von Kreisflaeche
+            // double abstand_ist=sqrt((y2m-y)*(y2m-y)+(z2m-z)*(z2m-z));
+            if (UbMath::lessEqual(abstand_ist, mRad)) // Punkt ist Schnittpunkt
+            {
+                bool exists = false;
+                for (int pos = 0; pos < (int)schnittpunkte.size(); ++pos) {
+                    if (fabs(schnittpunkte[pos]->getX1Coordinate() - x) < 1.E-13 &&
+                        fabs(schnittpunkte[pos]->getX2Coordinate() - y) < 1.E-13 &&
+                        fabs(schnittpunkte[pos]->getX3Coordinate() - z) < 1.E-13)
+                        exists = true;
+                }
+
+                if (!exists)
+                    schnittpunkte.push_back(new GbPoint3D(x, y, z));
+            }
+        }
+    }
+
+    nenner1ab = -y1a * x3a + y1a * x3b + y1b * x3a - y1b * x3b + x1a * y3a - x1a * y3b - x1b * y3a + x1b * y3b;
+
+    if (fabs(nenner1ab) > 1.E-13) // andernfalls sind die beiden Strecken parallel
+    {
+        // tStrecke ist fuer gegebene Strecke!
+        double t1ab = (-y1a * x3a + y1a * x3b - x1b * y3b - 2.0 * y3a * x3b - x1a * y3b + 2.0 * y3b * x3a + x1a * y3a +
+                       x1b * y3a - y1b * x3a + y1b * x3b) /
+                      nenner1ab;
+
+        if (UbMath::inClosedInterval(t1ab, -1.0, 1.0)) // Schnittpunkt innerhalb der Strecke
+        {
+            double x, y, z, abstand_ist;
+            if (this->isParallelToX1Axis()) {
+                x           = x1a * (0.5 - 0.5 * t1ab) + x1b * (0.5 + 0.5 * t1ab);
+                y           = y1a * (0.5 - 0.5 * t1ab) + y1b * (0.5 + 0.5 * t1ab);
+                z           = z1a * (0.5 - 0.5 * t1ab) + z1b * (0.5 + 0.5 * t1ab);
+                abstand_ist = sqrt((y3m - y) * (y3m - y) + (z3m - z) * (z3m - z));
+            } else if (this->isParallelToX2Axis()) {
+                y           = x1a * (0.5 - 0.5 * t1ab) + x1b * (0.5 + 0.5 * t1ab);
+                z           = y1a * (0.5 - 0.5 * t1ab) + y1b * (0.5 + 0.5 * t1ab);
+                x           = z1a * (0.5 - 0.5 * t1ab) + z1b * (0.5 + 0.5 * t1ab);
+                abstand_ist = sqrt((y3m - z) * (y3m - z) + (z3m - x) * (z3m - x));
+            } else if (this->isParallelToX3Axis()) {
+                z           = x1a * (0.5 - 0.5 * t1ab) + x1b * (0.5 + 0.5 * t1ab);
+                y           = y1a * (0.5 - 0.5 * t1ab) + y1b * (0.5 + 0.5 * t1ab);
+                x           = z1a * (0.5 - 0.5 * t1ab) + z1b * (0.5 + 0.5 * t1ab);
+                abstand_ist = sqrt((y3m - y) * (y3m - y) + (z3m - x) * (z3m - x));
+            } else
+                throw UbException(UB_EXARGS, "cylinder must be parallel to one axis");
+
+            // pruefen, ob Punkt Element von Kreisflaeche
+            // double abstand_ist=sqrt((y2m-y)*(y2m-y)+(z2m-z)*(z2m-z));
+
+            if (UbMath::lessEqual(abstand_ist, mRad)) // Punkt ist Schnittpunkt
+            {
+                bool exists = false;
+                for (int pos = 0; pos < (int)schnittpunkte.size(); ++pos) {
+                    if (fabs(schnittpunkte[pos]->getX1Coordinate() - x) < 1.E-13 &&
+                        fabs(schnittpunkte[pos]->getX2Coordinate() - y) < 1.E-13 &&
+                        fabs(schnittpunkte[pos]->getX3Coordinate() - z) < 1.E-13)
+                        exists = true;
+                }
+
+                if (!exists)
+                    schnittpunkte.push_back(new GbPoint3D(x, y, z));
+            }
+        }
+    }
+
+    int nofSchnittpunkte = (int)schnittpunkte.size();
+    if (nofSchnittpunkte == 0)
+        return NULL;
+    else if (nofSchnittpunkte > 2)
+        throw UbException(UB_EXARGS, "more than three intersection points - not possible");
+    else if (nofSchnittpunkte == 2)
+        return new GbLine3D(schnittpunkte[0], schnittpunkte[1]);
+    else if (nofSchnittpunkte == 1) {
+        if (this->isPointInGbObject3D(&point1))
+            return new GbLine3D(schnittpunkte[0], new GbPoint3D(point1));
+        else if (this->isPointInGbObject3D(&point2))
+            return new GbLine3D(schnittpunkte[0], new GbPoint3D(point2));
+        else
+            return new GbLine3D(
+                schnittpunkte[0],
+                new GbPoint3D(*(schnittpunkte[0]))); // strecke beruehrt clippedLine reduziert sich auf einen Punkt!!!
+    }
+
+    return NULL;
+}
+/*==========================================================*/
+vector<GbTriangle3D *> GbCylinder3D::getSurfaceTriangleSet()
+{
+    double x1ma, x1mb, x2m, x3m;
+    if (this->isParallelToX1Axis()) {
+        x1ma = this->getX1Minimum();
+        x1mb = this->getX1Maximum();
+        x2m  = this->getX2Centroid();
+        x3m  = this->getX3Centroid();
+    } else if (this->isParallelToX2Axis()) {
+        x1ma = this->getX2Minimum();
+        x1mb = this->getX2Maximum();
+        x2m  = this->getX1Centroid();
+        x3m  = this->getX3Centroid();
+    } else if (this->isParallelToX3Axis()) {
+        x1ma = this->getX3Minimum();
+        x1mb = this->getX3Maximum();
+        x2m  = this->getX2Centroid();
+        x3m  = this->getX1Centroid();
+    } else
+        throw UbException(UB_EXARGS, "cylinder not axis prallel");
+
+    vector<GbTriangle3D *> triangles;
+
+    int segmentsCircle = 20;
+    double deltaPhi    = UbMath::PI / (double)segmentsCircle;
+
+    double phiX1a, phiX1b;
+    double x1a, x2a, x3a, x1b, x2b, x3b, x1c, x2c, x3c, x1d, x2d, x3d;
+
+    double dXCylinder    = fabs((x1mb - x1ma)) / (double)segmentsCircle;
+    int segmentsCylinder = (int)(fabs(x1mb - x1ma) / dXCylinder);
+    for (int segCyl = 0; segCyl < segmentsCylinder; segCyl++) {
+        x1a = x1d = x1ma + segCyl * dXCylinder;
+        x1b = x1c = x1a + dXCylinder;
+
+        for (phiX1a = 2.0 * UbMath::PI; phiX1a > 0; phiX1a -= deltaPhi) {
+            phiX1b = phiX1a + deltaPhi;
+
+            x2a = x2m + mRad * std::sin(phiX1a);
+            x3a = x3m + mRad * std::cos(phiX1a);
+            x2b = x2m + mRad * std::sin(phiX1b);
+            x3b = x3m + mRad * std::cos(phiX1b);
+
+            if (this->isParallelToX1Axis()) {
+                triangles.push_back(new GbTriangle3D(new GbPoint3D(x1b, x2b, x3b), new GbPoint3D(x1b, x2a, x3a),
+                                                     new GbPoint3D(x1a, x2a, x3a)));
+                triangles.push_back(new GbTriangle3D(new GbPoint3D(x1a, x2a, x3a), new GbPoint3D(x1a, x2b, x3b),
+                                                     new GbPoint3D(x1b, x2b, x3b)));
+            } else if (this->isParallelToX2Axis()) {
+                triangles.push_back(new GbTriangle3D(new GbPoint3D(x2b, x1b, x3b), new GbPoint3D(x2a, x1b, x3a),
+                                                     new GbPoint3D(x2a, x1a, x3a)));
+                triangles.push_back(new GbTriangle3D(new GbPoint3D(x2a, x1a, x3a), new GbPoint3D(x2b, x1a, x3b),
+                                                     new GbPoint3D(x2b, x1b, x3b)));
+            } else if (this->isParallelToX3Axis()) {
+                triangles.push_back(new GbTriangle3D(new GbPoint3D(x3b, x2b, x1b), new GbPoint3D(x3a, x2a, x1b),
+                                                     new GbPoint3D(x3a, x2a, x1a)));
+                triangles.push_back(new GbTriangle3D(new GbPoint3D(x3a, x2a, x1a), new GbPoint3D(x3b, x2b, x1a),
+                                                     new GbPoint3D(x3b, x2b, x1b)));
+            }
+        }
+    }
+
+    int segmentsSide = (int)(mRad / dXCylinder);
+    double radius0, radius1;
+    for (int segCyl = 0; segCyl < segmentsSide; segCyl++) {
+        radius0 = segCyl * dXCylinder;
+        radius1 = radius0 + dXCylinder;
+        if (segCyl == segmentsSide - 1)
+            radius1 = mRad;
+
+        for (phiX1a = 2.0 * UbMath::PI; phiX1a > 0; phiX1a -= deltaPhi) {
+            phiX1b = phiX1a + deltaPhi;
+
+            x2a = x2m + radius0 * std::sin(phiX1a);
+            x3a = x3m + radius0 * std::cos(phiX1a);
+            x2b = x2m + radius0 * std::sin(phiX1b);
+            x3b = x3m + radius0 * std::cos(phiX1b);
+            x2c = x2m + radius1 * std::sin(phiX1b);
+            x3c = x3m + radius1 * std::cos(phiX1b);
+            x2d = x2m + radius1 * std::sin(phiX1a);
+            x3d = x3m + radius1 * std::cos(phiX1a);
+
+            if (this->isParallelToX1Axis()) {
+                triangles.push_back(new GbTriangle3D(new GbPoint3D(x1ma, x2a, x3a), new GbPoint3D(x1ma, x2b, x3b),
+                                                     new GbPoint3D(x1ma, x2c, x3c)));
+                triangles.push_back(new GbTriangle3D(new GbPoint3D(x1ma, x2c, x3c), new GbPoint3D(x1ma, x2d, x3d),
+                                                     new GbPoint3D(x1ma, x2a, x3a)));
+                triangles.push_back(new GbTriangle3D(new GbPoint3D(x1mb, x2c, x3c), new GbPoint3D(x1mb, x2b, x3b),
+                                                     new GbPoint3D(x1mb, x2a, x3a)));
+                triangles.push_back(new GbTriangle3D(new GbPoint3D(x1mb, x2a, x3a), new GbPoint3D(x1mb, x2d, x3d),
+                                                     new GbPoint3D(x1mb, x2c, x3c)));
+            } else if (this->isParallelToX2Axis()) {
+                triangles.push_back(new GbTriangle3D(new GbPoint3D(x2a, x1ma, x3a), new GbPoint3D(x2b, x1ma, x3b),
+                                                     new GbPoint3D(x2c, x1ma, x3c)));
+                triangles.push_back(new GbTriangle3D(new GbPoint3D(x2c, x1ma, x3c), new GbPoint3D(x2d, x1ma, x3d),
+                                                     new GbPoint3D(x2a, x1ma, x3a)));
+                triangles.push_back(new GbTriangle3D(new GbPoint3D(x2c, x1mb, x3c), new GbPoint3D(x2b, x1mb, x3b),
+                                                     new GbPoint3D(x2a, x1mb, x3a)));
+                triangles.push_back(new GbTriangle3D(new GbPoint3D(x2a, x1mb, x3a), new GbPoint3D(x2d, x1mb, x3d),
+                                                     new GbPoint3D(x2c, x1mb, x3c)));
+            } else if (this->isParallelToX3Axis()) {
+                triangles.push_back(new GbTriangle3D(new GbPoint3D(x3a, x2a, x1ma), new GbPoint3D(x3b, x2b, x1ma),
+                                                     new GbPoint3D(x3c, x2c, x1ma)));
+                triangles.push_back(new GbTriangle3D(new GbPoint3D(x3c, x2c, x1ma), new GbPoint3D(x3d, x2d, x1ma),
+                                                     new GbPoint3D(x3a, x2a, x1ma)));
+                triangles.push_back(new GbTriangle3D(new GbPoint3D(x3c, x2c, x1mb), new GbPoint3D(x3b, x2b, x1mb),
+                                                     new GbPoint3D(x3a, x2a, x1mb)));
+                triangles.push_back(new GbTriangle3D(new GbPoint3D(x3a, x2a, x1mb), new GbPoint3D(x3d, x2d, x1mb),
+                                                     new GbPoint3D(x3c, x2c, x1mb)));
+            }
+        }
+    }
+
+    return triangles;
+}
+/*==========================================================*/
+void GbCylinder3D::addSurfaceTriangleSet(vector<UbTupleFloat3> &nodes, vector<UbTupleInt3> &triangles)
+{
+    float x1ma, x1mb, x2m, x3m;
+    if (this->isParallelToX1Axis()) {
+        x1ma = (float)this->getX1Minimum();
+        x1mb = (float)this->getX1Maximum();
+        x2m  = (float)this->getX2Centroid();
+        x3m  = (float)this->getX3Centroid();
+    } else if (this->isParallelToX2Axis()) {
+        x1ma = (float)this->getX2Minimum();
+        x1mb = (float)this->getX2Maximum();
+        x2m  = (float)this->getX1Centroid();
+        x3m  = (float)this->getX3Centroid();
+    } else if (this->isParallelToX3Axis()) {
+        x1ma = (float)this->getX3Minimum();
+        x1mb = (float)this->getX3Maximum();
+        x2m  = (float)this->getX2Centroid();
+        x3m  = (float)this->getX1Centroid();
+    } else
+        throw UbException(UB_EXARGS, "cylinder not axis prallel");
+
+    int segmentsCircle = 20;
+    double deltaPhi    = UbMath::PI / (double)segmentsCircle;
+
+    double phiX1a, phiX1b;
+    float x1a, x2a, x3a, x1b, x2b, x3b, x1c, x2c, x3c, x1d, x2d, x3d;
+
+    double dXCylinder    = fabs((x1mb - x1ma)) / (double)segmentsCircle;
+    int segmentsCylinder = (int)(fabs(x1mb - x1ma) / dXCylinder);
+    int nodenr           = 0;
+    for (int segCyl = 0; segCyl < segmentsCylinder; segCyl++) {
+        x1a = x1d = (float)(x1ma + segCyl * dXCylinder);
+        x1b = x1c = (float)(x1a + dXCylinder);
+
+        for (phiX1a = 2.0 * UbMath::PI; phiX1a > 0; phiX1a -= deltaPhi) {
+            phiX1b = phiX1a + deltaPhi;
+
+            x2a = (float)(x2m + mRad * std::sin(phiX1a));
+            x3a = (float)(x3m + mRad * std::cos(phiX1a));
+            x2b = (float)(x2m + mRad * std::sin(phiX1b));
+            x3b = (float)(x3m + mRad * std::cos(phiX1b));
+
+            if (this->isParallelToX1Axis()) {
+                nodes.push_back(makeUbTuple(x1b, x2b, x3b));
+                nodes.push_back(makeUbTuple(x1b, x2a, x3a));
+                nodes.push_back(makeUbTuple(x1a, x2a, x3a));
+                nodes.push_back(makeUbTuple(x1a, x2a, x3a));
+                nodes.push_back(makeUbTuple(x1a, x2b, x3b));
+                nodes.push_back(makeUbTuple(x1b, x2b, x3b));
+            } else if (this->isParallelToX2Axis()) {
+                nodes.push_back(makeUbTuple(x2b, x1b, x3b));
+                nodes.push_back(makeUbTuple(x2a, x1b, x3a));
+                nodes.push_back(makeUbTuple(x2a, x1a, x3a));
+                nodes.push_back(makeUbTuple(x2a, x1a, x3a));
+                nodes.push_back(makeUbTuple(x2b, x1a, x3b));
+                nodes.push_back(makeUbTuple(x2b, x1b, x3b));
+            } else if (this->isParallelToX3Axis()) {
+                nodes.push_back(makeUbTuple(x3b, x2b, x1b));
+                nodes.push_back(makeUbTuple(x3a, x2a, x1b));
+                nodes.push_back(makeUbTuple(x3a, x2a, x1a));
+                nodes.push_back(makeUbTuple(x3a, x2a, x1a));
+                nodes.push_back(makeUbTuple(x3b, x2b, x1a));
+                nodes.push_back(makeUbTuple(x3b, x2b, x1b));
+            }
+            triangles.push_back(makeUbTuple(nodenr, nodenr + 1, nodenr + 2));
+            nodenr += 3;
+            triangles.push_back(makeUbTuple(nodenr, nodenr + 1, nodenr + 2));
+            nodenr += 3;
+        }
+    }
+
+    int segmentsSide = (int)(mRad / dXCylinder);
+    double radius0, radius1;
+    for (int segCyl = 0; segCyl < segmentsSide; segCyl++) {
+        radius0 = segCyl * dXCylinder;
+        radius1 = radius0 + dXCylinder;
+        if (segCyl == segmentsSide - 1)
+            radius1 = mRad;
+
+        for (phiX1a = 2.0 * UbMath::PI; phiX1a > 0; phiX1a -= deltaPhi) {
+            phiX1b = phiX1a + deltaPhi;
+
+            x2a = x2m + (float)(radius0 * std::sin(phiX1a));
+            x3a = x3m + (float)(radius0 * std::cos(phiX1a));
+            x2b = x2m + (float)(radius0 * std::sin(phiX1b));
+            x3b = x3m + (float)(radius0 * std::cos(phiX1b));
+            x2c = x2m + (float)(radius1 * std::sin(phiX1b));
+            x3c = x3m + (float)(radius1 * std::cos(phiX1b));
+            x2d = x2m + (float)(radius1 * std::sin(phiX1a));
+            x3d = x3m + (float)(radius1 * std::cos(phiX1a));
+
+            if (this->isParallelToX1Axis()) {
+                nodes.push_back(makeUbTuple(x1ma, x2a, x3a));
+                nodes.push_back(makeUbTuple(x1ma, x2b, x3b));
+                nodes.push_back(makeUbTuple(x1ma, x2c, x3c));
+                nodes.push_back(makeUbTuple(x1ma, x2c, x3c));
+                nodes.push_back(makeUbTuple(x1ma, x2d, x3d));
+                nodes.push_back(makeUbTuple(x1ma, x2a, x3a));
+                nodes.push_back(makeUbTuple(x1mb, x2c, x3c));
+                nodes.push_back(makeUbTuple(x1mb, x2b, x3b));
+                nodes.push_back(makeUbTuple(x1mb, x2a, x3a));
+                nodes.push_back(makeUbTuple(x1mb, x2a, x3a));
+                nodes.push_back(makeUbTuple(x1mb, x2d, x3d));
+                nodes.push_back(makeUbTuple(x1mb, x2c, x3c));
+            } else if (this->isParallelToX2Axis()) {
+                nodes.push_back(makeUbTuple(x2a, x1ma, x3a));
+                nodes.push_back(makeUbTuple(x2b, x1ma, x3b));
+                nodes.push_back(makeUbTuple(x2c, x1ma, x3c));
+                nodes.push_back(makeUbTuple(x2c, x1ma, x3c));
+                nodes.push_back(makeUbTuple(x2d, x1ma, x3d));
+                nodes.push_back(makeUbTuple(x2a, x1ma, x3a));
+                nodes.push_back(makeUbTuple(x2c, x1mb, x3c));
+                nodes.push_back(makeUbTuple(x2b, x1mb, x3b));
+                nodes.push_back(makeUbTuple(x2a, x1mb, x3a));
+                nodes.push_back(makeUbTuple(x2a, x1mb, x3a));
+                nodes.push_back(makeUbTuple(x2d, x1mb, x3d));
+                nodes.push_back(makeUbTuple(x2c, x1mb, x3c));
+            } else if (this->isParallelToX3Axis()) {
+                nodes.push_back(makeUbTuple(x3a, x2a, x1ma));
+                nodes.push_back(makeUbTuple(x3b, x2b, x1ma));
+                nodes.push_back(makeUbTuple(x3c, x2c, x1ma));
+                nodes.push_back(makeUbTuple(x3c, x2c, x1ma));
+                nodes.push_back(makeUbTuple(x3d, x2d, x1ma));
+                nodes.push_back(makeUbTuple(x3a, x2a, x1ma));
+                nodes.push_back(makeUbTuple(x3c, x2c, x1mb));
+                nodes.push_back(makeUbTuple(x3b, x2b, x1mb));
+                nodes.push_back(makeUbTuple(x3a, x2a, x1mb));
+                nodes.push_back(makeUbTuple(x3a, x2a, x1mb));
+                nodes.push_back(makeUbTuple(x3d, x2d, x1mb));
+                nodes.push_back(makeUbTuple(x3c, x2c, x1mb));
+            }
+
+            triangles.push_back(makeUbTuple(nodenr, nodenr + 1, nodenr + 2));
+            nodenr += 3;
+            triangles.push_back(makeUbTuple(nodenr, nodenr + 1, nodenr + 2));
+            nodenr += 3;
+            triangles.push_back(makeUbTuple(nodenr, nodenr + 1, nodenr + 2));
+            nodenr += 3;
+            triangles.push_back(makeUbTuple(nodenr, nodenr + 1, nodenr + 2));
+            nodenr += 3;
+        }
+    }
+}
+/*==========================================================*/
+void GbCylinder3D::addSurfaceTriangleSetSegments(vector<UbTupleFloat3> &nodes, vector<UbTupleInt3> &triangles,
+                                                 int segmentsRound, int segmentsHeight)
+{
+    float x1ma, x1mb, x2m, x3m;
+    if (this->isParallelToX1Axis()) {
+        x1ma = (float)this->getX1Minimum();
+        x1mb = (float)this->getX1Maximum();
+        x2m  = (float)this->getX2Centroid();
+        x3m  = (float)this->getX3Centroid();
+    } else if (this->isParallelToX2Axis()) {
+        x1ma = (float)this->getX2Minimum();
+        x1mb = (float)this->getX2Maximum();
+        x2m  = (float)this->getX1Centroid();
+        x3m  = (float)this->getX3Centroid();
+    } else if (this->isParallelToX3Axis()) {
+        x1ma = (float)this->getX3Minimum();
+        x1mb = (float)this->getX3Maximum();
+        x2m  = (float)this->getX2Centroid();
+        x3m  = (float)this->getX1Centroid();
+    } else
+        throw UbException(UB_EXARGS, "cylinder not axis prallel");
+
+    int segmentsCircle = segmentsRound;
+    double deltaPhi    = UbMath::PI / (double)segmentsCircle;
+
+    double phiX1a, phiX1b;
+    float x1a, x2a, x3a, x1b, x2b, x3b, x1c, x2c, x3c, x1d, x2d, x3d;
+
+    double dXCylinder = fabs((x1mb - x1ma)) / (double)segmentsHeight; // hier evtl. segmentsheight
+    int segmentsCylinder = (int)(fabs(x1mb - x1ma) / dXCylinder);
+    int nodenr           = 0;
+    for (int segCyl = 0; segCyl < segmentsCylinder; segCyl++) {
+        x1a = x1d = (float)(x1ma + segCyl * dXCylinder);
+        x1b = x1c = (float)(x1a + dXCylinder);
+
+        // for(phiX1a=2.0*UbMath::PI; phiX1a>0.0; phiX1a-=deltaPhi)
+        for (phiX1a = 0.0; phiX1a < 2.0 * UbMath::PI - 0.5 * deltaPhi; phiX1a += deltaPhi) {
+            phiX1b = phiX1a + deltaPhi;
+
+            x2a = (float)(x2m + mRad * std::sin(phiX1a));
+            x3a = (float)(x3m + mRad * std::cos(phiX1a));
+            x2b = (float)(x2m + mRad * std::sin(phiX1b));
+            x3b = (float)(x3m + mRad * std::cos(phiX1b));
+
+            if (this->isParallelToX1Axis()) {
+                nodes.push_back(makeUbTuple(x1b, x2b, x3b));
+                nodes.push_back(makeUbTuple(x1b, x2a, x3a));
+                nodes.push_back(makeUbTuple(x1a, x2a, x3a));
+                nodes.push_back(makeUbTuple(x1a, x2a, x3a));
+                nodes.push_back(makeUbTuple(x1a, x2b, x3b));
+                nodes.push_back(makeUbTuple(x1b, x2b, x3b));
+            } else if (this->isParallelToX2Axis()) {
+                nodes.push_back(makeUbTuple(x2b, x1b, x3b));
+                nodes.push_back(makeUbTuple(x2a, x1b, x3a));
+                nodes.push_back(makeUbTuple(x2a, x1a, x3a));
+                nodes.push_back(makeUbTuple(x2a, x1a, x3a));
+                nodes.push_back(makeUbTuple(x2b, x1a, x3b));
+                nodes.push_back(makeUbTuple(x2b, x1b, x3b));
+            } else if (this->isParallelToX3Axis()) {
+                nodes.push_back(makeUbTuple(x3b, x2b, x1b));
+                nodes.push_back(makeUbTuple(x3a, x2a, x1b));
+                nodes.push_back(makeUbTuple(x3a, x2a, x1a));
+                nodes.push_back(makeUbTuple(x3a, x2a, x1a));
+                nodes.push_back(makeUbTuple(x3b, x2b, x1a));
+                nodes.push_back(makeUbTuple(x3b, x2b, x1b));
+            }
+            triangles.push_back(makeUbTuple(nodenr, nodenr + 1, nodenr + 2));
+            nodenr += 3;
+            triangles.push_back(makeUbTuple(nodenr, nodenr + 1, nodenr + 2));
+            nodenr += 3;
+        }
+    }
+
+    int segmentsSide = (int)(mRad / dXCylinder);
+    double radius0, radius1;
+    for (int segCyl = 0; segCyl < segmentsSide; segCyl++) {
+        radius0 = segCyl * dXCylinder;
+        radius1 = radius0 + dXCylinder;
+        if (segCyl == segmentsSide - 1)
+            radius1 = mRad;
+
+        // for(phiX1a=2.0*UbMath::PI; phiX1a>0.0; phiX1a-=deltaPhi)
+        for (phiX1a = 0.0; phiX1a < 2.0 * UbMath::PI - 0.5 * deltaPhi; phiX1a += deltaPhi) {
+            phiX1b = phiX1a + deltaPhi;
+
+            x2a = x2m + (float)(radius0 * std::sin(phiX1a));
+            x3a = x3m + (float)(radius0 * std::cos(phiX1a));
+            x2b = x2m + (float)(radius0 * std::sin(phiX1b));
+            x3b = x3m + (float)(radius0 * std::cos(phiX1b));
+            x2c = x2m + (float)(radius1 * std::sin(phiX1b));
+            x3c = x3m + (float)(radius1 * std::cos(phiX1b));
+            x2d = x2m + (float)(radius1 * std::sin(phiX1a));
+            x3d = x3m + (float)(radius1 * std::cos(phiX1a));
+
+            if (this->isParallelToX1Axis()) {
+                nodes.push_back(makeUbTuple(x1ma, x2a, x3a));
+                nodes.push_back(makeUbTuple(x1ma, x2b, x3b));
+                nodes.push_back(makeUbTuple(x1ma, x2c, x3c));
+                nodes.push_back(makeUbTuple(x1ma, x2c, x3c));
+                nodes.push_back(makeUbTuple(x1ma, x2d, x3d));
+                nodes.push_back(makeUbTuple(x1ma, x2a, x3a));
+                nodes.push_back(makeUbTuple(x1mb, x2c, x3c));
+                nodes.push_back(makeUbTuple(x1mb, x2b, x3b));
+                nodes.push_back(makeUbTuple(x1mb, x2a, x3a));
+                nodes.push_back(makeUbTuple(x1mb, x2a, x3a));
+                nodes.push_back(makeUbTuple(x1mb, x2d, x3d));
+                nodes.push_back(makeUbTuple(x1mb, x2c, x3c));
+            } else if (this->isParallelToX2Axis()) {
+                nodes.push_back(makeUbTuple(x2a, x1ma, x3a));
+                nodes.push_back(makeUbTuple(x2b, x1ma, x3b));
+                nodes.push_back(makeUbTuple(x2c, x1ma, x3c));
+                nodes.push_back(makeUbTuple(x2c, x1ma, x3c));
+                nodes.push_back(makeUbTuple(x2d, x1ma, x3d));
+                nodes.push_back(makeUbTuple(x2a, x1ma, x3a));
+                nodes.push_back(makeUbTuple(x2c, x1mb, x3c));
+                nodes.push_back(makeUbTuple(x2b, x1mb, x3b));
+                nodes.push_back(makeUbTuple(x2a, x1mb, x3a));
+                nodes.push_back(makeUbTuple(x2a, x1mb, x3a));
+                nodes.push_back(makeUbTuple(x2d, x1mb, x3d));
+                nodes.push_back(makeUbTuple(x2c, x1mb, x3c));
+            } else if (this->isParallelToX3Axis()) {
+                nodes.push_back(makeUbTuple(x3a, x2a, x1ma));
+                nodes.push_back(makeUbTuple(x3b, x2b, x1ma));
+                nodes.push_back(makeUbTuple(x3c, x2c, x1ma));
+                nodes.push_back(makeUbTuple(x3c, x2c, x1ma));
+                nodes.push_back(makeUbTuple(x3d, x2d, x1ma));
+                nodes.push_back(makeUbTuple(x3a, x2a, x1ma));
+                nodes.push_back(makeUbTuple(x3c, x2c, x1mb));
+                nodes.push_back(makeUbTuple(x3b, x2b, x1mb));
+                nodes.push_back(makeUbTuple(x3a, x2a, x1mb));
+                nodes.push_back(makeUbTuple(x3a, x2a, x1mb));
+                nodes.push_back(makeUbTuple(x3d, x2d, x1mb));
+                nodes.push_back(makeUbTuple(x3c, x2c, x1mb));
+            }
+
+            triangles.push_back(makeUbTuple(nodenr, nodenr + 1, nodenr + 2));
+            nodenr += 3;
+            triangles.push_back(makeUbTuple(nodenr, nodenr + 1, nodenr + 2));
+            nodenr += 3;
+            triangles.push_back(makeUbTuple(nodenr, nodenr + 1, nodenr + 2));
+            nodenr += 3;
+            triangles.push_back(makeUbTuple(nodenr, nodenr + 1, nodenr + 2));
+            nodenr += 3;
+        }
+    }
+}
+
+/*==========================================================*/
+void GbCylinder3D::objectChanged(UbObservable *changedObject)
+{
+    GbLine3D *line = dynamic_cast<GbLine3D *>(changedObject);
+    if (!line || this->mLine != line)
+        return;
+
+    this->notifyObserversObjectChanged();
+}
+/*==========================================================*/
+void GbCylinder3D::objectWillBeDeleted(UbObservable *objectForDeletion)
+{
+    if (this->mLine) {
+        UbObservable *observedObj = dynamic_cast<UbObservable *>(this->mLine);
+        if (objectForDeletion == observedObj) {
+            this->mLine = NULL;
+        }
+    }
+}
+/*=======================================================*/
+void GbCylinder3D::scale(const double &sx1, const double &sx2, const double &sx3)
+{
+    if (this->isParallelToX1Axis()) {
+        if (!UbMath::equal(sx2, sx3))
+            throw UbException(UB_EXARGS, "|| to x1 -> different scaling sx2 and sx3 not possible");
+        this->mRad *= sx2;
+    } else if (this->isParallelToX2Axis()) {
+        if (!UbMath::equal(sx1, sx3))
+            throw UbException(UB_EXARGS, "|| to x2 -> different scaling sx1 and sx3 not possible");
+        this->mRad *= sx1;
+    } else if (this->isParallelToX3Axis()) {
+        if (!UbMath::equal(sx1, sx2))
+            throw UbException(UB_EXARGS, "|| to x3 -> different scaling sx1 and sx2 not possible");
+        this->mRad *= sx1;
+    } else
+        throw UbException(UB_EXARGS, "unknown direction");
+
+    this->mLine->scale(sx1, sx2, sx3);
+    // notify observer wird automatisch aufgerufen
+}
+
+/*==========================================================*/
+double GbCylinder3D::getIntersectionRaytraceFactor(const double &x1, const double &x2, const double &x3,
+                                                   const double &rx1, const double &rx2, const double &rx3)
+{
+    /*
+    Distance D of the intersection between a Ray((ox1,ox2,ox3),(dx1,dx2,dx3)) and a Plane P: ax+by+cz+d=0
+    dc = a*dx1 + b*dx2 + c*dx3
+    dw = a*ox1 + b*ox2 + c*ox3 + d
+    D =   - dw / dc
+    */
+    double px1, px2, px3;
+    double d = Ub::inf; // Distance to Min or Max Plane of the Zylinder
+                        // final distance should be less that d
+
+    if (this->isParallelToX1Axis()) {
+        if (UbMath::equal(x1, minX1) && UbMath::negative(rx1))
+            return -1.0;
+        else if (UbMath::equal(x1, maxX1) && UbMath::positive(rx1))
+            return -1.0;
+
+        // falls die Linie nicht parallel zu den Seitenflaechen ist
+        if (x1 < minX1 || x1 > maxX1) // nur fuer punkte links und rechts des cylinders
+        {
+            px1 = (x1 < minX1 ? minX1 : maxX1);
+            // falls die Linie nicht parallel zu den Seitenflaechen ist
+            if (!UbMath::zero(rx1)) {
+                // Plane a= 0, b= 1, c=0 d= -1*px2
+                d   = -1.0 * (x1 - px1) / rx1;
+                px2 = x2 + d * rx2;
+                px3 = x3 + d * rx3;
+
+                if (UbMath::greater(mLine->getDistance(px1, px2, px3), mRad)) {
+                    if (x1 < minX1 && rx1 > 0.0)
+                        d = Ub::inf; // punkt liegt "links" vom cylinder und strahl hat evtl weiteren SP auf oberflaeche
+                    else if (x1 > maxX1 && rx1 < 0.0)
+                        d = Ub::inf;
+                    else
+                        return -1.0;
+                } else
+                    return d;
+            } else
+                return -1.0;
+        } else {
+            if (UbMath::negative(rx1))
+                d = -1.0 * (x1 - minX1) / rx1;
+            else if (UbMath::positive(rx1))
+                d = -1.0 * (x1 - maxX1) / rx1;
+        }
+    } else if (this->isParallelToX2Axis()) {
+        if (UbMath::equal(x2, minX2) && UbMath::negative(rx2))
+            return -1;
+        else if (UbMath::equal(x2, maxX2) && UbMath::positive(rx2))
+            return -1;
+
+        if (minX2 > x2 || x2 > maxX2) {
+            px2 = (x2 < minX2 ? minX2 : maxX2);
+            // falls die Linie nicht parallel zu den Seitenflaechen ist
+            if (!UbMath::zero(rx2)) {
+                // Plane a= 0, b= 1, c=0 d= -1*px2
+                d   = -1 * (x2 - px2) / rx2;
+                px1 = x1 + d * rx1;
+                px3 = x3 + d * rx3;
+
+                if (UbMath::greater(mLine->getDistance(px1, px2, px3), mRad)) {
+                    if (x2 < minX2 && rx2 > 0.0)
+                        d = Ub::inf; // punkt liegt "links oberhalb" vom cylinder und strahl mit pos x1 hat evtl
+                                     // weiteren SP auf oberflaeche
+                    else if (x2 > maxX2 && rx2 < 0.0)
+                        d = Ub::inf;
+                    else
+                        return -1.0;
+                } else
+                    return d;
+            } else
+                return -1.0;
+        } else {
+            if (UbMath::negative(rx2))
+                d = -1.0 * (x2 - minX2) / rx2;
+            else if (UbMath::positive(rx2))
+                d = -1.0 * (x2 - maxX2) / rx2;
+        }
+    } else if (this->isParallelToX3Axis()) {
+        if (UbMath::equal(x3, minX3) && UbMath::negative(rx3))
+            return -1.0;
+        else if (UbMath::equal(x3, maxX3) && UbMath::positive(rx3))
+            return -1.0;
+
+        if (minX3 > x3 || x3 > maxX3) {
+            px3 = (x3 < minX3 ? minX3 : maxX3);
+            // falls die Linie nicht parallel zu den Seitenflaechen ist
+            if (!UbMath::zero(rx3)) {
+                // Plane a= 0, b= 0, c=1 d= -1*px3
+                d   = -1.0 * (x3 - px3) / rx3;
+                px2 = x2 + d * rx2;
+                px1 = x1 + d * rx1;
+                if (UbMath::greater(mLine->getDistance(px1, px2, px3), mRad)) {
+                    if (x3 < minX3 && rx3 > 0.0)
+                        d = Ub::inf;
+                    else if (x3 > maxX3 && rx3 < 0.0)
+                        d = Ub::inf;
+                    else
+                        return -1.0;
+                } else
+                    return d;
+            } else
+                return -1.0;
+        } else {
+            if (UbMath::negative(rx3))
+                d = -1.0 * (x3 - minX3) / rx3;
+            else if (UbMath::positive(rx3))
+                d = -1.0 * (x3 - maxX3) / rx3;
+        }
+    } else
+        throw UbException(UB_EXARGS, "funzt nur bei achsen parallelem cylinder");
+    //////////////////////////////////////////////////////////////////////////
+    // Q berechnen fuer Infinity Zylinder
+    double axisX1 = mLine->getPoint2()->x1 - mLine->getPoint1()->x1; /* Axis of the cylinder   */
+    double axisX2 = mLine->getPoint2()->x2 - mLine->getPoint1()->x2; /* mit p1 als base of cylinder */
+    double axisX3 = mLine->getPoint2()->x3 - mLine->getPoint1()->x3;
+
+    // double dirlen = mLine->getLength();
+    // double abs, t, s;
+
+    double RCx1 = x1 - mLine->getPoint1()->x1;
+    double RCx2 = x2 - mLine->getPoint1()->x2;
+    double RCx3 = x3 - mLine->getPoint1()->x3;
+
+    // n = ray x axis
+    double nx1     = rx2 * axisX3 - rx3 * axisX2;
+    double nx2     = rx3 * axisX1 - rx1 * axisX3;
+    double nx3     = rx1 * axisX2 - rx2 * axisX1;
+    double nLength = nx1 * nx1 + nx2 * nx2 + nx3 * nx3;
+
+    double abs;
+    if (UbMath::zero(nLength)) { /* ray parallel to cyl  */
+        // abs = RC dot axis
+        double tmpabs = RCx1 * axisX1 + RCx2 * axisX2 + RCx3 * axisX3;
+        double dx1    = RCx1 - tmpabs * axisX1;
+        double dx2    = RCx2 - tmpabs * axisX2;
+        double dx3    = RCx3 - tmpabs * axisX3;
+        if (UbMath::greater(dx1 * dx1 + dx2 * dx2 + dx3 * dx3, mRad * mRad))
+            return -1.0;
+    }
+
+    // normalize "n"
+    nLength           = std::sqrt(nLength);
+    double invnLength = 1.0 / nLength;
+    nx1 *= invnLength;
+    nx2 *= invnLength;
+    nx3 *= invnLength;
+
+    // shortest distance  = fabs( RC dot n )
+    abs = std::fabs(RCx1 * nx1 + RCx2 * nx2 + RCx3 * nx3);
+
+    if (UbMath::lessEqual(abs, mRad)) { /* if ray hits cylinder */
+        // Ox1 = RC x axis
+        double Ox1 = RCx2 * axisX3 - RCx3 * axisX2;
+        double Ox2 = RCx3 * axisX1 - RCx1 * axisX3;
+        double Ox3 = RCx1 * axisX2 - RCx2 * axisX1;
+        // t = - O dot n / nLength;
+        double t = -(Ox1 * nx1 + Ox2 * nx2 + Ox3 * nx3) / nLength;
+
+        // O = n x axis;
+        Ox1 = nx2 * axisX3 - nx3 * axisX2;
+        Ox2 = nx3 * axisX1 - nx1 * axisX3;
+        Ox3 = nx1 * axisX2 - nx2 * axisX1;
+
+        // normalize O
+        invnLength = 1.0 / std::sqrt(Ox1 * Ox1 + Ox2 * Ox2 + Ox3 * Ox3);
+        Ox1 *= invnLength;
+        Ox2 *= invnLength;
+        Ox3 *= invnLength;
+
+        double s = std::fabs(sqrt(mRad * mRad - abs * abs) / (rx1 * Ox1 + rx2 * Ox2 + rx3 * Ox3));
+
+        // Wert a) t-s: entering distance
+        //     b) t+s: exiting  distance
+        //
+        // -> we only consider factors in ray-dir -> means positive values!
+        //    (s is always positive)
+
+        if (t > s) {
+            return UbMath::min(t - s, d);
+        } else if ((t + s) > 0) {
+            return UbMath::min(t + s, d);
+        }
+    }
+
+    return -1.0;
+}
+/*==========================================================*/
diff --git a/src/basics/geometry3d/GbCylinder3D.h b/src/basics/geometry3d/GbCylinder3D.h
new file mode 100644
index 0000000000000000000000000000000000000000..5bb25a8650379540679fba693a396bc1a50434b5
--- /dev/null
+++ b/src/basics/geometry3d/GbCylinder3D.h
@@ -0,0 +1,156 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file GbCylinder3D.h
+//! \ingroup geometry3D
+//! \author Konstantin Kutscher, Soeren Textor, Sebastian Geller
+//=======================================================================================
+#ifndef GBCYLINDER3D_H
+#define GBCYLINDER3D_H
+
+#include <cmath>
+#include <vector>
+
+#include <basics/utilities/UbObserver.h>
+#include <geometry3d/GbLine3D.h>
+#include <geometry3d/GbObject3D.h>
+
+class GbPoint3D;
+class GbLine3D;
+class GbTriangle3D;
+
+class GbObject3DCreator;
+
+#include <PointerDefinitions.h>
+class GbCylinder3D;
+using GbCylinder3DPtr = SPtr<GbCylinder3D>;
+
+class GbCylinder3D : public GbObject3D, public UbObserver
+{
+public:
+    GbCylinder3D();
+    GbCylinder3D(const double &x1a, const double &x2a, const double &x3a, const double &x1b, const double &x2b,
+                 const double &x3b, const double &radius);
+    GbCylinder3D(GbPoint3D *p1, GbPoint3D *p2, const double &radius);
+    GbCylinder3D(GbLine3D *line, const double &rad);
+    GbCylinder3D(GbCylinder3D *cylinder);
+    ~GbCylinder3D() override;
+
+    GbCylinder3D *clone() override { return new GbCylinder3D(this); }
+    void finalize() override;
+
+    double getRadius() { return this->mRad; };
+    GbLine3D *getLine() { return mLine; }
+    GbPoint3D *getPoint1();
+    GbPoint3D *getPoint2();
+
+    void setRadius(const double &radius);
+    void setLine(GbLine3D *line);
+    void setPoint1(const double &x1, const double &x2, const double &x3);
+    void setPoint2(const double &x1, const double &x2, const double &x3);
+
+    bool isParallelToX1Axis() { return ((this->cylinderType & X1PARALLEL) == X1PARALLEL); }
+    bool isParallelToX2Axis() { return ((this->cylinderType & X2PARALLEL) == X2PARALLEL); }
+    bool isParallelToX3Axis() { return ((this->cylinderType & X3PARALLEL) == X3PARALLEL); }
+    bool isNotParallelToAxis() { return ((this->cylinderType & NOTPARALLELTOAXIS) == NOTPARALLELTOAXIS); }
+
+    double getHeight();
+
+    void scale(const double &sx1, const double &sx2, const double &sx3) override;
+
+    void translate(const double &x1, const double &x2, const double &x3) override
+    {
+        this->mLine->translate(x1, x2, x3);
+        this->calculateValues();
+        // this->notifyObserversObjectChanged();
+    }
+
+    double getX1Centroid() override { return centerX1; }
+    double getX1Minimum() override { return minX1; }
+    double getX1Maximum() override { return maxX1; }
+    double getX2Centroid() override { return centerX2; }
+    double getX2Minimum() override { return minX2; }
+    double getX2Maximum() override { return maxX2; }
+    double getX3Centroid() override { return centerX3; }
+    double getX3Minimum() override { return minX3; }
+    double getX3Maximum() override { return maxX3; }
+
+    bool isPointInGbObject3D(const double &x1p, const double &x2p, const double &x3p) override;
+    bool isPointInGbObject3D(const double &x1p, const double &x2p, const double &x3p, bool &pointIsOnBoundary) override;
+    bool isCellInsideGbObject3D(const double &x1a, const double &x2a, const double &x3a, const double &x1b,
+                                const double &x2b, const double &x3b) override;
+    bool isCellCuttingGbObject3D(const double &x1a, const double &x2a, const double &x3a, const double &x1b,
+                                 const double &x2b, const double &x3b) override;
+    bool isCellInsideOrCuttingGbObject3D(const double &x1a, const double &x2a, const double &x3a, const double &x1b,
+                                         const double &x2b, const double &x3b) override;
+
+    GbLine3D *createClippedLine3D(GbPoint3D &point1, GbPoint3D &point2) override;
+
+    // SG ausdokumentieren, da der nur unendlcihe Zylinder macht ...
+    // bool hasRaytracing() { return true; }
+    bool hasRaytracing() override { return false; }
+    bool raytracingSupportsPointsInside() override { return true; }
+
+    /*|r| must be 1! einheitsvector!!*/
+    double getIntersectionRaytraceFactor(const double &x1, const double &x2, const double &x3, const double &rx1,
+                                         const double &rx2, const double &rx3) override;
+
+    std::vector<GbTriangle3D *> getSurfaceTriangleSet() override;
+    void addSurfaceTriangleSet(std::vector<UbTupleFloat3> &nodes, std::vector<UbTupleInt3> &triangles) override;
+    void addSurfaceTriangleSetSegments(std::vector<UbTupleFloat3> &nodes, std::vector<UbTupleInt3> &triangles,
+                                       int segmentsRound, int segmentsHeight);
+
+    std::string toString() override;
+
+    // virtuelle Methoden von UbObserver
+    void objectChanged(UbObservable *changedObject) override;
+    void objectWillBeDeleted(UbObservable *objectForDeletion) override;
+
+    using GbObject3D::isPointInGbObject3D; // Grund: dadurch muss man hier  isPointInGbObject3D(GbPoint3D*) nicht
+                                           // ausprogrammieren, welche sonst hier "ueberdeckt" waere
+
+protected:
+    void calculateValues();
+
+    GbLine3D *mLine;
+    double mRad;
+
+    double minX1{ 0.0 }, minX2{ 0.0 }, minX3{ 0.0 };
+    double maxX1{ 0.0 }, maxX2{ 0.0 }, maxX3{ 0.0 };
+    double centerX1{ 0.0 }, centerX2{ 0.0 }, centerX3{ 0.0 };
+
+    int cylinderType;
+
+    // void berechneQuerschnittsWerte();
+    static const int NOTPARALLELTOAXIS = (1 << 0); // 1
+    static const int X1PARALLEL        = (1 << 1); // 2
+    static const int X2PARALLEL        = (1 << 2); // 4
+    static const int X3PARALLEL        = (1 << 3); // 8
+};
+
+#endif
diff --git a/src/basics/geometry3d/GbHalfSpace3D.cpp b/src/basics/geometry3d/GbHalfSpace3D.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9e72e281e0bc456d32e46780d66de787547b3806
--- /dev/null
+++ b/src/basics/geometry3d/GbHalfSpace3D.cpp
@@ -0,0 +1,131 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file GbHalfSpace3D.cpp
+//! \ingroup geometry3D
+//! \author Konstantin Kutscher, Soeren Textor, Sebastian Geller
+//=======================================================================================
+#include <geometry3d/GbHalfSpace3D.h>
+
+using namespace std;
+
+/*==========================================================*/
+GbHalfSpace3D::GbHalfSpace3D(GbTriangle3D *triangle)
+{
+    GbPoint3D *PointA = triangle->getPoint1();
+    GbPoint3D *PointB = triangle->getPoint2();
+    GbPoint3D *PointC = triangle->getPoint3();
+
+    GbVector3D A(PointA->x1, PointA->x2, PointA->x3);
+    GbVector3D BA(PointB->x1 - PointA->x1, PointB->x2 - PointA->x2, PointB->x3 - PointA->x3);
+    GbVector3D CA(PointC->x1 - PointA->x1, PointC->x2 - PointA->x2, PointC->x3 - PointA->x3);
+    GbVector3D BACA = BA.Cross(CA);
+    // this->Normal = PointB->subtract(PointA)->cross(PointC->subtract(PointA))->normalize();
+    BACA.Normalize();
+    // this->Normal = BACA;
+    normalX = BACA[0];
+    normalY = BACA[1];
+    normalZ = BACA[2];
+    // this->d = this->Normal.Dot(A);
+    this->d = normalX * A[0] + normalY * A[1] + normalZ * A[2];
+}
+/*==========================================================*/
+GbHalfSpace3D::GbHalfSpace3D(GbPoint3D *PointA, GbPoint3D *PointB, GbPoint3D *PointC)
+{
+    GbVector3D A(PointA->x1, PointA->x2, PointA->x3);
+    GbVector3D BA(PointB->x1 - PointA->x1, PointB->x2 - PointA->x2, PointB->x3 - PointA->x3);
+    GbVector3D CA(PointC->x1 - PointA->x1, PointC->x2 - PointA->x2, PointC->x3 - PointA->x3);
+    GbVector3D BACA = BA.Cross(CA);
+    // this->Normal = PointB->subtract(PointA)->cross(PointC->subtract(PointA))->normalize();
+    BACA.Normalize();
+    // this->Normal = BACA;
+    normalX = BACA[0];
+    normalY = BACA[1];
+    normalZ = BACA[2];
+    // this->d = this->Normal.Dot(A);
+    this->d = normalX * A[0] + normalY * A[1] + normalZ * A[2];
+}
+/*==========================================================*/
+GbHalfSpace3D::GbHalfSpace3D(GbPoint3D *PointA, GbPoint3D *PointB)
+{
+    GbVector3D A(PointA->x1, PointA->x2, PointA->x3);
+    GbVector3D B(PointB->x1, PointB->x2, PointB->x3);
+    GbVector3D K(0.0, 0.0, 0.99); // the vector from PointA - third point
+
+    GbVector3D PointBA  = B - A;
+    GbVector3D PointBAK = PointBA.Cross(K);
+    PointBAK.Normalize();
+
+    // this->Normal = PointBAK;
+    normalX = PointBAK[0];
+    normalY = PointBAK[1];
+    normalZ = PointBAK[2];
+
+    // this->d = this->Normal.Dot(A);
+    this->d = normalX * PointA->x1 + normalY * PointA->x2 + normalZ * PointA->x3;
+}
+/*==========================================================*/
+GbHalfSpace3D::GbHalfSpace3D(const double &p1x, const double &p1y, const double &p1z, const double &p2x,
+                             const double &p2y, const double &p2z, const double &p3x, const double &p3y,
+                             const double &p3z)
+{
+    double p2minusP1x = p2x - p1x;
+    double p2minusP1y = p2y - p1y;
+    double p2minusP1z = p2z - p1z;
+
+    double P3minusP1x = p3x - p1x;
+    double P3minusP1y = p3y - p1y;
+    double P3minusP1z = p3z - p1z;
+
+    // normal = BA x CA
+    normalX = p2minusP1y * P3minusP1z - p2minusP1z * P3minusP1y;
+    normalY = p2minusP1z * P3minusP1x - p2minusP1x * P3minusP1z;
+    normalZ = p2minusP1x * P3minusP1y - p2minusP1y * P3minusP1x;
+
+    // normalize BACA
+    double oneOverNormalLength = 1.0 / (std::sqrt(normalX * normalX + normalY * normalY + normalZ * normalZ));
+    normalX *= oneOverNormalLength;
+    normalY *= oneOverNormalLength;
+    normalZ *= oneOverNormalLength;
+
+    // d = normal * p1
+    this->d = normalX * p1x + normalY * p1y + normalZ * p1z;
+}
+/*==========================================================*/
+GbHalfSpace3D::GbHalfSpace3D(const double &p1x, const double &p1y, const double &p1z, const double &nx,
+                             const double &ny, const double &nz)
+{
+    // normal = BA x CA
+    normalX = nx;
+    normalY = ny;
+    normalZ = nz;
+
+    // d = normal * p1
+    this->d = nx * p1x + ny * p1y + nz * p1z;
+}
+/*==========================================================*/
diff --git a/src/basics/geometry3d/GbHalfSpace3D.h b/src/basics/geometry3d/GbHalfSpace3D.h
new file mode 100644
index 0000000000000000000000000000000000000000..b4ac549fbf21d136c3916980d6336fa92b0b4f44
--- /dev/null
+++ b/src/basics/geometry3d/GbHalfSpace3D.h
@@ -0,0 +1,108 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file GbHalfSpace3D.h
+//! \ingroup geometry3D
+//! \author Konstantin Kutscher, Soeren Textor, Sebastian Geller
+//=======================================================================================
+#ifndef GBHALFSPACE3D_H
+#define GBHALFSPACE3D_H
+
+#include <iostream>
+#include <sstream>
+
+#include <basics/utilities/UbMath.h>
+
+#include <geometry3d/GbPoint3D.h>
+#include <geometry3d/GbTriangle3D.h>
+#include <geometry3d/GbVector3D.h>
+
+#include <PointerDefinitions.h>
+
+/*=========================================================================*/
+/* GbHalfSpace3D                                                             */
+/*                                                                         */
+/**
+ * This Class helps in performing some operations on a halfspace defined by 2 or 3 points
+ */
+
+class GbHalfSpace3D
+{
+public:
+    GbHalfSpace3D(GbTriangle3D *triangle);
+
+    GbHalfSpace3D(GbPoint3D *PointA, GbPoint3D *PointB, GbPoint3D *PointC);
+
+    GbHalfSpace3D(GbPoint3D *PointA, GbPoint3D *PointB);
+
+    GbHalfSpace3D(const double &p1x, const double &p1y, const double &p1z, const double &p2x, const double &p2y,
+                  const double &p2z, const double &p3x, const double &p3y, const double &p3z);
+    GbHalfSpace3D(const double &p1x, const double &p1y, const double &p1z, const double &nx, const double &ny,
+                  const double &nz);
+
+    /*=======================================================*/
+    std::string getTypeID() { return "GbHalfSpace3D"; }
+    /*=============================================*/
+    bool ptInside(const double &x, const double &y, const double &z)
+    {
+        return UbMath::greaterEqual(normalX * x + normalY * y + normalZ * z, this->d);
+    }
+    /*=============================================*/
+    bool ptInside(GbPoint3D *pointX)
+    {
+        // GbVector3D X(PointX->x1, PointX->x2, PointX->x3 );
+        // return UbMath::greaterEqual(this->Normal.Dot(X), this->d);
+        return UbMath::greaterEqual(normalX * pointX->x1 + normalY * pointX->x2 + normalZ * pointX->x3, this->d);
+    }
+    /*=============================================*/
+    bool ptInside(GbVector3D &x)
+    {
+        // return UbMath::greaterEqual(this->Normal.Dot(X), this->d);
+        return UbMath::greaterEqual(normalX * x[0] + normalY * x[1] + normalZ * x[2], this->d);
+    }
+    /*=============================================*/
+    double getDistance(const double &x1p, const double &x2p, const double &x3p)
+    {
+        return (normalX * x1p + normalY * x2p + normalZ * x3p) - this->d;
+    }
+
+    const double &getNormalX() { return this->normalX; }
+    const double &getNormalY() { return this->normalY; }
+    const double &getNormalZ() { return this->normalZ; }
+    const double &getD() { return this->d; }
+
+private:
+    // GbVector3D Normal;
+    double normalX;
+    double normalY;
+    double normalZ;
+    double d;
+};
+/*=========================================================================*/
+
+#endif // GBHALFSPACE3D_H
diff --git a/src/basics/geometry3d/GbHalfSpaceKrischan3D.cpp b/src/basics/geometry3d/GbHalfSpaceKrischan3D.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..929868f764bdcdc4c420efcfb2d6b829ddcdd112
--- /dev/null
+++ b/src/basics/geometry3d/GbHalfSpaceKrischan3D.cpp
@@ -0,0 +1,303 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file GbHalfSpaceKrischan3D.cpp
+//! \ingroup geometry3D
+//! \author Konstantin Kutscher, Soeren Textor, Sebastian Geller
+//=======================================================================================
+#include <geometry3d/GbHalfSpaceKrischan3D.h>
+
+using namespace std;
+
+/*==========================================================*/
+GbHalfSpaceKrischan3D::GbHalfSpaceKrischan3D(GbTriangle3D *triangle)
+{
+    GbPoint3D *PointA = triangle->getPoint1();
+    GbPoint3D *PointB = triangle->getPoint2();
+    GbPoint3D *PointC = triangle->getPoint3();
+
+    GbVector3D A(PointA->x1, PointA->x2, PointA->x3);
+    GbVector3D BA(PointB->x1 - PointA->x1, PointB->x2 - PointA->x2, PointB->x3 - PointA->x3);
+    GbVector3D CA(PointC->x1 - PointA->x1, PointC->x2 - PointA->x2, PointC->x3 - PointA->x3);
+    GbVector3D BACA = BA.Cross(CA);
+    // this->Normal = PointB->subtract(PointA)->cross(PointC->subtract(PointA))->normalize();
+    BACA.Normalize();
+    this->Normal = BACA;
+    this->d      = this->Normal.Dot(A);
+}
+/*==========================================================*/
+GbHalfSpaceKrischan3D::GbHalfSpaceKrischan3D(GbPoint3D *PointA, GbPoint3D *PointB, GbPoint3D *PointC)
+{
+    GbVector3D A(PointA->x1, PointA->x2, PointA->x3);
+    GbVector3D BA(PointB->x1 - PointA->x1, PointB->x2 - PointA->x2, PointB->x3 - PointA->x3);
+    GbVector3D CA(PointC->x1 - PointA->x1, PointC->x2 - PointA->x2, PointC->x3 - PointA->x3);
+    GbVector3D BACA = BA.Cross(CA);
+    // this->Normal = PointB->subtract(PointA)->cross(PointC->subtract(PointA))->normalize();
+    BACA.Normalize();
+    this->Normal = BACA;
+    this->d      = this->Normal.Dot(A);
+}
+/*==========================================================*/
+GbHalfSpaceKrischan3D::GbHalfSpaceKrischan3D(GbPoint3D *PointA, GbPoint3D *PointB)
+{
+    GbVector3D A(PointA->x1, PointA->x2, PointA->x3);
+    GbVector3D B(PointB->x1, PointB->x2, PointB->x3);
+    GbVector3D K(0.0, 0.0, 0.99); // the vector from PointA - third point
+
+    GbVector3D PointBA  = B - A;
+    GbVector3D PointBAK = PointBA.Cross(K);
+    PointBAK.Normalize();
+    this->Normal = PointBAK;
+    this->d      = this->Normal.Dot(A);
+}
+/*==========================================================*/
+GbHalfSpaceKrischan3D::GbHalfSpaceKrischan3D(const double &p1x, const double &p1y, const double &p1z, const double &p2x,
+                                             const double &p2y, const double &p2z, const double &p3x, const double &p3y,
+                                             const double &p3z)
+{
+    GbVector3D A(p1x, p1y, p1z);
+    GbVector3D BA(p2x - p1x, p2y - p1y, p2z - p1z);
+    GbVector3D CA(p3x - p1x, p3y - p1y, p3z - p1z);
+    GbVector3D BACA = BA.Cross(CA);
+
+    BACA.Normalize();
+    this->Normal = BACA;
+    this->d      = this->Normal.Dot(A);
+}
+/*==========================================================*/
+GbHalfSpaceKrischan3D::GbHalfSpaceKrischan3D(double nx, double ny, double nz, double dist)
+{
+    this->Normal = GbVector3D(nx, ny, nz);
+    this->Normal.Normalize();
+    this->d = dist;
+}
+/*==========================================================*/
+double GbHalfSpaceKrischan3D::getCellVolumeInsideGbObject3D(const double &x1a, const double &x2a, const double &x3a,
+                                                            const double &x1b, const double &x2b, const double &x3b)
+{
+
+    double x1 = x1b - x1a;
+    double x2 = x2b - x2a;
+    double x3 = x3b - x3a;
+
+    if (this->isCellInsideGbObject3D(x1a, x2a, x3a, x1b, x2b, x3b))
+        return 1.0 * x1 * x2 * x3;
+    if (!(this->isCellCuttingGbObject3D(x1a, x2a, x3a, x1b, x2b, x3b)))
+        return 0.0;
+
+    double alpha = 0.0;
+    double internX1, internX2, internX3;
+
+    for (int x1vers = 0; x1vers < 2; x1vers++) {
+        for (int x2vers = 0; x2vers < 2; x2vers++) {
+            for (int x3vers = 0; x3vers < 2; x3vers++) {
+                internX1 = x1a + (x1b - x1a) * x1vers;
+                internX2 = x2a + (x2b - x2a) * x2vers;
+                internX3 = x3a + (x3b - x3a) * x3vers;
+
+                // if point is INSIDE the halfspace, distance is smaller than zero
+                // --> loop determines the minimum alpha...i.e. the alpha with maximum absolute value for all points
+                // INSIDE the halfspace
+                if (UbMath::lessEqual(this->getDistance(internX1, internX2, internX3), alpha))
+                    alpha = this->getDistance(internX1, internX2, internX3);
+                // cout<<zelltyp<<" "<<kugel->getDistance(internX1,internX2,internX3)<<" "<<alpha<<endl;
+            } // end first for
+        }     // end second for
+    }         // end third for
+
+    // PLIC needs alphas > 0.0
+    alpha = (-1) * alpha;
+
+    double n[3];
+    n[0] = this->Normal[0];
+    n[1] = this->Normal[1];
+    n[2] = this->Normal[2];
+
+    // cout << "Koordinaten:  "<<x1<<" "<<x2<<" "<<x3<<endl;
+    // cout << "Deltas:       "<<deltaX1<<" "<<deltaX2<<" "<<deltaX3<<endl;
+    // cout << "Halbe Zelle:  "<<halfcelldelta<<endl;
+
+    // cout<<"Centroid:  "<<kugel->getX1Centroid()<<" "<<kugel->getX2Centroid()<<" "<<kugel->getX3Centroid()<<endl;
+
+    // cout<<"Normals: "<<n[0]<<" "<<n[1]<<" "<<n[2]<<endl;
+
+    double normLength;
+    normLength = sqrt(n[0] * n[0] + n[1] * n[1] + n[2] * n[2]);
+    n[0] /= normLength;
+    n[1] /= normLength;
+    n[2] /= normLength;
+
+    if (UbMath::less(n[0], 0.0))
+        n[0] = -n[0];
+    if (UbMath::less(n[1], 0.0))
+        n[1] = -n[1];
+    if (UbMath::less(n[2], 0.0))
+        n[2] = -n[2];
+
+    // cout<<"Normals: "<<n[0]<<" "<<n[1]<<" "<<n[2]<<endl;
+
+    double dummy;
+    if (UbMath::greater(n[0], n[1])) {
+        dummy = n[1];
+        n[1]  = n[0];
+        n[0]  = dummy;
+    }
+    if (UbMath::greater(n[1], n[2])) {
+        dummy = n[2];
+        n[2]  = n[1];
+        n[1]  = dummy;
+    }
+    if (UbMath::greater(n[0], n[1])) {
+        dummy = n[1];
+        n[1]  = n[0];
+        n[0]  = dummy;
+    }
+
+    // cout<<"Normals: "<<n[0]<<" "<<n[1]<<" "<<n[2]<<endl;
+
+    double n1, n2, n3;
+    n1 = n[0];
+    n2 = n[1];
+    n3 = n[2];
+
+    double preresult = 0.0, result = 0.0;
+
+    // 1D Check
+    if (UbMath::lessEqual(n1, 0.00001) && UbMath::lessEqual(n2, 0.00001)) {
+        result = alpha * x1 * x2;
+    }
+    // 2D Check
+    else if (UbMath::lessEqual(n1, 0.00001)) {
+        preresult = (2 * n2 * n3);
+        result    = (alpha * alpha) / preresult;
+
+        if (UbMath::greater(alpha, n2 * x2)) {
+            result += -(alpha - n2 * x2) * (alpha - n2 * x2) / preresult;
+        }
+        if (UbMath::greater(alpha, n3 * x3)) {
+            result += -(alpha - n3 * x3) * (alpha - n3 * x3) / preresult;
+        }
+        if (UbMath::greater(alpha, n2 * x2 + n3 * x3)) {
+            result += (alpha - n2 * x2 - n3 * x3) * (alpha - n2 * x2 - n3 * x3) / preresult;
+        }
+
+        // tiefenrichtung mit einmultiplizieren...
+        result *= x1;
+    }
+    // 3D Check
+    else {
+        preresult = 6 * n1 * n2 * n3;
+
+        result = alpha * alpha * alpha / preresult;
+
+        if (UbMath::greater(alpha, n1 * x1)) {
+            result += -((alpha - n1 * x1) * (alpha - n1 * x1) * (alpha - n1 * x1)) / preresult;
+        }
+        if (UbMath::greater(alpha, n2 * x2)) {
+            result += -((alpha - n2 * x2) * (alpha - n2 * x2) * (alpha - n2 * x2)) / preresult;
+        }
+        if (UbMath::greater(alpha, n3 * x3)) {
+            result += -((alpha - n3 * x3) * (alpha - n3 * x3) * (alpha - n3 * x3)) / preresult;
+        }
+        if (UbMath::greater(alpha, (n1 * x1 + n2 * x2))) {
+            result += ((alpha - (n1 * x1 + n2 * x2)) * (alpha - (n1 * x1 + n2 * x2)) * (alpha - (n1 * x1 + n2 * x2))) /
+                      preresult;
+        }
+        if (UbMath::greater(alpha, (n1 * x1 + n3 * x3))) {
+            result += ((alpha - (n1 * x1 + n3 * x3)) * (alpha - (n1 * x1 + n3 * x3)) * (alpha - (n1 * x1 + n3 * x3))) /
+                      preresult;
+        }
+        if (UbMath::greater(alpha, (n2 * x2 + n3 * x3))) {
+            result += ((alpha - (n2 * x2 + n3 * x3)) * (alpha - (n2 * x2 + n3 * x3)) * (alpha - (n2 * x2 + n3 * x3))) /
+                      preresult;
+        }
+
+        // NEW
+        if (UbMath::greater(alpha, (n1 * x1 + n2 * x2 + n3 * x3))) {
+            result += -((alpha - (n1 * x1 + n2 * x2 + n3 * x3)) * (alpha - (n1 * x1 + n2 * x2 + n3 * x3)) *
+                        (alpha - (n1 * x1 + n2 * x2 + n3 * x3))) /
+                      preresult;
+        }
+    }
+
+    if (!UbMath::inClosedInterval(result / (x1 * x2 * x3), -0.01, 1.01)) {
+        stringstream errMsg;
+
+        errMsg << "Danger...Fuellstand " << result << " nicht im Interfall [0.0..1.0]" << endl;
+        errMsg << "NormVec: " << n1 << " " << n2 << " " << n3 << endl;
+        errMsg << "Cell:    " << x1 << " " << x2 << " " << x3 << endl;
+        errMsg << "Alpha:   " << alpha << endl;
+
+        throw UbException(UB_EXARGS, errMsg.str());
+    }
+
+    return result;
+
+    // double eps=0.0;
+    // if( UbMath::equal(n1,0.0) && UbMath::equal(n2,0.0) )
+    //{
+    //   eps = alpha/n3;
+    //}
+    // else if( UbMath::equal(n1,0.0) )
+    //{
+    //   double dim1,dim2;
+    //   dim1 = alpha/n2;
+    //   dim2 = alpha/n3;
+
+    //   eps = 0.5*dim1*dim2;
+    //   if( UbMath::greater(dim1,1.0) )   eps -= 0.5*(dim1-1.0)*dim2/dim1*(dim1-1.0);
+    //   if( UbMath::greater(dim2,1.0) )   eps -= 0.5*(dim2-1.0)*dim1/dim2*(dim2-1.0);
+    //}
+    // else
+    //{
+    //   eps = alpha*alpha*alpha;
+    //   if( UbMath::greater(alpha,n1) )
+    //      eps -= (alpha-n1)*(alpha-n1)*(alpha-n1);
+    //   if( UbMath::greater(alpha,n2) )
+    //      eps -= (alpha-n2)*(alpha-n2)*(alpha-n2);
+    //   if( UbMath::greater(alpha,n3) )
+    //      eps -= (alpha-n3)*(alpha-n3)*(alpha-n3);
+
+    //   if( UbMath::greater(alpha,n1+n2) )
+    //      eps += (alpha-n1-n2)*(alpha-n1-n2)*(alpha-n1-n2);
+    //   if( UbMath::greater(alpha,n1+n3) )
+    //      eps += (alpha-n1-n3)*(alpha-n1-n3)*(alpha-n1-n3);
+    //   if( UbMath::greater(alpha,n2+n3) )
+    //      eps += (alpha-n2-n3)*(alpha-n2-n3)*(alpha-n2-n3);
+
+    //   //attention: use without delta_i
+    //   eps = eps / (6*n[0]*n[1]*n[2]);
+
+    //   eps = eps / (deltaX1*deltaX2*deltaX3);
+    //}
+
+    // return(eps) ;
+    // cout << "alpha ist " << alpha << endl;
+    // cout << "fillLevel ist " << eps << endl;
+}
+/*==========================================================*/
diff --git a/src/basics/geometry3d/GbHalfSpaceKrischan3D.h b/src/basics/geometry3d/GbHalfSpaceKrischan3D.h
new file mode 100644
index 0000000000000000000000000000000000000000..d62046d4a63d17e3c272c177bdb50823ce1954bb
--- /dev/null
+++ b/src/basics/geometry3d/GbHalfSpaceKrischan3D.h
@@ -0,0 +1,226 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file GbHalfSpaceKrischan3D.h
+//! \ingroup geometry3D
+//! \author Konstantin Kutscher, Soeren Textor, Sebastian Geller
+//=======================================================================================
+#ifndef GbHalfSpaceKrischan3D_H
+#define GbHalfSpaceKrischan3D_H
+
+#include <iostream>
+#include <sstream>
+
+#include <basics/utilities/UbMath.h>
+
+#include <geometry3d/GbLine3D.h>
+#include <geometry3d/GbPoint3D.h>
+#include <geometry3d/GbTriangle3D.h>
+#include <geometry3d/GbVector3D.h>
+
+/*=========================================================================*/
+/* GbHalfSpaceKrischan3D                                                             */
+/*                                                                         */
+/**
+ * This Class helps in performing some operations on a halfspace defined by 2 or 3 points
+ */
+
+class GbHalfSpaceKrischan3D : public GbObject3D, public UbObserver
+{
+public:
+    GbHalfSpaceKrischan3D(GbTriangle3D *triangle);
+
+    GbHalfSpaceKrischan3D(GbPoint3D *PointA, GbPoint3D *PointB, GbPoint3D *PointC);
+
+    GbHalfSpaceKrischan3D(double nx, double ny, double nz, double dist);
+
+    GbHalfSpaceKrischan3D(GbPoint3D *PointA, GbPoint3D *PointB);
+
+    GbHalfSpaceKrischan3D(const double &p1x, const double &p1y, const double &p1z, const double &p2x, const double &p2y,
+                          const double &p2z, const double &p3x, const double &p3y, const double &p3z);
+
+    /*=======================================================*/
+    ~GbHalfSpaceKrischan3D() override = default;
+    /*=======================================================*/
+    std::string getTypeID() { return "GbHalfSpaceKrischan3D"; }
+    /*=============================================*/
+    bool ptInside(const double &x, const double &y, const double &z)
+    {
+        return UbMath::lessEqual(Normal[0] * x + Normal[1] * y + Normal[2] * z, this->d);
+    }
+    /*=============================================*/
+    bool ptInside(GbPoint3D *PointX)
+    {
+        GbVector3D X(PointX->x1, PointX->x2, PointX->x3);
+        return UbMath::lessEqual(this->Normal.Dot(X), this->d);
+    }
+    /*=============================================*/
+    bool ptInside(GbVector3D &X) { return UbMath::lessEqual(this->Normal.Dot(X), this->d); }
+
+    /*=====================================================*/
+    // true, wenn 'in Object' oder 'auf Boundary'!
+    bool isPointInGbObject3D(const double &x1p, const double &x2p, const double &x3p) override
+    {
+        return (ptInside(x1p, x2p, x3p));
+    }
+    /*=====================================================*/
+    // true, wenn 'in Object' oder 'auf Boundary'!
+    bool isPointInGbObject3D(const double &x1p, const double &x2p, const double &x3p,
+                             bool & /*pointIsOnBoundary*/) override
+    {
+        return (ptInside(x1p, x2p, x3p));
+    }
+
+    void finalize() override {}
+
+    double getX1Centroid() override { return 0.0; }
+    double getX1Minimum() override { return -99999.0; }
+    double getX1Maximum() override { return 99999.0; }
+    double getX2Centroid() override { return 0.0; }
+    double getX2Minimum() override { return -99999.0; }
+    double getX2Maximum() override { return 99999.0; }
+    double getX3Centroid() override { return 0.0; }
+    double getX3Minimum() override { return -99999.0; }
+    double getX3Maximum() override { return 99999.0; }
+
+    GbLine3D *createClippedLine3D(GbPoint3D &point1, GbPoint3D &point2) override
+    {
+        GbPoint3D *p1 = new GbPoint3D(point1);
+        GbPoint3D *p2 = new GbPoint3D(point2);
+
+        GbVector3D p1p2(p2->x1 - p1->x1, p2->x2 - p1->x2, p2->x3 - p1->x3);
+
+        double dist1 = getDistance(p1->x1, p1->x2, p1->x3);
+        double dist2 = getDistance(p2->x1, p2->x2, p2->x3);
+
+        double totalDist = std::abs(dist1) + std::abs(dist2);
+
+        // Falls erster Punkt nicht drinliegt
+        if (!ptInside(p1)) {
+            if (!ptInside(p2))
+                return NULL;
+
+            // distance ausrechnen (groesser null)
+            if (UbMath::less(dist1, 0.0))
+                throw UbException(UB_EXARGS, "Punkt ausserhalb, aber Distanz kleiner null???");
+
+            p1->x1 = p1->x1 + dist1 / totalDist * p1p2[0];
+            p1->x2 = p1->x2 + dist1 / totalDist * p1p2[1];
+            p1->x3 = p1->x3 + dist1 / totalDist * p1p2[2];
+        }
+        // Falls zweiter Punkt nicht drinliegt
+        if (!ptInside(p2)) {
+            if (!ptInside(p1))
+                return NULL;
+
+            // distance ausrechnen (groesser null)
+            if (UbMath::less(dist2, 0.0))
+                throw UbException(UB_EXARGS, "Punkt ausserhalb, aber Distanz kleiner null???");
+
+            p2->x1 = p2->x1 - dist2 / totalDist * p1p2[0];
+            p2->x2 = p2->x2 - dist2 / totalDist * p1p2[1];
+            p2->x3 = p2->x3 - dist2 / totalDist * p1p2[2];
+        }
+
+        return new GbLine3D(p1, p2);
+    }
+
+    double getCellVolumeInsideGbObject3D(const double &x1a, const double &x2a, const double &x3a, const double &x1b,
+                                         const double &x2b, const double &x3b) override;
+
+    double getDistance(const double &x1p, const double &x2p, const double &x3p)
+    {
+        return (Normal[0] * x1p + Normal[1] * x2p + Normal[2] * x3p) - this->d;
+    }
+
+    void getNormal(double &n1, double &n2, double &n3)
+    {
+        n1 = this->Normal[0];
+        n2 = this->Normal[1];
+        n3 = this->Normal[2];
+    }
+
+    void addSurfaceTriangleSet(std::vector<UbTupleFloat3> & /*nodes*/,
+                               std::vector<UbTupleInt3> & /*triangles*/) override
+    {
+        std::cout << " addSurfaceTriangleSet(): TO BE DONE AND CHECKED ... " << std::endl;
+    }
+
+    std::vector<GbTriangle3D *> getSurfaceTriangleSet() override
+    {
+        std::vector<GbTriangle3D *> triangles;
+        GbPoint3D p1(0.0, 0.0, 0.0);
+        GbPoint3D p2(1.0, 0.0, 0.0);
+        GbPoint3D p3(0.0, 1.0, 0.0);
+
+        triangles.push_back(new GbTriangle3D(new GbPoint3D(p1), new GbPoint3D(p2), new GbPoint3D(p3)));
+
+        return triangles;
+    }
+
+    void objectChanged(UbObservable * /*changedObject*/) override
+    {
+        return;
+
+        // GbLine3D* line = dynamic_cast<GbLine3D*>(changedObject);
+        // if(!line || this->mLine!=line) return;
+        // this->notifyObserversObjectChanged();
+    }
+    /*==========================================================*/
+    void objectWillBeDeleted(UbObservable * /*objectForDeletion*/) override
+    {
+        return;
+        // if(this->mLine)
+        //{
+        //   UbObservable* observedObj = dynamic_cast<UbObservable*>(this->mLine);
+        //   if(objectForDeletion == observedObj) { this->mLine = NULL; }
+        //}
+    }
+
+    ObObject *clone() override { return NULL; };
+
+    std::string toString() override
+    {
+        std::stringstream temp;
+
+        temp << "GbHalfSpaceKrischan3D:   ";
+        temp << " Distance   " << this->d;
+        temp << " Norm vec   " << this->Normal[0];
+        temp << " " << this->Normal[1];
+        temp << " " << this->Normal[2];
+
+        return temp.str();
+    };
+
+private:
+    GbVector3D Normal;
+    double d;
+};
+/*=========================================================================*/
+
+#endif // GbHalfSpaceKrischan3D_H
diff --git a/src/basics/geometry3d/GbMeshTools3D.h b/src/basics/geometry3d/GbMeshTools3D.h
new file mode 100644
index 0000000000000000000000000000000000000000..2464bcc34788dadfd99e64b9a94878d22df4a54b
--- /dev/null
+++ b/src/basics/geometry3d/GbMeshTools3D.h
@@ -0,0 +1,496 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file GbMeshTools3D.h
+//! \ingroup geometry3D
+//! \author Konstantin Kutscher, Soeren Textor, Sebastian Geller
+//=======================================================================================
+#ifndef GBMESHTOOLS3D_H
+#define GBMESHTOOLS3D_H
+
+#include <iostream>
+#include <sstream>
+#include <vector>
+
+#include <basics/utilities/UbMath.h>
+
+namespace GbMeshTools3D
+{
+inline int planeBoxOverlap(float normal[3], float vert[3], float maxbox[3]) // -NJMP-
+{
+    int q;
+    float vmin[3], vmax[3], v;
+
+    for (q = 0; q <= 2; q++) {
+        v = vert[q]; // -NJMP-
+        if (normal[q] > 0.0f) {
+            vmin[q] = -maxbox[q] - v; // -NJMP-
+            vmax[q] = maxbox[q] - v;  // -NJMP-
+        } else {
+            vmin[q] = maxbox[q] - v;  // -NJMP-
+            vmax[q] = -maxbox[q] - v; // -NJMP-
+        }
+    }
+    if ((normal[0] * vmin[0] + normal[1] * vmin[1] + normal[2] * vmin[2]) > 0.0f)
+        return 0; // -NJMP-
+    if ((normal[0] * vmax[0] + normal[1] * vmax[1] + normal[2] * vmax[2]) >= 0.0f)
+        return 1; // -NJMP-
+    return 0;
+}
+
+// Testet auf schnittpunkt Box <-> Dreieck
+// boxcenter   = Mittelpunkt der Box
+// boxhalfsize = Halbe Laenge/Hoehe/Breite der Box
+// triverts    = Koordinaten der Deickspunkte
+inline int triBoxOverlap(float boxcenter[3], float boxhalfsize[3], float triverts[3][3])
+{
+    /*    use separating axis theorem to test overlap between triangle and box */
+    /*    need to test for overlap in these directions: */
+    /*    1) the {x,y,z}-directions (actually, since we use the AABB of the triangle */
+    /*       we do not even need to test these) */
+    /*    2) normal of the triangle */
+    /*    3) crossproduct(edge from tri, {x,y,z}-directin) */
+    /*       this gives 3x3=9 more tests */
+
+    float v0[3], v1[3], v2[3];
+
+    //   float axis[3];
+
+    float min, max, p0, p1, p2, rad, fex, fey, fez; // -NJMP- "d" local variable removed
+    float normal[3], e0[3], e1[3], e2[3];
+
+    /* This is the fastest branch on Sun */
+    /* move everything so that the boxcenter is in (0,0,0) */
+    // SUB(v0,triverts[0],boxcenter);
+    //#define SUB(dest,v1,v2)
+    v0[0] = triverts[0][0] - boxcenter[0];
+    v0[1] = triverts[0][1] - boxcenter[1];
+    v0[2] = triverts[0][2] - boxcenter[2];
+
+    // SUB(v1,triverts[1],boxcenter);
+    //#define SUB(dest,v1,v2)
+    v1[0] = triverts[1][0] - boxcenter[0];
+    v1[1] = triverts[1][1] - boxcenter[1];
+    v1[2] = triverts[1][2] - boxcenter[2];
+
+    // SUB(v2,triverts[2],boxcenter);
+    //#define SUB(dest,v1,v2)
+    v2[0] = triverts[2][0] - boxcenter[0];
+    v2[1] = triverts[2][1] - boxcenter[1];
+    v2[2] = triverts[2][2] - boxcenter[2];
+
+    /* compute triangle edges */
+    // SUB(e0,v1,v0);      /* tri edge 0 */
+    //#define SUB(dest,v1,v2)
+    e0[0] = v1[0] - v0[0];
+    e0[1] = v1[1] - v0[1];
+    e0[2] = v1[2] - v0[2];
+
+    // SUB(e1,v2,v1);      /* tri edge 1 */
+    //#define SUB(dest,v1,v2)
+    e1[0] = v2[0] - v1[0];
+    e1[1] = v2[1] - v1[1];
+    e1[2] = v2[2] - v1[2];
+
+    // SUB(e2,v0,v2);      /* tri edge 2 */
+    //#define SUB(dest,v1,v2)
+    e2[0] = v0[0] - v2[0];
+    e2[1] = v0[1] - v2[1];
+    e2[2] = v0[2] - v2[2];
+
+    /* Bullet 3:  */
+    /*  test the 9 tests first (this was faster) */
+    fex = fabsf(e0[0]);
+    fey = fabsf(e0[1]);
+    fez = fabsf(e0[2]);
+
+    // AXISTEST_X01(e0[2], e0[1], fez, fey);
+    //#define AXISTEST_X01(a, b, fa, fb)
+    p0 = e0[2] * v0[1] - e0[1] * v0[2];
+    p2 = e0[2] * v2[1] - e0[1] * v2[2];
+    if (p0 < p2) {
+        min = p0;
+        max = p2;
+    } else {
+        min = p2;
+        max = p0;
+    }
+    rad = fez * boxhalfsize[1] + fey * boxhalfsize[2];
+    if (min > rad || max < -rad)
+        return 0;
+
+    // AXISTEST_Y02(e0[2], e0[0], fez, fex);
+    //#define AXISTEST_Y02(a, b, fa, fb)
+    p0 = -e0[2] * v0[0] + e0[0] * v0[2];
+    p2 = -e0[2] * v2[0] + e0[0] * v2[2];
+    if (p0 < p2) {
+        min = p0;
+        max = p2;
+    } else {
+        min = p2;
+        max = p0;
+    }
+    rad = fez * boxhalfsize[0] + fex * boxhalfsize[2];
+    if (min > rad || max < -rad)
+        return 0;
+
+    // AXISTEST_Z12(e0[1], e0[0], fey, fex);
+    //#define AXISTEST_Z12(a, b, fa, fb)
+    p1 = e0[1] * v1[0] - e0[0] * v1[1];
+    p2 = e0[1] * v2[0] - e0[0] * v2[1];
+    if (p2 < p1) {
+        min = p2;
+        max = p1;
+    } else {
+        min = p1;
+        max = p2;
+    }
+    rad = fey * boxhalfsize[0] + fex * boxhalfsize[1];
+    if (min > rad || max < -rad)
+        return 0;
+
+    fex = fabsf(e1[0]);
+    fey = fabsf(e1[1]);
+    fez = fabsf(e1[2]);
+
+    // AXISTEST_X01(e1[2], e1[1], fez, fey);
+    //#define AXISTEST_X01(a, b, fa, fb)
+    p0 = e1[2] * v0[1] - e1[1] * v0[2];
+    p2 = e1[2] * v2[1] - e1[1] * v2[2];
+    if (p0 < p2) {
+        min = p0;
+        max = p2;
+    } else {
+        min = p2;
+        max = p0;
+    }
+    rad = fez * boxhalfsize[1] + fey * boxhalfsize[2];
+    if (min > rad || max < -rad)
+        return 0;
+
+    // AXISTEST_Y02(e1[2], e1[0], fez, fex);
+    //#define AXISTEST_Y02(a, b, fa, fb)
+    p0 = -e1[2] * v0[0] + e1[0] * v0[2];
+    p2 = -e1[2] * v2[0] + e1[0] * v2[2];
+    if (p0 < p2) {
+        min = p0;
+        max = p2;
+    } else {
+        min = p2;
+        max = p0;
+    }
+    rad = fez * boxhalfsize[0] + fex * boxhalfsize[2];
+    if (min > rad || max < -rad)
+        return 0;
+
+    // AXISTEST_Z0(e1[1], e1[0], fey, fex);
+    //#define AXISTEST_Z0(a, b, fa, fb)
+    p0 = e1[1] * v0[0] - e1[0] * v0[1];
+    p1 = e1[1] * v1[0] - e1[0] * v1[1];
+    if (p0 < p1) {
+        min = p0;
+        max = p1;
+    } else {
+        min = p1;
+        max = p0;
+    }
+    rad = fey * boxhalfsize[0] + fex * boxhalfsize[2];
+    if (min > rad || max < -rad)
+        return 0;
+
+    fex = fabsf(e2[0]);
+    fey = fabsf(e2[1]);
+    fez = fabsf(e2[2]);
+    // AXISTEST_X2(e2[2], e2[1], fez, fey);
+    //#define AXISTEST_X2(a, b, fa, fb)
+    p0 = e2[2] * v0[1] - e2[1] * v0[2];
+    p1 = e2[2] * v1[1] - e2[1] * v1[2];
+    if (p0 < p1) {
+        min = p0;
+        max = p1;
+    } else {
+        min = p1;
+        max = p0;
+    }
+    rad = fez * boxhalfsize[1] + fey * boxhalfsize[2];
+    if (min > rad || max < -rad)
+        return 0;
+
+    // AXISTEST_Y1(e2[2], e2[0], fez, fex);
+    //#define AXISTEST_Y1(a, b, fa, fb)
+    p0 = -e2[2] * v0[0] + e2[0] * v0[2];
+    p1 = -e2[2] * v1[0] + e2[0] * v1[2];
+    if (p0 < p1) {
+        min = p0;
+        max = p1;
+    } else {
+        min = p1;
+        max = p0;
+    }
+    rad = fez * boxhalfsize[0] + fex * boxhalfsize[2];
+    if (min > rad || max < -rad)
+        return 0;
+
+    // AXISTEST_Z12(e2[1], e2[0], fey, fex);
+    //#define AXISTEST_Z12(a, b, fa, fb)
+    p1 = e2[1] * v1[0] - e2[0] * v1[1];
+    p2 = e2[1] * v2[0] - e2[0] * v2[1];
+    if (p2 < p1) {
+        min = p2;
+        max = p1;
+    } else {
+        min = p1;
+        max = p2;
+    }
+    rad = fey * boxhalfsize[0] + fex * boxhalfsize[1];
+    if (min > rad || max < -rad)
+        return 0;
+
+    /* Bullet 1: */
+    /*  first test overlap in the {x,y,z}-directions */
+    /*  find min, max of the triangle each direction, and test for overlap in */
+    /*  that direction -- this is equivalent to testing a minimal AABB around */
+    /*  the triangle against the AABB */
+    /* test in X-direction */
+    // FINDMINMAX(v0[0],v1[0],v2[0],min,max);
+    min = (float)UbMath::min(v0[0], v1[0], v2[0]);
+    max = (float)UbMath::max(v0[0], v1[0], v2[0]);
+    if (min > boxhalfsize[0] || max < -boxhalfsize[0])
+        return 0;
+
+    /* test in Y-direction */
+    // FINDMINMAX(v0[1],v1[1],v2[1],min,max);
+    min = (float)UbMath::min(v0[1], v1[1], v2[1]);
+    max = (float)UbMath::max(v0[1], v1[1], v2[1]);
+    if (min > boxhalfsize[1] || max < -boxhalfsize[1])
+        return 0;
+
+    /* test in Z-direction */
+    // FINDMINMAX(v0[2],v1[2],v2[2],min,max);
+    min = (float)UbMath::min(v0[2], v1[2], v2[2]);
+    max = (float)UbMath::max(v0[2], v1[2], v2[2]);
+
+    if (min > boxhalfsize[2] || max < -boxhalfsize[2])
+        return 0;
+
+    /* Bullet 2: */
+    /*  test if the box intersects the plane of the triangle */
+    /*  compute plane equation of triangle: normal*x+d=0 */
+    // CROSS(normal,e0,e1);
+    //#define CROSS(dest,v1,v2)
+    normal[0] = e0[1] * e1[2] - e0[2] * e1[1];
+    normal[1] = e0[2] * e1[0] - e0[0] * e1[2];
+    normal[2] = e0[0] * e1[1] - e0[1] * e1[0];
+
+    // -NJMP- (line removed here)
+    if (!planeBoxOverlap(normal, v0, boxhalfsize))
+        return 0; // -NJMP-
+    return 1;     /* box and triangle overlaps */
+}
+
+} // namespace GbMeshTools3D
+
+#endif
+
+// original - NICHT LOESCHEN - von kroete lynn
+
+//#define X 0
+//#define Y 1
+//#define Z 2
+//
+//#define CROSS(dest,v1,v2)
+//   dest[0]=v1[1]*v2[2]-v1[2]*v2[1];
+//   dest[1]=v1[2]*v2[0]-v1[0]*v2[2];
+//   dest[2]=v1[0]*v2[1]-v1[1]*v2[0];
+//
+//#define DOT(v1,v2) (v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2])
+//
+//#define SUB(dest,v1,v2)
+//   dest[0]=v1[0]-v2[0];
+//   dest[1]=v1[1]-v2[1];
+//   dest[2]=v1[2]-v2[2];
+//
+//#define FINDMINMAX(x0,x1,x2,min,max)
+//   min = max = x0;
+//   if(x1<min) min=x1;
+//   if(x1>max) max=x1;
+//   if(x2<min) min=x2;
+//   if(x2>max) max=x2;
+//
+// int planeBoxOverlap(float normal[3], float vert[3], float maxbox[3])	// -NJMP-
+//{
+//   int q;
+//   float vmin[3],vmax[3],v;
+//
+//   for(q=X;q<=Z;q++)
+//   {
+//      v=vert[q];					// -NJMP-
+//      if(normal[q]>0.0f)
+//      {
+//         vmin[q]=-maxbox[q] - v;	// -NJMP-
+//         vmax[q]= maxbox[q] - v;	// -NJMP-
+//      }
+//      else
+//      {
+//         vmin[q]= maxbox[q] - v;	// -NJMP-
+//         vmax[q]=-maxbox[q] - v;	// -NJMP-
+//      }
+//   }
+//   if(DOT(normal,vmin)>0.0f) return 0;	// -NJMP-
+//   if(DOT(normal,vmax)>=0.0f) return 1;	// -NJMP-
+//   return 0;
+//}
+//
+///*======================== X-tests ========================
+//
+//#define AXISTEST_X01(a, b, fa, fb)
+//   p0 = a*v0[Y] - b*v0[Z];
+//   p2 = a*v2[Y] - b*v2[Z];
+//      if(p0<p2) {min=p0; max=p2;} else {min=p2; max=p0;}
+//   rad = fa * boxhalfsize[Y] + fb * boxhalfsize[Z];
+//   if(min>rad || max<-rad) return 0;
+//
+//#define AXISTEST_X2(a, b, fa, fb)
+//   p0 = a*v0[Y] - b*v0[Z];
+//   p1 = a*v1[Y] - b*v1[Z];
+//      if(p0<p1) {min=p0; max=p1;} else {min=p1; max=p0;}
+//   rad = fa * boxhalfsize[Y] + fb * boxhalfsize[Z];
+//   if(min>rad || max<-rad) return 0;
+//
+//
+//
+///*======================== Y-tests ========================
+//
+//#define AXISTEST_Y02(a, b, fa, fb)
+//   p0 = -a*v0[X] + b*v0[Z];
+//   p2 = -a*v2[X] + b*v2[Z];
+//   if(p0<p2) {min=p0; max=p2;} else {min=p2; max=p0;}
+//   rad = fa * boxhalfsize[X] + fb * boxhalfsize[Z];
+//   if(min>rad || max<-rad) return 0;
+//
+//#define AXISTEST_Y1(a, b, fa, fb)
+//   p0 = -a*v0[X] + b*v0[Z];
+//   p1 = -a*v1[X] + b*v1[Z];
+//      if(p0<p1) {min=p0; max=p1;} else {min=p1; max=p0;}
+//   rad = fa * boxhalfsize[X] + fb * boxhalfsize[Z];
+//   if(min>rad || max<-rad) return 0;
+//
+//======================== Z-tests ========================
+//
+//#define AXISTEST_Z12(a, b, fa, fb)
+//   p1 = a*v1[X] - b*v1[Y];
+//   p2 = a*v2[X] - b*v2[Y];
+//      if(p2<p1) {min=p2; max=p1;} else {min=p1; max=p2;}
+//   rad = fa * boxhalfsize[X] + fb * boxhalfsize[Y];
+//   if(min>rad || max<-rad) return 0;
+//
+//#define AXISTEST_Z0(a, b, fa, fb)
+//   p0 = a*v0[X] - b*v0[Y];
+//   p1 = a*v1[X] - b*v1[Y];
+//      if(p0<p1) {min=p0; max=p1;} else {min=p1; max=p0;}
+//   rad = fa * boxhalfsize[X] + fb * boxhalfsize[Y];
+//   if(min>rad || max<-rad) return 0;
+//
+// int triBoxOverlap(float boxcenter[3],float boxhalfsize[3],float triverts[3][3])
+//{
+//      //use separating axis theorem to test overlap between triangle and box
+//      //need to test for overlap in these directions:
+//      //1) the {x,y,z}-directions (actually, since we use the AABB of the triangle
+//      //   we do not even need to test these)
+//      //2) normal of the triangle
+//      //3) crossproduct(edge from tri, {x,y,z}-directin)
+//      //   this gives 3x3=9 more tests
+//
+//   float v0[3],v1[3],v2[3];
+//
+//   //   float axis[3];
+//
+//   float min,max,p0,p1,p2,rad,fex,fey,fez;		// -NJMP- "d" local variable removed
+//   float normal[3],e0[3],e1[3],e2[3];
+//
+//   /* This is the fastest branch on Sun */
+//   /* move everything so that the boxcenter is in (0,0,0) */
+//   SUB(v0,triverts[0],boxcenter);
+//   SUB(v1,triverts[1],boxcenter);
+//   SUB(v2,triverts[2],boxcenter);
+//
+//   /* compute triangle edges */
+//   SUB(e0,v1,v0);      /* tri edge 0 */
+//   SUB(e1,v2,v1);      /* tri edge 1 */
+//   SUB(e2,v0,v2);      /* tri edge 2 */
+//
+//   /* Bullet 3:  */
+//   /*  test the 9 tests first (this was faster) */
+//   fex = fabsf(e0[X]);
+//   fey = fabsf(e0[Y]);
+//   fez = fabsf(e0[Z]);
+//
+//   AXISTEST_X01(e0[Z], e0[Y], fez, fey);
+//   AXISTEST_Y02(e0[Z], e0[X], fez, fex);
+//   AXISTEST_Z12(e0[Y], e0[X], fey, fex);
+//   fex = fabsf(e1[X]);
+//   fey = fabsf(e1[Y]);
+//   fez = fabsf(e1[Z]);
+//
+//   AXISTEST_X01(e1[Z], e1[Y], fez, fey);
+//   AXISTEST_Y02(e1[Z], e1[X], fez, fex);
+//   AXISTEST_Z0(e1[Y], e1[X], fey, fex);
+//
+//   fex = fabsf(e2[X]);
+//   fey = fabsf(e2[Y]);
+//   fez = fabsf(e2[Z]);
+//   AXISTEST_X2(e2[Z], e2[Y], fez, fey);
+//   AXISTEST_Y1(e2[Z], e2[X], fez, fex);
+//   AXISTEST_Z12(e2[Y], e2[X], fey, fex);
+//
+//   /* Bullet 1: */
+//   /*  first test overlap in the {x,y,z}-directions */
+//   /*  find min, max of the triangle each direction, and test for overlap in */
+//   /*  that direction -- this is equivalent to testing a minimal AABB around */
+//   /*  the triangle against the AABB */
+//   /* test in X-direction */
+//   FINDMINMAX(v0[X],v1[X],v2[X],min,max);
+//   if(min>boxhalfsize[X] || max<-boxhalfsize[X]) return 0;
+//
+//   /* test in Y-direction */
+//   FINDMINMAX(v0[Y],v1[Y],v2[Y],min,max);
+//   if(min>boxhalfsize[Y] || max<-boxhalfsize[Y]) return 0;
+//
+//   /* test in Z-direction */
+//   FINDMINMAX(v0[Z],v1[Z],v2[Z],min,max);
+//   if(min>boxhalfsize[Z] || max<-boxhalfsize[Z]) return 0;
+//
+//   /* Bullet 2: */
+//   /*  test if the box intersects the plane of the triangle */
+//   /*  compute plane equation of triangle: normal*x+d=0 */
+//   CROSS(normal,e0,e1);
+//
+//   // -NJMP- (line removed here)
+//   if(!planeBoxOverlap(normal,v0,boxhalfsize)) return 0;	// -NJMP-
+//   return 1;   /* box and triangle overlaps */
+//}
diff --git a/src/basics/geometry3d/GbObjectGroup3D.cpp b/src/basics/geometry3d/GbObjectGroup3D.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a3a964b1dc95a9f13a122f985375873baa830f7d
--- /dev/null
+++ b/src/basics/geometry3d/GbObjectGroup3D.cpp
@@ -0,0 +1,148 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file GbObjectGroup3D.cpp
+//! \ingroup geometry3D
+//! \author Konstantin Kutscher, Soeren Textor, Sebastian Geller
+//=======================================================================================
+#include <geometry3d/GbLine3D.h>
+#include <geometry3d/GbObjectGroup3D.h>
+#include <geometry3d/GbPoint3D.h>
+#include <geometry3d/GbSystem3D.h>
+#include <geometry3d/GbTriangle3D.h>
+
+using namespace std;
+
+/*=====================================================*/
+GbObjectGroup3D::GbObjectGroup3D() { this->setName("ObjectGroup"); }
+/*=====================================================*/
+GbObjectGroup3D::~GbObjectGroup3D() = default;
+/*=====================================================*/
+void GbObjectGroup3D::finalize() { throw UbException(UB_EXARGS, "not implemented."); }
+/*=======================================================*/
+void GbObjectGroup3D::setCenterCoordinates(const double & /*x1*/, const double & /*x2*/, const double & /*x3*/)
+{
+    throw UbException(UB_EXARGS, "not implemented.");
+}
+/*=====================================================*/
+double GbObjectGroup3D::getDistance(GbPoint3D * /*p*/) { throw UbException(UB_EXARGS, "not implemented."); }
+/*=====================================================*/
+
+void GbObjectGroup3D::setCenterX1Coordinate(const double & /*value*/)
+{
+    throw UbException(UB_EXARGS, "not implemented.");
+}
+/*=====================================================*/
+void GbObjectGroup3D::setCenterX2Coordinate(const double & /*value*/)
+{
+    throw UbException(UB_EXARGS, "not implemented.");
+}
+/*=====================================================*/
+void GbObjectGroup3D::setCenterX3Coordinate(const double & /*value*/)
+{
+    throw UbException(UB_EXARGS, "not implemented.");
+}
+/*=====================================================*/
+void GbObjectGroup3D::setRadius(const double & /*radius*/) { throw UbException(UB_EXARGS, "not implemented."); }
+/*=====================================================*/
+double GbObjectGroup3D::getDistance(const double & /*x1p*/, const double & /*x2p*/, const double & /*x3p*/)
+{
+    throw UbException(UB_EXARGS, "not implemented.");
+}
+/*=====================================================*/
+// true, wenn 'in Object' oder 'auf Boundary'!
+bool GbObjectGroup3D::isPointInGbObject3D(const double & /*x1p*/, const double & /*x2p*/, const double & /*x3p*/)
+{
+    return false;
+}
+/*=====================================================*/
+// true, wenn 'in Object' oder 'auf Boundary'!
+bool GbObjectGroup3D::isPointInGbObject3D(const double & /*x1p*/, const double & /*x2p*/, const double & /*x3p*/,
+                                          bool & /*pointIsOnBoundary*/)
+{
+    return false;
+}
+/*=====================================================*/
+string GbObjectGroup3D::toString()
+{
+    stringstream ss;
+    ss << "GbObjectGroup3D[";
+    ss << "mid=" << midPoint->toString() << ", r=" << radius << "]";
+    return ss.str();
+}
+/*=====================================================*/
+GbLine3D *GbObjectGroup3D::createClippedLine3D(GbPoint3D & /*point1*/, GbPoint3D & /*point2*/) { return NULL; }
+/*=========================================================================*/
+vector<GbTriangle3D *> GbObjectGroup3D::getSurfaceTriangleSet()
+{
+    vector<GbTriangle3D *> allTriangles;
+
+    // loop ueber alle objekte in der group
+    for (std::list<GbObject3D *>::iterator iter = this->geoobjects.begin(); iter != this->geoobjects.end(); iter++) {
+        vector<GbTriangle3D *> triangles;
+        triangles = (*iter)->getSurfaceTriangleSet();
+
+        for (size_t i = 0; i < triangles.size(); i++) {
+            // kopieren...
+            allTriangles.push_back(triangles[i]);
+        }
+    }
+    return allTriangles;
+}
+/*=======================================================*/
+void GbObjectGroup3D::addSurfaceTriangleSet(vector<UbTupleFloat3> &/*nodes*/, vector<UbTupleInt3> &/*triangles*/) {}
+/*=======================================================*/
+bool GbObjectGroup3D::hasIntersectionWithDirectedLine(GbPoint3D /*origin*/, GbPoint3D /*direction*/) { return false; }
+/*=======================================================*/
+bool GbObjectGroup3D::isCellCuttingGbObject3D(const double & /*x1a*/, const double & /*x2a*/, const double & /*x3a*/,
+                                              const double & /*x1b*/, const double & /*x2b*/, const double & /*x3b*/)
+{
+    return false;
+}
+/*=======================================================*/
+bool GbObjectGroup3D::isCellInsideOrCuttingGbObject3D(const double & /*x1a*/, const double & /*x2a*/,
+                                                      const double & /*x3a*/, const double & /*x1b*/,
+                                                      const double & /*x2b*/, const double & /*x3b*/)
+{
+    return false;
+}
+/*==========================================================*/
+double GbObjectGroup3D::getCellVolumeInsideGbObject3D(const double & /*x1a*/, const double & /*x2a*/,
+                                                      const double & /*x3a*/, const double & /*x1b*/,
+                                                      const double & /*x2b*/, const double & /*x3b*/)
+{
+    return 0.0;
+}
+/*==========================================================*/
+double GbObjectGroup3D::getIntersectionRaytraceFactor(const double & /*x1*/, const double & /*x2*/,
+                                                      const double & /*x3*/, const double & /*rx1*/,
+                                                      const double & /*rx2*/, const double & /*rx3*/)
+{
+    return 0.0;
+}
+/*=======================================================*/
diff --git a/src/basics/geometry3d/GbObjectGroup3D.h b/src/basics/geometry3d/GbObjectGroup3D.h
new file mode 100644
index 0000000000000000000000000000000000000000..6c748a12a403594e7604f580fdc30245c1c6d28c
--- /dev/null
+++ b/src/basics/geometry3d/GbObjectGroup3D.h
@@ -0,0 +1,163 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file GbObjectGroup3D.h
+//! \ingroup geometry3D
+//! \author Konstantin Kutscher, Soeren Textor, Sebastian Geller
+//=======================================================================================
+#ifndef GBOBJECTGROUP3D_H
+#define GBOBJECTGROUP3D_H
+
+#ifdef CAB_CTL
+#include <ctl.h>
+#endif // CAB_CTL
+
+#include <cmath>
+#include <vector>
+
+#include <basics/utilities/UbObserver.h>
+#include <geometry3d/GbObject3D.h>
+#include <geometry3d/GbPoint3D.h>
+
+#include <PointerDefinitions.h>
+
+class GbLine3D;
+class GbTriangle3D;
+class GbObject3DCreator;
+
+class GbObjectGroup3D : public GbObject3D, public UbObserver
+{
+public:
+    enum TRIANGULATIONMODE { CUBOIDPROJECTION, RAYPROJECTION };
+
+    //////////////////////////////////////////////////////////////////////////
+    // Konstruktoren
+    GbObjectGroup3D();
+    GbObjectGroup3D(GbObjectGroup3D * /*group*/){};
+    ~GbObjectGroup3D() override;
+
+    GbObjectGroup3D *clone() override { return new GbObjectGroup3D(this); }
+    void finalize() override;
+
+    void addGbObject(GbObject3D *object) { this->geoobjects.push_back(object); }
+
+    double getRadius() const { return this->radius; }
+
+    double getX1Centroid() override { return midPoint->getX1Coordinate(); }
+    double getX1Minimum() override { return midPoint->getX1Coordinate() - radius; }
+    double getX1Maximum() override { return midPoint->getX1Coordinate() + radius; }
+    double getX2Centroid() override { return midPoint->getX2Coordinate(); }
+    double getX2Minimum() override { return midPoint->getX2Coordinate() - radius; }
+    double getX2Maximum() override { return midPoint->getX2Coordinate() + radius; }
+    double getX3Centroid() override { return midPoint->getX3Coordinate(); }
+    double getX3Minimum() override { return midPoint->getX3Coordinate() - radius; }
+    double getX3Maximum() override { return midPoint->getX3Coordinate() + radius; }
+
+    void setCenterX1Coordinate(const double &value) override;
+    void setCenterX2Coordinate(const double &value) override;
+    void setCenterX3Coordinate(const double &value) override;
+    void setCenterCoordinates(const double &x1, const double &x2, const double &x3) override;
+    void setRadius(const double &radius);
+
+    GbLine3D *createClippedLine3D(GbPoint3D &point1, GbPoint3D &point2) override;
+    double getDistance(GbPoint3D *p);
+    double getDistance(const double &x1p, const double &x2p, const double &x3p);
+
+    bool isPointInGbObject3D(const double &x1, const double &x2, const double &x3) override;
+    bool isPointInGbObject3D(const double &x1p, const double &x2p, const double &x3p, bool &pointIsOnBoundary) override;
+
+    bool isCellCuttingGbObject3D(const double &x1a, const double &x2a, const double &x3a, const double &x1b,
+                                 const double &x2b, const double &x3b) override;
+    bool isCellInsideOrCuttingGbObject3D(const double &x1a, const double &x2a, const double &x3a, const double &x1b,
+                                         const double &x2b, const double &x3b) override;
+    double getCellVolumeInsideGbObject3D(const double &x1a, const double &x2a, const double &x3a, const double &x1b,
+                                         const double &x2b, const double &x3b) override;
+
+    std::vector<GbTriangle3D *> getSurfaceTriangleSet() override;
+    void addSurfaceTriangleSet(std::vector<UbTupleFloat3> &nodes, std::vector<UbTupleInt3> &triangles) override;
+
+    bool hasRaytracing() override { return true; }
+    /*|r| must be 1! einheitsvector!!*/
+    double getIntersectionRaytraceFactor(const double &x1, const double &x2, const double &x3, const double &rx1,
+                                         const double &rx2, const double &rx3) override;
+
+    bool hasIntersectionWithDirectedLine(GbPoint3D origin, GbPoint3D direction);
+
+    std::string toString() override;
+
+    void translate(const double &x1, const double &x2, const double &x3) override
+    {
+        this->midPoint->translate(x1, x2, x3);
+        this->notifyObserversObjectChanged();
+    }
+    void rotate(const double &/*rx1*/, const double &/*rx2*/, const double &/*rx3*/) override
+    { /* rotation makes no sense*/
+    }
+    void scale(const double &sx1, const double & /*sx2*/, const double & /*sx3*/) override { this->radius *= sx1; }
+
+    TRIANGULATIONMODE getTriangulationMode() { return triangulationMode; }
+    void setTriangulationMode(TRIANGULATIONMODE mode) { this->triangulationMode = mode; }
+
+    // virtuelle Methoden von UbObserver
+    void objectChanged(UbObservable * /*changedObject*/) override
+    {
+        this->notifyObserversObjectChanged();
+        // std::cout<<"GbSphere:objectChanged() - toDo-);";
+    }
+    void objectWillBeDeleted(UbObservable * /*objectForDeletion*/) override
+    {
+        std::cout << "throw UbException(-GbObjectGroup3D::finalize() - toDo-);";
+    }
+
+    using GbObject3D::isPointInGbObject3D; // Grund: dadurch muss man hier  isPointInGbObject3D(GbPoint3D*) nicht
+                                           // ausprogrammieren, welche sonst hier "ueberdeckt" waere, weil man eine
+
+    std::list<GbObject3D *> getGbObject3DList() { return this->geoobjects; }
+
+#ifdef CAB_CTL
+    ctl::oStream &write(ctl::oStream &os) const
+    {
+        midPoint->write(os);
+        return os << radius;
+    }
+    ctl::iStream &read(ctl::iStream &is)
+    {
+        midPoint->read(is);
+        return is >> radius;
+    }
+#endif // CAB_CTL
+
+private:
+    GbPoint3D *midPoint;
+    double radius; // Radius des Kreises
+    TRIANGULATIONMODE triangulationMode;
+
+    std::list<GbObject3D *> geoobjects;
+};
+
+#endif // GbObjectGroup3D_H
diff --git a/src/basics/geometry3d/GbQuadFaceMesh3D.cpp b/src/basics/geometry3d/GbQuadFaceMesh3D.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1b2c2aeaabf1eacd78577cc67b678be895747e05
--- /dev/null
+++ b/src/basics/geometry3d/GbQuadFaceMesh3D.cpp
@@ -0,0 +1,342 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file GbQuadFaceMesh3D.cpp
+//! \ingroup geometry3D
+//! \author Konstantin Kutscher, Soeren Textor, Sebastian Geller
+//=======================================================================================
+#include <geometry3d/GbQuadFaceMesh3D.h>
+
+#include <geometry3d/GbCuboid3D.h>
+#include <geometry3d/GbHalfSpace3D.h>
+
+using namespace std;
+
+GbQuadFaceMesh3D::GbQuadFaceMesh3D() : GbObject3D()
+{
+    this->name       = "new GbMesh";
+    this->nodes      = new vector<Vertex>;
+    this->quads      = new vector<QuadFace>;
+    this->consistent = false;
+}
+
+GbQuadFaceMesh3D::GbQuadFaceMesh3D(string name, vector<Vertex> *nodes, vector<QuadFace> *quads) : GbObject3D()
+{
+    if (name.size() == 0)
+        throw UbException(UB_EXARGS, "no name specified");
+    if (!nodes)
+        throw UbException(UB_EXARGS, "no nodes specified");
+    if (!quads)
+        throw UbException(UB_EXARGS, "no quads specified");
+
+    this->name       = name;
+    this->nodes      = nodes;
+    this->quads      = quads;
+    this->consistent = false;
+}
+/*=============================================================================================*/
+
+GbQuadFaceMesh3D::~GbQuadFaceMesh3D()
+{
+    if (nodes) {
+        //	for(unsigned u=0; u<nodes->size(); u++) delete (*nodes)[u];
+        delete nodes;
+    }
+    if (quads) {
+        delete quads;
+    }
+}
+/*======================================================================*/
+
+void GbQuadFaceMesh3D::init()
+{
+    nodes      = NULL;
+    quads      = NULL;
+    x1min      = 0.0;
+    x1max      = 0.0;
+    x2min      = 0.0;
+    x2max      = 0.0;
+    x3min      = 0.0;
+    x3max      = 0.0;
+    consistent = false;
+}
+/**
+ * Returns a string representation of this triangular mesh.
+ * @return a string representation of this triangular mesh
+ */
+string GbQuadFaceMesh3D::toString()
+{
+    stringstream ss;
+    ss << "GbQuadFaceMesh3D[";
+    ss << (int)this->quads->size() << "-Quadangles, " << (int)this->nodes->size() << "-Nodes, " << endl;
+    // ss<<"\""<<this->name<<", Area=sollt mal berechnet werden ;-)"<<"\"";
+    // ss<<", x1min="<<this->x1min;
+    // ss<<", x1max="<<this->x1max;
+    // ss<<", x2min="<<this->x2min;
+    // ss<<", x2max="<<this->x2max;
+    // ss<<", x3min="<<this->x3min;
+    // ss<<", x3max="<<this->x3max;
+    ss << "]";
+    return (ss.str());
+}
+/**
+ * Returns the name of this triangular mesh.
+ * @return the name of this triangular mesh
+ */
+string GbQuadFaceMesh3D::getName() { return (this->name); }
+
+/**
+ * Returns the nodes of this triangular mesh.
+ * @return the nodes of this triangular mesh
+ */
+vector<GbQuadFaceMesh3D::Vertex> *GbQuadFaceMesh3D::getNodes() { return (this->nodes); }
+/**
+ * Returns the quads of this triangular mesh.
+ * @return the quads of this triangular mesh
+ */
+vector<GbQuadFaceMesh3D::QuadFace> *GbQuadFaceMesh3D::getQuads() { return (this->quads); }
+/**
+ * Returns the center x1 coordinate of this triangular mesh.
+ * @return the center x1 coordinate of this triangular mesh
+ */
+double GbQuadFaceMesh3D::getX1Centroid()
+{
+    if (!this->consistent)
+        this->calculateValues();
+    return (0.5 * (this->x1min + this->x1max));
+}
+/**
+ * Returns the center x2 coordinate of this triangular mesh.
+ * @return the center x2 coordinate of this triangular mesh
+ */
+double GbQuadFaceMesh3D::getX2Centroid()
+{
+    if (!this->consistent)
+        this->calculateValues();
+    return (0.5 * (this->x2min + this->x2max));
+}
+/**
+ * Returns the center x3 coordinate of this triangular mesh.
+ * @return the center x3 coordinate of this triangular mesh
+ */
+double GbQuadFaceMesh3D::getX3Centroid()
+{
+    if (!this->consistent)
+        this->calculateValues();
+    return (0.5 * (this->x3min + this->x3max));
+}
+
+/**
+ * Returns the minimum x1 coordinate of this triangular mesh.
+ * @return the minimum x1 coordinate of this triangular mesh
+ */
+double GbQuadFaceMesh3D::getX1Minimum()
+{
+    if (!this->consistent)
+        this->calculateValues();
+    return (this->x1min);
+}
+/**
+ * Returns the maximum x1 coordinate of this triangular mesh.
+ * @return the maximum x1 coordinate of this triangular mesh
+ */
+double GbQuadFaceMesh3D::getX1Maximum()
+{
+    if (!this->consistent)
+        this->calculateValues();
+    return (this->x1max);
+}
+/**
+ * Returns the minimum x2 coordinate of this triangular mesh.
+ * @return the minimum x2 coordinate of this triangular mesh
+ */
+double GbQuadFaceMesh3D::getX2Minimum()
+{
+    if (!this->consistent)
+        this->calculateValues();
+    return (this->x2min);
+}
+/**
+ * Returns the maximum x2 coordinate of this triangular mesh.
+ * @return the maximum x2 coordinate of this triangular mesh
+ */
+double GbQuadFaceMesh3D::getX2Maximum()
+{
+    if (!this->consistent)
+        this->calculateValues();
+    return (this->x2max);
+}
+/**
+ * Returns the minimum x3 coordinate of this triangular mesh.
+ * @return the minimum x3 coordinate of this triangular mesh
+ */
+double GbQuadFaceMesh3D::getX3Minimum()
+{
+    if (!this->consistent)
+        this->calculateValues();
+    return (this->x3min);
+}
+/**
+ * Returns the maximum x3 coordinate of this triangular mesh.
+ * @return the maximum x3 coordinate of this triangular mesh
+ */
+double GbQuadFaceMesh3D::getX3Maximum()
+{
+    if (!this->consistent)
+        this->calculateValues();
+    return (this->x3max);
+}
+
+void GbQuadFaceMesh3D::calculateValues()
+{
+    double x1, x2, x3;
+
+    this->x1min = (*this->nodes)[0].x;
+    this->x1max = (*this->nodes)[0].x;
+    this->x2min = (*this->nodes)[0].y;
+    this->x2max = (*this->nodes)[0].y;
+    this->x3min = (*this->nodes)[0].z;
+    this->x3max = (*this->nodes)[0].z;
+
+    for (int i = 1; i < (int)this->nodes->size(); i++) {
+        x1 = (*this->nodes)[i].x;
+        x2 = (*this->nodes)[i].y;
+        x3 = (*this->nodes)[i].z;
+        if (x1 < this->x1min)
+            this->x1min = x1;
+        if (x1 > this->x1max)
+            this->x1max = x1;
+        if (x2 < this->x2min)
+            this->x2min = x2;
+        if (x2 > this->x2max)
+            this->x2max = x2;
+        if (x3 < this->x3min)
+            this->x3min = x3;
+        if (x3 > this->x3max)
+            this->x3max = x3;
+    }
+    this->consistent = true;
+}
+
+/*======================================================================*/
+vector<GbTriangle3D *> GbQuadFaceMesh3D::getSurfaceTriangleSet()
+{
+    vector<GbTriangle3D *> triangles(0);
+    return triangles;
+    // throw UbException(__FILE__, __LINE__, "GbQuadFaceMesh3D::getSurfaceTriangelSet - not implemented");
+}
+// vector<GbQuad3D*> GbQuadFaceMesh3D::getSurfaceQuadSet()
+//{
+//   throw UbException(__FILE__, __LINE__, "GbQuadFaceMesh3D::getSurfaceQuadSet - not implemented");
+//   //vector<GbQuadangle3D*> tris;
+//   //GbQuadangle3D* quad;
+//   //GbPoint3D* p1;
+//   //GbPoint3D* p2;
+//   //GbPoint3D* p3;
+//   //int size = (int)this->quads->size();
+//   //for(int u=0; u<size;u++)
+//   //{
+//   //   quad = (*this->quads)[u];
+//   //   p1 = new GbPoint3D(quad->getPoint1());
+//   //   p2 = new GbPoint3D(quad->getPoint2());
+//   //   p3 = new GbPoint3D(quad->getPoint3());
+//   //   tris.push_back(new GbQuadangle3D(p1, p2, p3));
+//   //}
+//   //return tris;
+//}
+/*======================================================================*/
+/*
+ * Function to determine if the point is inside the polyhedron defined as a 3D object
+ * using the Halfspace algorithm
+ * @param xp the x-coordinate of the point
+ * @param yp the y-coordinate of the point
+ * @param zp the z-coordinate of the point
+ * @return true if point is inside else return false
+ */
+bool GbQuadFaceMesh3D::isPointInObject3DHalfSpace(const double & /*xp*/, const double & /*yp*/, const double & /*zp*/)
+{
+    throw UbException(UB_EXARGS, "not implemented");
+    // vector<GbQuadangle3D*> *Quadangles = this->quads;
+    // int Quadanglesize = (int)Quadangles->size();
+    // GbPoint3D Point(xp,yp,zp);
+    // for (int i=0; i<Quadanglesize; i++)
+    //{
+    //   GbPoint3D* point1 = (*Quadangles)[i]->getPoint1();
+    //   GbPoint3D* point2 = (*Quadangles)[i]->getPoint2();
+    //   GbPoint3D* point3 = (*Quadangles)[i]->getPoint3();
+
+    //   GbHalfSpace3D halfspace(point1, point2, point3);
+    //   if (halfspace.ptInside(&Point)) return false;
+    //}
+    // return true;
+}
+/*======================================================================*/
+/*======================================================================*/
+bool GbQuadFaceMesh3D::isPointInGbObject3D(const double &x1, const double &x2, const double &x3)
+{
+
+    double xmin = this->getX1Minimum();
+    double xmax = this->getX1Maximum();
+    double ymin = this->getX2Minimum();
+    double ymax = this->getX2Maximum();
+    double zmin = this->getX3Minimum();
+    double zmax = this->getX3Maximum();
+    double dX   = (xmax - xmin) / 100.;
+    double dY   = (ymax - ymin) / 100.;
+    double dZ   = (zmax - zmin) / 100.;
+    GbCuboid3D boundingCube(xmin - dX, ymin - dY, zmin - dZ, xmax + dX, ymax + dY, zmax + dZ);
+    if (!boundingCube.isPointInGbObject3D(x1, x2, x3)) {
+        boundingCube.finalize();
+        return false;
+    }
+    boundingCube.finalize();
+
+    // Halfspace algorithm, Area of spherical polygons algorithm or Ray crossing algorithm
+    GbVector3D bMin(boundingCube.getPoint1());
+    GbVector3D bMax(boundingCube.getPoint2());
+    bMin = bMax.Subtract(bMin);
+    // int radius = (int)bMin.Length();
+
+    // if(((GbQuadFaceMesh3D*)this->geoObject3D)->isPointInObject3DHalfSpace(x1,x2,x3) )
+    // if(((GbQuadFaceMesh3D*)this->geoObject3D)->isPointInObject3Darea(x11,x12,x13,numQuadangles))
+    // if(this->isPointInObject3DRayCrossing(x1,x2,x3,radius,(int)this->nodes->size(),(int)this->quads->size()))
+    //   return true;
+    // else
+    return false;
+}
+/*======================================================================*/
+bool GbQuadFaceMesh3D::isPointInGbObject3D(const double & /*x1*/, const double & /*x2*/, const double & /*x3*/,
+                                           bool & /*pointIsOnBoundary*/)
+{
+    throw UbException(UB_EXARGS, "not implemented");
+}
+/*======================================================================*/
+GbLine3D *GbQuadFaceMesh3D::createClippedLine3D(GbPoint3D & /*point1*/, GbPoint3D & /*point2*/)
+{
+    throw UbException(UB_EXARGS, "not implemented");
+}
diff --git a/src/basics/geometry3d/GbQuadFaceMesh3D.h b/src/basics/geometry3d/GbQuadFaceMesh3D.h
new file mode 100644
index 0000000000000000000000000000000000000000..2671488303695158dcaa618a4ffa9c101bb5e1c3
--- /dev/null
+++ b/src/basics/geometry3d/GbQuadFaceMesh3D.h
@@ -0,0 +1,150 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file GbQuadFaceMesh3D.h
+//! \ingroup geometry3D
+//! \author Konstantin Kutscher, Soeren Textor, Sebastian Geller
+//=======================================================================================
+#ifndef GBQUADFACEMESH3D_H
+#define GBQUADFACEMESH3D_H
+
+#include <iostream>
+#include <sstream>
+
+#include <basics/utilities/UbException.h>
+#include <geometry3d/GbObject3D.h>
+
+#include <PointerDefinitions.h>
+
+class UbFileOutput;
+class UbFileInput;
+/*=========================================================================*/
+/* GbQuadFaceMesh3D                                                                  */
+/*                                                                         */
+/**
+ * This Class provides the triangular meshes.
+ * Note, that up to now no methods for checking consistency are included.
+ * in this context this class describes facettes from an 3D-object !!!
+ */
+class GbQuadFaceMesh3D : public GbObject3D
+{
+public:
+    // nested class start
+    class Vertex
+    {
+    public:
+        Vertex() = default;
+        Vertex(float x, float y, float z)
+        {
+            this->x = x;
+            this->y = y;
+            this->z = z;
+        }
+        float x, y, z;
+    };
+
+    class QuadFace
+    {
+    public:
+        QuadFace() = default;
+        QuadFace(int v1, int v2, int v3, int v4)
+        {
+            this->vertex1 = v1;
+            this->vertex2 = v2;
+            this->vertex3 = v3;
+            this->vertex4 = v4;
+        }
+
+        int vertex1, vertex2, vertex3, vertex4;
+    };
+    // nested class end
+
+public:
+    GbQuadFaceMesh3D();
+    GbQuadFaceMesh3D(std::string name, std::vector<Vertex> *nodes, std::vector<QuadFace> *quads);
+    ~GbQuadFaceMesh3D() override;
+    GbQuadFaceMesh3D *clone() override { throw UbException(UB_EXARGS, "clone() - not implemented"); }
+    void finalize() override { throw UbException(UB_EXARGS, "finalize() - not implemented"); }
+
+    std::string toString() override;
+    std::string getName() override;
+    std::vector<Vertex> *getNodes();
+    std::vector<QuadFace> *getQuads();
+    double getX1Centroid() override;
+    double getX2Centroid() override;
+    double getX3Centroid() override;
+    double getX1Minimum() override;
+    double getX1Maximum() override;
+    double getX2Minimum() override;
+    double getX2Maximum() override;
+    double getX3Minimum() override;
+    double getX3Maximum() override;
+    void calculateValues();
+
+    bool isPointInGbObject3D(const double &x1, const double &x2, const double &x3) override;
+    bool isPointInGbObject3D(const double &x1, const double &x2, const double &x3, bool &pointIsOnBoundary) override;
+
+    bool isPointInObject3DHalfSpace(const double &xp, const double &yp,
+                                    const double &zp); // based on Halfspace algorithm
+    // bool isPointInObject3DSpherical(const double& xp, const double& yp, const double& zp, int numQuads);    //based
+    // on Spherical polygon area method bool isPointInObject3DRayCrossing(const double& xp, const double& yp, const
+    // double& zp, int radius, int numVertices, int numQuads);  //based on Ray tracing algorithm
+
+    // char SegPlaneInt(GbQuad3D *quad, GbVector3D  &PointQ, GbVector3D &PointR, GbVector3D &Point, int *m);
+    // char SegQuadCross(GbQuad3D *quad, GbVector3D  &PointQ, GbVector3D &PointR);
+    // till here !!!
+
+    GbLine3D *createClippedLine3D(GbPoint3D &point1, GbPoint3D &point2) override;
+    // virtual std::vector<GbQuad3D*> getSurfaceQuadSet();
+    std::vector<GbTriangle3D *> getSurfaceTriangleSet() override;
+
+    virtual void write(UbFileOutput * /*out*/) { std::cout << "GbQuadFaceMesh3D::write - sorry not implemented\n"; }
+    virtual void read(UbFileInput * /*in*/) { std::cout << "GbQuadFaceMesh3D::read  - sorry not implemented\n"; }
+
+    void writeAVSMesh(UbFileOutput *out, bool normals = false);
+
+    /*======================================================================*/
+    using GbObject3D::isPointInGbObject3D; // Grund: dadurch muss man hier  isPointInGbObject3D(GbPoint3D*) nicht
+                                           // ausprogrammieren, welche sonst hier "ueberdeckt" waere
+private:
+    void init();
+    /*======================================================================*/
+    std::string name;
+    std::vector<Vertex> *nodes;
+    std::vector<QuadFace> *quads;
+    double x1min;
+    double x1max;
+    double x2min;
+    double x2max;
+    double x3min;
+    double x3max;
+    bool consistent;
+};
+/*=========================================================================*/
+
+#endif
diff --git a/src/basics/geometry3d/GbSphere3D.cpp b/src/basics/geometry3d/GbSphere3D.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2cb94c462c6e2c1b95e820fab06fe2d37325ecb1
--- /dev/null
+++ b/src/basics/geometry3d/GbSphere3D.cpp
@@ -0,0 +1,957 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file GbSphere3D.cpp
+//! \ingroup geometry3D
+//! \author Konstantin Kutscher, Soeren Textor, Sebastian Geller
+//=======================================================================================
+#include <geometry3d/GbLine3D.h>
+#include <geometry3d/GbPoint3D.h>
+#include <geometry3d/GbSphere3D.h>
+#include <geometry3d/GbSystem3D.h>
+#include <geometry3d/GbTriangle3D.h>
+
+using namespace std;
+
+/*=====================================================*/
+GbSphere3D::GbSphere3D() : GbObject3D(), UbObserver()
+{
+    this->setName("sphere");
+    radius   = 0;
+    midPoint = new GbPoint3D(0, 0, 0);
+}
+/*=====================================================*/
+GbSphere3D::GbSphere3D(const double &x1, const double &x2, const double &x3, const double &radius)
+    : GbObject3D(), UbObserver()
+{
+    this->setName("sphere");
+    midPoint = new GbPoint3D(x1, x2, x3);
+    midPoint->addObserver(this);
+
+    this->radius      = radius;
+    triangulationMode = RAYPROJECTION;
+    // triangulationMode = CUBOIDPROJECTION;
+}
+/*=====================================================*/
+GbSphere3D::GbSphere3D(const GbSphere3D &sphere) : GbObject3D(sphere), UbObserver()
+{
+    this->setName("sphere");
+
+    this->midPoint    = sphere.midPoint->clone();
+    this->radius      = sphere.radius;
+    triangulationMode = RAYPROJECTION;
+
+    this->midPoint->addObserver(this);
+}
+/*=====================================================*/
+GbSphere3D::GbSphere3D(GbSphere3D *sphere) : GbObject3D(), UbObserver()
+{
+    this->setName(sphere->getName());
+    midPoint = sphere->midPoint->clone();
+    midPoint->addObserver(this);
+
+    this->radius      = sphere->getRadius();
+    triangulationMode = RAYPROJECTION;
+}
+/*=====================================================*/
+GbSphere3D::~GbSphere3D()
+{
+    if (this->midPoint)
+        this->midPoint->removeObserver(this);
+}
+/*=====================================================*/
+void GbSphere3D::finalize()
+{
+    if (this->midPoint) {
+        this->midPoint->removeObserver(this);
+        this->midPoint->finalize();
+        delete this->midPoint;
+        this->midPoint = NULL;
+    }
+
+    if (this->midPoint)
+        this->midPoint->removeObserver(this);
+}
+/*=====================================================*/
+bool GbSphere3D::intersects(SPtr<GbSphere3D> sphere)
+{
+    return this->getDistance(sphere->midPoint) < radius + sphere->radius;
+}
+/*=======================================================*/
+void GbSphere3D::setCenterCoordinates(const double &x1, const double &x2, const double &x3)
+{
+    this->translate(x1 - getX1Centroid(), x2 - getX2Centroid(), x3 - getX3Centroid());
+}
+
+void GbSphere3D::setCenterCoordinates(const UbTupleDouble3 &position)
+{
+    this->setCenterCoordinates(val<1>(position), val<2>(position), val<3>(position));
+}
+
+/*=====================================================*/
+double GbSphere3D::getDistance(GbPoint3D *p)
+{
+    return this->getDistance(p->getX1Centroid(), p->getX2Coordinate(), p->getX3Coordinate());
+}
+/*=====================================================*/
+void GbSphere3D::setCenterX1Coordinate(const double &value)
+{
+    if (this->midPoint)
+        this->midPoint->setX1(value);
+    else
+        throw UbException(UB_EXARGS, "Sphere has no midPoint");
+    // kein notifyObserver(), da der knoten notifyObserver() ausfuehrt und die GbSphere dieses event
+    // abfaengt und dann selbst notifyObservers ausfuehrt ;-)
+}
+/*=====================================================*/
+void GbSphere3D::setCenterX2Coordinate(const double &value)
+{
+    if (this->midPoint)
+        this->midPoint->setX2(value);
+    else
+        throw UbException(UB_EXARGS, "Sphere has no midPoint");
+    // kein notifyObserver(), da der knoten notifyObserver() ausfuehrt und die GbSphere dieses event
+    // abfaengt und dann selbst notifyObservers ausfuehrt ;-)
+}
+/*=====================================================*/
+void GbSphere3D::setCenterX3Coordinate(const double &value)
+{
+    if (this->midPoint)
+        this->midPoint->setX3(value);
+    else
+        throw UbException(UB_EXARGS, "sphere has no midPoint");
+    // kein notifyObserver(), da der knoten notifyObserver() ausfuehrt und die GbSphere dieses event
+    // abfaengt und dann selbst notifyObservers ausfuehrt ;-)
+}
+/*=====================================================*/
+void GbSphere3D::setRadius(const double &radius)
+{
+    if (radius != this->radius) {
+        this->radius = radius;
+        this->notifyObserversObjectChanged();
+    }
+}
+/*=====================================================*/
+double GbSphere3D::getDistance(const double &x1p, const double &x2p, const double &x3p)
+{
+    double deltaX1 = x1p - midPoint->getX1Coordinate();
+    double deltaX2 = x2p - midPoint->getX2Coordinate();
+    double deltaX3 = x3p - midPoint->getX3Coordinate();
+    return sqrt(deltaX1 * deltaX1 + deltaX2 * deltaX2 + deltaX3 * deltaX3) - this->radius;
+}
+/*=====================================================*/
+// true, wenn 'in Object' oder 'auf Boundary'!
+bool GbSphere3D::isPointInGbObject3D(const double &x1p, const double &x2p, const double &x3p)
+{
+    double deltaX1 = x1p - midPoint->getX1Coordinate();
+    double deltaX2 = x2p - midPoint->getX2Coordinate();
+    double deltaX3 = x3p - midPoint->getX3Coordinate();
+
+    return UbMath::lessEqual(deltaX1 * deltaX1 + deltaX2 * deltaX2 + deltaX3 * deltaX3, this->radius * this->radius);
+}
+/*=====================================================*/
+// true, wenn 'in Object' oder 'auf Boundary'!
+bool GbSphere3D::isPointInGbObject3D(const double &x1p, const double &x2p, const double &x3p, bool &pointIsOnBoundary)
+{
+    double deltaX1 = x1p - midPoint->getX1Coordinate();
+    double deltaX2 = x2p - midPoint->getX2Coordinate();
+    double deltaX3 = x3p - midPoint->getX3Coordinate();
+
+    double distanceSquare = deltaX1 * deltaX1 + deltaX2 * deltaX2 + deltaX3 * deltaX3;
+    double radiusSquare   = this->radius * this->radius;
+
+    pointIsOnBoundary = UbMath::equal(distanceSquare, radiusSquare);
+
+    return UbMath::lessEqual(distanceSquare, radiusSquare);
+}
+/*=====================================================*/
+// bool GbSphere3D::crossCellCrossSection(double x11,double x21,double x12,double x22, double ra)
+//{
+//   if(this->isPointInCrossection(x11, x12) || this->isPointInCrossection(x21, x22) || this->isPointInCrossection(x11,
+//   x22) || this->isPointInCrossection(x21, x12))
+//   {
+//		if(!this->isPointInCrossection(x11, x12) || !this->isPointInCrossection(x21, x22) ||
+//!this->isPointInCrossection(x11, x22) || !this->isPointInCrossection(x21, x12)) return true;
+//   }
+//   return false;
+//}
+//
+///*=====================================================*/
+// bool GbSphere3D::cellCrossAndInsideCrossSection(double x11,double x21,double x12,double x22, double ra)
+//{
+//   if(this->isPointInCrossection(x11, x12) || this->isPointInCrossection(x21, x22) || this->isPointInCrossection(x11,
+//   x22) || this->isPointInCrossection(x21, x12))  return true; return false;
+//}
+/*=====================================================*/
+string GbSphere3D::toString()
+{
+    stringstream ss;
+    ss << "GbSphere3D[";
+    ss << "mid=" << midPoint->toString() << ", r=" << radius << "]";
+    return ss.str();
+}
+/*=====================================================*/
+GbLine3D *GbSphere3D::createClippedLine3D(GbPoint3D &point1, GbPoint3D &point2)
+{
+    double factor = 100.0; // um rundungsfehler beim wurzelterm zu minimieren
+    double xa = factor * point1.getX1Coordinate();
+    double ya = factor * point1.getX2Coordinate();
+    double za = factor * point1.getX3Coordinate();
+    double xb = factor * point2.getX1Coordinate();
+    double yb = factor * point2.getX2Coordinate();
+    double zb = factor * point2.getX3Coordinate();
+    double xm = factor * this->midPoint->getX1Coordinate();
+    double ym = factor * this->midPoint->getX2Coordinate();
+    double zm = factor * this->midPoint->getX3Coordinate();
+    double r  = factor * this->radius;
+
+    double xa2 = xa * xa;
+    double ya2 = ya * ya;
+    double za2 = za * za;
+    double xb2 = xb * xb;
+    double yb2 = yb * yb;
+    double zb2 = zb * zb;
+    double xm2 = xm * xm;
+    double ym2 = ym * ym;
+    double zm2 = zm * zm;
+    double r2  = r * r;
+
+    double wurzel =
+        2.0 * xa * xb * ym2 - 2.0 * ya * yb * r2 + 2.0 * ya * ym * xb2 + 2.0 * yb * ym * za2 + 2.0 * ya * ym * zb2 +
+        2.0 * xb * xm * za2 + 2.0 * za * zb * ym2 + 2.0 * xb * xm * ya2 + 2.0 * xa * xm * yb2 + 2.0 * yb * ym * xa2 +
+        2.0 * zb * zm * ya2 + 2.0 * xa * xm * zb2 + 2.0 * za * zm * xb2 + 2.0 * za * zm * yb2 + 2.0 * xa * xb * zm2 -
+        2.0 * xa * xb * r2 - 2.0 * za * zb * r2 + 2.0 * za * zb * xm2 - 2.0 * ya * yb * xa * xm +
+        2.0 * ya * yb * xa * xb + 2.0 * zb * zm * xa2 - 2.0 * ya * yb * xb * xm + 2.0 * ya * yb * xm2 -
+        2.0 * ya * yb * zb * zm + 2.0 * ya * yb * zm2 + 2.0 * zb * zm * yb * ym - 2.0 * zb * zm * ya * ym +
+        2.0 * zb * zm * xb * xm - 2.0 * xa * xm * yb * ym + 2.0 * xa * xm * za * zm + 2.0 * xa * xm * ya * ym -
+        2.0 * yb * ym * za * zm + 2.0 * yb * ym * xb * xm + 2.0 * za * zm * ya * ym - 2.0 * za * zm * xb * xm -
+        2.0 * ya * ym * xb * xm + 2.0 * za * zb * xa * xb - 2.0 * za * zb * xa * xm - 2.0 * za * zb * xb * xm +
+        2.0 * za * zb * ya * yb - 2.0 * za * zb * ya * ym - 2.0 * za * zb * yb * ym - 2.0 * ya * yb * za * zm -
+        xa2 * zb2 - xa2 * yb2 - zb2 * ya2 - za2 * xb2 - za2 * yb2 - xb2 * ya2 - 2.0 * zb * zm * xa * xm -
+        2.0 * xa * xb * za * zm - 2.0 * xa * xb * zb * zm - 2.0 * xa * xb * ya * ym - 2.0 * xa * xb * yb * ym +
+        za2 * r2 - za2 * xm2 - za2 * ym2 + zb2 * r2 - zb2 * xm2 - zb2 * ym2 + xa2 * r2 - xa2 * zm2 - xa2 * ym2 +
+        xb2 * r2 - xb2 * zm2 - xb2 * ym2 + ya2 * r2 - ya2 * zm2 - ya2 * xm2 + yb2 * r2 - yb2 * zm2 - yb2 * xm2;
+    double nenner  = -2.0 * za * zb - 2.0 * ya * yb - 2.0 * xa * xb + za2 + zb2 + xa2 + xb2 + ya2 + yb2;
+    double zaehler = 2.0 * zb * zm - 2.0 * xa * xm + 2.0 * yb * ym - 2.0 * za * zm + xa2 - 2.0 * ya * ym +
+                     2.0 * xb * xm - zb2 + za2 - xb2 + ya2 - yb2;
+
+    vector<GbPoint3D *> schnittpunkte;
+
+    if (fabs(nenner) > 1.E-13 && UbMath::greaterEqual(wurzel, 0.0)) {
+        double t1 = (zaehler + 2.0 * sqrt(wurzel)) / nenner;
+        double t2 = (zaehler - 2.0 * sqrt(wurzel)) / nenner;
+
+        if (UbMath::inClosedInterval(t1, -1.0, 1.0)) {
+            double x = (xa * (0.5 - 0.5 * t1) + xb * (0.5 + 0.5 * t1)) / factor;
+            double y = (ya * (0.5 - 0.5 * t1) + yb * (0.5 + 0.5 * t1)) / factor;
+            double z = (za * (0.5 - 0.5 * t1) + zb * (0.5 + 0.5 * t1)) / factor;
+
+            schnittpunkte.push_back(new GbPoint3D(x, y, z));
+        }
+        if (fabs(t2 - t1) > 1.E-13 && UbMath::inClosedInterval(t2, -1.0, 1.0)) {
+            double x = (xa * (0.5 - 0.5 * t2) + xb * (0.5 + 0.5 * t2)) / factor;
+            double y = (ya * (0.5 - 0.5 * t2) + yb * (0.5 + 0.5 * t2)) / factor;
+            double z = (za * (0.5 - 0.5 * t2) + zb * (0.5 + 0.5 * t2)) / factor;
+
+            schnittpunkte.push_back(new GbPoint3D(x, y, z));
+        }
+    }
+
+    int nofSchnittpunkte = (int)schnittpunkte.size();
+    if (nofSchnittpunkte == 1) {
+        if (this->isPointInGbObject3D(&point1))
+            return new GbLine3D(schnittpunkte[0], new GbPoint3D(point1));
+        else if (this->isPointInGbObject3D(&point2))
+            return new GbLine3D(schnittpunkte[0], new GbPoint3D(point2));
+        else // line beruehrt kugel! -> clippedLine reduziert sich zu einem Punkt!
+        {
+            if (std::fabs(this->getDistance(schnittpunkte[0]) - this->radius) < 1.E-13)
+                throw UbException(UB_EXARGS, "Beide LinenPunkte ausserhalb des Kreises, der berechnete Punkt ist "
+                                             "jedoch KEIN Beruhrungspunkt der Sphere...");
+            return new GbLine3D(schnittpunkte[0], new GbPoint3D(*(schnittpunkte[0])));
+        }
+    } else if (nofSchnittpunkte == 2)
+        return new GbLine3D(schnittpunkte[0], schnittpunkte[1]);
+
+    return NULL;
+}
+/*=========================================================================*/
+vector<GbTriangle3D *> GbSphere3D::getSurfaceTriangleSet()
+{
+    if (triangulationMode == RAYPROJECTION) {
+        double x1m = midPoint->getX1Coordinate();
+        double x2m = midPoint->getX2Coordinate();
+        double x3m = midPoint->getX3Coordinate();
+
+        vector<GbTriangle3D *> triangles;
+
+        int segments    = 30;
+        double deltaPhi = UbMath::PI / (double)segments;
+        double phiX1a, phiX1b, phiX3a, phiX3b;
+        double x1a, x2a, x3a, x1b, x2b, x3b, x1c, x2c, x3c, x1d, x2d, x3d;
+
+        for (phiX3a = 0.5 * UbMath::PI; phiX3a > -1.5 * UbMath::PI; phiX3a -= deltaPhi) {
+            for (phiX1a = 0.0; phiX1a < UbMath::PI; phiX1a += deltaPhi) {
+                phiX1b = phiX1a + deltaPhi;
+                phiX3b = phiX3a + deltaPhi;
+
+                x1a = x1m + radius * cos(phiX3a) * std::cos(phiX1a);
+                x2a = x2m + radius * cos(phiX3a) * std::sin(phiX1a);
+                x3a = x3m + radius * sin(phiX3a);
+                x1b = x1m + radius * cos(phiX3a) * std::cos(phiX1b);
+                x2b = x2m + radius * cos(phiX3a) * std::sin(phiX1b);
+                x3b = x3m + radius * sin(phiX3a);
+                x1c = x1m + radius * cos(phiX3b) * std::cos(phiX1b);
+                x2c = x2m + radius * cos(phiX3b) * std::sin(phiX1b);
+                x3c = x3m + radius * sin(phiX3b);
+                x1d = x1m + radius * cos(phiX3b) * std::cos(phiX1a);
+                x2d = x2m + radius * cos(phiX3b) * std::sin(phiX1a);
+                x3d = x3m + radius * sin(phiX3b);
+
+                if (UbMath::greater(phiX3b, -0.5 * UbMath::PI) && UbMath::less(phiX3a, 0.5 * UbMath::PI)) {
+                    triangles.push_back(new GbTriangle3D(new GbPoint3D(x1a, x2a, x3a), new GbPoint3D(x1b, x2b, x3b),
+                                                         new GbPoint3D(x1c, x2c, x3c)));
+                    triangles.push_back(new GbTriangle3D(new GbPoint3D(x1a, x2a, x3a), new GbPoint3D(x1c, x2c, x3c),
+                                                         new GbPoint3D(x1d, x2d, x3d)));
+                } else {
+                    triangles.push_back(new GbTriangle3D(new GbPoint3D(x1d, x2d, x3d), new GbPoint3D(x1c, x2c, x3c),
+                                                         new GbPoint3D(x1a, x2a, x3a)));
+                    triangles.push_back(new GbTriangle3D(new GbPoint3D(x1c, x2c, x3c), new GbPoint3D(x1b, x2b, x3b),
+                                                         new GbPoint3D(x1a, x2a, x3a)));
+                }
+            }
+        }
+        return triangles;
+    } else if (triangulationMode == CUBOIDPROJECTION) {
+        vector<GbTriangle3D *> triangles;
+        vector<GbPoint3D *> points;
+        double x1min = this->getX1Minimum();
+        double x2min = this->getX2Minimum();
+        double x3min = this->getX3Minimum();
+        double x1max = this->getX1Maximum();
+        double x2max = this->getX2Maximum();
+        double x3max = this->getX3Maximum();
+        double ax1   = x1min;
+        double bx2   = x2min;
+        double cx1   = x1min;
+        double ax2   = x2min;
+        double bx3   = x3min;
+        double cx3   = x3min;
+
+        int anzahl = 20;
+        double dx1 = (x1max - x1min) / (double)(anzahl - 1);
+        double dx2 = (x2max - x2min) / (double)(anzahl - 1);
+        double dx3 = (x3max - x3min) / (double)(anzahl - 1);
+
+        for (int u = 0; u < anzahl; u++) {
+            ax2 = x2min;
+            bx2 = x2min;
+            cx3 = x3min;
+            for (int v = 0; v < anzahl; v++) {
+                GbPoint3D p1 = GbPoint3D(ax1, ax2, x3max);
+                GbPoint3D p2 = GbPoint3D(ax1, ax2, x3min);
+                GbPoint3D p3 = GbPoint3D(cx1, x2min, cx3);
+                GbPoint3D p4 = GbPoint3D(cx1, x2max, cx3);
+                GbPoint3D p5 = GbPoint3D(x1min, bx2, bx3);
+                GbPoint3D p6 = GbPoint3D(x1max, bx2, bx3);
+
+                GbLine3D *clippedline1 = this->createClippedLine3D(*this->midPoint, p1);
+                GbLine3D *clippedline2 = this->createClippedLine3D(*this->midPoint, p2);
+                GbLine3D *clippedline3 = this->createClippedLine3D(*this->midPoint, p3);
+                GbLine3D *clippedline4 = this->createClippedLine3D(*this->midPoint, p4);
+                GbLine3D *clippedline5 = this->createClippedLine3D(*this->midPoint, p5);
+                GbLine3D *clippedline6 = this->createClippedLine3D(*this->midPoint, p6);
+                points.push_back(new GbPoint3D(clippedline1->getPoint1()));
+                points.push_back(new GbPoint3D(clippedline2->getPoint1()));
+                points.push_back(new GbPoint3D(clippedline3->getPoint1()));
+                points.push_back(new GbPoint3D(clippedline4->getPoint1()));
+                points.push_back(new GbPoint3D(clippedline5->getPoint1()));
+                points.push_back(new GbPoint3D(clippedline6->getPoint1()));
+                clippedline1->deletePoints();
+                delete clippedline1;
+                clippedline2->deletePoints();
+                delete clippedline2;
+                clippedline3->deletePoints();
+                delete clippedline3;
+                clippedline4->deletePoints();
+                delete clippedline4;
+                clippedline5->deletePoints();
+                delete clippedline5;
+                clippedline6->deletePoints();
+                delete clippedline6;
+                ax2 += dx2;
+                cx3 += dx3;
+                bx2 += dx2;
+            }
+            ax1 += dx1;
+            cx1 += dx1;
+            bx3 += dx3;
+        }
+
+        int anz           = anzahl * anzahl * 6;
+        GbPoint3D *point1 = NULL;
+        GbPoint3D *point2 = NULL;
+        GbPoint3D *point3 = NULL;
+        int anzahl2       = anzahl * 6;
+        int anzahl3       = anzahl2 + 6;
+        for (int u = 0; u < anz - anzahl3; u++) {
+            point1 = new GbPoint3D(points[u + 6]);
+            point2 = new GbPoint3D(points[u]);
+            point3 = new GbPoint3D(points[u + anzahl2]);
+            if (u % 2 == 0)
+                triangles.push_back(new GbTriangle3D(point1, point2, point3));
+            else
+                triangles.push_back(new GbTriangle3D(point2, point1, point3));
+
+            point1 = new GbPoint3D(points[u + 6]);
+            point2 = new GbPoint3D(points[u + anzahl2]);
+            point3 = new GbPoint3D(points[u + anzahl3]);
+            if (u % 2 == 0)
+                triangles.push_back(new GbTriangle3D(point1, point2, point3));
+            else
+                triangles.push_back(new GbTriangle3D(point2, point1, point3));
+        }
+        for (int u = 0; u < anz; u++)
+            delete points[u];
+
+        return triangles;
+    } else
+        throw UbException(UB_EXARGS, "undefined triangulationmode");
+}
+/*=======================================================*/
+void GbSphere3D::addSurfaceTriangleSet(vector<UbTupleFloat3> &nodes, vector<UbTupleInt3> &triangles)
+{
+    // wenn ich viele Kugeln bei der PE rausschreibe sollten die vektoren nicht geresized werden
+    // nodes.resize(0);
+    // triangles.resize(0);
+
+    if (triangulationMode == RAYPROJECTION) {
+        float x1m = (float)midPoint->getX1Coordinate();
+        float x2m = (float)midPoint->getX2Coordinate();
+        float x3m = (float)midPoint->getX3Coordinate();
+
+        int segments   = 30;
+        float deltaPhi = (float)UbMath::PI / (float)segments;
+        float phiX1a, phiX1b, phiX3a, phiX3b;
+        float x1a, x2a, x3a, x1b, x2b, x3b, x1c, x2c, x3c, x1d, x2d, x3d;
+        int nodeNr = int(nodes.size());
+        for (phiX3a = (float)(0.5 * UbMath::PI); phiX3a > (float)(-1.5 * UbMath::PI); phiX3a -= deltaPhi) {
+            for (phiX1a = 0.0; phiX1a < UbMath::PI; phiX1a += deltaPhi) {
+                phiX1b = phiX1a + deltaPhi;
+                phiX3b = phiX3a + deltaPhi;
+
+                x1a = x1m + (float)(radius * cos(phiX3a) * std::cos(phiX1a));
+                x2a = x2m + (float)(radius * cos(phiX3a) * std::sin(phiX1a));
+                x3a = x3m + (float)(radius * sin(phiX3a));
+                x1b = x1m + (float)(radius * cos(phiX3a) * std::cos(phiX1b));
+                x2b = x2m + (float)(radius * cos(phiX3a) * std::sin(phiX1b));
+                x3b = x3m + (float)(radius * sin(phiX3a));
+                x1c = x1m + (float)(radius * cos(phiX3b) * std::cos(phiX1b));
+                x2c = x2m + (float)(radius * cos(phiX3b) * std::sin(phiX1b));
+                x3c = x3m + (float)(radius * sin(phiX3b));
+                x1d = x1m + (float)(radius * cos(phiX3b) * std::cos(phiX1a));
+                x2d = x2m + (float)(radius * cos(phiX3b) * std::sin(phiX1a));
+                x3d = x3m + (float)(radius * sin(phiX3b));
+
+                if (UbMath::greater(phiX3b, -0.5 * UbMath::PI) && UbMath::less(phiX3a, 0.5 * UbMath::PI)) {
+                    nodes.push_back(makeUbTuple(x1a, x2a, x3a));
+                    nodes.push_back(makeUbTuple(x1b, x2b, x3b));
+                    nodes.push_back(makeUbTuple(x1c, x2c, x3c));
+
+                    nodes.push_back(makeUbTuple(x1a, x2a, x3a));
+                    nodes.push_back(makeUbTuple(x1c, x2c, x3c));
+                    nodes.push_back(makeUbTuple(x1d, x2d, x3d));
+                } else {
+                    nodes.push_back(makeUbTuple(x1d, x2d, x3d));
+                    nodes.push_back(makeUbTuple(x1c, x2c, x3c));
+                    nodes.push_back(makeUbTuple(x1a, x2a, x3a));
+
+                    nodes.push_back(makeUbTuple(x1c, x2c, x3c));
+                    nodes.push_back(makeUbTuple(x1b, x2b, x3b));
+                    nodes.push_back(makeUbTuple(x1a, x2a, x3a));
+                }
+                triangles.push_back(makeUbTuple(nodeNr, nodeNr + 1, nodeNr + 2));
+                triangles.push_back(makeUbTuple(nodeNr + 3, nodeNr + 4, nodeNr + 5));
+                nodeNr += 6;
+            }
+        }
+    } else if (triangulationMode == CUBOIDPROJECTION) {
+        vector<GbPoint3D *> points;
+        double x1min = this->getX1Minimum();
+        double x2min = this->getX2Minimum();
+        double x3min = this->getX3Minimum();
+        double x1max = this->getX1Maximum();
+        double x2max = this->getX2Maximum();
+        double x3max = this->getX3Maximum();
+        double ax1   = x1min;
+        double bx2   = x2min;
+        double cx1   = x1min;
+        double ax2   = x2min;
+        double bx3   = x3min;
+        double cx3   = x3min;
+
+        int anzahl = 20;
+        double dx1 = (x1max - x1min) / (double)(anzahl - 1);
+        double dx2 = (x2max - x2min) / (double)(anzahl - 1);
+        double dx3 = (x3max - x3min) / (double)(anzahl - 1);
+
+        for (int u = 0; u < anzahl; u++) {
+            ax2 = x2min;
+            bx2 = x2min;
+            cx3 = x3min;
+            for (int v = 0; v < anzahl; v++) {
+                GbPoint3D p1 = GbPoint3D(ax1, ax2, x3max);
+                GbPoint3D p2 = GbPoint3D(ax1, ax2, x3min);
+                GbPoint3D p3 = GbPoint3D(cx1, x2min, cx3);
+                GbPoint3D p4 = GbPoint3D(cx1, x2max, cx3);
+                GbPoint3D p5 = GbPoint3D(x1min, bx2, bx3);
+                GbPoint3D p6 = GbPoint3D(x1max, bx2, bx3);
+
+                GbLine3D *clippedline1 = this->createClippedLine3D(*this->midPoint, p1);
+                GbLine3D *clippedline2 = this->createClippedLine3D(*this->midPoint, p2);
+                GbLine3D *clippedline3 = this->createClippedLine3D(*this->midPoint, p3);
+                GbLine3D *clippedline4 = this->createClippedLine3D(*this->midPoint, p4);
+                GbLine3D *clippedline5 = this->createClippedLine3D(*this->midPoint, p5);
+                GbLine3D *clippedline6 = this->createClippedLine3D(*this->midPoint, p6);
+                points.push_back(new GbPoint3D(clippedline1->getPoint1()));
+                points.push_back(new GbPoint3D(clippedline2->getPoint1()));
+                points.push_back(new GbPoint3D(clippedline3->getPoint1()));
+                points.push_back(new GbPoint3D(clippedline4->getPoint1()));
+                points.push_back(new GbPoint3D(clippedline5->getPoint1()));
+                points.push_back(new GbPoint3D(clippedline6->getPoint1()));
+                clippedline1->deletePoints();
+                delete clippedline1;
+                clippedline2->deletePoints();
+                delete clippedline2;
+                clippedline3->deletePoints();
+                delete clippedline3;
+                clippedline4->deletePoints();
+                delete clippedline4;
+                clippedline5->deletePoints();
+                delete clippedline5;
+                clippedline6->deletePoints();
+                delete clippedline6;
+                ax2 += dx2;
+                cx3 += dx3;
+                bx2 += dx2;
+            }
+            ax1 += dx1;
+            cx1 += dx1;
+            bx3 += dx3;
+        }
+
+        int anz     = anzahl * anzahl * 6;
+        int anzahl2 = anzahl * 6;
+        int anzahl3 = anzahl2 + 6;
+        int nodeNr  = 0;
+        for (int u = 0; u < anz - anzahl3; u++) {
+            nodes.push_back(makeUbTuple((float)points[u + 6]->x1, (float)points[u + 6]->x2, (float)points[u + 6]->x3));
+            nodes.push_back(makeUbTuple((float)points[u]->x1, (float)points[u]->x2, (float)points[u]->x3));
+            nodes.push_back(makeUbTuple((float)points[u + anzahl2]->x1, (float)points[u + anzahl2]->x2,
+                                        (float)points[u + anzahl2]->x3));
+
+            if (u % 2 == 0)
+                triangles.push_back(makeUbTuple(nodeNr, nodeNr + 1, nodeNr + 2));
+            else
+                triangles.push_back(makeUbTuple(nodeNr, nodeNr + 1, nodeNr + 2));
+
+            nodes.push_back(makeUbTuple((float)points[u + 6]->x1, (float)points[u + 6]->x2, (float)points[u + 6]->x3));
+            nodes.push_back(makeUbTuple((float)points[u + anzahl2]->x1, (float)points[u + anzahl2]->x2,
+                                        (float)points[u + anzahl2]->x3));
+            nodes.push_back(makeUbTuple((float)points[u + anzahl3]->x1, (float)points[u + anzahl3]->x2,
+                                        (float)points[u + anzahl3]->x3));
+            if (u % 2 == 0)
+                triangles.push_back(makeUbTuple(nodeNr + 3, nodeNr + 4, nodeNr + 5));
+            else
+                triangles.push_back(makeUbTuple(nodeNr + 3, nodeNr + 4, nodeNr + 5));
+
+            nodeNr += 6;
+        }
+        for (int u = 0; u < anz; u++)
+            delete points[u];
+    } else
+        throw UbException(UB_EXARGS, "undefined triangulationmode");
+}
+/*=======================================================*/
+void GbSphere3D::transform(const double matrix[4][4])
+{
+    midPoint->transform(matrix);
+    this->setRadius(this->getRadius() * matrix[0][0]);
+    this->notifyObserversObjectChanged();
+}
+/*=======================================================*/
+bool GbSphere3D::hasIntersectionWithDirectedLine(GbPoint3D origin, GbPoint3D direction)
+{
+    GbVector3D vecOrigin(origin.getX1Coordinate(), origin.getX2Coordinate(), origin.getX3Coordinate());
+    GbVector3D vecDirection(direction.getX1Coordinate(), direction.getX2Coordinate(), direction.getX3Coordinate());
+    GbVector3D vecSfereCenter(getX1Centroid(), getX2Centroid(), getX3Centroid());
+    GbVector3D diff = vecOrigin - vecSfereCenter;
+    float a         = (float)(vecDirection.Dot(vecDirection));
+    float b         = (float)(2.0 * vecDirection.Dot(diff));
+    float c         = (float)(diff.Dot(diff) - this->getRadius() * this->getRadius());
+
+    // use 'abc'-formula for finding root t_1,2 = (-b +/- sqrt(b^2-4ac))/(2a)
+    float inRoot = (float)(b * b - 4.0 * a * c);
+    if (inRoot < 0)
+        return false;
+    float root = sqrt(inRoot);
+
+    float dist = (float)((-b - root) / (2.0 * a));
+
+    double infinity = DBL_MAX;
+    double eps      = 1E-4;
+
+    if (dist > infinity)
+        return false;
+
+    if (dist < eps) {
+        dist = (float)((-b + root) / (2.0 * a));
+        if (dist < eps || dist > infinity)
+            return false;
+    }
+    return true;
+}
+/*=======================================================*/
+bool GbSphere3D::isCellCuttingGbObject3D(const double &x1a, const double &x2a, const double &x3a, const double &x1b,
+                                         const double &x2b, const double &x3b)
+// Merksatz: cell oder deren Volumen schneidet oder beinhaltet komplette oder Teile der SphereUmrandung
+// returns true:
+//  - cell cuts  sphere3D
+//  - cell boxes sphere3D
+// returns false:
+//  - cell completely inside sphere3D ( = sphere3D boxes cell)
+//  - cell und sphere3D haben kein gemeinsames Volumen
+{
+    double midX[] = { this->getX1Centroid(), this->getX2Centroid(), this->getX3Centroid() };
+
+    double Bmin[] = { UbMath::min(x1a, x1b), UbMath::min(x2a, x2b), UbMath::min(x3a, x3b) };
+
+    double Bmax[] = { UbMath::max(x1a, x1b), UbMath::max(x2a, x2b), UbMath::max(x3a, x3b) };
+
+    /* Solid Box - Hollow Sphere */
+    double dmin = 0.0;
+    double dmax = 0.0;
+    double r2   = radius * radius;
+
+    for (int i = 0; i < 3; i++) {
+        double a = pow(midX[i] - Bmin[i], 2.0);
+        double b = pow(midX[i] - Bmax[i], 2.0);
+        dmax += UbMath::max(a, b);
+        if (UbMath::less(midX[i], Bmin[i]))
+            dmin += a;
+        else if (UbMath::greater(midX[i], Bmax[i]))
+            dmin += b;
+    }
+    if (UbMath::lessEqual(dmin, r2) && UbMath::lessEqual(r2, dmax)) {
+        return true;
+    }
+    return false;
+}
+/*=======================================================*/
+bool GbSphere3D::isCellInsideOrCuttingGbObject3D(const double &x1a, const double &x2a, const double &x3a,
+                                                 const double &x1b, const double &x2b, const double &x3b)
+// returns true:
+//  - cell completely inside sphere3D ( = sphere3D boxes cell)
+//  - cell cuts  sphere3D
+//  - cell boxes sphere3D
+// returns false:
+//  - cell und sphere3D haben kein gemeinsames Volumen
+{
+    // URL: http://tog.acm.org/GraphicsGems/gems/BoxSphere.c (mode=4, beides solids!!!)
+    // solid - solid
+    // this routine tests for intersection between an 3-dimensional
+    // axis-aligned box and an 3-dimensional sphere.
+
+    // true:
+    //  - wenn Schnitt
+    //  - Cell komplett innerhalb GbSphere3D
+    //  - Cell umhuellt GbSphere3D
+
+    double midX1 = this->getX1Centroid();
+    double midX2 = this->getX2Centroid();
+    double midX3 = this->getX3Centroid();
+
+    double dmin = 0.0;
+
+    if (UbMath::less(midX1, x1a))
+        dmin += std::pow(midX1 - x1a, 2.0);
+    else if (UbMath::greater(midX1, x1b))
+        dmin += std::pow(midX1 - x1b, 2.0);
+
+    if (UbMath::less(midX2, x2a))
+        dmin += std::pow(midX2 - x2a, 2.0);
+    else if (UbMath::greater(midX2, x2b))
+        dmin += std::pow(midX2 - x2b, 2.0);
+
+    if (UbMath::less(midX3, x3a))
+        dmin += std::pow(midX3 - x3a, 2.0);
+    else if (UbMath::greater(midX3, x3b))
+        dmin += std::pow(midX3 - x3b, 2.0);
+
+    if (UbMath::lessEqual(dmin, radius * radius)) {
+        return true;
+    }
+
+    return false;
+}
+/*==========================================================*/
+double GbSphere3D::getCellVolumeInsideGbObject3D(const double &x1a, const double &x2a, const double &x3a,
+                                                 const double &x1b, const double &x2b, const double &x3b)
+{
+    double deltaX1 = (x1b - x1a);
+    double deltaX2 = (x2b - x2a);
+    double deltaX3 = (x3b - x3a);
+
+    if (this->isCellInsideGbObject3D(x1a, x2a, x3a, x1b, x2b, x3b))
+        return 1.0 * deltaX1 * deltaX2 * deltaX3;
+    if (!(this->isCellCuttingGbObject3D(x1a, x2a, x3a, x1b, x2b, x3b)))
+        return 0.0;
+
+    double tempResult = 0.0;
+
+    int iMax = 10;
+    int jMax = 10;
+    int kMax = 10;
+
+    for (int i = 0; i < iMax; i++) {
+        for (int j = 0; j < jMax; j++) {
+            for (int k = 0; k < kMax; k++) {
+
+                tempResult += getCellVolumeInsideGbObject3DHelperFunction(
+                    x1a + ((double)i) * deltaX1 / ((double)iMax), x2a + ((double)j) * deltaX2 / ((double)jMax),
+                    x3a + ((double)k) * deltaX3 / ((double)kMax), x1a + ((double)(i + 1)) * deltaX1 / ((double)iMax),
+                    x2a + ((double)(j + 1)) * deltaX2 / ((double)jMax),
+                    x3a + ((double)(k + 1)) * deltaX3 / ((double)kMax));
+            }
+        }
+    }
+
+    // double resultWithOneCell = getCellVolumeInsideGbObject3DHelperFunction( x1a, x2a, x3a, x1b, x2b, x3b );
+    // cout << tempResult << " vs. " << resultWithOneCell << endl;
+
+    return tempResult;
+}
+/*==========================================================*/
+double GbSphere3D::getCellVolumeInsideGbObject3DHelperFunction(const double &x1a, const double &x2a, const double &x3a,
+                                                               const double &x1b, const double &x2b, const double &x3b)
+{
+
+    double deltaX1 = x1b - x1a;
+    double deltaX2 = x2b - x2a;
+    double deltaX3 = x3b - x3a;
+
+    if (this->isCellInsideGbObject3D(x1a, x2a, x3a, x1b, x2b, x3b))
+        return 1.0 * deltaX1 * deltaX2 * deltaX3;
+    if (!(this->isCellCuttingGbObject3D(x1a, x2a, x3a, x1b, x2b, x3b)))
+        return 0.0;
+
+    double alpha = 0.0;
+    double internX1, internX2, internX3;
+
+    for (int x1vers = 0; x1vers < 2; x1vers++) {
+        for (int x2vers = 0; x2vers < 2; x2vers++) {
+            for (int x3vers = 0; x3vers < 2; x3vers++) {
+                internX1 = x1a + (x1b - x1a) * x1vers;
+                internX2 = x2a + (x2b - x2a) * x2vers;
+                internX3 = x3a + (x3b - x3a) * x3vers;
+
+                if (UbMath::lessEqual(this->getDistance(internX1, internX2, internX3), alpha))
+                    alpha = this->getDistance(internX1, internX2, internX3);
+                // cout<<zelltyp<<" "<<kugel->getDistance(internX1,internX2,internX3)<<" "<<alpha<<endl;
+            } // end first for
+        }     // end second for
+    }         // end third for
+
+    alpha = (-1) * alpha;
+
+    double n[3];
+    n[0] = 0.5 * (x1b + x1a) - this->getX1Centroid();
+    n[1] = 0.5 * (x2b + x2a) - this->getX2Centroid();
+    n[2] = 0.5 * (x3b + x3a) - this->getX3Centroid();
+
+    // cout << "Koordinaten:  "<<x1<<" "<<x2<<" "<<x3<<endl;
+    // cout << "Deltas:       "<<deltaX1<<" "<<deltaX2<<" "<<deltaX3<<endl;
+    // cout << "Halbe Zelle:  "<<halfcelldelta<<endl;
+
+    // cout<<"Centroid:  "<<kugel->getX1Centroid()<<" "<<kugel->getX2Centroid()<<" "<<kugel->getX3Centroid()<<endl;
+
+    // cout<<"Normals: "<<n[0]<<" "<<n[1]<<" "<<n[2]<<endl;
+
+    double normLength;
+    normLength = sqrt(n[0] * n[0] + n[1] * n[1] + n[2] * n[2]);
+    n[0] /= normLength;
+    n[1] /= normLength;
+    n[2] /= normLength;
+
+    if (UbMath::less(n[0], 0.0))
+        n[0] = -n[0];
+    if (UbMath::less(n[1], 0.0))
+        n[1] = -n[1];
+    if (UbMath::less(n[2], 0.0))
+        n[2] = -n[2];
+
+    // cout<<"Normals: "<<n[0]<<" "<<n[1]<<" "<<n[2]<<endl;
+
+    double dummy;
+    if (UbMath::greater(n[0], n[1])) {
+        dummy = n[1];
+        n[1]  = n[0];
+        n[0]  = dummy;
+    }
+    if (UbMath::greater(n[1], n[2])) {
+        dummy = n[2];
+        n[2]  = n[1];
+        n[1]  = dummy;
+    }
+    if (UbMath::greater(n[0], n[1])) {
+        dummy = n[1];
+        n[1]  = n[0];
+        n[0]  = dummy;
+    }
+
+    // cout<<"Normals: "<<n[0]<<" "<<n[1]<<" "<<n[2]<<endl;
+
+    double n1, n2, n3;
+    n1 = n[0];
+    n2 = n[1];
+    n3 = n[2];
+
+    double maxVol = deltaX1 * deltaX2 * deltaX3;
+
+    double result = 0.0, preresult = 0.0;
+
+    if (UbMath::lessEqual(maxVol, 0.000001))
+        return 0.0;
+
+    // 1D Check
+    if (UbMath::lessEqual(n1, 0.001) && UbMath::lessEqual(n2, 0.001)) {
+        result = alpha * deltaX1 * deltaX2;
+    }
+    // 2D Check
+    else if (UbMath::lessEqual(n1, 0.001)) {
+        preresult = (2 * n2 * n3);
+        result    = (alpha * alpha) / preresult;
+
+        if (UbMath::greater(alpha, n2 * deltaX2)) {
+            result += -(alpha - n2 * deltaX2) * (alpha - n2 * deltaX2) / preresult;
+        }
+        if (UbMath::greater(alpha, n3 * deltaX3)) {
+            result += -(alpha - n3 * deltaX3) * (alpha - n3 * deltaX3) / preresult;
+        }
+        if (UbMath::greater(alpha, n2 * deltaX2 + n3 * deltaX3)) {
+            result += (alpha - n2 * deltaX2 - n3 * deltaX3) * (alpha - n2 * deltaX2 - n3 * deltaX3) / preresult;
+        }
+
+        // tiefenrichtung mit einmultiplizieren...
+        result *= deltaX1;
+    }
+    // 3D Check
+    else {
+        preresult = 6 * n1 * n2 * n3;
+
+        result = alpha * alpha * alpha;
+
+        if (UbMath::greaterEqual(alpha, n1 * deltaX1)) {
+            result += -((alpha - n1 * deltaX1) * (alpha - n1 * deltaX1) * (alpha - n1 * deltaX1));
+        }
+        if (UbMath::greaterEqual(alpha, n2 * deltaX2)) {
+            result += -((alpha - n2 * deltaX2) * (alpha - n2 * deltaX2) * (alpha - n2 * deltaX2));
+        }
+        if (UbMath::greaterEqual(alpha, n3 * deltaX3)) {
+            result += -((alpha - n3 * deltaX3) * (alpha - n3 * deltaX3) * (alpha - n3 * deltaX3));
+        }
+        if (UbMath::greaterEqual(alpha, (n1 * deltaX1 + n2 * deltaX2))) {
+            result += ((alpha - (n1 * deltaX1 + n2 * deltaX2)) * (alpha - (n1 * deltaX1 + n2 * deltaX2)) *
+                       (alpha - (n1 * deltaX1 + n2 * deltaX2)));
+        }
+        if (UbMath::greaterEqual(alpha, (n1 * deltaX1 + n3 * deltaX3))) {
+            result += ((alpha - (n1 * deltaX1 + n3 * deltaX3)) * (alpha - (n1 * deltaX1 + n3 * deltaX3)) *
+                       (alpha - (n1 * deltaX1 + n3 * deltaX3)));
+        }
+        if (UbMath::greaterEqual(alpha, (n2 * deltaX2 + n3 * deltaX3))) {
+            result += ((alpha - (n2 * deltaX2 + n3 * deltaX3)) * (alpha - (n2 * deltaX2 + n3 * deltaX3)) *
+                       (alpha - (n2 * deltaX2 + n3 * deltaX3)));
+        }
+
+        // NEW
+        if (UbMath::greaterEqual(alpha, (n1 * deltaX1 + n2 * deltaX2 + n3 * deltaX3))) {
+            result += -((alpha - (n1 * deltaX1 + n2 * deltaX2 + n3 * deltaX3)) *
+                        (alpha - (n1 * deltaX1 + n2 * deltaX2 + n3 * deltaX3)) *
+                        (alpha - (n1 * deltaX1 + n2 * deltaX2 + n3 * deltaX3)));
+        }
+
+        result = result / preresult;
+    }
+    return (result);
+
+    // cout << "alpha ist " << alpha << endl;
+    // cout << "fillLevel ist " << eps << endl;
+}
+/*==========================================================*/
+double GbSphere3D::getIntersectionRaytraceFactor(const double &x1, const double &x2, const double &x3,
+                                                 const double &rx1, const double &rx2, const double &rx3)
+{
+    double lx1  = midPoint->x1 - x1;
+    double lx2  = midPoint->x2 - x2;
+    double lx3  = midPoint->x3 - x3;
+    double l_sq = lx1 * lx1 + lx2 * lx2 + lx3 * lx3; // l = abstand Punkt(x1,x2,x3)<->kreismittelpunkt
+
+    double s    = lx1 * rx1 + lx2 * rx2 + lx3 * rx3; // s= l*ray_dir)
+    double r_sq = this->radius * this->radius;       // r� =r*r
+    // if (d<0 (fuer die Richtung falls sie gegen das Kreis dann haben wir ein negativer Zahl)
+    //     && l� > r� (point outside ))
+    // wenn s<0->Punkt liegt rechts vom mittelpunkt, wenn nun punkt ausserhalb des kreises liegt, kann es keinen SP mehr
+    // geben
+    if (s < -1.E-10 && l_sq > r_sq + 1.E-10)
+        return -1.0;
+    // Pythagor on Triangle Rectangle (point, center of the cercle, intersection of the direction on point and m)
+    // l� = m� + d�
+    double m_sq = l_sq - s * s;
+    // if (m� > r� (dann gibt es kein schnittpunt zwischen direction und circle))
+    if (m_sq > r_sq + 1.E-10)
+        return -1.0;
+    // Pythagoras on Triangle Rectangle in cercle (direction , m, r)
+    // r� = m� + h�
+
+    // patch: rundungsfehler bei kleinen delta!!!
+    //-> wenn wurzel minimal null->
+    double wurzelTerm = r_sq - m_sq;
+    if (wurzelTerm < 0.0) {
+        if (wurzelTerm < -1E-10)
+            return -1.0; // definitiv kein SP
+        else
+            return s; // im rundungsfehler-bereich. SP liegt dierkt auf sphere umrandung
+    }
+
+    // if point outside of the circle
+    if (l_sq > r_sq)
+        return s - sqrt(wurzelTerm);
+
+    return s + sqrt(wurzelTerm);
+}
+/*=======================================================*/
diff --git a/src/basics/geometry3d/GbSphere3D.h b/src/basics/geometry3d/GbSphere3D.h
new file mode 100644
index 0000000000000000000000000000000000000000..2ffef25dbfa7e0732ddd3e24b158d7046a7b11b6
--- /dev/null
+++ b/src/basics/geometry3d/GbSphere3D.h
@@ -0,0 +1,172 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file GbSphere3D.h
+//! \ingroup geometry3D
+//! \author Konstantin Kutscher, Soeren Textor, Sebastian Geller
+//=======================================================================================
+#ifndef GBSPHERE3D_H
+#define GBSPHERE3D_H
+
+#ifdef CAB_CTL
+#include <ctl.h>
+#endif // CAB_CTL
+
+#include <cmath>
+#include <vector>
+
+#include <basics/utilities/UbObserver.h>
+
+#include <geometry3d/GbObject3D.h>
+#include <geometry3d/GbPoint3D.h>
+
+#include <PointerDefinitions.h>
+
+class GbLine3D;
+class GbTriangle3D;
+class GbObject3DCreator;
+
+class GbSphere3D : public GbObject3D, public UbObserver
+{
+public:
+    enum TRIANGULATIONMODE { CUBOIDPROJECTION, RAYPROJECTION };
+
+    //////////////////////////////////////////////////////////////////////////
+    // Konstruktoren
+    GbSphere3D();
+    GbSphere3D(const double &x1, const double &x2, const double &x3, const double &radius);
+    GbSphere3D(const GbSphere3D &sphere);
+    GbSphere3D(GbSphere3D *sphere); //<-unschoen!
+
+    ~GbSphere3D() override;
+
+    GbSphere3D *clone() override { return new GbSphere3D(*this); }
+    void finalize() override;
+
+    bool intersects(SPtr<GbSphere3D> sphere);
+
+    double getRadius() const { return this->radius; }
+
+    double getX1Centroid() override { return midPoint->getX1Coordinate(); }
+    double getX1Minimum() override { return midPoint->getX1Coordinate() - radius; }
+    double getX1Maximum() override { return midPoint->getX1Coordinate() + radius; }
+    double getX2Centroid() override { return midPoint->getX2Coordinate(); }
+    double getX2Minimum() override { return midPoint->getX2Coordinate() - radius; }
+    double getX2Maximum() override { return midPoint->getX2Coordinate() + radius; }
+    double getX3Centroid() override { return midPoint->getX3Coordinate(); }
+    double getX3Minimum() override { return midPoint->getX3Coordinate() - radius; }
+    double getX3Maximum() override { return midPoint->getX3Coordinate() + radius; }
+
+    void setCenterX1Coordinate(const double &value) override;
+    void setCenterX2Coordinate(const double &value) override;
+    void setCenterX3Coordinate(const double &value) override;
+    void setCenterCoordinates(const double &x1, const double &x2, const double &x3) override;
+    void setCenterCoordinates(const UbTupleDouble3 &position) override;
+    void setRadius(const double &radius);
+
+    GbLine3D *createClippedLine3D(GbPoint3D &point1, GbPoint3D &point2) override;
+    double getDistance(GbPoint3D *p);
+    double getDistance(const double &x1p, const double &x2p, const double &x3p);
+
+    bool isPointInGbObject3D(const double &x1, const double &x2, const double &x3) override;
+    bool isPointInGbObject3D(const double &x1p, const double &x2p, const double &x3p, bool &pointIsOnBoundary) override;
+
+    bool isCellCuttingGbObject3D(const double &x1a, const double &x2a, const double &x3a, const double &x1b,
+                                 const double &x2b, const double &x3b) override;
+    bool isCellInsideOrCuttingGbObject3D(const double &x1a, const double &x2a, const double &x3a, const double &x1b,
+                                         const double &x2b, const double &x3b) override;
+    double getCellVolumeInsideGbObject3D(const double &x1a, const double &x2a, const double &x3a, const double &x1b,
+                                         const double &x2b, const double &x3b) override;
+    double getCellVolumeInsideGbObject3DHelperFunction(const double &x1a, const double &x2a, const double &x3a,
+                                                       const double &x1b, const double &x2b, const double &x3b);
+
+    std::vector<GbTriangle3D *> getSurfaceTriangleSet() override;
+    void addSurfaceTriangleSet(std::vector<UbTupleFloat3> &nodes, std::vector<UbTupleInt3> &triangles) override;
+
+    bool hasRaytracing() override { return true; }
+    /*|r| must be 1! einheitsvector!!*/
+    double getIntersectionRaytraceFactor(const double &x1, const double &x2, const double &x3, const double &rx1,
+                                         const double &rx2, const double &rx3) override;
+
+    bool hasIntersectionWithDirectedLine(GbPoint3D origin, GbPoint3D direction);
+
+    std::string toString() override;
+
+    void translate(const double &x1, const double &x2, const double &x3) override
+    {
+        this->midPoint->translate(x1, x2, x3);
+        this->notifyObserversObjectChanged();
+    }
+    void rotate(const double &rx1, const double &rx2, const double &rx3) override
+    { /* rotation makes no sense*/
+    }
+    void scale(const double &sx1, const double & /*sx2*/, const double & /*sx3*/) override
+    {
+        this->radius *= sx1;
+        this->notifyObserversObjectChanged();
+    }
+
+    void transform(const double matrix[4][4]);
+
+    TRIANGULATIONMODE getTriangulationMode() { return triangulationMode; }
+    void setTriangulationMode(TRIANGULATIONMODE mode) { this->triangulationMode = mode; }
+
+    // virtuelle Methoden von UbObserver
+    void objectChanged(UbObservable * /*changedObject*/) override
+    {
+        this->notifyObserversObjectChanged();
+        // std::cout<<"GbSphere:objectChanged() - toDo-);";
+    }
+    void objectWillBeDeleted(UbObservable * /*objectForDeletion*/) override
+    {
+        throw UbException(UB_EXARGS, "not implemented");
+    }
+
+    using GbObject3D::isPointInGbObject3D; // Grund: dadurch muss man hier  isPointInGbObject3D(GbPoint3D*) nicht
+                                           // ausprogrammieren, welche sonst hier "ueberdeckt" waere, weil man eine
+
+#ifdef CAB_CTL
+    ctl::oStream &write(ctl::oStream &os) const
+    {
+        midPoint->write(os);
+        return os << radius;
+    }
+    ctl::iStream &read(ctl::iStream &is)
+    {
+        midPoint->read(is);
+        return is >> radius;
+    }
+#endif // CAB_CTL
+
+private:
+    GbPoint3D *midPoint;
+    double radius; // Radius des Kreises
+    TRIANGULATIONMODE triangulationMode;
+};
+
+#endif // GBSPHERE3D_H
diff --git a/src/basics/geometry3d/GbTriFaceMesh3D.cpp b/src/basics/geometry3d/GbTriFaceMesh3D.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7da89fc9bf0565ec7862939ffa652b3ff1880a4f
--- /dev/null
+++ b/src/basics/geometry3d/GbTriFaceMesh3D.cpp
@@ -0,0 +1,1170 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file GbTriFaceMesh3D.cpp
+//! \ingroup geometry3D
+//! \author Konstantin Kutscher, Soeren Textor, Sebastian Geller
+//=======================================================================================
+#include <geometry3d/GbTriFaceMesh3D.h>
+
+#include <basics/utilities/UbFileInputASCII.h>
+#include <basics/utilities/UbLogger.h>
+#include <basics/utilities/UbRandom.h>
+#include <basics/utilities/UbTiming.h>
+#include <basics/writer/WbWriter.h>
+#include <geometry3d/CoordinateTransformation3D.h>
+#include <geometry3d/GbCuboid3D.h>
+#include <geometry3d/GbHalfSpace3D.h>
+
+#include <geometry3d/KdTree/KdTree.h>
+#include <geometry3d/KdTree/intersectionhandler/KdCountLineIntersectionHandler.h>
+#include <geometry3d/KdTree/intersectionhandler/KdCountRayIntersectionHandler.h>
+#include <geometry3d/KdTree/splitalgorithms/KdSAHSplit.h>
+#include <geometry3d/KdTree/splitalgorithms/KdSpatiallMedianSplit.h>
+
+#define MAX_ITER 10
+
+using namespace std;
+
+GbTriFaceMesh3D::GbTriFaceMesh3D() : GbObject3D()
+{
+    this->setName("CAB_GbTriFaceMesh3D");
+    this->nodes          = new vector<Vertex>;
+    this->triangles      = new vector<TriFace>;
+    this->consistent     = false;
+    this->kdtreeSplitAlg = KDTREE_SAHPLIT;
+}
+/*=======================================================================*/
+GbTriFaceMesh3D::GbTriFaceMesh3D(string name, vector<Vertex> *nodes, vector<TriFace> *triangles,
+                                 KDTREE_SPLITAGORITHM splitAlg, bool removeRedundantNodes)
+    : GbObject3D(), nodes(nodes), triangles(triangles), kdtreeSplitAlg(splitAlg)
+{
+    if (name.empty())
+        throw UbException(UB_EXARGS, "no name specified");
+    if (!nodes)
+        throw UbException(UB_EXARGS, "no nodes specified");
+    if (!triangles)
+        throw UbException(UB_EXARGS, "no triangles specified");
+
+    this->setName(name);
+
+    if (removeRedundantNodes) {
+        this->deleteRedundantNodes(); // dort wird autoamtisch calculateValues() aufgerufen
+    } else {
+        this->calculateValues();
+    }
+}
+/*=======================================================================*/
+GbTriFaceMesh3D::~GbTriFaceMesh3D()
+{
+    if (nodes) {
+        delete nodes;
+        nodes = NULL;
+    }
+    if (triangles) {
+        delete triangles;
+        triangles = NULL;
+    }
+    if (kdTree) {
+        delete kdTree;
+        kdTree = NULL;
+    }
+}
+/*======================================================================*/
+void GbTriFaceMesh3D::init()
+{
+    //nodes      = NULL;
+    //triangles  = NULL;
+    x1min      = 0.0;
+    x1max      = 0.0;
+    x1center   = 0.0;
+    x2min      = 0.0;
+    x2max      = 0.0;
+    x2center   = 0.0;
+    x3min      = 0.0;
+    x3max      = 0.0;
+    x3center   = 0.0;
+    consistent = false;
+}
+/*======================================================================*/
+GbTriFaceMesh3D *GbTriFaceMesh3D::clone()
+{
+    vector<GbTriFaceMesh3D::Vertex> *newNodes      = new vector<GbTriFaceMesh3D::Vertex>;
+    vector<GbTriFaceMesh3D::TriFace> *newTriangles = new vector<GbTriFaceMesh3D::TriFace>;
+
+    int numberNodes = (int)this->nodes->size();
+
+    double x, y, z;
+    for (int u = 0; u < numberNodes; u++) {
+        x = (*nodes)[u].x;
+        y = (*nodes)[u].y;
+        z = (*nodes)[u].z;
+        newNodes->push_back(GbTriFaceMesh3D::Vertex((float)x, (float)y, (float)z));
+    }
+    int numberTris = (int)this->triangles->size();
+    UBLOG(logDEBUG1, "numberTris:" << numberTris);
+
+    int id1, id2, id3;
+    for (int u = 0; u < numberTris; u++) {
+        id1 = (*this->triangles)[u].v1;
+        id2 = (*this->triangles)[u].v2;
+        id3 = (*this->triangles)[u].v3;
+        newTriangles->push_back(GbTriFaceMesh3D::TriFace(id1, id2, id3));
+        // cout<<u<<" - id1,id2,id3:"<<id1<<","<<id2<<","<<id3<<endl;
+    }
+    UBLOG(logDEBUG1, "Tris gelesen");
+
+    GbTriFaceMesh3D *mesh = new GbTriFaceMesh3D("no name", newNodes, newTriangles);
+    UBLOG(logDEBUG1, "mesh cloned ...");
+
+    return mesh;
+}
+
+/*======================================================================*/
+// checks for doppelt nodes und fixed Dreicke die zweimal denselben Knoten haben
+void GbTriFaceMesh3D::deleteRedundantNodes()
+{
+    UBLOG(logDEBUG1,
+          "GbTriFaceMesh3D::deleteRedundantNodes - Nodes before deleting redundant: " << this->nodes->size());
+
+    map<Vertex, size_t /*new vecIndex*/> vertexMap;
+    map<Vertex, size_t /*new vecIndex*/>::iterator pos;
+    map<Vertex, size_t /*new vecIndex*/>::iterator it;
+
+    vector<TriFace> &tris    = *this->triangles;
+    vector<Vertex> &oldNodes = *this->nodes;
+    vector<Vertex> newNodes;
+
+    for (size_t t = 0; t < tris.size(); t++) {
+        if (t % 100 == 0) {
+            UBLOG(logDEBUG5, "GbTriFaceMesh3D::deleteRedundantNodes - tri: " << (t) << " von " << tris.size());
+        }
+        TriFace &tri = tris[t];
+        // Knoten bereits in neuem node vector?
+        for (int v = 0; v <= 2; v++) {
+            Vertex &vert = tri.getNode(v, oldNodes);
+            // pos=vertexMap.find( vert );
+            // if( pos==vertexMap.end() )
+            {
+                for (pos = vertexMap.begin(); pos != vertexMap.end(); pos++) {
+                    Vertex rhs = pos->first;
+                    // if(UbMath::inClosedInterval(vert.z,0.01999, 0.02001))
+                    if (fabs(vert.x - rhs.x) < 1.E-5 && fabs(vert.y - rhs.y) < 1.E-5 && fabs(vert.z - rhs.z) < 1.E-5) {
+                        break;
+                    }
+                }
+            }
+            if (pos != vertexMap.end())
+                tri.setNode(v, (int)pos->second);
+            else {
+                newNodes.push_back(vert);
+                int index       = (int)newNodes.size() - 1;
+                vertexMap[vert] = index;
+                tri.setNode(v, index);
+            }
+        }
+    }
+
+    std::swap(*nodes, newNodes);
+
+    UBLOG(logDEBUG1, "GbTriFaceMesh3D::deleteRedundantNodes - Nodes after deleting redundant:" << this->nodes->size());
+    //
+    // Das geht irgendwie nicht ...
+    //
+    // UBLOG(logDEBUG1,"GbTriFaceMesh3D::deleteRedundantNodes - checking for double triangles !!!");
+    // UBLOG(logDEBUG1,"GbTriFaceMesh3D::deleteRedundantNodes - Triangles before deleting redundant:
+    // "<<this->triangles->size()); vector<TriFace> newSingleTris; newSingleTris.reserve( this->triangles->size() );
+    // for(size_t t=0; t<tris.size(); t++)
+    //{
+    //   Vertex& v1 = tris[t].getNode(0,*nodes);
+    //   Vertex& v2 = tris[t].getNode(1,*nodes);
+    //   Vertex& v3 = tris[t].getNode(2,*nodes);
+
+    //   if(UbMath::greater(std::fabs(v1.x), 0.0634) && UbMath::inClosedInterval(v1.z, 0.01999, 0.02001))
+    //   {
+    //      UBLOG2(logINFO,std::cout, "V1:"<<v1.x<<" "<<v1.y<<" "<<v1.z);
+    //   }
+    //   if(UbMath::greater(std::fabs(v2.x), 0.0634) && UbMath::inClosedInterval(v2.z, 0.01999, 0.02001))
+    //   {
+    //      UBLOG2(logINFO,std::cout, "V2:"<<v2.x<<" "<<v2.y<<" "<<v2.z);
+    //   }
+    //   if(UbMath::greater(std::fabs(v3.x), 0.0634) && UbMath::inClosedInterval(v3.z, 0.01999, 0.02001))
+    //   {
+    //      UBLOG2(logINFO,std::cout, "V3:"<<v3.x<<" "<<v3.y<<" "<<v3.z);
+    //   }
+
+    //   bool inList = false;
+    //   for(size_t u=0; u<newSingleTris.size(); u++)
+    //   {
+    //      Vertex& vn1 = newSingleTris[t].getNode(0,*nodes);
+    //      Vertex& vn2 = newSingleTris[t].getNode(1,*nodes);
+    //      Vertex& vn3 = newSingleTris[t].getNode(2,*nodes);
+
+    //      if(v1==vn1 && v2==vn2 && v3==vn3)      inList = true;
+    //      else if(v1==vn1 && v2==vn3 && v3==vn2) inList = true;
+    //      else if(v1==vn2 && v2==vn3 && v3==vn1) inList = true;
+    //      else if(v1==vn2 && v2==vn1 && v3==vn3) inList = true;
+    //      else if(v1==vn3 && v2==vn1 && v3==vn2) inList = true;
+    //      else if(v1==vn3 && v2==vn2 && v3==vn1) inList = true;
+    //   }
+    //   if(!inList) newSingleTris.push_back(tris[t]);
+    //   else
+    //      UBLOG(logDEBUG1,"GbTriFaceMesh3D::deleteRedundantNodes - inList !!!!");
+
+    //}
+    // swap(tris,newSingleTris);
+
+    // UBLOG(logDEBUG1,"GbTriFaceMesh3D::deleteRedundantNodes - Triangles after deleting
+    // redundant:"<<this->triangles->size());
+    UBLOG(logDEBUG1, "GbTriFaceMesh3D::deleteRedundantNodes - checking for triangles that have same node several times "
+                     "or are lines!!!");
+    int counter1 = 0;
+    int counter2 = 0;
+    vector<TriFace> newTris;
+    newTris.reserve(this->triangles->size());
+    for (size_t t = 0; t < tris.size(); t++) {
+        Vertex &v1 = tris[t].getNode(0, *nodes);
+        Vertex &v2 = tris[t].getNode(1, *nodes);
+        Vertex &v3 = tris[t].getNode(2, *nodes);
+        if (v1 == v2 || v1 == v3 || v2 == v3) {
+            counter1++;
+        } else if (tris[t].getArea(*nodes) < 1.0E-8) {
+            counter2++;
+        } else
+            newTris.push_back(tris[t]);
+    }
+    if (counter1) {
+        UBLOG(logDEBUG1, "GbTriFaceMesh3D::deleteRedundantNodes - ### Warning ###: found and removed  "
+                             << counter1 << " triangle with double nodes!");
+    }
+    if (counter2) {
+        UBLOG(logDEBUG1, "GbTriFaceMesh3D::deleteRedundantNodes - ### Warning ###: found and removed  "
+                             << counter2 << " triangle that are lines!");
+    }
+    if (!counter1 && !counter2) {
+        UBLOG(logDEBUG1, "GbTriFaceMesh3D::deleteRedundantNodes - alles gut... nix doppelt");
+    } else
+        swap(tris, newTris);
+
+    UBLOG(logDEBUG1, "GbTriFaceMesh3D::deleteRedundantNodes - done");
+    this->calculateValues();
+}
+/*======================================================================*/
+void GbTriFaceMesh3D::setKdTreeSplitAlgorithm(KDTREE_SPLITAGORITHM mode)
+{
+    if (kdTree && mode != this->kdtreeSplitAlg) {
+        delete kdTree;
+        kdTree = NULL;
+    }
+    this->kdtreeSplitAlg = mode;
+}
+/*======================================================================*/
+/**
+ * Returns a string representation of this triangular mesh.
+ * @return a string representation of this triangular mesh
+ */
+string GbTriFaceMesh3D::toString()
+{
+    stringstream ss;
+    ss << "GbTriFaceMesh3D[";
+    ss << (int)this->triangles->size() << "-Triangles, " << (int)this->nodes->size() << "-Nodes, " << endl;
+    ss << "]";
+    return (ss.str());
+}
+/**
+ * Returns the nodes of this triangular mesh.
+ * @return the nodes of this triangular mesh
+ */
+vector<GbTriFaceMesh3D::Vertex> *GbTriFaceMesh3D::getNodes() { return this->nodes; }
+/**
+ * Returns the triangles of this triangular mesh.
+ * @return the triangles of this triangular mesh
+ */
+vector<GbTriFaceMesh3D::TriFace> *GbTriFaceMesh3D::getTriangles() { return this->triangles; }
+/**
+ * Returns the center x1 coordinate of this triangular mesh.
+ * @return the center x1 coordinate of this triangular mesh
+ */
+double GbTriFaceMesh3D::getVolume()
+{
+    vector<Vertex> &vertices = *nodes;
+    vector<TriFace> &tris    = *triangles;
+
+    double x1, x2, x3, y1, y2, y3, z1, z2, z3, G3i;
+    // double rSP1 = 0.0;double rSP2 = 0.0;double rSP3 = 0.0;
+    double volume = 0.0;
+    for (size_t t = 0; t < tris.size(); t++) {
+        TriFace &triangle = tris[t];
+        x1                = triangle.getV1x(vertices);
+        y1                = triangle.getV1y(vertices);
+        z1                = triangle.getV1z(vertices);
+        x2                = triangle.getV2x(vertices);
+        y2                = triangle.getV2y(vertices);
+        z2                = triangle.getV2z(vertices);
+        x3                = triangle.getV3x(vertices);
+        y3                = triangle.getV3y(vertices);
+        z3                = triangle.getV3z(vertices);
+        G3i               = x1 * (y2 * z3 - z2 * y3) + y1 * (z2 * x3 - x2 * z3) + z1 * (x2 * y3 - y2 * x3);
+        volume            = volume + G3i / 6.0;
+    }
+    return volume;
+}
+/*===============================================*/
+UbTupleDouble3 GbTriFaceMesh3D::calculateCenterOfGravity()
+{
+    vector<Vertex> &vertices = *nodes;
+    vector<TriFace> &tris    = *triangles;
+
+    double x1, x2, x3, y1, y2, y3, z1, z2, z3;
+    double G3i;
+    double rSP1 = 0.0, rSP2 = 0.0, rSP3 = 0.0, volume = 0.0;
+
+    for (size_t t = 0; t < tris.size(); t++) {
+        TriFace &triangle = tris[t];
+        x1                = triangle.getV1x(vertices);
+        y1                = triangle.getV1y(vertices);
+        z1                = triangle.getV1z(vertices);
+        x2                = triangle.getV2x(vertices);
+        y2                = triangle.getV2y(vertices);
+        z2                = triangle.getV2z(vertices);
+        x3                = triangle.getV3x(vertices);
+        y3                = triangle.getV3y(vertices);
+        z3                = triangle.getV3z(vertices);
+        G3i               = x1 * (y2 * z3 - z2 * y3) + y1 * (z2 * x3 - x2 * z3) + z1 * (x2 * y3 - y2 * x3);
+        volume            = volume + G3i / 6.0;
+        rSP1              = rSP1 + G3i * (x1 + x2 + x3);
+        rSP2              = rSP2 + G3i * (y1 + y2 + y3);
+        rSP3              = rSP3 + G3i * (z1 + z2 + z3);
+    }
+    rSP1 = rSP1 / (24.0 * volume);
+    rSP2 = rSP2 / (24.0 * volume);
+    rSP3 = rSP3 / (24.0 * volume);
+
+    return { rSP1, rSP2, rSP3 };
+}
+/*===============================================*/
+UbTupleDouble6 GbTriFaceMesh3D::calculateMomentOfInertia(double rhoP)
+{
+    vector<Vertex> &vertices = *nodes;
+
+    double x1, x2, x3, y1, y2, y3, z1, z2, z3;
+    double G3i;
+    double xx, yy, zz, xy, yz, zx;
+    double rSP1   = 0.0;
+    double rSP2   = 0.0;
+    double rSP3   = 0.0;
+    double volume = 0.0;
+    double top11  = 0.0;
+    double top22  = 0.0;
+    double top33  = 0.0;
+    double top12  = 0.0;
+    double top23  = 0.0;
+    double top13  = 0.0;
+    int size      = (int)this->triangles->size();
+    for (int u = 0; u < size; u++) {
+        TriFace &triangle = (*this->triangles)[u];
+        x1                = triangle.getV1x(vertices);
+        y1                = triangle.getV1y(vertices);
+        z1                = triangle.getV1z(vertices);
+        x2                = triangle.getV2x(vertices);
+        y2                = triangle.getV2y(vertices);
+        z2                = triangle.getV2z(vertices);
+        x3                = triangle.getV3x(vertices);
+        y3                = triangle.getV3y(vertices);
+        z3                = triangle.getV3z(vertices);
+        G3i               = x1 * (y2 * z3 - z2 * y3) + y1 * (z2 * x3 - x2 * z3) + z1 * (x2 * y3 - y2 * x3);
+        volume            = volume + G3i / 6.0;
+        rSP1              = rSP1 + G3i * (x1 + x2 + x3);
+        rSP2              = rSP2 + G3i * (y1 + y2 + y3);
+        rSP3              = rSP3 + G3i * (z1 + z2 + z3);
+    }
+    rSP1 = rSP1 / (24.0 * volume);
+    rSP2 = rSP2 / (24.0 * volume);
+    rSP3 = rSP3 / (24.0 * volume);
+
+    double x1s = 0.0; // rSP1;//0.0;//
+    double x2s = 0.0; // rSP2;//0.0;//
+    double x3s = 0.0; // rSP3;//0.0;//
+
+    for (int u = 0; u < size; u++) {
+        TriFace &triangle = (*this->triangles)[u];
+        x1                = triangle.getV1x(vertices) - x1s;
+        y1                = triangle.getV1y(vertices) - x2s;
+        z1                = triangle.getV1z(vertices) - x3s;
+        x2                = triangle.getV2x(vertices) - x1s;
+        y2                = triangle.getV2y(vertices) - x2s;
+        z2                = triangle.getV2z(vertices) - x3s;
+        x3                = triangle.getV3x(vertices) - x1s;
+        y3                = triangle.getV3y(vertices) - x2s;
+        z3                = triangle.getV3z(vertices) - x3s;
+        G3i               = x1 * (y2 * z3 - z2 * y3) + y1 * (z2 * x3 - x2 * z3) + z1 * (x2 * y3 - y2 * x3);
+        // rSP1 = rSP1+G3i*(x1+x2+x3)/(24.0*volume);
+        // rSP2 = rSP2+G3i*(y1+y2+y3)/(24.0*volume);
+        // rSP3 = rSP3+G3i*(z1+z2+z3)/(24.0*volume);
+        xx    = x1 * x1 + x2 * x2 + x3 * x3 + x1 * x2 + x2 * x3 + x3 * x1;
+        yy    = y1 * y1 + y2 * y2 + y3 * y3 + y1 * y2 + y2 * y3 + y3 * y1;
+        zz    = z1 * z1 + z2 * z2 + z3 * z3 + z1 * z2 + z2 * z3 + z3 * z1;
+        top11 = top11 + (yy + zz) * rhoP * G3i / 60.;
+        top22 = top22 + (xx + zz) * rhoP * G3i / 60.;
+        top33 = top33 + (yy + xx) * rhoP * G3i / 60.;
+        xy    = 2.0 * (x1 * y1 + x2 * y2 + x3 * y3) + x2 * y3 + x3 * y1 + x1 * y2 + x3 * y2 + x1 * y3 + x2 * y1;
+        yz    = 2.0 * (y1 * z1 + y2 * z2 + y3 * z3) + y2 * z3 + y3 * z1 + y1 * z2 + y3 * z2 + y1 * z3 + y2 * z1;
+        zx    = 2.0 * (z1 * x1 + z2 * x2 + z3 * x3) + z2 * x3 + z3 * x1 + z1 * x2 + z3 * x2 + z1 * x3 + z2 * x1;
+        top12 = top12 - xy * rhoP * G3i / 120.;
+        top23 = top23 - yz * rhoP * G3i / 120.;
+        top13 = top13 - zx * rhoP * G3i / 120.;
+    }
+    // Satz von Steiner ...
+    top11 = top11 - rhoP * volume * (rSP2 * rSP2 + rSP3 + rSP3);
+    top22 = top22 - rhoP * volume * (rSP3 * rSP3 + rSP1 * rSP1);
+    top33 = top33 - rhoP * volume * (rSP1 * rSP1 + rSP2 * rSP2);
+    top12 = top12 + rhoP * volume * rSP1 * rSP2;
+    top23 = top23 + rhoP * volume * rSP2 * rSP3;
+    top13 = top13 + rhoP * volume * rSP3 * rSP1;
+
+    cout << "Volume:" << volume << "\n Traegheitsmomente:\n";
+    cout << " top11:" << top11 << " top22:" << top22 << " top33:" << top33 << endl;
+    cout << " top12:" << top12 << " top23:" << top23 << " top13:" << top13 << endl;
+
+    return { top11, top22, top33, top12, top23, top13 };
+}
+/*==============================================================*/
+void GbTriFaceMesh3D::calculateValues()
+{
+    relationVertTris.clear();
+
+    if (nodes->empty()) {
+        x1min = x1max = x2min = x2max = x3min = x3max = 0.0;
+    } else {
+        Vertex &v = (*nodes)[0];
+        x1min = x1max = v.x;
+        x2min = x2max = v.y;
+        x3min = x3max = v.z;
+
+        for (size_t i = 1; i < this->nodes->size(); i++) {
+            Vertex &v1 = (*nodes)[i];
+
+            x1min = UbMath::min<double>(x1min, v1.x);
+            x2min = UbMath::min<double>(x2min, v1.y);
+            x3min = UbMath::min<double>(x3min, v1.z);
+
+            x1max = UbMath::max<double>(x1max, v1.x);
+            x2max = UbMath::max<double>(x2max, v1.y);
+            x3max = UbMath::max<double>(x3max, v1.z);
+        }
+        x1center = 0.5 * (x1min + x1max);
+        x2center = 0.5 * (x2min + x2max);
+        x3center = 0.5 * (x3min + x3max);
+
+        vector<TriFace> &tris = *this->triangles;
+        vector<Vertex> &verts = *this->nodes;
+        for (size_t i = 0; i < this->triangles->size(); i++) {
+            tris[i].calculateNormal(verts);
+        }
+        // relation Vertex <-> Triangle ermitteln
+        if (buildVertTriRelationMap) {
+            for (size_t t = 0; t < tris.size(); t++) {
+                TriFace &tri = tris[t];
+                relationVertTris.insert(make_pair(&verts[tri.v1], &tri));
+                relationVertTris.insert(make_pair(&verts[tri.v2], &tri));
+                relationVertTris.insert(make_pair(&verts[tri.v3], &tri));
+            }
+        }
+    }
+    if (kdTree) {
+        delete kdTree;
+        kdTree = NULL;
+    }
+
+    this->consistent = true;
+}
+/*=========================================================================*/
+std::vector<GbTriFaceMesh3D::TriFace *> GbTriFaceMesh3D::getTrianglesForVertex(Vertex *vertex)
+{
+    if (!buildVertTriRelationMap) {
+        buildVertTriRelationMap = true;
+        consistent              = false;
+    }
+    if (!consistent)
+        this->calculateValues();
+
+    typedef std::multimap<Vertex *, TriFace *>::iterator Iterator;
+    pair<Iterator, Iterator> objRange = relationVertTris.equal_range(vertex);
+
+    std::vector<TriFace *> tmpTris;
+    for (Iterator pos = objRange.first; pos != objRange.second; ++pos)
+        tmpTris.push_back(pos->second);
+
+    return tmpTris;
+}
+/*=======================================================*/
+void GbTriFaceMesh3D::setCenterCoordinates(const double &x1, const double &x2, const double &x3)
+{
+    this->translate(x1 - getX1Centroid(), x2 - getX2Centroid(), x3 - getX3Centroid());
+}
+
+/*======================================================================*/
+void GbTriFaceMesh3D::setCenterCoordinates(const UbTupleDouble3 & /*position*/)
+{
+    throw UbException(UB_EXARGS, "not implemented for " + (std::string) typeid(*this).name());
+}
+
+/*======================================================================*/
+void GbTriFaceMesh3D::scale(const double &sx1, const double &sx2, const double &sx3)
+{
+    CoordinateTransformation3D trafoForw(this->getX1Centroid(), this->getX2Centroid(), this->getX3Centroid(), 1.0, 1.0,
+                                         1.0, 0.0, 0.0, 0.0);
+    CoordinateTransformation3D trafoBack(this->getX1Centroid(), this->getX2Centroid(), this->getX3Centroid(), sx1, sx2,
+                                         sx3, 0, 0, 0);
+
+    vector<Vertex> &vertices = *nodes;
+    for (size_t i = 0; i < vertices.size(); i++) {
+        Vertex &v   = vertices[i];
+        double p1x1 = trafoForw.transformForwardToX1Coordinate(v.x, v.y, v.z);
+        double p1x2 = trafoForw.transformForwardToX2Coordinate(v.x, v.y, v.z);
+        double p1x3 = trafoForw.transformForwardToX3Coordinate(v.x, v.y, v.z);
+        v.x         = (float)trafoBack.transformBackwardToX1Coordinate(p1x1, p1x2, p1x3);
+        v.y         = (float)trafoBack.transformBackwardToX2Coordinate(p1x1, p1x2, p1x3);
+        v.z         = (float)trafoBack.transformBackwardToX3Coordinate(p1x1, p1x2, p1x3);
+    }
+    this->calculateValues();
+}
+/*======================================================================*/
+void GbTriFaceMesh3D::rotate(const double &alpha, const double &beta, const double &gamma)
+{
+    CoordinateTransformation3D trafoForw(this->getX1Centroid(), this->getX2Centroid(), this->getX3Centroid(), 1.0, 1.0,
+                                         1.0, 0.0, 0.0, 0.0);
+    CoordinateTransformation3D trafoBack(this->getX1Centroid(), this->getX2Centroid(), this->getX3Centroid(), 1.0, 1.0,
+                                         1.0, alpha, beta, gamma);
+
+    vector<Vertex> &vertices = *nodes;
+    for (size_t i = 0; i < vertices.size(); i++) {
+        Vertex &v   = vertices[i];
+        double p1x1 = trafoForw.transformForwardToX1Coordinate(v.x, v.y, v.z);
+        double p1x2 = trafoForw.transformForwardToX2Coordinate(v.x, v.y, v.z);
+        double p1x3 = trafoForw.transformForwardToX3Coordinate(v.x, v.y, v.z);
+        v.x         = (float)trafoBack.transformBackwardToX1Coordinate(p1x1, p1x2, p1x3);
+        v.y         = (float)trafoBack.transformBackwardToX2Coordinate(p1x1, p1x2, p1x3);
+        v.z         = (float)trafoBack.transformBackwardToX3Coordinate(p1x1, p1x2, p1x3);
+    }
+    this->calculateValues();
+}
+/*======================================================================*/
+void GbTriFaceMesh3D::rotateAroundPoint(const double &px1, const double &px2, const double &px3, const double &alpha,
+                                        const double &beta, const double &gamma)
+{
+    CoordinateTransformation3D trafoForw(px1, px2, px3, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0);
+    CoordinateTransformation3D trafoBack(px1, px2, px3, 1.0, 1.0, 1.0, alpha, beta, gamma);
+
+    vector<Vertex> &vertices = *nodes;
+    for (size_t i = 0; i < vertices.size(); i++) {
+        Vertex &v   = vertices[i];
+        double p1x1 = trafoForw.transformForwardToX1Coordinate(v.x, v.y, v.z);
+        double p1x2 = trafoForw.transformForwardToX2Coordinate(v.x, v.y, v.z);
+        double p1x3 = trafoForw.transformForwardToX3Coordinate(v.x, v.y, v.z);
+        v.x         = (float)trafoBack.transformBackwardToX1Coordinate(p1x1, p1x2, p1x3);
+        v.y         = (float)trafoBack.transformBackwardToX2Coordinate(p1x1, p1x2, p1x3);
+        v.z         = (float)trafoBack.transformBackwardToX3Coordinate(p1x1, p1x2, p1x3);
+    }
+    this->calculateValues();
+}
+
+/*======================================================================*/
+void GbTriFaceMesh3D::translate(const double &x1, const double &x2, const double &x3)
+{
+    vector<Vertex> &vertices = *nodes;
+    for (size_t i = 0; i < vertices.size(); i++) {
+        Vertex &v = vertices[i];
+        v.x += static_cast<float>(x1);
+        v.y += static_cast<float>(x2);
+        v.z += static_cast<float>(x3);
+    }
+    this->calculateValues();
+}
+/*======================================================================*/
+vector<GbTriangle3D *> GbTriFaceMesh3D::getSurfaceTriangleSet()
+{
+    // SirAnn: eine miese Speicherlochmethode
+    //        hier werden dynmamische Objekte angelegt
+    //        mit sowas rechnet von aussen kein Mensch!!!
+    vector<GbTriangle3D *> tris(triangles->size());
+
+    for (size_t i = 0; i < this->triangles->size(); i++) {
+        Vertex &v1 = (*nodes)[(*triangles)[i].v1];
+        Vertex &v2 = (*nodes)[(*triangles)[i].v2];
+        Vertex &v3 = (*nodes)[(*triangles)[i].v3];
+
+        tris[i] = new GbTriangle3D(new GbPoint3D(v1.x, v1.y, v1.z), new GbPoint3D(v2.x, v2.y, v2.z),
+                                   new GbPoint3D(v3.x, v3.y, v3.z));
+    }
+    return tris;
+}
+/*=======================================================*/
+void GbTriFaceMesh3D::addSurfaceTriangleSet(vector<UbTupleFloat3> &pts, vector<UbTupleInt3> &tris)
+{
+    int nodeNr = int(pts.size());
+    for (int i = 0; i < (int)this->triangles->size(); i++) {
+        Vertex &v1 = (*nodes)[(*triangles)[i].v1];
+        Vertex &v2 = (*nodes)[(*triangles)[i].v2];
+        Vertex &v3 = (*nodes)[(*triangles)[i].v3];
+        pts.push_back(makeUbTuple(v1.x, v1.y, v1.z));
+        pts.push_back(makeUbTuple(v2.x, v2.y, v2.z));
+        pts.push_back(makeUbTuple(v3.x, v3.y, v3.z));
+
+        tris.push_back(makeUbTuple(nodeNr, nodeNr + 1, nodeNr + 2));
+        nodeNr += 3;
+    }
+}
+/*======================================================================*/
+// bool GbTriFaceMesh3D::isPointInGbObject3D(const double& x1, const double& x2, const double& x3, int counter)
+//{
+//
+//
+//   if( !nodes->empty() )
+//   {
+//      //Baum erstellen, wen noch keiner vorhanden
+//      if( !kdTree)
+//      {
+//         UBLOG(logDEBUG3, "GbTriFaceMesh3D::calculateValues - build KdTree start");
+//         UbTimer timer; timer.start();
+//         if(kdtreeSplitAlg == KDTREE_SAHPLIT     )
+//         {
+//            UBLOG(logDEBUG3, "GbTriFaceMesh3D::calculateValues - build KdTree with SAHSplit");
+//            this->kdTree = new Kd::Tree<double>( *this, Kd::SAHSplit<double>()            );
+//         }
+//         else if(kdtreeSplitAlg == KDTREE_SPATIALSPLIT)
+//         {
+//            UBLOG(logDEBUG3, "GbTriFaceMesh3D::calculateValues - build KdTree with SpatialMedianSplit");
+//            this->kdTree = new Kd::Tree<double>( *this, Kd::SpatialMedianSplit<double>() );
+//         }
+//         else throw UbException(UB_EXARGS, "unknown kdtree split option)" );
+//         UBLOG(logDEBUG3, "GbTriFaceMesh3D::calculateValues - built kdTree in "<<timer.stop()<<"seconds");
+//      }
+//
+//      //eigentlicher PIO-Test
+//      //int iSec;
+//      //for(int i=0; i<100; i++)
+//      //{
+//      //   Kd::Ray<double> ray(  x1, x2, x3  //, 1, 0 ,0 );
+//      //                        , ( x1 < x1center ? UbRandom::rand(-1.0,-0.001, 10) : UbRandom::rand(0.001, 1.0, 10) )
+//      //                        , ( x2 < x2center ? UbRandom::rand(-1.0,-0.001, 10) : UbRandom::rand(0.001, 1.0, 10) )
+//      //                        , ( x3 < x3center ? UbRandom::rand(-1.0,-0.001, 10) : UbRandom::rand(0.001, 1.0, 10) )
+//      );
+//      //
+//      //   iSec = kdTree->intersectRay( ray, Kd::CountRayIntersectionHandler<double>() );
+//      //
+//      //   if( iSec != Kd::Intersection::INTERSECT_EDGE ) //KEINE Kante getroffen
+//      //   {
+//      //      if(iSec == Kd::Intersection::ON_BOUNDARY )
+//      //      {
+//      //         return true;
+//      //      }
+//      //      return (iSec&1);  //ungerade anzahl an schnitten --> drinnen
+//      //   }
+//      //   UBLOG(logDEBUG3, "GbTriFaceMesh3D.isPointInGbObject3D.if  - an edge was hit ");
+//      //}
+//      //throw UbException(UB_EXARGS, "ups, nach 100 Strahlen immer noch kein Ergebnis");
+//      int iSec1,iSec2;
+//
+//      Kd::Ray<double> ray1(  x1, x2, x3, 1.0, 0.0 ,0.0 );
+//      iSec1 = kdTree->intersectRay( ray1, Kd::CountRayIntersectionHandler<double>() );
+//      Kd::Ray<double> ray2(  x1, x2, x3, -1.0, 0.0 ,0.0 );
+//      iSec2 = kdTree->intersectRay( ray2, Kd::CountRayIntersectionHandler<double>() );
+//
+//      if(iSec1 == Kd::Intersection::ON_BOUNDARY || iSec2 == Kd::Intersection::ON_BOUNDARY)
+//      {
+//         return true;
+//      }
+//      if( iSec1 == Kd::Intersection::INTERSECT_EDGE && iSec2 == Kd::Intersection::INTERSECT_EDGE)
+//      {
+//         UBLOG(logINFO, "GbTriFaceMesh3D.isPointInGbObject3D.INTERSECT_EDGE");
+//         double eps = UbMath::getEqualityEpsilon<float>()*1000.0;
+//         if (counter>100) {return(iSec1&1);  UBLOG(logINFO, "NACH 100 Iterationen Eps umsetzen aufgegeben!");}
+//         return this->isPointInGbObject3D(x1+eps, x2+eps, x3+eps,(counter+1));
+//      }
+//      else if( iSec1 == Kd::Intersection::INTERSECT_EDGE)
+//      {
+//         return (iSec2&1);
+//      }
+//      else if( iSec2 == Kd::Intersection::INTERSECT_EDGE)
+//      {
+//         return (iSec1&1);
+//      }
+//      else
+//      {
+//         if((iSec1&1) != (iSec2&1))
+//         {
+//            UBLOG(logINFO, "GbTriFaceMesh3D.isPointInGbObject3D.iSec1&1 != iSec2&1");
+//            double eps = UbMath::getEqualityEpsilon<float>()*1000.0;
+//            if (counter>100) {return(iSec1&1);  UBLOG(logINFO, "NACH 100 Iterationen Eps umsetzen aufgegeben!");}
+//            return this->isPointInGbObject3D(x1+eps, x2+eps, x3+eps,(counter+1));
+//         }
+//         return iSec1&1;
+//      }
+//      //throw UbException(UB_EXARGS, "ups, nach 100 Strahlen immer noch kein Ergebnis");
+//
+//   }
+//   return false;
+//}
+bool GbTriFaceMesh3D::isPointInGbObject3D(const double &x1, const double &x2, const double &x3, int counter)
+{
+
+    if (!nodes->empty()) {
+        // Baum erstellen, wen noch keiner vorhanden
+        if (!kdTree) {
+            UBLOG(logDEBUG3, "GbTriFaceMesh3D::calculateValues - build KdTree start");
+            UbTimer timer;
+            timer.start();
+            if (kdtreeSplitAlg == KDTREE_SAHPLIT) {
+                UBLOG(logDEBUG3, "GbTriFaceMesh3D::calculateValues - build KdTree with SAHSplit");
+                this->kdTree = new Kd::Tree<double>(*this, Kd::SAHSplit<double>());
+            } else if (kdtreeSplitAlg == KDTREE_SPATIALSPLIT) {
+                UBLOG(logDEBUG3, "GbTriFaceMesh3D::calculateValues - build KdTree with SpatialMedianSplit");
+                this->kdTree = new Kd::Tree<double>(*this, Kd::SpatialMedianSplit<double>());
+            } else
+                throw UbException(UB_EXARGS, "unknown kdtree split option)");
+            UBLOG(logDEBUG3, "GbTriFaceMesh3D::calculateValues - built kdTree in " << timer.stop() << "seconds");
+        }
+
+        // eigentlicher PIO-Test
+        // int iSec;
+        // for(int i=0; i<100; i++)
+        //{
+        //   Kd::Ray<double> ray(  x1, x2, x3  //, 1, 0 ,0 );
+        //                        , ( x1 < x1center ? UbRandom::rand(-1.0,-0.001, 10) : UbRandom::rand(0.001, 1.0, 10) )
+        //                        , ( x2 < x2center ? UbRandom::rand(-1.0,-0.001, 10) : UbRandom::rand(0.001, 1.0, 10) )
+        //                        , ( x3 < x3center ? UbRandom::rand(-1.0,-0.001, 10) : UbRandom::rand(0.001, 1.0, 10) )
+        //                        );
+        //
+        //   iSec = kdTree->intersectRay( ray, Kd::CountRayIntersectionHandler<double>() );
+        //
+        //   if( iSec != Kd::Intersection::INTERSECT_EDGE ) //KEINE Kante getroffen
+        //   {
+        //      if(iSec == Kd::Intersection::ON_BOUNDARY )
+        //      {
+        //         return true;
+        //      }
+        //      return (iSec&1);  //ungerade anzahl an schnitten --> drinnen
+        //   }
+        //   UBLOG(logDEBUG3, "GbTriFaceMesh3D.isPointInGbObject3D.if  - an edge was hit ");
+        //}
+        // throw UbException(UB_EXARGS, "ups, nach 100 Strahlen immer noch kein Ergebnis");
+        int iSec1, iSec2;
+        double eps = 0.05;
+        Kd::Ray<double> ray1(x1, x2, x3, 1.0 + eps * ((double)counter), eps * ((double)counter),
+                             eps * ((double)counter));
+        iSec1 = kdTree->intersectRay(ray1, Kd::CountRayIntersectionHandler<double>());
+        Kd::Ray<double> ray2(x1, x2, x3, -1.0 - eps * ((double)counter), -eps * ((double)counter),
+                             -eps * ((double)counter));
+
+        iSec2 = kdTree->intersectRay(ray2, Kd::CountRayIntersectionHandler<double>());
+
+        if (iSec1 == Kd::Intersection::ON_BOUNDARY || iSec2 == Kd::Intersection::ON_BOUNDARY) {
+            return true;
+        }
+        if (iSec1 == Kd::Intersection::INTERSECT_EDGE && iSec2 == Kd::Intersection::INTERSECT_EDGE) {
+            // UBLOG(logINFO, "GbTriFaceMesh3D.isPointInGbObject3D.INTERSECT_EDGE");
+
+            if (counter > 20) {
+                return (iSec1 & 1); /*UBLOG(logINFO, "NACH 100 Iterationen Eps umsetzen aufgegeben!");*/
+            }
+            return this->isPointInGbObject3D(x1, x2, x3, (counter + 1));
+        } else if (iSec1 == Kd::Intersection::INTERSECT_EDGE) {
+            return (iSec2 & 1);
+        } else if (iSec2 == Kd::Intersection::INTERSECT_EDGE) {
+            return (iSec1 & 1);
+        } else {
+            if ((iSec1 & 1) != (iSec2 & 1)) {
+                // UBLOG(logINFO, "GbTriFaceMesh3D.isPointInGbObject3D.iSec1&1 != iSec2&1");
+
+                if (counter > 20) {
+                    return (iSec1 & 1); /* UBLOG(logINFO, "NACH 100 Iterationen Eps umsetzen aufgegeben!");*/
+                }
+                return this->isPointInGbObject3D(x1, x2, x3, (counter + 1));
+            }
+            return iSec1 & 1;
+        }
+        // throw UbException(UB_EXARGS, "ups, nach 100 Strahlen immer noch kein Ergebnis");
+    }
+    return false;
+}
+/*======================================================================*/
+bool GbTriFaceMesh3D::isPointInGbObject3D(const double &x1, const double &x2, const double &x3)
+{
+    if (!nodes->empty()) {
+        // Baum erstellen, wen noch keiner vorhanden
+        if (!kdTree) {
+            UBLOG(logDEBUG3, "GbTriFaceMesh3D::calculateValues - build KdTree start");
+            UbTimer timer;
+            timer.start();
+            if (kdtreeSplitAlg == KDTREE_SAHPLIT) {
+                UBLOG(logDEBUG3, "GbTriFaceMesh3D::calculateValues - build KdTree with SAHSplit");
+                //cout << "GbTriFaceMesh3D::calculateValues - build KdTree with SAHSplit" << std::endl;
+                this->kdTree = new Kd::Tree<double>(*this, Kd::SAHSplit<double>());
+            } else if (kdtreeSplitAlg == KDTREE_SPATIALSPLIT) {
+                UBLOG(logDEBUG3, "GbTriFaceMesh3D::calculateValues - build KdTree with SpatialMedianSplit");
+                this->kdTree = new Kd::Tree<double>(*this, Kd::SpatialMedianSplit<double>());
+            } else
+                throw UbException(UB_EXARGS, "unknown kdtree split option)");
+            UBLOG(logDEBUG3, "GbTriFaceMesh3D::calculateValues - built kdTree in " << timer.stop() << "seconds");
+            //cout << "GbTriFaceMesh3D::calculateValues - built kdTree in " << timer.stop() << "seconds" << std::endl;
+        }
+
+        // eigentlicher PIO-Test
+        int iSec;
+        for (int i = 0; i < MAX_ITER; i++) {
+            Kd::Ray<double> ray(x1, x2, x3 //, 1, 0 ,0 );
+                                ,
+                                (x1 < x1center ? UbRandom::rand(-1.0, -0.001, 10) : UbRandom::rand(0.001, 1.0, 10)),
+                                (x2 < x2center ? UbRandom::rand(-1.0, -0.001, 10) : UbRandom::rand(0.001, 1.0, 10)),
+                                (x3 < x3center ? UbRandom::rand(-1.0, -0.001, 10) : UbRandom::rand(0.001, 1.0, 10)));
+
+            iSec = kdTree->intersectRay(ray, Kd::CountRayIntersectionHandler<double>());
+
+            if (iSec != Kd::Intersection::INTERSECT_EDGE) // KEINE Kante getroffen
+            {
+                if (iSec == Kd::Intersection::ON_BOUNDARY) {
+                    return true;
+                }
+                return (iSec & 1); // ungerade anzahl an schnitten --> drinnen
+            }
+            UBLOG(logDEBUG3, "GbTriFaceMesh3D.isPointInGbObject3D.if  - an edge was hit ");
+        }
+        throw UbException(UB_EXARGS, "ups, nach 100 Strahlen immer noch kein Ergebnis");
+
+        //   int iSec1,iSec2;
+        //
+        //   Kd::Ray<double> ray1(  x1, x2, x3, 1.0, 0.0 ,0.0 );
+        //   iSec1 = kdTree->intersectRay( ray1, Kd::CountRayIntersectionHandler<double>() );
+        //   Kd::Ray<double> ray2(  x1, x2, x3, -1.0, 0.0 ,0.0 );
+        //   iSec2 = kdTree->intersectRay( ray2, Kd::CountRayIntersectionHandler<double>() );
+
+        //   if(iSec1 == Kd::Intersection::ON_BOUNDARY || iSec2 == Kd::Intersection::ON_BOUNDARY)
+        //   {
+        //      return true;
+        //   }
+        //   if( iSec1 == Kd::Intersection::INTERSECT_EDGE && iSec2 == Kd::Intersection::INTERSECT_EDGE)
+        //   {
+        //      //UBLOG(logINFO, "GbTriFaceMesh3D.isPointInGbObject3D.INTERSECT_EDGE");
+        //      double eps = UbMath::getEqualityEpsilon<double>();
+        //      if (counter>100) {return(iSec1&1);  UBLOG(logINFO, "NACH 100 Iterationen Eps umsetzen aufgegeben!");}
+        //      return this->isPointInGbObject3D(x1+eps, x2+eps, x3+eps,(counter+1));
+        //   }
+        //   else if( iSec1 == Kd::Intersection::INTERSECT_EDGE)
+        //   {
+        //      return (iSec2&1);
+        //   }
+        //   else if( iSec2 == Kd::Intersection::INTERSECT_EDGE)
+        //   {
+        //      return (iSec1&1);
+        //   }
+        //   else
+        //   {
+        //      if((iSec1&1) != (iSec2&1))
+        //      {
+        //         UBLOG(logINFO, "GbTriFaceMesh3D.isPointInGbObject3D.iSec1&1 != iSec2&1");
+        //         double eps = UbMath::getEqualityEpsilon<double>();
+        //         if (counter>100) {return(iSec1&1);  UBLOG(logINFO, "NACH 100 Iterationen Eps umsetzen aufgegeben!");}
+        //         return this->isPointInGbObject3D(x1+eps, x2+eps, x3+eps,(counter+1));
+        //      }
+        //      return iSec1&1;
+        //   }
+        //   //throw UbException(UB_EXARGS, "ups, nach 100 Strahlen immer noch kein Ergebnis");
+    }
+    return false;
+}
+/*======================================================================*/
+bool GbTriFaceMesh3D::isPointInGbObject3D(const double &x1, const double &x2, const double &x3, bool &pointIsOnBoundary)
+{
+    if (!nodes->empty()) {
+        // Baum erstellen, wen noch keiner vorhanden
+        if (!kdTree) {
+            UBLOG(logDEBUG3, "GbTriFaceMesh3D::calculateValues - build KdTree start");
+            UbTimer timer;
+            timer.start();
+            if (kdtreeSplitAlg == KDTREE_SAHPLIT) {
+                UBLOG(logDEBUG3, "GbTriFaceMesh3D::calculateValues - build KdTree with SAHSplit");
+                this->kdTree = new Kd::Tree<double>(*this, Kd::SAHSplit<double>());
+            } else if (kdtreeSplitAlg == KDTREE_SPATIALSPLIT) {
+                UBLOG(logDEBUG3, "GbTriFaceMesh3D::calculateValues - build KdTree with SpatialMedianSplit");
+                this->kdTree = new Kd::Tree<double>(*this, Kd::SpatialMedianSplit<double>());
+            } else
+                throw UbException(UB_EXARGS, "unknown kdtree split option)");
+            UBLOG(logDEBUG3, "GbTriFaceMesh3D::calculateValues - built kdTree in " << timer.stop() << "seconds");
+        }
+
+        // eigentlicher PIO-Test
+        int iSec;
+        for (int i = 0; i < MAX_ITER; i++) {
+            Kd::Ray<double> ray(
+                x1, x2, x3, float((x1 < x1center ? UbRandom::rand(-1.0, -0.001, 10) : UbRandom::rand(0.001, 1.0, 10))),
+                float((x2 < x2center ? UbRandom::rand(-1.0, -0.001, 10) : UbRandom::rand(0.001, 1.0, 10))),
+                float((x3 < x3center ? UbRandom::rand(-1.0, -0.001, 10) : UbRandom::rand(0.001, 1.0, 10))));
+
+            iSec = kdTree->intersectRay(ray, Kd::CountRayIntersectionHandler<double>());
+
+            if (iSec != Kd::Intersection::INTERSECT_EDGE) // KEINE Kante getroffen
+            {
+                if (iSec == Kd::Intersection::ON_BOUNDARY) {
+                    pointIsOnBoundary = true;
+                    return true;
+                }
+                pointIsOnBoundary = false;
+                return (iSec & 1); // ungerade anzahl an schnitten --> drinnen
+            }
+        }
+
+        throw UbException(UB_EXARGS, "ups, nach 100 Strahlen immer noch kein Ergebnis");
+    }
+
+    return false;
+}
+/*======================================================================*/
+bool GbTriFaceMesh3D::intersectLine(const double &p1_x1, const double &p1_x2, const double &p1_x3, const double &p2_x1,
+                                    const double &p2_x2, const double &p2_x3)
+{
+    // Baum erstellen, wen noch keiner vorhanden
+    if (!kdTree) {
+        UBLOG(logDEBUG3, "GbTriFaceMesh3D::calculateValues - build KdTree start");
+        UbTimer timer;
+        timer.start();
+        if (kdtreeSplitAlg == KDTREE_SAHPLIT) {
+            UBLOG(logDEBUG3, "GbTriFaceMesh3D::calculateValues - build KdTree with SAHSplit");
+            this->kdTree = new Kd::Tree<double>(*this, Kd::SAHSplit<double>());
+        } else if (kdtreeSplitAlg == KDTREE_SPATIALSPLIT) {
+            UBLOG(logDEBUG3, "GbTriFaceMesh3D::calculateValues - build KdTree with SpatialMedianSplit");
+            this->kdTree = new Kd::Tree<double>(*this, Kd::SpatialMedianSplit<double>());
+        } else
+            throw UbException(UB_EXARGS, "unknown kdtree split option)");
+        UBLOG(logDEBUG3, "GbTriFaceMesh3D::calculateValues - built kdTree in " << timer.stop() << "seconds");
+    }
+
+    int iSec = kdTree->intersectLine(UbTupleDouble3(p1_x1, p1_x2, p1_x3), UbTupleDouble3(p2_x1, p2_x2, p2_x3),
+                                     Kd::CountLineIntersectionHandler<double>());
+
+    return (iSec != Kd::Intersection::NO_INTERSECTION);
+}
+/*======================================================================*/
+GbLine3D *GbTriFaceMesh3D::createClippedLine3D(GbPoint3D & /*point1*/, GbPoint3D & /*point2*/)
+{
+    throw UbException(UB_EXARGS, "not implemented");
+}
+
+/*======================================================================*/
+UbTuple<string, string> GbTriFaceMesh3D::writeMesh(string filename, WbWriter *writer, bool writeNormals,
+                                                   vector<string> *datanames,
+                                                   std::vector<std::vector<double>> *nodedata)
+{
+    UBLOG(logINFO, "GbTriFaceMesh3D::writeMesh ");
+
+    vector<UbTupleFloat3> triNodes(nodes->size());
+    vector<UbTupleInt3> tris(triangles->size());
+
+    for (size_t i = 0; i < nodes->size(); i++)
+        triNodes[i] = makeUbTuple((*nodes)[i].x, (*nodes)[i].y, (*nodes)[i].z);
+
+    for (size_t i = 0; i < triangles->size(); i++)
+        tris[i] = makeUbTuple((*triangles)[i].v1, (*triangles)[i].v2, (*triangles)[i].v3);
+
+    UbTuple<string, string> filenames("", "");
+
+    if (!datanames || datanames->empty() || !nodedata) {
+        val<1>(filenames) = writer->writeTriangles(filename, triNodes, tris);
+    } else {
+        val<1>(filenames) = writer->writeTrianglesWithNodeData(filename, triNodes, tris, *datanames, *nodedata);
+    }
+
+    if (writeNormals) {
+        vector<UbTupleFloat3> lineNodes(triangles->size() * 2);
+        vector<UbTupleInt2> lines(triangles->size());
+        for (size_t i = 0; i < triangles->size(); i++) {
+            TriFace &triangle = (*triangles)[i];
+            lineNodes[i * 2]  = makeUbTuple(triangle.getX1Centroid(*nodes), triangle.getX2Centroid(*nodes),
+                                           triangle.getX3Centroid(*nodes));
+
+            lineNodes[i * 2 + 1] = makeUbTuple((float)(triangle.getX1Centroid(*nodes) + 1.0 * triangle.nx),
+                                               (float)(triangle.getX2Centroid(*nodes) + 1.0 * triangle.ny),
+                                               (float)(triangle.getX3Centroid(*nodes) + 1.0 * triangle.nz));
+
+            lines[i] = makeUbTuple((int)i * 2, (int)i * 2 + 1);
+        }
+        val<2>(filenames) = writer->writeLines(filename + "_normals", lineNodes, lines);
+    }
+
+    return filenames;
+}
+/*======================================================================*/
+void GbTriFaceMesh3D::writeMeshPly(const std::string &filename)
+{
+    ofstream out(filename.c_str());
+    if (!out)
+        throw UbException(UB_EXARGS, "couldn't open " + filename);
+
+    out << "ply" << endl;
+    out << "format ascii 1.0" << endl;
+    out << "element vertex " << (int)nodes->size() << endl;
+    out << "property float x" << endl;
+    out << "property float y" << endl;
+    out << "property float z" << endl;
+    out << "element face " << (int)triangles->size() << endl;
+    out << "property list uchar int vertex_indices" << endl;
+    out << "end_header" << endl;
+
+    for (size_t i = 0; i < nodes->size(); i++)
+        out << (*nodes)[i].x << " " << (*nodes)[i].y << " " << (*nodes)[i].z << endl;
+
+    for (size_t i = 0; i < triangles->size(); i++)
+        out << "3 " << (*triangles)[i].v1 << " " << (*triangles)[i].v2 << " " << (*triangles)[i].v3 << endl;
+}
+/*======================================================================*/
+void GbTriFaceMesh3D::readMeshFromSTLFileASCII(string filename, bool removeRedundantNodes)
+{
+    UBLOG(logDEBUG1, "GbTriFaceMesh3DCreator::readMeshFromSTLFile !!! Dieses Format hat leider redundante Knoten ...");
+
+    int nr = 0;
+
+    ifstream in(filename.c_str());
+    if (!in.good()) {
+        (*nodes).clear();
+        (*triangles).clear();
+        UB_THROW(UbException(UB_EXARGS, "Can not open STL file: " + filename));
+    }
+    char title[80];
+    std::string s0, s1;
+    float n0, n1, n2, f0, f1, f2, f3, f4, f5, f6, f7, f8;
+    in.read(title, 80);
+    while (!in.eof()) {
+        in >> s0; // facet || endsolid
+        if (s0 == "facet") {
+            in >> s1 >> n0 >> n1 >> n2; // normal x y z
+            in >> s0 >> s1;             // outer loop
+            in >> s0 >> f0 >> f1 >> f2; // vertex x y z
+            in >> s0 >> f3 >> f4 >> f5; // vertex x y z
+            in >> s0 >> f6 >> f7 >> f8; // vertex x y z
+            in >> s0;                   // endloop
+            in >> s0;                   // endfacet
+            // Generate a new Triangle without Normal as 3 Vertices
+            nodes->push_back(GbTriFaceMesh3D::Vertex(f0, f1, f2));
+            nodes->push_back(GbTriFaceMesh3D::Vertex(f3, f4, f5));
+            nodes->push_back(GbTriFaceMesh3D::Vertex(f6, f7, f8));
+            triangles->push_back(GbTriFaceMesh3D::TriFace(nr, nr + 1, nr + 2));
+            nr += 3;
+        } else if (s0 == "endsolid") {
+            break;
+        }
+    }
+    in.close();
+
+    if (removeRedundantNodes) {
+        this->deleteRedundantNodes(); // dort wird autoamtisch calculateValues() aufgerufen
+    } else {
+        this->calculateValues();
+    }
+    //UBLOG(logDEBUG1, "GbTriFaceMesh3DCreator::readMeshFromSTLFile !!! Dieses Format hat leider redundante Knoten ...");
+
+    //string dummy;
+
+    //double x, y, z;
+    //int nr = 0;
+
+    //UbFileInputASCII in(filename);
+    //in.readLine();
+    //while (dummy != "endsolid") {
+    //    in.readLine();
+    //    in.readLine();
+    //    dummy = in.readString();
+    //    if (dummy != "vertex")
+    //        throw UbException(UB_EXARGS, "no vertex format");
+    //    x = in.readDouble();
+    //    y = in.readDouble();
+    //    z = in.readDouble();
+    //    nodes->push_back(GbTriFaceMesh3D::Vertex((float)x, (float)y, (float)z));
+    //    in.readLine();
+    //    in.readString();
+    //    x = in.readDouble();
+    //    y = in.readDouble();
+    //    z = in.readDouble();
+    //    nodes->push_back(GbTriFaceMesh3D::Vertex((float)x, (float)y, (float)z));
+    //    in.readLine();
+    //    in.readString();
+    //    x = in.readDouble();
+    //    y = in.readDouble();
+    //    z = in.readDouble();
+    //    nodes->push_back(GbTriFaceMesh3D::Vertex((float)x, (float)y, (float)z));
+    //    triangles->push_back(GbTriFaceMesh3D::TriFace(nr, nr + 1, nr + 2));
+    //    in.readLine();
+    //    in.readLine();
+    //    in.readLine();
+    //    dummy = in.readString();
+    //    nr += 3;
+    //    // std::cout<<"read mesh "<< nr <<" \n";
+    //}
+
+    //if (removeRedundantNodes) {
+    //    this->deleteRedundantNodes(); // dort wird autoamtisch calculateValues() aufgerufen
+    //} else {
+    //    this->calculateValues();
+    //}
+}
+/*======================================================================*/
+void GbTriFaceMesh3D::readMeshFromSTLFileBinary(string filename, bool removeRedundantNodes)
+{
+    int nr  = 0;
+    FILE *f = fopen(filename.c_str(), "rb");
+    if (!f) {
+        (*nodes).clear();
+        (*triangles).clear();
+        UB_THROW(UbException(UB_EXARGS, "Can not open STL file: " + filename));
+    }
+    char title[80];
+    int nFaces;
+    size_t sizef = fread(title, 80, 1, f);
+    sizef        = fread((void *)&nFaces, 4, 1, f);
+    float v[12]; // normal=3, vertices=3*3 = 12
+    unsigned short uint16;
+    // Every Face is 50 Bytes: Normal(3*float), Vertices(9*float), 2 Bytes Spacer
+    for (int i = 0; i < nFaces; ++i) {
+        for (size_t j = 0; j < 12; ++j) {
+            sizef = fread((void *)&v[j], sizeof(float), 1, f);
+        }
+        sizef = fread((void *)&uint16, sizeof(unsigned short), 1, f); // spacer between successive faces
+        nodes->push_back(GbTriFaceMesh3D::Vertex(v[3], v[4], v[5]));
+        nodes->push_back(GbTriFaceMesh3D::Vertex(v[6], v[7], v[8]));
+        nodes->push_back(GbTriFaceMesh3D::Vertex(v[9], v[10], v[11]));
+        triangles->push_back(GbTriFaceMesh3D::TriFace(nr, nr + 1, nr + 2));
+        nr += 3;
+    }
+    (void)sizef;
+    fclose(f);
+
+    if (removeRedundantNodes) {
+        this->deleteRedundantNodes(); // dort wird autoamtisch calculateValues() aufgerufen
+    } else {
+        this->calculateValues();
+    }
+}
diff --git a/src/basics/geometry3d/GbTriFaceMesh3D.h b/src/basics/geometry3d/GbTriFaceMesh3D.h
new file mode 100644
index 0000000000000000000000000000000000000000..33ddbe2fdd82fb1cfd8fe96fd8b98843a6e82879
--- /dev/null
+++ b/src/basics/geometry3d/GbTriFaceMesh3D.h
@@ -0,0 +1,436 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file GbTriFaceMesh3D.h
+//! \ingroup geometry3D
+//! \author Konstantin Kutscher, Soeren Textor, Sebastian Geller
+//=======================================================================================
+#ifndef GBTRIFACEMESH3D_H
+#define GBTRIFACEMESH3D_H
+
+#include <iostream>
+#include <map>
+#include <sstream>
+#include <vector>
+
+#include <basics/utilities/UbException.h>
+#include <basics/utilities/UbMath.h>
+#include <basics/utilities/Vector3D.h>
+
+#include <geometry3d/GbPoint3D.h>
+
+#include <PointerDefinitions.h>
+
+#include <basics_export.h>
+
+namespace Kd
+{
+template <typename T>
+class Tree;
+template <typename T>
+class SplitAlgorithm;
+template <typename T>
+class RayIntersectionHandler;
+} // namespace Kd
+
+class WbWriter;
+
+/*=========================================================================*/
+/* GbTriFaceMesh3D                                                                  */
+/*                                                                         */
+/**
+ * This Class provides the triangular meshes.
+ * Note, that up to now no methods for checking consistency are included.
+ * in this context this class describes facettes from an 3D-object !!!
+ */
+class BASICS_EXPORT GbTriFaceMesh3D : public GbObject3D
+{
+public:
+    // nested class start
+    class Vertex
+    {
+    public:
+        Vertex() = default;
+        Vertex(const float &x, const float &y, const float &z) : x(x), y(y), z(z) {}
+        Vertex(Vertex *vert)
+        {
+            this->x = vert->x;
+            this->y = vert->y;
+            this->z = vert->z;
+        }
+        float operator[](const int &i) const
+        {
+            if (i == 0)
+                return x;
+            else if (i == 1)
+                return y;
+            else if (i == 2)
+                return z;
+
+            throw UbException(UB_EXARGS, "i not in [0;2]");
+        }
+        float &operator[](const int &i)
+        {
+            if (i == 0)
+                return x;
+            else if (i == 1)
+                return y;
+            else if (i == 2)
+                return z;
+
+            throw UbException(UB_EXARGS, "not in [0;2]");
+        }
+        bool operator==(const Vertex &rhs)
+        {
+            return (fabs(x - rhs.x) < 1.E-8 && fabs(y - rhs.y) < 1.E-8 && fabs(z - rhs.z) < 1.E-8);
+        }
+        friend inline bool operator<(const Vertex &lhsVert, const Vertex &rhsVert)
+        {
+            if (lhsVert.x < rhsVert.x)
+                return true;
+            if (lhsVert.x > rhsVert.x)
+                return false;
+            if (lhsVert.y < rhsVert.y)
+                return true;
+            if (lhsVert.y > rhsVert.y)
+                return false;
+            if (lhsVert.z < rhsVert.z)
+                return true;
+
+            return false;
+        }
+        friend std::ostream &operator<<(std::ostream &os, const Vertex &node)
+        {
+            return os << node.x << "," << node.y << "," << node.z;
+        }
+        Vertex *clone() { return (new Vertex(this)); }
+
+    public:
+        float x{ 0.0 }, y{ 0.0 }, z{ 0.0 };
+    };
+    //////////////////////////////////////////////////////////////////////////
+    class TriFace
+    {
+    public:
+        TriFace()
+
+            = default;
+        TriFace(const int &v1, const int &v2, const int &v3) : v1(v1), v2(v2), v3(v3) {}
+
+        const int &getIndexVertex1() const { return v1; }
+        const int &getIndexVertex2() const { return v2; }
+        const int &getIndexVertex3() const { return v3; }
+
+        Vertex &getNode(const int &i, std::vector<Vertex> &nodes)
+        {
+            if (i == 0)
+                return nodes[v1];
+            if (i == 1)
+                return nodes[v2];
+            if (i == 2)
+                return nodes[v3];
+            throw UbException(UB_EXARGS, "invalid i - not in range [0;2]");
+        }
+        void setNode(const int &i, const int &index)
+        {
+            if (i == 0)
+                v1 = index;
+            else if (i == 1)
+                v2 = index;
+            else if (i == 2)
+                v3 = index;
+            else
+                throw UbException(UB_EXARGS, "invalid i - not in range [0;2]");
+        }
+
+        int operator[](int index)
+        {
+            if (index == 0)
+                return v1;
+            if (index == 1)
+                return v2;
+            if (index == 2)
+                return v3;
+            throw UbException(UB_EXARGS, "invalid i - not in range [0;2]");
+        }
+
+        float &getV1x(std::vector<Vertex> &nodes) { return nodes[v1].x; }
+        float &getV1y(std::vector<Vertex> &nodes) { return nodes[v1].y; }
+        float &getV1z(std::vector<Vertex> &nodes) { return nodes[v1].z; }
+
+        float &getV2x(std::vector<Vertex> &nodes) { return nodes[v2].x; }
+        float &getV2y(std::vector<Vertex> &nodes) { return nodes[v2].y; }
+        float &getV2z(std::vector<Vertex> &nodes) { return nodes[v2].z; }
+
+        float &getV3x(std::vector<Vertex> &nodes) { return nodes[v3].x; }
+        float &getV3y(std::vector<Vertex> &nodes) { return nodes[v3].y; }
+        float &getV3z(std::vector<Vertex> &nodes) { return nodes[v3].z; }
+
+        float getMinX(std::vector<Vertex> &nodes) { return (float)UbMath::min(nodes[v1].x, nodes[v2].x, nodes[v3].x); }
+        float getMinY(std::vector<Vertex> &nodes) { return (float)UbMath::min(nodes[v1].y, nodes[v2].y, nodes[v3].y); }
+        float getMinZ(std::vector<Vertex> &nodes) { return (float)UbMath::min(nodes[v1].z, nodes[v2].z, nodes[v3].z); }
+
+        float getMaxX(std::vector<Vertex> &nodes) { return (float)UbMath::max(nodes[v1].x, nodes[v2].x, nodes[v3].x); }
+        float getMaxY(std::vector<Vertex> &nodes) { return (float)UbMath::max(nodes[v1].y, nodes[v2].y, nodes[v3].y); }
+        float getMaxZ(std::vector<Vertex> &nodes) { return (float)UbMath::max(nodes[v1].z, nodes[v2].z, nodes[v3].z); }
+
+        float getX1Centroid(std::vector<Vertex> &nodes)
+        {
+            return (float)UbMath::c1o3 * (getV1x(nodes) + getV2x(nodes) + getV3x(nodes));
+        }
+        float getX2Centroid(std::vector<Vertex> &nodes)
+        {
+            return (float)UbMath::c1o3 * (getV1y(nodes) + getV2y(nodes) + getV3y(nodes));
+        }
+        float getX3Centroid(std::vector<Vertex> &nodes)
+        {
+            return (float)UbMath::c1o3 * (getV1z(nodes) + getV2z(nodes) + getV3z(nodes));
+        }
+
+        double calculateDistanceToPoint3D(const double &x1, const double &x2, const double &x3,
+                                          std::vector<Vertex> &nodes);
+
+        double getArea(std::vector<Vertex> &nodes)
+        {
+            // GbVector3D A(nodes[v1].x, nodes[v1].y, nodes[v1].z);
+            // GbVector3D B(nodes[v2].x, nodes[v2].y, nodes[v2].z);
+            // GbVector3D C(nodes[v3].x, nodes[v3].y, nodes[v3].z);
+            // GbVector3D AB = B-A;
+            // GbVector3D AC = C-A;
+            // GbVector3D N = AB.Cross(AC);
+            // return 0.5*N.Length();
+            Vector3D A(nodes[v1].x, nodes[v1].y, nodes[v1].z);
+            Vector3D B(nodes[v2].x, nodes[v2].y, nodes[v2].z);
+            Vector3D C(nodes[v3].x, nodes[v3].y, nodes[v3].z);
+            Vector3D AB = B - A;
+            Vector3D AC = C - A;
+            Vector3D N  = AB.Cross(AC);
+            return 0.5 * N.Length();
+        }
+        void calculateNormal(std::vector<Vertex> &nodes)
+        {
+            const float &v1x = nodes[v1].x;
+            const float &v1y = nodes[v1].y;
+            const float &v1z = nodes[v1].z;
+            const float &v2x = nodes[v2].x;
+            const float &v2y = nodes[v2].y;
+            const float &v2z = nodes[v2].z;
+            const float &v3x = nodes[v3].x;
+            const float &v3y = nodes[v3].y;
+            const float &v3z = nodes[v3].z;
+
+            nx = (v3z - v1z) * (v2y - v1y) - (v2z - v1z) * (v3y - v1y);
+            ny = (v2z - v1z) * (v3x - v1x) - (v2x - v1x) * (v3z - v1z);
+            nz = (v2x - v1x) * (v3y - v1y) - (v2y - v1y) * (v3x - v1x);
+
+            float length = std::sqrt(nx * nx + ny * ny + nz * nz);
+            if (length > 1.E-10) {
+                length = 1.0f / length;
+                nx *= length;
+                ny *= length;
+                nz *= length;
+            } else {
+                std::cerr << "GbTriFaceMesh3D::TriFace - calculateNormal: nx=ny=nz=0 -> kann nich sein "
+                          << "(dreieck hat evtl knoten doppelt oder ist ne Linie)"
+                          << "->removeRedunantNodes" << std::endl;
+            }
+        }
+
+    public:
+        int v1{ -1 }, v2{ -1 }, v3{ -1 };
+        float nx{ 0.0 }, ny{ 0.0 }, nz{ 0.0 };
+    };
+
+public:
+    enum KDTREE_SPLITAGORITHM { KDTREE_SAHPLIT, KDTREE_SPATIALSPLIT };
+
+public:
+    GbTriFaceMesh3D();
+    GbTriFaceMesh3D(std::string name, std::vector<Vertex> *nodes, std::vector<TriFace> *triangles,
+                    KDTREE_SPLITAGORITHM splitAlg = KDTREE_SAHPLIT, bool removeRedundantNodes = true);
+    ~GbTriFaceMesh3D() override;
+
+    GbTriFaceMesh3D *clone() override; // { throw UbException(UB_EXARGS,"not implemented"); }
+    void finalize() override {}
+
+    // void setRegardPointInPolyhedronTest(bool value) { this->regardPiO=value; }
+
+    std::string toString() override;
+
+    // std::string getName();
+    std::vector<Vertex> *getNodes();
+    std::vector<TriFace> *getTriangles();
+
+    void setTransferViaFilename(bool transferViaFilename, std::string filename, double transX1, double transX2,
+                                double transX3)
+    {
+        this->filename            = filename;
+        this->transferViaFilename = transferViaFilename;
+        this->transX1             = transX1;
+        this->transX2             = transX2;
+        this->transX3             = transX3;
+    }
+    void readMeshFromSTLFileASCII(std::string filename, bool removeRedundantNodes);
+    void readMeshFromSTLFileBinary(std::string filename, bool removeRedundantNodes);
+
+    double getX1Minimum() override
+    {
+        if (!this->consistent)
+            this->calculateValues();
+        return this->x1min;
+    }
+    double getX1Maximum() override
+    {
+        if (!this->consistent)
+            this->calculateValues();
+        return this->x1max;
+    }
+    double getX1Centroid() override
+    {
+        if (!this->consistent)
+            this->calculateValues();
+        return this->x1center;
+    }
+
+    double getX2Minimum() override
+    {
+        if (!this->consistent)
+            this->calculateValues();
+        return this->x2min;
+    }
+    double getX2Maximum() override
+    {
+        if (!this->consistent)
+            this->calculateValues();
+        return this->x2max;
+    }
+    double getX2Centroid() override
+    {
+        if (!this->consistent)
+            this->calculateValues();
+        return this->x2center;
+    }
+
+    double getX3Minimum() override
+    {
+        if (!this->consistent)
+            this->calculateValues();
+        return this->x3min;
+    }
+    double getX3Centroid() override
+    {
+        if (!this->consistent)
+            this->calculateValues();
+        return this->x3center;
+    }
+    double getX3Maximum() override
+    {
+        if (!this->consistent)
+            this->calculateValues();
+        return this->x3max;
+    }
+
+    void calculateValues();
+
+    double getVolume();
+    void deleteRedundantNodes();
+
+    UbTupleDouble6 calculateMomentOfInertia(double rhoP);
+    UbTupleDouble3 calculateCenterOfGravity();
+
+    void setCenterCoordinates(const double &x1, const double &x2, const double &x3) override;
+
+    void setCenterCoordinates(const UbTupleDouble3 & /*position*/) override;
+
+    void scale(const double &sx1, const double &sx2, const double &sx3) override;
+    void rotate(const double &alpha, const double &beta, const double &gamma) override;
+    void rotateAroundPoint(const double &px1, const double &px2, const double &px3, const double &alpha,
+                           const double &beta, const double &gamma);
+    void translate(const double &x1, const double &x2, const double &x3) override;
+    //void reflectAcrossXYLine(const double &alpha);
+
+    bool isPointInGbObject3D(const double &x1, const double &x2, const double &x3) override;
+    bool isPointInGbObject3D(const double &x1, const double &x2, const double &x3, int counter);
+    bool isPointInGbObject3D(const double &x1, const double &x2, const double &x3, bool &pointIsOnBoundary) override;
+
+    GbLine3D *createClippedLine3D(GbPoint3D &point1, GbPoint3D &point2) override;
+
+    std::vector<GbTriangle3D *> getSurfaceTriangleSet() override;
+    void addSurfaceTriangleSet(std::vector<UbTupleFloat3> &nodes, std::vector<UbTupleInt3> &triangles) override;
+
+    std::vector<GbTriFaceMesh3D::TriFace *> getTrianglesForVertex(Vertex *vertex);
+
+    void setKdTreeSplitAlgorithm(KDTREE_SPLITAGORITHM mode);
+    KDTREE_SPLITAGORITHM getKdTreeSplitAlgorithm() { return this->kdtreeSplitAlg; }
+    Kd::Tree<double> *getKdTree() { return this->kdTree; }
+
+    virtual UbTuple<std::string, std::string> writeMesh(std::string filename, WbWriter *writer,
+                                                        bool writeNormals                          = false,
+                                                        std::vector<std::string> *datanames        = NULL,
+                                                        std::vector<std::vector<double>> *nodedata = NULL);
+    void writeMeshPly(const std::string &filename);
+
+    /*======================================================================*/
+    using GbObject3D::isPointInGbObject3D; // Grund: dadurch muss man hier  isPointInGbObject3D(GbPoint3D*) nicht
+                                           // ausprogrammieren, welche sonst hier "ueberdeckt" waere
+
+    bool intersectLine(const double &p1_x1, const double &p1_x2, const double &p1_x3, const double &p2_x1,
+                       const double &p2_x2, const double &p2_x3);
+
+protected:
+    KDTREE_SPLITAGORITHM kdtreeSplitAlg;
+    void init();
+
+    std::vector<Vertex> * nodes;
+    std::vector<TriFace> * triangles;
+    // for transfer
+    std::string filename;
+    bool transferViaFilename{ false };
+    double transX1{ 0.0 };
+    double transX2{ 0.0 };
+    double transX3{ 0.0 };
+
+    double x1min;
+    double x1max;
+    double x2min;
+    double x2max;
+    double x3min;
+    double x3max;
+    double x1center;
+    double x2center;
+    double x3center;
+
+    bool consistent{ false };
+
+    bool buildVertTriRelationMap{ false };
+    std::multimap<Vertex *, TriFace *> relationVertTris;
+
+    Kd::Tree<double> *kdTree = nullptr;
+};
+
+#endif // GBTRIFACEMESH3D_H
diff --git a/src/basics/geometry3d/GbTriangularMesh3D.cpp b/src/basics/geometry3d/GbTriangularMesh3D.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3fc0495fad3a1426a9749b43bca7348be4aa6186
--- /dev/null
+++ b/src/basics/geometry3d/GbTriangularMesh3D.cpp
@@ -0,0 +1,1531 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file GbTriangularMesh3D.cpp
+//! \ingroup geometry3D
+//! \author Konstantin Kutscher, Soeren Textor, Sebastian Geller
+//=======================================================================================
+#include <geometry3d/GbTriangularMesh3D.h>
+
+#include <map>
+
+#include <basics/utilities/UbMath.h>
+
+#include <geometry3d/CoordinateTransformation3D.h>
+#include <geometry3d/GbCuboid3D.h>
+#include <geometry3d/GbHalfSpace3D.h>
+
+using namespace std;
+
+GbTriangularMesh3D::GbTriangularMesh3D() : GbObject3D()
+{
+    this->setName("new GbMesh");
+    this->nodes     = new vector<GbPoint3D *>;
+    this->triangles = new vector<GbTriangle3D *>;
+    this->edges     = new vector<GbLine3D *>;
+
+    this->pointinobjecttest = RAYCROSSING;
+
+    this->consistent = false;
+    x1min = x1max = x2min = x2max = x3min = x3max = 0.0;
+}
+/*=============================================================================================*/
+GbTriangularMesh3D::GbTriangularMesh3D(string name, vector<GbPoint3D *> *nodes, vector<GbTriangle3D *> *triangles)
+    : GbObject3D()
+{
+    if (name.size() == 0)
+        throw UbException(UB_EXARGS, "no name specified");
+    if (!nodes)
+        throw UbException(UB_EXARGS, "no nodes specified");
+    if (!triangles)
+        throw UbException(UB_EXARGS, "no triangles specified");
+
+    this->setName(name);
+    this->nodes             = nodes;
+    this->triangles         = triangles;
+    this->edges             = new vector<GbLine3D *>;
+    this->pointinobjecttest = RAYCROSSING;
+
+    this->consistent = false;
+    x1min = x1max = x2min = x2max = x3min = x3max = 0.0;
+}
+/*=============================================================================================*/
+GbTriangularMesh3D::GbTriangularMesh3D(string name, vector<GbTriangle3D *> *tris) : GbObject3D()
+{
+    cout << "Das Teil erzeugt seinen KnotenVector aus den Dreiecken ...\n Es sollte deleteRedundantNodes() aufgerufen "
+            "werden \n";
+    if (name.size() == 0)
+        throw UbException(UB_EXARGS, "no name specified");
+    if (!tris)
+        throw UbException(UB_EXARGS, "no triangles specified");
+
+    vector<GbPoint3D *> *points = new vector<GbPoint3D *>;
+    this->triangles             = new vector<GbTriangle3D *>;
+    GbPoint3D *p1               = NULL;
+    GbPoint3D *p2               = NULL;
+    GbPoint3D *p3               = NULL;
+    for (int u = 0; u < (int)tris->size(); u++) {
+        if (UbMath::zero((*tris)[u]->getArea())) {
+            (*tris)[u]->finalize();
+            delete (*tris)[u];
+            (*tris)[u] = NULL;
+            continue;
+        }
+        this->triangles->push_back((*tris)[u]);
+        p1 = (*tris)[u]->getPoint1();
+        p2 = (*tris)[u]->getPoint2();
+        p3 = (*tris)[u]->getPoint3();
+        points->push_back(p1);
+        points->push_back(p2);
+        points->push_back(p3);
+    }
+
+    this->setName(name);
+    this->nodes = points;
+    // this->triangles        = triangles;
+    this->edges = new vector<GbLine3D *>;
+    this->edges->resize(0, NULL);
+    this->pointinobjecttest = RAYCROSSING;
+
+    this->consistent = false;
+    x1min = x1max = x2min = x2max = x3min = x3max = 0.0;
+}
+/*=============================================================================================*/
+GbTriangularMesh3D::GbTriangularMesh3D(string name, vector<GbPoint3D *> *nodes, vector<GbLine3D *> *edges,
+                                       vector<GbTriangle3D *> *triangles)
+    : GbObject3D()
+{
+    if (name.size() == 0)
+        throw UbException(UB_EXARGS, "no name specified");
+    if (!nodes)
+        throw UbException(UB_EXARGS, "no nodes specified");
+    if (!triangles)
+        throw UbException(UB_EXARGS, "no triangles specified");
+    if (!edges)
+        throw UbException(UB_EXARGS, "no edges specified");
+
+    this->setName(name);
+    this->nodes             = nodes;
+    this->edges             = edges;
+    this->triangles         = triangles;
+    this->pointinobjecttest = RAYCROSSING;
+
+    this->consistent = false;
+    x1min = x1max = x2min = x2max = x3min = x3max = 0.0;
+}
+/*=============================================================================================*/
+GbTriangularMesh3D::~GbTriangularMesh3D()
+{
+    if (this->nodes) {
+        for (unsigned u = 0; u < nodes->size(); u++)
+            delete (*nodes)[u];
+        delete nodes;
+    }
+    if (triangles) {
+        for (unsigned u = 0; u < triangles->size(); u++)
+            delete (*triangles)[u];
+        delete triangles;
+    }
+}
+/*======================================================================*/
+void GbTriangularMesh3D::deleteRedundantNodes()
+{
+    std::map<GbPoint3D *, GbTriangle3D *> pointTriMap;
+    GbPoint3D *p1     = NULL;
+    GbPoint3D *p2     = NULL;
+    GbPoint3D *p3     = NULL;
+    GbTriangle3D *tri = NULL;
+
+    for (int u = 0; u < (int)this->triangles->size(); u++) {
+        tri = (*this->triangles)[u];
+        p1  = tri->getPoint1();
+        p2  = tri->getPoint2();
+        p3  = tri->getPoint3();
+        pointTriMap.insert(pair<GbPoint3D *, GbTriangle3D *>(p1, tri));
+        pointTriMap.insert(pair<GbPoint3D *, GbTriangle3D *>(p2, tri));
+        pointTriMap.insert(pair<GbPoint3D *, GbTriangle3D *>(p3, tri));
+    }
+
+    cout << "Nodes before deleting redundant:" << this->nodes->size() << endl;
+    GbPoint3D *pA = NULL;
+    GbPoint3D *pB = NULL;
+    std::map<GbPoint3D *, GbTriangle3D *>::iterator mapIterator;
+    for (int u = 0; u < (int)this->nodes->size(); u++) {
+        // cout<<u<<" von "<<this->nodes->size()<<endl;
+        pA = (*this->nodes)[u];
+        if (pA == NULL)
+            continue;
+        for (int w = u + 1; w < (int)this->nodes->size(); w++) {
+            //   cout<<w<<" Wvon "<<this->nodes->size()<<endl;
+            pB = (*this->nodes)[w];
+            if (pB == NULL)
+                continue;
+            if (pA->equals(pB)) {
+                // doppelter Knoten ...
+                mapIterator = pointTriMap.find(pB);
+                tri         = dynamic_cast<GbTriangle3D *>(mapIterator->second);
+                if (!tri)
+                    throw UbException(UB_EXARGS, "triangle not found");
+                p1 = tri->getPoint1();
+                p2 = tri->getPoint2();
+                p3 = tri->getPoint3();
+                if (pB == p1)
+                    tri->setPoint(pA, 0);
+                else if (pB == p2)
+                    tri->setPoint(pA, 1);
+                else if (pB == p3)
+                    tri->setPoint(pA, 2);
+                else
+                    throw UbException(UB_EXARGS, "node should be there");
+                delete pB;
+                (*this->nodes)[w] = NULL;
+            }
+        }
+    }
+    vector<GbPoint3D *> *points = new vector<GbPoint3D *>;
+    for (int u = 0; u < (int)this->nodes->size(); u++) {
+        pA = (*this->nodes)[u];
+        if (pA != NULL)
+            points->push_back(pA);
+    }
+    delete this->nodes;
+    this->nodes = points;
+    cout << "Nodes after deleting redundant:" << this->nodes->size() << endl;
+
+    // nochmal kontrolle ...
+    pointTriMap.clear();
+    for (int u = 0; u < (int)this->triangles->size(); u++) {
+        tri = (*this->triangles)[u];
+        p1  = tri->getPoint1();
+        p2  = tri->getPoint2();
+        p3  = tri->getPoint3();
+        pointTriMap.insert(pair<GbPoint3D *, GbTriangle3D *>(p1, tri));
+        pointTriMap.insert(pair<GbPoint3D *, GbTriangle3D *>(p2, tri));
+        pointTriMap.insert(pair<GbPoint3D *, GbTriangle3D *>(p3, tri));
+    }
+    for (int u = 0; u < (int)this->nodes->size(); u++) {
+        pA = (*this->nodes)[u];
+        if (pA == NULL)
+            throw UbException(UB_EXARGS, "sollte kein NULL pointer sein ...");
+        mapIterator = pointTriMap.find(pA);
+        tri         = dynamic_cast<GbTriangle3D *>(mapIterator->second);
+        if (!tri)
+            throw UbException(UB_EXARGS, "triangle not found");
+    }
+}
+/*======================================================================*/
+void GbTriangularMesh3D::translate(const double &x1, const double &x2, const double &x3)
+{
+    GbPoint3D *pt;
+    for (int u = 0; u < (int)this->nodes->size(); u++) {
+        pt = (*nodes)[u];
+        pt->setX1(pt->getX1Coordinate() + x1);
+        pt->setX2(pt->getX2Coordinate() + x2);
+        pt->setX3(pt->getX3Coordinate() + x3);
+    }
+    this->consistent = false;
+}
+/*======================================================================*/
+void GbTriangularMesh3D::rotate(const double &alpha, const double &beta, const double &gamma)
+{
+    if (!this->consistent)
+        this->calculateValues();
+    double a1 = this->getX1Centroid();
+    double a2 = this->getX2Centroid();
+    double a3 = this->getX3Centroid();
+    CoordinateTransformation3D trafoFor(a1, a2, a3, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0);
+    CoordinateTransformation3D trafoBack(a1, a2, a3, 1.0, 1.0, 1.0, alpha, beta, gamma);
+
+    vector<GbPoint3D *> points;
+    GbPoint3D *p1 = NULL;
+    GbPoint3D *p2 = NULL;
+    GbPoint3D *p3 = NULL;
+    for (int u = 0; u < (int)this->triangles->size(); u++) {
+        p1          = (*triangles)[u]->getPoint1();
+        p2          = (*triangles)[u]->getPoint2();
+        p3          = (*triangles)[u]->getPoint3();
+        double p1x1 = trafoFor.transformForwardToX1Coordinate(p1->x1, p1->x2, p1->x3);
+        double p1x2 = trafoFor.transformForwardToX2Coordinate(p1->x1, p1->x2, p1->x3);
+        double p1x3 = trafoFor.transformForwardToX3Coordinate(p1->x1, p1->x2, p1->x3);
+        double p2x1 = trafoFor.transformForwardToX1Coordinate(p2->x1, p2->x2, p2->x3);
+        double p2x2 = trafoFor.transformForwardToX2Coordinate(p2->x1, p2->x2, p2->x3);
+        double p2x3 = trafoFor.transformForwardToX3Coordinate(p2->x1, p2->x2, p2->x3);
+        double p3x1 = trafoFor.transformForwardToX1Coordinate(p3->x1, p3->x2, p3->x3);
+        double p3x2 = trafoFor.transformForwardToX2Coordinate(p3->x1, p3->x2, p3->x3);
+        double p3x3 = trafoFor.transformForwardToX3Coordinate(p3->x1, p3->x2, p3->x3);
+        p1->x1      = trafoBack.transformBackwardToX1Coordinate(p1x1, p1x2, p1x3);
+        p1->x2      = trafoBack.transformBackwardToX2Coordinate(p1x1, p1x2, p1x3);
+        p1->x3      = trafoBack.transformBackwardToX3Coordinate(p1x1, p1x2, p1x3);
+        p2->x1      = trafoBack.transformBackwardToX1Coordinate(p2x1, p2x2, p2x3);
+        p2->x2      = trafoBack.transformBackwardToX2Coordinate(p2x1, p2x2, p2x3);
+        p2->x3      = trafoBack.transformBackwardToX3Coordinate(p2x1, p2x2, p2x3);
+        p3->x1      = trafoBack.transformBackwardToX1Coordinate(p3x1, p3x2, p3x3);
+        p3->x2      = trafoBack.transformBackwardToX2Coordinate(p3x1, p3x2, p3x3);
+        p3->x3      = trafoBack.transformBackwardToX3Coordinate(p3x1, p3x2, p3x3);
+    }
+    this->calculateValues();
+}
+/*======================================================================*/
+/**
+ * Returns a string representation of this triangular mesh.
+ * @return a string representation of this triangular mesh
+ */
+string GbTriangularMesh3D::toString()
+{
+    stringstream ss;
+    ss << "GbTriangularMesh3D[";
+    ss << (int)this->triangles->size() << "-Triangles, " << (int)this->nodes->size() << "-Nodes, "
+       << (int)this->edges->size() << "-Edges" << endl;
+    // ss<<"\""<<this->name<<", Area=sollt mal berechnet werden ;-)"<<"\"";
+    // ss<<", x1min="<<this->x1min;
+    // ss<<", x1max="<<this->x1max;
+    // ss<<", x2min="<<this->x2min;
+    // ss<<", x2max="<<this->x2max;
+    // ss<<", x3min="<<this->x3min;
+    // ss<<", x3max="<<this->x3max;
+    ss << "]";
+    return (ss.str());
+}
+/**
+ * Returns the name of this triangular mesh.
+ * @return the name of this triangular mesh
+ */
+// string GbTriangularMesh3D::getName(){ return(this->name); }
+
+/**
+ * Returns the nodes of this triangular mesh.
+ * @return the nodes of this triangular mesh
+ */
+vector<GbPoint3D *> *GbTriangularMesh3D::getNodes() { return (this->nodes); }
+/**
+ * Returns the triangles of this triangular mesh.
+ * @return the triangles of this triangular mesh
+ */
+vector<GbTriangle3D *> *GbTriangularMesh3D::getTriangles() { return (this->triangles); }
+/**
+ * Returns the center x1 coordinate of this triangular mesh.
+ * @return the center x1 coordinate of this triangular mesh
+ */
+double GbTriangularMesh3D::getX1Centroid()
+{
+    if (!this->consistent)
+        this->calculateValues();
+    return (0.5 * (this->x1min + this->x1max));
+}
+/**
+ * Returns the center x2 coordinate of this triangular mesh.
+ * @return the center x2 coordinate of this triangular mesh
+ */
+double GbTriangularMesh3D::getX2Centroid()
+{
+    if (!this->consistent)
+        this->calculateValues();
+    return (0.5 * (this->x2min + this->x2max));
+}
+/**
+ * Returns the center x3 coordinate of this triangular mesh.
+ * @return the center x3 coordinate of this triangular mesh
+ */
+double GbTriangularMesh3D::getX3Centroid()
+{
+    if (!this->consistent)
+        this->calculateValues();
+    return (0.5 * (this->x3min + this->x3max));
+}
+
+/**
+ * Returns the minimum x1 coordinate of this triangular mesh.
+ * @return the minimum x1 coordinate of this triangular mesh
+ */
+double GbTriangularMesh3D::getX1Minimum()
+{
+    if (!this->consistent)
+        this->calculateValues();
+    return (this->x1min);
+}
+/**
+ * Returns the maximum x1 coordinate of this triangular mesh.
+ * @return the maximum x1 coordinate of this triangular mesh
+ */
+double GbTriangularMesh3D::getX1Maximum()
+{
+    if (!this->consistent)
+        this->calculateValues();
+    return (this->x1max);
+}
+/**
+ * Returns the minimum x2 coordinate of this triangular mesh.
+ * @return the minimum x2 coordinate of this triangular mesh
+ */
+double GbTriangularMesh3D::getX2Minimum()
+{
+    if (!this->consistent)
+        this->calculateValues();
+    return (this->x2min);
+}
+/**
+ * Returns the maximum x2 coordinate of this triangular mesh.
+ * @return the maximum x2 coordinate of this triangular mesh
+ */
+double GbTriangularMesh3D::getX2Maximum()
+{
+    if (!this->consistent)
+        this->calculateValues();
+    return (this->x2max);
+}
+/**
+ * Returns the minimum x3 coordinate of this triangular mesh.
+ * @return the minimum x3 coordinate of this triangular mesh
+ */
+double GbTriangularMesh3D::getX3Minimum()
+{
+    if (!this->consistent)
+        this->calculateValues();
+    return (this->x3min);
+}
+/**
+ * Returns the maximum x3 coordinate of this triangular mesh.
+ * @return the maximum x3 coordinate of this triangular mesh
+ */
+double GbTriangularMesh3D::getX3Maximum()
+{
+    if (!this->consistent)
+        this->calculateValues();
+    return (this->x3max);
+}
+
+void GbTriangularMesh3D::calculateValues()
+{
+    double x1, x2, x3;
+
+    this->x1min = (*this->nodes)[0]->getX1Coordinate();
+    this->x1max = (*this->nodes)[0]->getX1Coordinate();
+    this->x2min = (*this->nodes)[0]->getX2Coordinate();
+    this->x2max = (*this->nodes)[0]->getX2Coordinate();
+    this->x3min = (*this->nodes)[0]->getX3Coordinate();
+    this->x3max = (*this->nodes)[0]->getX3Coordinate();
+
+    for (int i = 1; i < (int)this->nodes->size(); i++) {
+        x1 = (*this->nodes)[i]->getX1Coordinate();
+        x2 = (*this->nodes)[i]->getX2Coordinate();
+        x3 = (*this->nodes)[i]->getX3Coordinate();
+        if (x1 < this->x1min)
+            this->x1min = x1;
+        if (x1 > this->x1max)
+            this->x1max = x1;
+        if (x2 < this->x2min)
+            this->x2min = x2;
+        if (x2 > this->x2max)
+            this->x2max = x2;
+        if (x3 < this->x3min)
+            this->x3min = x3;
+        if (x3 > this->x3max)
+            this->x3max = x3;
+    }
+    this->consistent = true;
+}
+
+/**
+ * Returns the total area of this triangular mesh.
+ * @return the total area of this triangular mesh
+ */
+double GbTriangularMesh3D::getArea()
+{
+    double area = 0.0;
+    for (int i = 0; i < (int)this->triangles->size(); i++)
+        area += (*this->triangles)[i]->getArea();
+    return (area);
+}
+/**
+ * Returns the total volume of this triangular mesh.
+ * @return the total volume of this triangular mesh
+ */
+double GbTriangularMesh3D::getVolume()
+{
+    GbTriangle3D *triangle;
+    GbPoint3D *p1;
+    GbPoint3D *p2;
+    GbPoint3D *p3;
+
+    double x1, x2, x3, y1, y2, y3, z1, z2, z3;
+    double G3i;
+    double volume = 0.0;
+    int size      = (int)this->triangles->size();
+    for (int u = 0; u < size; u++) {
+        triangle = (*this->triangles)[u];
+        p1       = triangle->getPoint1();
+        p2       = triangle->getPoint2();
+        p3       = triangle->getPoint3();
+        x1       = p1->getX1Coordinate();
+        y1       = p1->getX2Coordinate();
+        z1       = p1->getX3Coordinate();
+        x2       = p2->getX1Coordinate();
+        y2       = p2->getX2Coordinate();
+        z2       = p2->getX3Coordinate();
+        x3       = p3->getX1Coordinate();
+        y3       = p3->getX2Coordinate();
+        z3       = p3->getX3Coordinate();
+        G3i      = x1 * (y2 * z3 - z2 * y3) + y1 * (z2 * x3 - x2 * z3) + z1 * (x2 * y3 - y2 * x3);
+        volume   = volume + G3i / 6.0;
+    }
+    return volume;
+}
+/*===============================================*/
+UbTupleDouble3 GbTriangularMesh3D::calculateCenterOfGravity()
+{
+    GbTriangle3D *triangle;
+    GbPoint3D *p1;
+    GbPoint3D *p2;
+    GbPoint3D *p3;
+
+    double x1, x2, x3, y1, y2, y3, z1, z2, z3;
+    double G3i;
+    double rSP1   = 0.0;
+    double rSP2   = 0.0;
+    double rSP3   = 0.0;
+    double volume = 0.0;
+    int size      = (int)this->triangles->size();
+    for (int u = 0; u < size; u++) {
+        triangle = (*this->triangles)[u];
+        p1       = triangle->getPoint1();
+        p2       = triangle->getPoint2();
+        p3       = triangle->getPoint3();
+        x1       = p1->getX1Coordinate();
+        y1       = p1->getX2Coordinate();
+        z1       = p1->getX3Coordinate();
+        x2       = p2->getX1Coordinate();
+        y2       = p2->getX2Coordinate();
+        z2       = p2->getX3Coordinate();
+        x3       = p3->getX1Coordinate();
+        y3       = p3->getX2Coordinate();
+        z3       = p3->getX3Coordinate();
+        G3i      = x1 * (y2 * z3 - z2 * y3) + y1 * (z2 * x3 - x2 * z3) + z1 * (x2 * y3 - y2 * x3);
+        volume   = volume + G3i / 6.0;
+        rSP1     = rSP1 + G3i * (x1 + x2 + x3);
+        rSP2     = rSP2 + G3i * (y1 + y2 + y3);
+        rSP3     = rSP3 + G3i * (z1 + z2 + z3);
+    }
+    rSP1 = rSP1 / (24.0 * volume);
+    rSP2 = rSP2 / (24.0 * volume);
+    rSP3 = rSP3 / (24.0 * volume);
+
+    return { rSP1, rSP2, rSP3 };
+}
+/*===============================================*/
+UbTupleDouble6 GbTriangularMesh3D::calculateMomentOfInertia(double rhoP)
+{
+    GbTriangle3D *triangle;
+    GbPoint3D *p1;
+    GbPoint3D *p2;
+    GbPoint3D *p3;
+
+    double x1, x2, x3, y1, y2, y3, z1, z2, z3;
+    double G3i;
+    double xx, yy, zz, xy, yz, zx;
+    double rSP1   = 0.0;
+    double rSP2   = 0.0;
+    double rSP3   = 0.0;
+    double volume = 0.0;
+    double top11  = 0.0;
+    double top22  = 0.0;
+    double top33  = 0.0;
+    double top12  = 0.0;
+    double top23  = 0.0;
+    double top13  = 0.0;
+    int size      = (int)this->triangles->size();
+    for (int u = 0; u < size; u++) {
+        triangle = (*this->triangles)[u];
+        p1       = triangle->getPoint1();
+        p2       = triangle->getPoint2();
+        p3       = triangle->getPoint3();
+        x1       = p1->getX1Coordinate();
+        y1       = p1->getX2Coordinate();
+        z1       = p1->getX3Coordinate();
+        x2       = p2->getX1Coordinate();
+        y2       = p2->getX2Coordinate();
+        z2       = p2->getX3Coordinate();
+        x3       = p3->getX1Coordinate();
+        y3       = p3->getX2Coordinate();
+        z3       = p3->getX3Coordinate();
+        G3i      = x1 * (y2 * z3 - z2 * y3) + y1 * (z2 * x3 - x2 * z3) + z1 * (x2 * y3 - y2 * x3);
+        volume   = volume + G3i / 6.0;
+        rSP1     = rSP1 + G3i * (x1 + x2 + x3);
+        rSP2     = rSP2 + G3i * (y1 + y2 + y3);
+        rSP3     = rSP3 + G3i * (z1 + z2 + z3);
+    }
+    rSP1 = rSP1 / (24.0 * volume);
+    rSP2 = rSP2 / (24.0 * volume);
+    rSP3 = rSP3 / (24.0 * volume);
+
+    double x1s = 0.0; // rSP1;//0.0;//
+    double x2s = 0.0; // rSP2;//0.0;//
+    double x3s = 0.0; // rSP3;//0.0;//
+
+    for (int u = 0; u < size; u++) {
+        triangle = (*this->triangles)[u];
+        p1       = triangle->getPoint1();
+        p2       = triangle->getPoint2();
+        p3       = triangle->getPoint3();
+        x1       = p1->getX1Coordinate() - x1s;
+        y1       = p1->getX2Coordinate() - x2s;
+        z1       = p1->getX3Coordinate() - x3s;
+        x2       = p2->getX1Coordinate() - x1s;
+        y2       = p2->getX2Coordinate() - x2s;
+        z2       = p2->getX3Coordinate() - x3s;
+        x3       = p3->getX1Coordinate() - x1s;
+        y3       = p3->getX2Coordinate() - x2s;
+        z3       = p3->getX3Coordinate() - x3s;
+        G3i      = x1 * (y2 * z3 - z2 * y3) + y1 * (z2 * x3 - x2 * z3) + z1 * (x2 * y3 - y2 * x3);
+        // rSP1 = rSP1+G3i*(x1+x2+x3)/(24.0*volume);
+        // rSP2 = rSP2+G3i*(y1+y2+y3)/(24.0*volume);
+        // rSP3 = rSP3+G3i*(z1+z2+z3)/(24.0*volume);
+        xx    = x1 * x1 + x2 * x2 + x3 * x3 + x1 * x2 + x2 * x3 + x3 * x1;
+        yy    = y1 * y1 + y2 * y2 + y3 * y3 + y1 * y2 + y2 * y3 + y3 * y1;
+        zz    = z1 * z1 + z2 * z2 + z3 * z3 + z1 * z2 + z2 * z3 + z3 * z1;
+        top11 = top11 + (yy + zz) * rhoP * G3i / 60.;
+        top22 = top22 + (xx + zz) * rhoP * G3i / 60.;
+        top33 = top33 + (yy + xx) * rhoP * G3i / 60.;
+        xy    = 2.0 * (x1 * y1 + x2 * y2 + x3 * y3) + x2 * y3 + x3 * y1 + x1 * y2 + x3 * y2 + x1 * y3 + x2 * y1;
+        yz    = 2.0 * (y1 * z1 + y2 * z2 + y3 * z3) + y2 * z3 + y3 * z1 + y1 * z2 + y3 * z2 + y1 * z3 + y2 * z1;
+        zx    = 2.0 * (z1 * x1 + z2 * x2 + z3 * x3) + z2 * x3 + z3 * x1 + z1 * x2 + z3 * x2 + z1 * x3 + z2 * x1;
+        top12 = top12 - xy * rhoP * G3i / 120.;
+        top23 = top23 - yz * rhoP * G3i / 120.;
+        top13 = top13 - zx * rhoP * G3i / 120.;
+    }
+    // Satz von Steiner ...
+    top11 = top11 - rhoP * volume * (rSP2 * rSP2 + rSP3 + rSP3);
+    top22 = top22 - rhoP * volume * (rSP3 * rSP3 + rSP1 * rSP1);
+    top33 = top33 - rhoP * volume * (rSP1 * rSP1 + rSP2 * rSP2);
+    top12 = top12 + rhoP * volume * rSP1 * rSP2;
+    top23 = top23 + rhoP * volume * rSP2 * rSP3;
+    top13 = top13 + rhoP * volume * rSP3 * rSP1;
+
+    cout << "Volume:" << volume << "\n Traegheitsmomente:\n";
+    cout << " top11:" << top11 << " top22:" << top22 << " top33:" << top33 << endl;
+    cout << " top12:" << top12 << " top23:" << top23 << " top13:" << top13 << endl;
+
+    return { top11, top22, top33, top12, top23, top13 };
+}
+
+/**
+ * Returns the volume of this triangular mesh within the specified rectangle.
+ * @param p1x1 the 1st x1 coordinate of the rectangle
+ * @param p1x2 the 1st x2 coordinate of the rectangle
+ * @param p2x1 the 2nd x1 coordinate of the rectangle
+ * @param p2x2 the 2nd x2 coordinate of the rectangle
+ * @return the volume of this triangular mesh within the specified rectangle
+ * @exception NullPointerException if no triangles are found within the specified rectangle
+ */
+double GbTriangularMesh3D::getVolumeForRectangle(const double & /*p1x1*/, const double & /*p1x2*/,
+                                                 const double & /*p2x1*/, const double & /*p2x2*/)
+{
+    throw UbException(UB_EXARGS, "not yet implemented");
+    //    GbPolygon2D polygon;
+    //    double      volume = 0.0;
+    //    double      area1 = Math.abs((p1x1-p2x1)*(p1x2-p2x2));
+    //    double      area2 = 0.0;
+    //    double      t1min, t1max, t2min, t2max;
+    //    double      x1, x2;
+    //    boolean     f = false;
+
+    //    for(int i=0; i<this.triangles.length; i++)
+    //    {
+    //	t1min = this.triangles[i].getX1Minimum();
+    //	t1max = this.triangles[i].getX1Maximum();
+    //	if(GbSystem.less2(t1min, t1max, p1x1, p2x1))    continue;
+    //	if(GbSystem.greater2(t1min, t1max, p1x1, p2x1)) continue;
+
+    //	t2min = this.triangles[i].getX2Minimum();
+    //	t2max = this.triangles[i].getX2Maximum();
+    //	if(GbSystem.less2(t2min, t2max, p1x2, p2x2))    continue;
+    //	if(GbSystem.greater2(t2min, t2max, p1x2, p2x2)) continue;
+
+    //	if(GbSystem.inOpenInterval(t1min, p1x1, p2x1) && GbSystem.inOpenInterval(t1max, p1x1, p2x1) &&
+    //		GbSystem.inOpenInterval(t2min, p1x2, p2x2) && GbSystem.inOpenInterval(t2max, p1x2, p2x2))
+    //	{
+    //		volume += this.triangles[i].getVolume();
+    //		area2  += this.triangles[i].getArea();
+    //		f       = true;
+    //	}
+    //	else
+    //	{
+    //		polygon = this.triangles[i].createClippedPolygon3D(p1x1, p1x2, p2x1, p2x2);
+
+    //		if(polygon != null && polygon.size() > 2)
+    //		{
+    //			try
+    //			{
+    //				x1      = polygon.getX1Centroid();
+    //				x2      = polygon.getX2Centroid();
+    //				volume += this.triangles[i].getX3Coordinate(x1, x2) * Math.abs(polygon.getArea());
+    //				area2  += Math.abs(polygon.getArea());
+    //				f       = true;
+    //			}
+    //			catch(Exception e){}
+    //		}
+    //	}
+    //	if(GbSystem.greaterEqual(area2, area1)) break;
+    //}
+    //    if(f) return(volume);
+    //    else  throw new NullPointerException();
+}
+
+/**
+ * Returns the triangles of this triangular mesh located within the specified rectangle (may be an empty array).
+ * @param p1x1 the 1st x1 coordinate of the rectangle
+ * @param p1x2 the 1st x2 coordinate of the rectangle
+ * @param p2x1 the 2nd x1 coordinate of the rectangle
+ * @param p2x2 the 2nd x2 coordinate of the rectangle
+ * @return the triangles of this triangular mesh located within the specified rectangle
+ */
+vector<GbTriangle3D *> *GbTriangularMesh3D::getTrianglesForRectangle(const double & /*p1x1*/, const double & /*p1x2*/,
+                                                                     const double & /*p2x1*/, const double & /*p2x2*/)
+{
+    throw UbException(UB_EXARGS, "not yet implemented");
+    //    QbList      triangleList = new QbList(GbTriangle3D.class);
+    //    GbPolygon2D polygon;
+    //    double      t1min, t1max, t2min, t2max;
+    //    double      area1 = Math.abs((p1x1-p2x1)*(p1x2-p2x2));
+    //    double      area2 = 0.0;
+
+    //    for(int i=0; i<this.triangles.length; i++)
+    //    {
+    //	t1min = this.triangles[i].getX1Minimum();
+    //	t1max = this.triangles[i].getX1Maximum();
+    //	if(GbSystem.less2(t1min, t1max, p1x1, p2x1))    continue;
+    //	if(GbSystem.greater2(t1min, t1max, p1x1, p2x1)) continue;
+
+    //	t2min = this.triangles[i].getX2Minimum();
+    //	t2max = this.triangles[i].getX2Maximum();
+    //	if(GbSystem.less2(t2min, t2max, p1x2, p2x2))    continue;
+    //	if(GbSystem.greater2(t2min, t2max, p1x2, p2x2)) continue;
+
+    //	if(GbSystem.inOpenInterval(t1min, p1x1, p2x1) && GbSystem.inOpenInterval(t1max, p1x1, p2x1) &&
+    //		GbSystem.inOpenInterval(t2min, p1x2, p2x2) && GbSystem.inOpenInterval(t2max, p1x2, p2x2))
+    //	{
+    //		try { triangleList.append(this.triangles[i]); } catch(Exception e){}
+    //		area2 += this.triangles[i].getArea();
+    //	}
+    //	else
+    //	{
+    //		polygon = this.triangles[i].createClippedPolygon3D(p1x1, p1x2, p2x1, p2x2);
+    //		if(polygon != null && polygon.size() > 2)
+    //		{
+    //			try { triangleList.append(this.triangles[i]); } catch(Exception e){}
+    //			area2 += Math.abs(polygon.getArea());
+    //		}
+    //	}
+    //	if(GbSystem.greaterEqual(area2, area1)) break;
+    //}
+    //    return((GbTriangle3D[])triangleList.getObjectArray());
+}
+/**
+ * Returns the nodes of this triangular mesh located within the specified rectangle (may be an empty array).
+ * @param p1x1 the 1st x1 coordinate of the rectangle
+ * @param p1x2 the 1st x2 coordinate of the rectangle
+ * @param p2x1 the 2nd x1 coordinate of the rectangle
+ * @param p2x2 the 2nd x2 coordinate of the rectangle
+ * @return the nodes of this triangular mesh located within the specified rectangle
+ */
+vector<GbPoint3D *> *GbTriangularMesh3D::getNodesForRectangle(const double & /*p1x1*/, const double & /*p1x2*/,
+                                                              const double & /*p2x1*/, const double & /*p2x2*/)
+{
+    throw UbException(UB_EXARGS, "not implemented");
+    //   QbList nodeList = new QbList(GbPoint3D.class);
+
+    //   for(int i=0; i<this.edges.length; i++)
+    //   {
+    // if(GbSystem.inClosedInterval(this.nodes[i].getX1Coordinate(), p1x1, p2x1) &&
+    // GbSystem.inClosedInterval(this.nodes[i].getX2Coordinate(), p1x2, p2x2))
+    //{
+    //	try { nodeList.append(this.nodes[i]); } catch(Exception e){}
+    //}
+    //   }
+    //   return((GbPoint3D[])nodeList.getObjectArray());
+}
+
+/**
+ * Returns the difference of maximum and minimum x3 coordinates
+ * of this triangular mesh within the specified rectangle.
+ * @param p1x1 the 1st x1 coordinate of the rectangle
+ * @param p1x2 the 1st x2 coordinate of the rectangle
+ * @param p2x1 the 2nd x1 coordinate of the rectangle
+ * @param p2x2 the 2nd x2 coordinate of the rectangle
+ * @return the difference of maximum and minimum x3 coordinates of this triangular mesh within the specified rectangle
+ * @exception NullPointerException if no triangles are found within the specified rectangle
+ */
+double GbTriangularMesh3D::getX3RangeForRectangle(const double & /*p1x1*/, const double & /*p1x2*/,
+                                                  const double & /*p2x1*/, const double & /*p2x2*/)
+{
+    throw UbException(UB_EXARGS, "not implemented");
+    //     GbPolygon3D polygon;
+    //     boolean     f     = false;
+    //     double      x3min = 0.0;
+    //     double      x3max = 0.0;
+    //     double      t1min, t1max, t2min, t2max;
+    //     double      area1 = Math.abs((p1x1-p2x1)*(p1x2-p2x2));
+    //     double      area2 = 0.0;
+
+    //     for(int i=0; i<this.triangles.length; i++)
+    //     {
+    // t1min = this.triangles[i].getX1Minimum();
+    // t1max = this.triangles[i].getX1Maximum();
+    // if(GbSystem.less2(t1min, t1max, p1x1, p2x1))    continue;
+    // if(GbSystem.greater2(t1min, t1max, p1x1, p2x1)) continue;
+
+    // t2min = this.triangles[i].getX2Minimum();
+    // t2max = this.triangles[i].getX2Maximum();
+    // if(GbSystem.less2(t2min, t2max, p1x2, p2x2))    continue;
+    // if(GbSystem.greater2(t2min, t2max, p1x2, p2x2)) continue;
+
+    // if(GbSystem.inOpenInterval(t1min, p1x1, p2x1) && GbSystem.inOpenInterval(t1max, p1x1, p2x1) &&
+    //    GbSystem.inOpenInterval(t2min, p1x2, p2x2) && GbSystem.inOpenInterval(t2max, p1x2, p2x2))
+    // {
+    //    if(f)
+    //    {
+    //       if(this.triangles[i].getX3Minimum() < x3min) x3min = this.triangles[i].getX3Minimum();
+    //       if(this.triangles[i].getX3Maximum() > x3max) x3max = this.triangles[i].getX3Maximum();
+    //    }
+    //    else
+    //    {
+    //       x3min = this.triangles[i].getX3Minimum();
+    //       x3max = this.triangles[i].getX3Maximum();
+    //       f     = true;
+    //    }
+    //    area2 += this.triangles[i].getArea();
+    //}
+    // else
+    // {
+    //    polygon = this.triangles[i].createClippedPolygon3D(p1x1, p1x2, p2x1, p2x2);
+
+    //    if(polygon != null && polygon.size() > 2)
+    //    {
+    //       if(f)
+    //       {
+    //          if(polygon.getX3Minimum() < x3min) x3min = polygon.getX3Minimum();
+    //          if(polygon.getX3Maximum() > x3max) x3max = polygon.getX3Maximum();
+    //       }
+    //       else
+    //       {
+    //          x3min = polygon.getX3Minimum();
+    //          x3max = polygon.getX3Maximum();
+    //          f     = true;
+    //       }
+    //       area2 += Math.abs(polygon.getArea());
+    //    }
+    // }
+    // if(GbSystem.greaterEqual(area2, area1)) break;
+    //     }
+    //     if(f) return(x3max-x3min);
+    //     else  throw new NullPointerException();
+}
+/**
+ * Returns the minimum x3 coordinates of this triangular mesh within the specified rectangle.
+ * @param p1x1 the 1st x1 coordinate of the rectangle
+ * @param p1x2 the 1st x2 coordinate of the rectangle
+ * @param p2x1 the 2nd x1 coordinate of the rectangle
+ * @param p2x2 the 2nd x2 coordinate of the rectangle
+ * @return the minimum x3 coordinates of this triangular mesh within the specified rectangle
+ * @exception NullPointerException if no triangles are found within the specified rectangle
+ */
+double GbTriangularMesh3D::getX3MinimumForRectangle(const double & /*p1x1*/, const double & /*p1x2*/,
+                                                    const double & /*p2x1*/, const double & /*p2x2*/)
+{
+    throw UbException(UB_EXARGS, "not implemented");
+    //    GbPolygon3D polygon;
+    //    boolean     f     = false;
+    //    double      x3min = 0.0;
+    //    double      t1min, t1max, t2min, t2max;
+    //    double      area1 = Math.abs((p1x1-p2x1)*(p1x2-p2x2));
+    //    double      area2 = 0.0;
+
+    //    for(int i=0; i<this.triangles.length; i++)
+    //    {
+    // t1min = this.triangles[i].getX1Minimum();
+    // t1max = this.triangles[i].getX1Maximum();
+    // if(GbSystem.less2(t1min, t1max, p1x1, p2x1))    continue;
+    // if(GbSystem.greater2(t1min, t1max, p1x1, p2x1)) continue;
+
+    // t2min = this.triangles[i].getX2Minimum();
+    // t2max = this.triangles[i].getX2Maximum();
+    // if(GbSystem.less2(t2min, t2max, p1x2, p2x2))    continue;
+    // if(GbSystem.greater2(t2min, t2max, p1x2, p2x2)) continue;
+
+    // if(GbSystem.inOpenInterval(t1min, p1x1, p2x1) && GbSystem.inOpenInterval(t1max, p1x1, p2x1) &&
+    //   GbSystem.inOpenInterval(t2min, p1x2, p2x2) && GbSystem.inOpenInterval(t2max, p1x2, p2x2))
+    //{
+    //   if(f)
+    //   {
+    //      if(this.triangles[i].getX3Minimum() < x3min) x3min = this.triangles[i].getX3Minimum();
+    //   }
+    //   else
+    //   {
+    //      x3min = this.triangles[i].getX3Minimum();
+    //      f     = true;
+    //   }
+    //   area2 += this.triangles[i].getArea();
+    //}
+    // else
+    //{
+    //   polygon = this.triangles[i].createClippedPolygon3D(p1x1, p1x2, p2x1, p2x2);
+
+    //   if(polygon != null && polygon.size() > 2)
+    //   {
+    //      if(f)
+    //      {
+    //         if(polygon.getX3Minimum() < x3min) x3min = polygon.getX3Minimum();
+    //      }
+    //      else
+    //      {
+    //         x3min = polygon.getX3Minimum();
+    //         f     = true;
+    //      }
+    //      area2 += Math.abs(polygon.getArea());
+    //   }
+    //}
+    // if(GbSystem.greaterEqual(area2, area1)) break;
+    //    }
+    //    if(f) return(x3min);
+    //    else  throw new NullPointerException();
+}
+/**
+ * Returns the maximum x3 coordinates of this triangular mesh within the specified rectangle.
+ * @param p1x1 the 1st x1 coordinate of the rectangle
+ * @param p1x2 the 1st x2 coordinate of the rectangle
+ * @param p2x1 the 2nd x1 coordinate of the rectangle
+ * @param p2x2 the 2nd x2 coordinate of the rectangle
+ * @return the maximum x3 coordinates of this triangular mesh within the specified rectangle
+ * @exception NullPointerException if no triangles are found within the specified rectangle
+ */
+double GbTriangularMesh3D::getX3MaximumForRectangle(const double & /*p1x1*/, const double & /*p1x2*/,
+                                                    const double & /*p2x1*/, const double & /*p2x2*/)
+{
+    throw UbException(UB_EXARGS, "not implemented");
+    //    GbPolygon3D polygon;
+    //    boolean     f     = false;
+    //    double      x3max = 0.0;
+    //    double      t1min, t1max, t2min, t2max;
+    //    double      area1 = Math.abs((p1x1-p2x1)*(p1x2-p2x2));
+    //    double      area2 = 0.0;
+
+    //    for(int i=0; i<this.triangles.length; i++)
+    //    {
+    // t1min = this.triangles[i].getX1Minimum();
+    // t1max = this.triangles[i].getX1Maximum();
+    // if(GbSystem.less2(t1min, t1max, p1x1, p2x1))    continue;
+    // if(GbSystem.greater2(t1min, t1max, p1x1, p2x1)) continue;
+
+    // t2min = this.triangles[i].getX2Minimum();
+    // t2max = this.triangles[i].getX2Maximum();
+    // if(GbSystem.less2(t2min, t2max, p1x2, p2x2))    continue;
+    // if(GbSystem.greater2(t2min, t2max, p1x2, p2x2)) continue;
+
+    // if(GbSystem.inOpenInterval(t1min, p1x1, p2x1) && GbSystem.inOpenInterval(t1max, p1x1, p2x1) &&
+    //   GbSystem.inOpenInterval(t2min, p1x2, p2x2) && GbSystem.inOpenInterval(t2max, p1x2, p2x2))
+    //{
+    //   if(f)
+    //   {
+    //      if(this.triangles[i].getX3Maximum() < x3max) x3max = this.triangles[i].getX3Maximum();
+    //   }
+    //   else
+    //   {
+    //      x3max = this.triangles[i].getX3Maximum();
+    //      f     = true;
+    //   }
+    //   area2 += this.triangles[i].getArea();
+    //}
+    // else
+    //{
+    //   polygon = this.triangles[i].createClippedPolygon3D(p1x1, p1x2, p2x1, p2x2);
+
+    //   if(polygon != null && polygon.size() > 2)
+    //   {
+    //      if(f)
+    //      {
+    //         if(polygon.getX3Maximum() < x3max) x3max = polygon.getX3Maximum();
+    //      }
+    //      else
+    //      {
+    //         x3max = polygon.getX3Maximum();
+    //         f     = true;
+    //      }
+    //      area2 += Math.abs(polygon.getArea());
+    //   }
+    //}
+    // if(GbSystem.greaterEqual(area2, area1)) break;
+    //    }
+    //    if(f) return(x3max);
+    //    else  throw new NullPointerException();
+}
+/*======================================================================*/
+vector<GbTriangle3D *> GbTriangularMesh3D::getSurfaceTriangleSet()
+{
+    vector<GbTriangle3D *> tris;
+    GbTriangle3D *triangle;
+    GbPoint3D *p1;
+    GbPoint3D *p2;
+    GbPoint3D *p3;
+    int size = (int)this->triangles->size();
+    for (int u = 0; u < size; u++) {
+        triangle = (*this->triangles)[u];
+        p1       = new GbPoint3D(triangle->getPoint1());
+        p2       = new GbPoint3D(triangle->getPoint2());
+        p3       = new GbPoint3D(triangle->getPoint3());
+        tris.push_back(new GbTriangle3D(p1, p2, p3));
+    }
+    return tris;
+}
+/*======================================================================*/
+/*
+ * Function to determine if the point is inside the polyhedron defined as a 3D object
+ * using the Halfspace algorithm
+ * @param xp the x-coordinate of the point
+ * @param yp the y-coordinate of the point
+ * @param zp the z-coordinate of the point
+ * @return true if point is inside else return false
+ */
+bool GbTriangularMesh3D::isPointInObject3DHalfSpace(const double &xp, const double &yp, const double &zp)
+{
+    vector<GbTriangle3D *> *Triangles = this->triangles;
+    int Trianglesize                  = (int)Triangles->size();
+    // GbPoint3D Point(xp,yp,zp);
+    for (int i = 0; i < Trianglesize; i++) {
+        // GbPoint3D* point1 = (*Triangles)[i]->getPoint1();
+        // GbPoint3D* point2 = (*Triangles)[i]->getPoint2();
+        // GbPoint3D* point3 = (*Triangles)[i]->getPoint3();
+
+        // GbHalfSpace3D halfspace(point1, point2, point3);
+        GbHalfSpace3D halfspace((*Triangles)[i]);
+        if (halfspace.ptInside(xp, yp, zp))
+            return false;
+    }
+    return true;
+}
+/*======================================================================*/
+bool GbTriangularMesh3D::isPointInObject3DRayCrossing(const double &xp, const double &yp, const double &zp, int radius,
+                                                      int /*numVertices*/, int numTriangles)
+{
+    GbVector3D point(xp, yp, zp);
+
+    if (this->InPolyhedron(numTriangles, point, radius))
+        return true;
+    else
+        return false;
+}
+/*======================================================================*/
+bool GbTriangularMesh3D::isPointInGbObject3D(const double &x1, const double &x2, const double &x3)
+{
+    double xmin = this->getX1Minimum();
+    double xmax = this->getX1Maximum();
+    double ymin = this->getX2Minimum();
+    double ymax = this->getX2Maximum();
+    double zmin = this->getX3Minimum();
+    double zmax = this->getX3Maximum();
+    double dX   = (xmax - xmin) / 100.;
+    double dY   = (ymax - ymin) / 100.;
+    double dZ   = (zmax - zmin) / 100.;
+    GbCuboid3D boundingCube(xmin - dX, ymin - dY, zmin - dZ, xmax + dX, ymax + dY, zmax + dZ);
+    if (!boundingCube.isPointInGbObject3D(x1, x2, x3)) {
+        boundingCube.finalize();
+        return false;
+    }
+
+    // Halfspace algorithm, Area of spherical polygons algorithm or Ray crossing algorithm
+    GbVector3D bMin(boundingCube.getPoint1());
+    GbVector3D bMax(boundingCube.getPoint2());
+
+    boundingCube.finalize();
+
+    bMin       = bMax.Subtract(bMin);
+    int radius = (int)(bMin.Length() + 1) + 1;
+
+    if (this->pointinobjecttest == HALFSPACE)
+        return this->isPointInObject3DHalfSpace(x1, x2, x3);
+    else if (this->pointinobjecttest == RAYCROSSING)
+        return this->isPointInObject3DRayCrossing(x1, x2, x3, radius, (int)this->nodes->size(),
+                                                  (int)this->triangles->size());
+    else
+        throw UbException(UB_EXARGS, "no ptInObjTest");
+}
+/*======================================================================*/
+bool GbTriangularMesh3D::isPointInGbObject3D(const double & /*x1*/, const double & /*x2*/, const double & /*x3*/,
+                                             bool & /*pointIsOnBoundary*/)
+{
+    throw UbException(UB_EXARGS, "not implemented");
+}
+/*======================================================================*/
+GbLine3D *GbTriangularMesh3D::createClippedLine3D(GbPoint3D & /*point1*/, GbPoint3D & /*point2*/)
+{
+    throw UbException(UB_EXARGS, "not implemented");
+}
+/*======================================================================*/
+void GbTriangularMesh3D::writeMesh(string filename, WbWriter *writer, bool writeNormals)
+{
+    vector<UbTupleFloat3> nodes(triangles->size() * 3);
+    vector<UbTupleInt3> tris(triangles->size());
+
+    for (size_t i = 0; i < triangles->size(); i++) {
+        GbTriangle3D &tri = *((*triangles)[i]);
+        GbPoint3D &node1  = *tri.getPoint(0);
+        GbPoint3D &node2  = *tri.getPoint(1);
+        GbPoint3D &node3  = *tri.getPoint(2);
+
+        nodes[i * 3] =
+            makeUbTuple((float)node1.getX1Coordinate(), (float)node1.getX2Coordinate(), (float)node1.getX3Coordinate());
+        nodes[i * 3 + 1] =
+            makeUbTuple((float)node2.getX1Coordinate(), (float)node2.getX2Coordinate(), (float)node2.getX3Coordinate());
+        nodes[i * 3 + 2] =
+            makeUbTuple((float)node3.getX1Coordinate(), (float)node3.getX2Coordinate(), (float)node3.getX3Coordinate());
+
+        tris[i] = makeUbTuple((int)i * 3, (int)i * 3 + 1, (int)i * 3 + 2);
+    }
+    writer->writeTriangles(filename, nodes, tris);
+
+    if (writeNormals) {
+        vector<UbTupleFloat3> lineNodes(triangles->size() * 2);
+        vector<UbTupleInt2> lines(triangles->size());
+        for (size_t i = 0; i < triangles->size(); i++) {
+            GbVector3D vec = (*triangles)[i]->getNormal();
+            lineNodes[i * 2] =
+                makeUbTuple((float)(*triangles)[i]->getX1Centroid(), (float)(*triangles)[i]->getX2Centroid(),
+                            (float)(*triangles)[i]->getX3Centroid());
+            lineNodes[i * 2 + 1] = makeUbTuple((float)((*triangles)[i]->getX1Centroid() + vec.X1()),
+                                               (float)((*triangles)[i]->getX2Centroid() + vec.X2()),
+                                               (float)((*triangles)[i]->getX3Centroid() + vec.X3()));
+
+            lines[i] = makeUbTuple((int)i * 2, (int)i * 2 + 1);
+        }
+        writer->writeLines(filename + "_normals", lineNodes, lines);
+    }
+}
+
+/*======================================================================*/
+/*
+This function returns a char:
+'V': the query point a coincides with a Vertex of polyhedron P.
+'E': the query point a is in the relative interior of an Edge of polyhedron P.
+'F': the query point a is in the relative interior of a Face of polyhedron P.
+'i': the query point a is strictly interior to polyhedron P.
+'o': the query point a is strictly exterior to( or outside of) polyhedron P.
+*/
+bool GbTriangularMesh3D::InPolyhedron(int F, GbVector3D &q, int radius)
+{
+    GbVector3D r; /* Ray endpoint. */
+    GbVector3D p; /* Intersection point; not used. */
+    int f, k = 0, crossings = 0;
+    char code = '?';
+
+    while (k++ < F) {
+        crossings = 0;
+
+        RandomRay(r, radius);
+        r = q.Add(r);
+        // printf("Ray endpoint: (%d,%d,%d)\n", r[0],r[1],r[2] );
+
+        for (f = 0; f < F; f++) /* Begin check each face */
+        {
+            if (BoxTest((*this->triangles)[f], q, r) == false)
+                code = '0'; // printf("BoxTest = 0!\n");
+            else
+                code = SegTriInt((*this->triangles)[f], q, r,
+                                 p); // printf( "Face = %d: BoxTest/SegTriInt returns %c\n\n", f, code );
+
+            /* If ray is degenerate, then goto outer while to generate another. */
+            if (code == 'p' || code == 'v' || code == 'e')
+                break; // goto LOOP; //printf("Degenerate ray\n");
+            /* If ray hits face at interior point, increment crossings. */
+            else if (code == 'f')
+                crossings++; // printf( "crossings = %d\n", crossings );
+            /* If query endpoint q sits on a V/E/F, return that code. */
+            else if (code == 'V' || code == 'E' || code == 'F')
+                return true;
+            /* If ray misses triangle, do nothing. */
+            else if (code == '0') { /*nothing to do*/
+            } else
+                throw UbException(UB_EXARGS, "Error");
+        } /* End check each face */
+
+        /* No degeneracies encountered: ray is generic, so finished. */
+        if (f >= F)
+            break;
+    } /* End while loop */
+
+    //   printf( "Crossings = %d\n", crossings );
+    /* q strictly interior to polyhedron iff an odd number of crossings. */
+    if ((crossings % 2) == 1)
+        return true;
+
+    return false;
+}
+
+/* Return a random ray endpoint */
+void GbTriangularMesh3D::RandomRay(GbVector3D &ray, int radius)
+{
+    double x, y, z, w, t;
+
+    double MAX_INT = 2147483647;
+    /* Generate a random point on a sphere of radius 1. */
+    /* the sphere is sliced at z, and a random point at angle t
+    generated on the circle of intersection. */
+    z = 2.0 * (double)rand() / MAX_INT - 1.0;
+    t = 2.0 * UbMath::PI * (double)rand() / MAX_INT;
+    w = sqrt(1 - z * z);
+    x = w * cos(t);
+    y = w * sin(t);
+
+    ray[0] = radius * x;
+    ray[1] = radius * y;
+    ray[2] = radius * z;
+
+    /*printf( "RandomRay returns %6d %6d %6d\n", ray[X], ray[Y], ray[Z] );*/
+}
+
+/*---------------------------------------------------------------------
+'p': The segment lies wholly within the plane.
+'q': The q endpoint is on the plane (but not 'p').
+'r': The r endpoint is on the plane (but not 'p').
+'0': The segment lies strictly to one side or the other of the plane.
+'1': The segement intersects the plane, and 'p' does not hold.
+---------------------------------------------------------------------*/
+char GbTriangularMesh3D::SegPlaneInt(GbTriangle3D *T, GbVector3D &q, GbVector3D &r, GbVector3D &p, int *m)
+{
+    // cout<<"SegPlaneInt..\n";
+    GbVector3D N;
+    double D;
+    GbVector3D rq;
+    double num, denom, t;
+    int i;
+
+    *m = PlaneCoeff(T, N, &D);
+    /*printf("m=%d; plane=(%lf,%lf,%lf,%lf)\n", m, N[X],N[Y],N[Z],D);*/
+    num   = D - q.Dot(N);
+    rq    = r.Subtract(q);
+    denom = rq.Dot(N);
+    /*printf("SegPlaneInt: num=%lf, denom=%lf\n", num, denom );*/
+
+    if (denom == 0.0) { /* Segment is parallel to plane. */
+        if (num == 0.0) /* q is on plane. */
+                        // if (UbMath::zero(denom)) {  /* Segment is parallel to plane. */
+            //   if ( UbMath::zero(num))   /* q is on plane. */
+            return 'p';
+        else
+            return '0';
+    } else
+        t = num / denom;
+    /*printf("SegPlaneInt: t=%lf \n", t );*/
+
+    for (i = 0; i < 3; i++)
+        p[i] = q[i] + t * (r[i] - q[i]);
+
+    if ((0.0 < t) && (t < 1.0))
+        return '1';
+    else if (num == 0.0) /* t == 0 */
+        return 'q';
+    else if (num == denom) /* t == 1 */
+        return 'r';
+    else
+        return '0';
+
+    // if ( (0.0 < t) && (t < 1.0) )
+    //   return '1';
+    // else if ( UbMath::zero(num))   /* t == 0 */
+    //   return 'q';
+    // else if ( UbMath::equal(num , denom) ) /* t == 1 */
+    //   return 'r';
+    // else return '0';
+}
+/*---------------------------------------------------------------------
+Computes N & D and returns index m of largest component.
+---------------------------------------------------------------------*/
+int GbTriangularMesh3D::PlaneCoeff(GbTriangle3D *T, GbVector3D &N, double *D)
+{
+    int i;
+    double t;             /* Temp storage */
+    double biggest = 0.0; /* Largest component of normal vector. */
+    int m          = 0;   /* Index of largest component. */
+
+    N = T->getNormal();
+    /*printf("PlaneCoeff: N=(%lf,%lf,%lf)\n", N[X],N[Y],N[Z]);*/
+    GbVector3D a(T->getPoint1());
+
+    *D = a.Dot(N);
+
+    /* Find the largest component of N. */
+    for (i = 0; i < 3; i++) {
+        t = std::fabs(N[i]);
+        if (t > biggest) {
+            biggest = t;
+            m       = i;
+        }
+    }
+    return m;
+}
+
+/* Assumption: p lies in the plane containing T.
+Returns a char:
+'V': the query point p coincides with a Vertex of triangle T.
+'E': the query point p is in the relative interior of an Edge of triangle T.
+'F': the query point p is in the relative interior of a Face of triangle T.
+'0': the query point p does not intersect (misses) triangle T.
+*/
+
+char GbTriangularMesh3D::InTri3D(GbTriangle3D *T, int m, GbVector3D & /*p*/)
+{
+    //   int i;           /* Index for X,Y,Z           */
+    int j;            /* Index for X,Y             */
+                      //   int k;           /* Index for triangle vertex */
+    GbVector3D pp;    /* projected p */
+    GbVector3D Tp[3]; /* projected T: three new vertices */
+
+    /* Project out coordinate m in both p and the triangular face */
+    // j = 0;
+    // for ( i = 0; i < 3; i++ ) {
+    //   if ( i != m ) {    /* skip largest coordinate */
+    //      pp[j] = p[i];
+    //      //for ( k = 0; k < 3; k++ )
+    //         std::cout<<"aachtung###############################################";
+    //      //            Tp[k][j] = Vertices[T[k]][i];
+    //      j++;
+    //   }
+    //}
+    j = 0;
+    if (m != 0) {
+        Tp[0][j] = T->getPoint1()->getX1Coordinate();
+        Tp[1][j] = T->getPoint2()->getX1Coordinate();
+        Tp[2][j] = T->getPoint3()->getX1Coordinate();
+        j++;
+    }
+    if (m != 1) {
+        Tp[0][j] = T->getPoint1()->getX2Coordinate();
+        Tp[1][j] = T->getPoint2()->getX2Coordinate();
+        Tp[2][j] = T->getPoint3()->getX2Coordinate();
+        j++;
+    }
+    if (m != 2) {
+        Tp[0][j] = T->getPoint1()->getX3Coordinate();
+        Tp[1][j] = T->getPoint2()->getX3Coordinate();
+        Tp[2][j] = T->getPoint3()->getX3Coordinate();
+        j++;
+    }
+
+    return (InTri2D(Tp, pp));
+}
+
+char GbTriangularMesh3D::InTri2D(GbVector3D Tp[3], GbVector3D &pp)
+{
+    double area0, area1, area2;
+
+    /* compute three AreaSign() values for pp w.r.t. each edge of the face in 2D */
+    area0 = AreaSign(pp, Tp[0], Tp[1]);
+    area1 = AreaSign(pp, Tp[1], Tp[2]);
+    area2 = AreaSign(pp, Tp[2], Tp[0]);
+    //  printf("area0=%f  area1=%f  area2=%f\n",area0,area1,area2);
+
+    if (((area0 == 0.) && (area1 > 0.) && (area2 > 0.)) || ((area1 == 0.) && (area0 > 0.) && (area2 > 0.)) ||
+        ((area2 == 0.) && (area0 > 0.) && (area1 > 0.)))
+        return 'E';
+
+    if (((area0 == 0.) && (area1 < 0.) && (area2 < 0.)) || ((area1 == 0.) && (area0 < 0.) && (area2 < 0.)) ||
+        ((area2 == 0.) && (area0 < 0.) && (area1 < 0.)))
+        return 'E';
+
+    if (((area0 > 0.) && (area1 > 0.) && (area2 > 0.)) || ((area0 < 0.) && (area1 < 0.) && (area2 < 0.)))
+        return 'F';
+
+    if ((area0 == 0.0) && (area1 == 0.0) && (area2 == 0.0))
+        fprintf(stderr, "Error in InTriD\n"), exit(EXIT_FAILURE);
+
+    if (((area0 == 0.) && (area1 == 0.)) || ((area0 == 0.) && (area2 == 0.)) || ((area1 == 0.) && (area2 == 0.)))
+        return 'V';
+
+    else
+        return '0';
+}
+
+double GbTriangularMesh3D::AreaSign(GbVector3D &a, GbVector3D &b, GbVector3D &c)
+{
+    double area2;
+
+    area2 = (b[0] - a[0]) * (c[1] - a[1]) - (c[0] - a[0]) * (b[1] - a[1]);
+
+    return area2;
+    /* The area should be an integer. */
+    // FIXME: unrechable code
+    // if      ( area2 >  0.5 ) return  1;
+    // else if ( area2 < -0.5 ) return -1;
+    // else                     return  0;
+}
+
+char GbTriangularMesh3D::SegTriInt(GbTriangle3D *T, GbVector3D &q, GbVector3D &r, GbVector3D &p)
+{
+    int code = '?';
+    int m    = -1;
+
+    code = (unsigned char)SegPlaneInt(T, q, r, p, &m);
+    //  printf("SegPlaneInt code=%c, m=%d; p=(%lf,%lf,%lf)\n", code,m,p[0],p[1],p[2]);
+
+    if (code == '0')
+        return '0';
+    else if (code == 'q')
+        return InTri3D(T, m, q);
+    else if (code == 'r')
+        return InTri3D(T, m, r);
+    else if (code == 'p')
+        return InPlane(T, m, q, r, p);
+    else if (code == '1')
+        return SegTriCross(T, q, r);
+    else /* Error */
+        return code;
+}
+
+char GbTriangularMesh3D::InPlane(GbTriangle3D * /*T*/, int /*m*/, GbVector3D & /*q*/, GbVector3D & /*r*/,
+                                 GbVector3D & /*p*/)
+{
+    // cout<<"inplane\n";
+    /* NOT IMPLEMENTED */
+    return 'p';
+}
+
+/*---------------------------------------------------------------------
+The signed volumes of three tetrahedra are computed, determined
+by the segment qr, and each edge of the triangle.
+Returns a char:
+'v': the open segment includes a vertex of T.
+'e': the open segment includes a point in the relative interior of an edge
+of T.
+'f': the open segment includes a point in the relative interior of a face
+of T.
+'0': the open segment does not intersect triangle T.
+---------------------------------------------------------------------*/
+
+char GbTriangularMesh3D::SegTriCross(GbTriangle3D *T, GbVector3D &q, GbVector3D &r)
+{
+    // cout<<"SegTriCross\n";
+    double vol0, vol1, vol2;
+    GbVector3D vert0(T->getPoint1());
+    GbVector3D vert1(T->getPoint2());
+    GbVector3D vert2(T->getPoint3());
+
+    vol0 = VolumeSign(q, vert0, vert1, r);
+    vol1 = VolumeSign(q, vert1, vert2, r);
+    vol2 = VolumeSign(q, vert2, vert0, r);
+
+    //  printf( "SegTriCross:  vol0 = %d; vol1 = %d; vol2 = %d\n", vol0, vol1, vol2 );
+
+    /* Same sign: segment intersects interior of triangle. */
+    if (((vol0 > 0.) && (vol1 > 0.) && (vol2 > 0.)) || ((vol0 < 0.) && (vol1 < 0.) && (vol2 < 0.)))
+    // if ( ( UbMath::greater(vol0, 0. ) && UbMath::greater(vol1 , 0. ) && UbMath::greater(vol2 , 0. ) ) ||
+    //     ( UbMath::less(vol0, 0. ) && UbMath::less(vol1, 0. ) && UbMath::less(vol2, 0. ) ) )
+    {
+        return 'f';
+    }
+
+    /* Opposite sign: no intersection between segment and triangle */
+    if (((vol0 > 0.) || (vol1 > 0.) || (vol2 > 0.)) && ((vol0 < 0.) || (vol1 < 0.) || (vol2 < 0.))) {
+        return '0';
+    } else if ((vol0 == 0.0) && (vol1 == 0.0) && (vol2 == 0.0)) {
+        std::cout << vol0 << " " << vol1 << " " << vol2 << std::endl;
+        fprintf(stderr, "Error 1 in SegTriCross\n"), exit(EXIT_FAILURE);
+    }
+
+    /* Two zeros: segment intersects vertex. */
+    else if (((vol0 == 0.) && (vol1 == 0.)) || ((vol0 == 0.) && (vol2 == 0.)) || ((vol1 == 0.) && (vol2 == 0.))) {
+        return 'v';
+    }
+
+    /* One zero: segment intersects edge. */
+    else if ((vol0 == 0.) || (vol1 == 0.) || (vol2 == 0.)) {
+        return 'e';
+    }
+
+    throw UbException(UB_EXARGS, "fprintf( stderr, Error 2 in SegTriCross\n ), exit(EXIT_FAILURE);");
+}
+
+double GbTriangularMesh3D::VolumeSign(GbVector3D &a, GbVector3D &b, GbVector3D &c, GbVector3D &d)
+{
+    double vol;
+    double ax, ay, az, bx, by, bz, cx, cy, cz, dx, dy, dz;
+    double bxdx, bydy, bzdz, cxdx, cydy, czdz;
+
+    ax = a[0];
+    ay = a[1];
+    az = a[2];
+    bx = b[0];
+    by = b[1];
+    bz = b[2];
+    cx = c[0];
+    cy = c[1];
+    cz = c[2];
+    dx = d[0];
+    dy = d[1];
+    dz = d[2];
+
+    bxdx = bx - dx;
+    bydy = by - dy;
+    bzdz = bz - dz;
+    cxdx = cx - dx;
+    cydy = cy - dy;
+    czdz = cz - dz;
+    vol  = (az - dz) * (bxdx * cydy - bydy * cxdx) + (ay - dy) * (bzdz * cxdx - bxdx * czdz) +
+          (ax - dx) * (bydy * czdz - bzdz * cydy);
+
+    // std::cout<< vol<<std::endl;
+    return vol;
+
+    /* The volume should be an integer. */
+    // FIXME: unreachable code
+    // if      ( vol > 0.5 )   return  1;
+    // else if ( vol < -0.5 )  return -1;
+    // else                    return  0;
+}
+
+bool GbTriangularMesh3D::BoxTest(GbTriangle3D *triangle, GbVector3D &PointQ, GbVector3D &PointR)
+{
+    double minX1 = triangle->getX1Minimum();
+    double minX2 = triangle->getX2Minimum();
+    double minX3 = triangle->getX3Minimum();
+
+    double maxX1 = triangle->getX1Maximum();
+    double maxX2 = triangle->getX2Maximum();
+    double maxX3 = triangle->getX3Maximum();
+
+    if ((PointQ.X1() < minX1) && (PointR.X1() < minX1))
+        return false;
+    if ((PointQ.X2() < minX2) && (PointR.X2() < minX2))
+        return false;
+    if ((PointQ.X3() < minX3) && (PointR.X3() < minX3))
+        return false;
+    if ((PointQ.X1() > maxX1) && (PointR.X1() > maxX1))
+        return false;
+    if ((PointQ.X2() > maxX2) && (PointR.X2() > maxX2))
+        return false;
+    if ((PointQ.X3() > maxX3) && (PointR.X3() > maxX3))
+        return false;
+
+    return true;
+}
diff --git a/src/basics/geometry3d/GbTriangularMesh3D.h b/src/basics/geometry3d/GbTriangularMesh3D.h
new file mode 100644
index 0000000000000000000000000000000000000000..61f8a4f4b7a0b9b1122bf78b74129ec5da437f86
--- /dev/null
+++ b/src/basics/geometry3d/GbTriangularMesh3D.h
@@ -0,0 +1,199 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file GbTriangularMesh3D.h
+//! \ingroup geometry3D
+//! \author Konstantin Kutscher, Soeren Textor, Sebastian Geller
+//=======================================================================================
+#ifndef GBTRIANGULARMESH_H
+#define GBTRIANGULARMESH_H
+
+#include <iostream>
+#include <sstream>
+
+#include <geometry3d/GbLine3D.h>
+#include <geometry3d/GbPoint3D.h>
+#include <geometry3d/GbTriangle3D.h>
+#include <geometry3d/GbVector3D.h>
+
+#include <basics/writer/WbWriter.h>
+
+#ifdef CAB_RCF
+#include <3rdParty/rcf/RcfSerializationIncludes.h>
+#endif // CAB_RCF
+
+#include <PointerDefinitions.h>
+
+/*=========================================================================*/
+/* GbTriangularMesh3D                                                                  */
+/*                                                                         */
+/**
+ * This Class provides the triangular meshes.
+ * Note, that up to now no methods for checking consistency are included.
+ * in this context this class describes facettes from an 3D-object !!!
+ */
+class GbTriangularMesh3D : public GbObject3D
+{
+public:
+    enum POINTINOBJECTTEST { RAYCROSSING, HALFSPACE };
+
+    GbTriangularMesh3D();
+    GbTriangularMesh3D(std::string name, std::vector<GbPoint3D *> *nodes, std::vector<GbTriangle3D *> *triangles);
+    GbTriangularMesh3D(std::string name, std::vector<GbTriangle3D *> *triangles);
+    GbTriangularMesh3D(std::string name, std::vector<GbPoint3D *> *nodes, std::vector<GbLine3D *> *edges,
+                       std::vector<GbTriangle3D *> *triangles);
+    ~GbTriangularMesh3D() override;
+    GbTriangularMesh3D *clone() override { throw UbException(UB_EXARGS, "not implemented"); }
+    void finalize() override { throw UbException("GbTriangularMesh3D::finalize() - toDo"); }
+    void setPointInObjectTest(POINTINOBJECTTEST mode) { this->pointinobjecttest = mode; }
+
+    std::string getClassName() { return "GbTriangularMesh3D"; }
+
+    std::string toString() override;
+    // std::string getName();
+    std::vector<GbPoint3D *> *getNodes();
+    std::vector<GbTriangle3D *> *getTriangles();
+    double getX1Centroid() override;
+    double getX2Centroid() override;
+    double getX3Centroid() override;
+    double getX1Minimum() override;
+    double getX1Maximum() override;
+    double getX2Minimum() override;
+    double getX2Maximum() override;
+    double getX3Minimum() override;
+    double getX3Maximum() override;
+
+    void rotate(const double &alpha, const double &beta, const double &gamma) override;
+    void translate(const double &x1, const double &x2, const double &x3) override;
+
+    void calculateValues();
+    void deleteRedundantNodes();
+
+    UbTupleDouble6 calculateMomentOfInertia(double rhoP);
+    UbTupleDouble3 calculateCenterOfGravity();
+
+    double getArea();
+    double getVolume();
+    double getVolumeForRectangle(const double &p1x1, const double &p1x2, const double &p2x1, const double &p2x2);
+    std::vector<GbTriangle3D *> *getTrianglesForRectangle(const double &p1x1, const double &p1x2, const double &p2x1,
+                                                          const double &p2x2);
+    std::vector<GbPoint3D *> *getNodesForRectangle(const double &p1x1, const double &p1x2, const double &p2x1,
+                                                   const double &p2x2);
+    double getX3RangeForRectangle(const double &p1x1, const double &p1x2, const double &p2x1, const double &p2x2);
+    double getX3MinimumForRectangle(const double &p1x1, const double &p1x2, const double &p2x1, const double &p2x2);
+    double getX3MaximumForRectangle(const double &p1x1, const double &p1x2, const double &p2x1, const double &p2x2);
+
+    bool isPointInGbObject3D(const double &x1, const double &x2, const double &x3) override;
+
+    bool isPointInGbObject3D(const double &x1, const double &x2, const double &x3, bool &pointIsOnBoundary) override;
+
+    bool isPointInObject3DHalfSpace(const double &xp, const double &yp,
+                                    const double &zp); // based on Halfspace algorithm
+    bool isPointInObject3DSpherical(const double &xp, const double &yp, const double &zp,
+                                    int numTriangles); // based on Spherical polygon area method
+
+    // should be checked !!!
+    bool isPointInObject3DRayCrossing(const double &xp, const double &yp, const double &zp, int radius, int numVertices,
+                                      int numTriangles); // based on Ray tracing algorithm
+
+    bool InPolyhedron(int F, GbVector3D &q, int radius);
+    void RandomRay(GbVector3D &ray, int radius);
+    char SegPlaneInt(GbTriangle3D *Tri, GbVector3D &q, GbVector3D &r, GbVector3D &p, int *m);
+    int PlaneCoeff(GbTriangle3D *Tri, GbVector3D &Normal, double *D);
+    char InTri3D(GbTriangle3D *T, int m, GbVector3D &p);
+    char InTri2D(GbVector3D Tp[3], GbVector3D &pp);
+    double AreaSign(GbVector3D &a, GbVector3D &b, GbVector3D &c);
+    char SegTriInt(GbTriangle3D *Tri, GbVector3D &q, GbVector3D &r, GbVector3D &p);
+    char InPlane(GbTriangle3D *T, int m, GbVector3D &q, GbVector3D &r, GbVector3D &p);
+    char SegTriCross(GbTriangle3D *T, GbVector3D &q, GbVector3D &r);
+    double VolumeSign(GbVector3D &a, GbVector3D &b, GbVector3D &c, GbVector3D &d);
+    bool BoxTest(GbTriangle3D *triangle, GbVector3D &PointQ, GbVector3D &PointR);
+    // till here !!!
+
+    GbLine3D *createClippedLine3D(GbPoint3D &point1, GbPoint3D &point2) override;
+    std::vector<GbTriangle3D *> getSurfaceTriangleSet() override;
+
+    void writeMesh(std::string filename, WbWriter *writer, bool writeNormals = false);
+    /*======================================================================*/
+    using GbObject3D::isPointInGbObject3D; // Grund: dadurch muss man hier  isPointInGbObject3D(GbPoint3D*) nicht
+                                           // ausprogrammieren, welche sonst hier "ueberdeckt" waere
+
+#ifdef CAB_RCF
+    template <class Archive>
+    void SF_SERIALIZE(Archive &ar)
+    {
+        SF_SERIALIZE_PARENT<GbObject3D>(ar, *this);
+        ar &triangles;
+        if (ArchiveTools::isWriting(ar)) {
+            for (std::size_t t = 0; t < triangles->size(); t++) {
+                nodes->push_back((*triangles)[t]->getPoint(0));
+                nodes->push_back((*triangles)[t]->getPoint(1));
+                nodes->push_back((*triangles)[t]->getPoint(2));
+            }
+        }
+        // ar & nodes; //<- problem redundanz
+        // ar & edges;
+        ar &pointinobjecttest;
+        ar &x1min;
+        ar &x1max;
+        ar &x2min;
+        ar &x2max;
+        ar &x3min;
+        ar &x3max;
+        ar &consistent;
+    }
+#endif // CAB_RCF
+
+protected:
+    std::vector<GbPoint3D *> *nodes;
+    std::vector<GbLine3D *> *edges;
+    std::vector<GbTriangle3D *> *triangles;
+
+private:
+    POINTINOBJECTTEST pointinobjecttest;
+    void init();
+    /*======================================================================*/
+    double x1min;
+    double x1max;
+    double x2min;
+    double x2max;
+    double x3min;
+    double x3max;
+    bool consistent;
+};
+/*=========================================================================*/
+
+#if defined(RCF_USE_SF_SERIALIZATION) && !defined(SWIG)
+#if CAB_RCF <= 903
+SF_SERIALIZE_ENUM(GbTriangularMesh3D::POINTINOBJECTTEST) // bei klassen ausserhalb der klasse;-)
+#endif
+UB_AUTO_RUN_NAMED(SF::registerType<GbTriangularMesh3D>("GbTriangularMesh3D "), SF_GbTriangularMesh3D);
+UB_AUTO_RUN_NAMED((SF::registerBaseAndDerived<GbObject3D, GbTriangularMesh3D>()), SF_GbTriangularMesh3D_BD1);
+#endif // RCF_USE_SF_SERIALIZATION
+
+#endif
diff --git a/src/basics/geometry3d/GbVoxelMatrix3D.cpp b/src/basics/geometry3d/GbVoxelMatrix3D.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c88f1d13104a5312efd161143d40e835f5654571
--- /dev/null
+++ b/src/basics/geometry3d/GbVoxelMatrix3D.cpp
@@ -0,0 +1,996 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file GbVoxelMatrix3D.cpp
+//! \ingroup geometry3D
+//! \author Konstantin Kutscher, Soeren Textor, Sebastian Geller
+//=======================================================================================
+#include <geometry3d/GbVoxelMatrix3D.h>
+
+#include <basics/utilities/UbFileInputASCII.h>
+#include <basics/utilities/UbFileOutputASCII.h>
+#include <basics/utilities/UbMath.h>
+#include <geometry3d/CoordinateTransformation3D.h>
+#include <geometry3d/GbTriangle3D.h>
+
+#include <basics/utilities/UbSystem.h>
+
+#ifdef MC_CUBES
+#include <MarchingCubes/MarchingCubes.h>
+#endif // MC_CUBES
+
+using namespace std;
+
+const float GbVoxelMatrix3D::SOLID = 1.0f;
+const float GbVoxelMatrix3D::FLUID = 0.0f;
+
+/*=======================================================*/
+// Konstruktor
+GbVoxelMatrix3D::GbVoxelMatrix3D(int nx1, int nx2, int nx3, float initVal, double lowerThreshold, double upperThreshold)
+    : GbObject3D(), lowerThreshold(lowerThreshold), upperThreshold(upperThreshold), nodesX1(nx1), nodesX2(nx2),
+      nodesX3(nx3), voxelMatrix(Matrix3D(nx1, nx2, nx3, initVal))
+{
+    this->setName("VoxelMatrix3D");
+}
+/*=======================================================*/
+GbVoxelMatrix3D::GbVoxelMatrix3D() : GbObject3D() { this->setName("VoxelMatrix3D"); }
+/*=======================================================*/
+GbVoxelMatrix3D::GbVoxelMatrix3D(const Matrix3D &voxelMatrix, double lowerThreshold, double upperThreshold)
+    : GbObject3D(), nodesX1((int)voxelMatrix.getNX1()), nodesX2((int)voxelMatrix.getNX2()),
+      nodesX3((int)voxelMatrix.getNX3()), lowerThreshold(lowerThreshold), upperThreshold(upperThreshold),
+      voxelMatrix(voxelMatrix)
+{
+    this->setName("VoxelMatrix3D");
+}
+/*=======================================================*/
+GbVoxelMatrix3D *GbVoxelMatrix3D::clone()
+{
+    GbVoxelMatrix3D *vm = new GbVoxelMatrix3D(voxelMatrix, lowerThreshold, upperThreshold);
+    vm->setVoxelMatrixMininum(minX1, minX2, minX3);
+    vm->setVoxelMatrixDelta(deltaX1, deltaX2, deltaX3);
+    return vm;
+}
+/*=======================================================*/
+void GbVoxelMatrix3D::setCenterCoordinates(const double &x1, const double &x2, const double &x3)
+{
+    this->translate(x1 - getX1Centroid(), x2 - getX2Centroid(), x3 - getX3Centroid());
+}
+/*=======================================================*/
+void GbVoxelMatrix3D::translate(const double &tx1, const double &tx2, const double &tx3)
+{
+    this->minX1 += tx1;
+    this->minX2 += tx2;
+    this->minX3 += tx3;
+    this->notifyObserversObjectChanged();
+}
+/*=======================================================*/
+void GbVoxelMatrix3D::setClosedVoidSpaceToSolid()
+{
+    voxelMatrixTemp = Matrix3D(nodesX1, nodesX2, nodesX3, SOLID);
+    flagMatrix      = CbArray3D<char>(nodesX1, nodesX2, nodesX3, 0);
+
+    for (int x3 = 0; x3 < nodesX3; x3++) {
+        for (int x2 = 0; x2 < nodesX2; x2++) {
+            for (int x1 = 0; x1 < nodesX1; x1++) {
+                if (voxelMatrix(x1, x2, x3) == FLUID) {
+                    UBLOG(logINFO, "setClosedVoidSpaceToSolid:start");
+                    x1Nbr.push_back(x1);
+                    x2Nbr.push_back(x2);
+                    x3Nbr.push_back(x3);
+                    int size = (int)x1Nbr.size();
+                    while (size > 0) {
+                        for (int i = 0; i < size; i++) {
+                            findFluidNeighbor(x1Nbr[i], x2Nbr[i], x3Nbr[i]);
+                        }
+
+                        swap(x1Nbr, x1NbrTemp);
+                        swap(x2Nbr, x2NbrTemp);
+                        swap(x3Nbr, x3NbrTemp);
+
+                        x1NbrTemp.clear();
+                        x2NbrTemp.clear();
+                        x3NbrTemp.clear();
+                        size = (int)x1Nbr.size();
+                    }
+                    UBLOG(logINFO, "setClosedVoidSpaceToSolid:end");
+                    voxelMatrix = voxelMatrixTemp;
+                    return;
+                }
+            }
+        }
+    }
+}
+/*=======================================================*/
+void GbVoxelMatrix3D::findFluidNeighbor(int x1, int x2, int x3)
+{
+    for (int k3 = -1; k3 <= 1; k3++) {
+        for (int k2 = -1; k2 <= 1; k2++) {
+            for (int k1 = -1; k1 <= 1; k1++) {
+                int j1 = x1 + k1;
+                int j2 = x2 + k2;
+                int j3 = x3 + k3;
+                if (j1 >= 0 && j1 < nodesX1 && j2 >= 0 && j2 < nodesX2 && j3 >= 0 && j3 < nodesX3) {
+                    if (voxelMatrix(j1, j2, j3) == FLUID) {
+                        if (flagMatrix(j1, j2, j3) == 0) {
+                            voxelMatrixTemp(j1, j2, j3) = FLUID;
+                            flagMatrix(j1, j2, j3)      = 1;
+                            x1NbrTemp.push_back(j1);
+                            x2NbrTemp.push_back(j2);
+                            x3NbrTemp.push_back(j3);
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+/*=======================================================*/
+void GbVoxelMatrix3D::calculateNumberOfSolidAndFluid()
+{
+    numberOfSolid = 0;
+
+    for (int x3 = 0; x3 < nodesX3; x3++)
+        for (int x2 = 0; x2 < nodesX2; x2++)
+            for (int x1 = 0; x1 < nodesX1; x1++) {
+                if (voxelMatrix(x1, x2, x3) == GbVoxelMatrix3D::SOLID) {
+                    numberOfSolid++;
+                }
+            }
+
+    numberOfFluid = (long)nodesX1 * (long)nodesX2 * (long)nodesX3 - numberOfSolid;
+}
+/*=======================================================*/
+long GbVoxelMatrix3D::getNumberOfSolid() { return numberOfSolid; }
+/*=======================================================*/
+long GbVoxelMatrix3D::getNumberOfFluid() { return numberOfFluid; }
+/*=======================================================*/
+double GbVoxelMatrix3D::getIntersectionRaytraceFactor(const double &x1, const double &x2, const double &x3,
+                                                      const double &rx1, const double &rx2, const double &rx3)
+{
+    if (!((UbMath::equal(rx1, 0.0) || UbMath::equal(fabs(rx1), 1.0) ||
+           UbMath::equal(fabs(rx1), UbMath::one_over_sqrt2) || UbMath::equal(fabs(rx1), UbMath::one_over_sqrt3)) &&
+          (UbMath::equal(rx2, 0.0) || UbMath::equal(fabs(rx2), 1.0) ||
+           UbMath::equal(fabs(rx2), UbMath::one_over_sqrt2) || UbMath::equal(fabs(rx2), UbMath::one_over_sqrt3)) &&
+          (UbMath::equal(rx3, 0.0) || UbMath::equal(fabs(rx3), 1.0) ||
+           UbMath::equal(fabs(rx3), UbMath::one_over_sqrt2) || UbMath::equal(fabs(rx3), UbMath::one_over_sqrt3)))) {
+        throw UbException(UB_EXARGS, "nur fuer diskrete Boltzmannrichungen implementiert!!!");
+    }
+
+    // nachbarindex ermitteln
+    int ndx1 = 0, ndx2 = 0, ndx3 = 0;
+    if (UbMath::greater(rx1, 0.0))
+        ndx1 = 1;
+    else if (UbMath::less(rx1, 0.0))
+        ndx1 = -1;
+    if (UbMath::greater(rx2, 0.0))
+        ndx2 = 1;
+    else if (UbMath::less(rx2, 0.0))
+        ndx2 = -1;
+    if (UbMath::greater(rx3, 0.0))
+        ndx3 = 1;
+    else if (UbMath::less(rx3, 0.0))
+        ndx3 = -1;
+
+    int nix1 = UbMath::integerRounding((x1 - minX1) / deltaX1) + ndx1;
+    int nix2 = UbMath::integerRounding((x2 - minX2) / deltaX2) + ndx2;
+    int nix3 = UbMath::integerRounding((x3 - minX3) / deltaX3) + ndx3;
+
+    // test ob nachbar solid
+    if (nix1 >= 0 && nix2 >= 0 && nix3 >= 0 && nix1 < (int)voxelMatrix.getNX1() && nix2 < (int)voxelMatrix.getNX2() &&
+        nix3 < (int)voxelMatrix.getNX3()) {
+        if (UbMath::equal(voxelMatrix(nix1, nix2, nix3), SOLID)) {
+            // return halber abstand der beiden knoten
+            return 0.5 * sqrt((ndx1 * deltaX1) * (ndx1 * deltaX1) + (ndx2 * deltaX2) * (ndx2 * deltaX2) +
+                              (ndx3 * deltaX3) * (ndx3 * deltaX3));
+        }
+    }
+
+    return 0.0;
+}
+/*=======================================================*/
+bool GbVoxelMatrix3D::isPointInGbObject3D(const double &x1p, const double &x2p, const double &x3p)
+{
+    int ix1 = UbMath::integerRounding((x1p - minX1) / deltaX1);
+    int ix2 = UbMath::integerRounding((x2p - minX2) / deltaX2);
+    int ix3 = UbMath::integerRounding((x3p - minX3) / deltaX3);
+
+    if (ix1 >= 0 && ix2 >= 0 && ix3 >= 0 && ix1 < (int)voxelMatrix.getNX1() && ix2 < (int)voxelMatrix.getNX2() &&
+        ix3 < (int)voxelMatrix.getNX3()) {
+        if (UbMath::equal(voxelMatrix(ix1, ix2, ix3), SOLID))
+            return true;
+    }
+    return false;
+}
+/*=======================================================*/
+bool GbVoxelMatrix3D::isPointInGbObject3D(const double &x1p, const double &x2p, const double &x3p,
+                                          bool &pointIsOnBoundary)
+{
+    pointIsOnBoundary = false;
+
+    return isPointInGbObject3D(x1p, x2p, x3p);
+}
+/*=======================================================*/
+bool GbVoxelMatrix3D::isCellInsideGbObject3D(const double & /*x1p1*/, const double & /*x2p1*/, const double & /*x3p1*/,
+                                             const double & /*x1p2*/, const double & /*x2p2*/, const double & /*x3p2*/)
+{
+    return false;
+    // FIXME: unreachable cide
+    ////dass haengt von der Konfigration ab, aber meist ist der Block groesser wie etliche Poren ...
+
+    //   //indizes ermitteln
+    // int startix1 = (int)std::floor((x1p1-minX1)/deltaX1+1E-13);
+    // int startix2 = (int)std::floor((x2p1-minX2)/deltaX2+1E-13);
+    // int startix3 = (int)std::floor((x3p1-minX3)/deltaX3+1E-13);
+
+    // if (startix1<0) return false;
+    // if (startix2<0) return false;
+    // if (startix3<0) return false;
+
+    // int maxiX1 = (int)voxelMatrix.getNX1()-1;
+    // int maxiX2 = (int)voxelMatrix.getNX2()-1;
+    // int maxiX3 = (int)voxelMatrix.getNX3()-1;
+
+    // int endix1 = (int)std::ceil((x1p2-minX1)/deltaX1-1E-13);
+    // int endix2 = (int)std::ceil((x2p2-minX2)/deltaX2-1E-13);
+    // int endix3 = (int)std::ceil((x3p2-minX3)/deltaX3-1E-13);
+
+    // if (endix1>maxiX1) return false;
+    // if (endix2>maxiX2) return false;
+    // if (endix3>maxiX3) return false;
+
+    // for (int ix3 = startix3; ix3<=endix3; ix3++)
+    //   for (int ix2 = startix2; ix2<=endix2; ix2++)
+    //      for (int ix1 = startix1; ix1<=endix1; ix1++)
+    //         if (UbMath::equal(voxelMatrix(ix1, ix2, ix3), FLUID))
+    //            return false;
+    // return true;
+}
+/*=======================================================*/
+bool GbVoxelMatrix3D::isCellCuttingGbObject3D(const double &x1a, const double &x2a, const double &x3a,
+                                              const double &x1b, const double &x2b, const double &x3b)
+// Merksatz: cell oder deren Volumen schneidet oder beinhaltet komplette oder Teile der CuboidUmrandung
+// returns true:
+//  - cell cuts  GbVoxelMatrix3D
+//  - cell boxes GbVoxelMatrix3D
+// returns false:
+//  - cell completely inside GbVoxelMatrix3D
+//  - cell und cuboid3D haben kein gemeinsames Volumen
+{
+    // erstmal die dumm Loesung
+    if (!(this->isCellInsideGbObject3D(x1a, x2a, x3a, x1b, x2b, x3b)) &&
+        this->isCellInsideOrCuttingGbObject3D(x1a, x2a, x3a, x1b, x2b, x3b)) {
+        return true;
+    }
+
+    return false;
+}
+/*=======================================================*/
+bool GbVoxelMatrix3D::isCellInsideOrCuttingGbObject3D(const double &x1a, const double &x2a, const double &x3a,
+                                                      const double &x1b, const double &x2b, const double &x3b)
+// returns true:
+//  - cell completely inside cuboid3D ( = cuboid3D boxes cell)
+//  - cell cuts  cuboid3D
+//  - cell boxes cuboid3D
+// returns false:
+//  - cell und cuboid3D haben kein gemeinsames Volumen
+{
+    // simpler check, da unser GbCuboid3D ein AABB is:
+    //  anfA        midA         endA             anfB    midB    endB
+    //   |            x<-- dxA -->|                 |<-dxB->x       |
+    //                |<----------------- T --------------->|
+    // ist |T| <= dxA + dxB -> overlap!
+
+    if (UbMath::lessEqual(std::fabs(this->getX1Centroid() - 0.5 * (x1b + x1a) /*Tx1*/),
+                          0.5 * (this->getLengthX1() + std::fabs(x1b - x1a) /*dx1A+dx1B*/))
+
+        && UbMath::lessEqual(std::fabs(this->getX2Centroid() - 0.5 * (x2b + x2a) /*Tx2*/),
+                             0.5 * (this->getLengthX2() + std::fabs(x2b - x2a) /*dx2A+dx2B*/))
+
+        && UbMath::lessEqual(std::fabs(this->getX3Centroid() - 0.5 * (x3b + x3a) /*Tx3*/),
+                             0.5 * (this->getLengthX3() + std::fabs(x3b - x3a) /*dx3A+dx3B*/))) {
+        return true;
+    }
+
+    return false;
+}
+/*=======================================================*/
+vector<GbTriangle3D *> GbVoxelMatrix3D::getSurfaceTriangleSet()
+{
+    vector<GbTriangle3D *> triangles;
+
+#ifdef MC_CUBES
+    // MC
+    typedef McCubes::Matrix3DWrapper<Matrix3D> McMatrixWrapper;
+    typedef McCubes::MarchingCubes<McMatrixWrapper> McMarchingCubesGenerator;
+    typedef McMarchingCubesGenerator::Vertex McVertex;
+    typedef McMarchingCubesGenerator::Triangle McTriangle;
+
+    McMatrixWrapper wrapper(
+        &voxelMatrix); //,0,0,0,voxelMatrix.getNX1()-1,voxelMatrix.getNX2()-1,voxelMatrix.getNX3()-1);
+    McMarchingCubesGenerator mc(wrapper);
+
+    mc.init_all();
+    mc.run(0.5);
+
+    // const int   nofVertices  = mc.nverts();
+    const int nofTriangles = mc.ntrigs();
+
+    McVertex *mcvertices    = mc.vertices();
+    McTriangle *mctriangles = mc.triangles();
+
+    for (int t = 0; t < nofTriangles; t++) {
+        triangles.push_back(
+            new GbTriangle3D(new GbPoint3D(minX1 + deltaX1 * (mcvertices[mctriangles[t].v1].x /*-1*/),
+                                           minX2 + deltaX2 * (mcvertices[mctriangles[t].v1].y /*-1*/),
+                                           minX3 + deltaX3 * (mcvertices[mctriangles[t].v1].z /*-1*/)),
+                             new GbPoint3D(minX1 + deltaX1 * (mcvertices[mctriangles[t].v2].x /*-1*/),
+                                           minX2 + deltaX2 * (mcvertices[mctriangles[t].v2].y /*-1*/),
+                                           minX3 + deltaX3 * (mcvertices[mctriangles[t].v2].z /*-1*/)),
+                             new GbPoint3D(minX1 + deltaX1 * (mcvertices[mctriangles[t].v3].x /*-1*/),
+                                           minX2 + deltaX2 * (mcvertices[mctriangles[t].v3].y /*-1*/),
+                                           minX3 + deltaX3 * (mcvertices[mctriangles[t].v3].z /*-1*/))));
+    }
+#else
+    cerr
+        << "vector<GbTriangle3D*> GbVoxelMatrix3D::getSurfaceTriangleSet() - benoetigt MARCHING_CUBE paket aus 3rdParty"
+        << endl;
+#endif // MC_CUBES
+
+    return triangles;
+}
+/*=======================================================*/
+void GbVoxelMatrix3D::addSurfaceTriangleSet(vector<UbTupleFloat3> & /*nodes*/, vector<UbTupleInt3> & /*triangles*/)
+{
+    UBLOG(logINFO, " GbVoxelMatrix3D addSurfaceTriangleSet start")
+    if (!this->addSurfaceTriangleSetFlag) {
+        UBLOG(logINFO, " GbVoxelMatrix3D addSurfaceTriangleSet end without TriangleSetCreation")
+        return;
+    }
+#ifdef MC_CUBES
+    UBLOG(logDEBUG1, " GbVoxelMatrix3D addSurfaceTriangleSet MC defined")
+
+    typedef McCubes::Matrix3DWrapper<Matrix3D> McMatrixWrapper;
+    typedef McCubes::MarchingCubes<McMatrixWrapper> McMarchingCubesGenerator;
+    typedef McMarchingCubesGenerator::Vertex McVertex;
+    typedef McMarchingCubesGenerator::Triangle McTriangle;
+
+    // MC
+    { // standard( fuer voxelmatrix)
+        McMatrixWrapper wrapper(&voxelMatrix);
+        McMarchingCubesGenerator mc(wrapper);
+
+        UBLOG(logDEBUG1, " GbVoxelMatrix3D addSurfaceTriangleSet McMarchingCubesGenerator")
+
+        UBLOG(logDEBUG1, " GbVoxelMatrix3D addSurfaceTriangleSet mc.init")
+        mc.init_all();
+        UBLOG(logDEBUG1, " GbVoxelMatrix3D addSurfaceTriangleSet mc.run")
+        mc.run(0.5);
+        UBLOG(logDEBUG1, " GbVoxelMatrix3D addSurfaceTriangleSet mc.run done")
+
+        const int nofVertices  = mc.nverts();
+        const int nofTriangles = mc.ntrigs();
+
+        McVertex *mcvertices    = mc.vertices();
+        McTriangle *mctriangles = mc.triangles();
+
+        UBLOG(logDEBUG1, " GbVoxelMatrix3D node tuple")
+        for (int n = 0; n < nofVertices; n++)
+            nodes.push_back(makeUbTuple(
+                (float)(minX1 + deltaX1 * (mcvertices[n].x /*-1*/)), // Anm: kein -1, da man durch manipulation der
+                                                                     // indices die dreiecke um eins versetzt bekommt
+                (float)(minX2 + deltaX2 * (mcvertices[n].y /*-1*/)),
+                (float)(minX3 + deltaX3 * (mcvertices[n].z /*-1*/))));
+        UBLOG(logDEBUG1, " GbVoxelMatrix3D triangles tuple")
+        for (int t = 0; t < nofTriangles; t++)
+            triangles.push_back(makeUbTuple(mctriangles[t].v1, mctriangles[t].v2, mctriangles[t].v3));
+        UBLOG(logDEBUG1, " GbVoxelMatrix3D triangles tuple done")
+    }
+
+    // false - das scheint probleme bei der asphaltprobe zu machen 1500x600x100
+    // da lief es bis C - evtl. memory voll
+    if (false) // extension... um die raender koerrekt abzubilden muesste man eine dummy FLUID reihe um
+    {          // die matrix legen( lsg1: temp matrix mit 2 reihen pro richtung mehr -> zuviel speicher, 500^3 = 500MB
+      // lsg2: fuer jede flaeche eine dummy matrix -> wie folgt:
+        int nx1 = (int)voxelMatrix.getNX1();
+        int nx2 = (int)voxelMatrix.getNX2();
+        int nx3 = (int)voxelMatrix.getNX3();
+        UBLOG(logINFO, " A ")
+        Matrix3D tmpX1Min(2, nx2 + 2, nx3 + 2, FLUID);
+        Matrix3D tmpX1Max(2, nx2 + 2, nx3 + 2, FLUID);
+        for (int x3 = 0; x3 < nx3; x3++)
+            for (int x2 = 0; x2 < nx2; x2++) {
+                tmpX1Min(1, x2 + 1, x3 + 1) = voxelMatrix(0, x2, x3);
+                tmpX1Max(0, x2 + 1, x3 + 1) = voxelMatrix(nx1 - 1, x2, x3);
+            }
+        UBLOG(logINFO, " B")
+        Matrix3D tmpX2Min(nx1 + 2, 2, nx3 + 2, FLUID);
+        Matrix3D tmpX2Max(nx1 + 2, 2, nx3 + 2, FLUID);
+        for (int x3 = 0; x3 < nx3; x3++)
+            for (int x1 = 0; x1 < nx1; x1++) {
+                tmpX2Min(x1 + 1, 1, x3 + 1) = voxelMatrix(x1, 0, x3);
+                tmpX2Max(x1 + 1, 0, x3 + 1) = voxelMatrix(x1, nx2 - 1, x3);
+            }
+        UBLOG(logINFO, " C ")
+        Matrix3D tmpX3Min(nx1 + 2, nx3 + 2, 2, FLUID);
+        Matrix3D tmpX3Max(nx1 + 2, nx3 + 2, 2, FLUID);
+        for (int x2 = 0; x2 < nx2; x2++)
+            for (int x1 = 0; x1 < nx1; x1++) {
+                tmpX3Min(x1 + 1, x2 + 1, 1) = voxelMatrix(x1, x2, 0);
+                tmpX3Max(x1 + 1, x2 + 1, 0) = voxelMatrix(x1, x2, nx3 - 1);
+            }
+        UBLOG(logINFO, " D")
+        Matrix3D *matrices[] = { &tmpX1Min, &tmpX1Max, &tmpX2Min, &tmpX2Max, &tmpX3Min, &tmpX3Max };
+        int dx1[]            = { -1, nx1 - 1, -1, -1, -1, -1 };
+        int dx2[]            = { -1, -1, -1, nx2 - 1, -1, -1 };
+        int dx3[]            = { -1, -1, -1, -1, -1, nx3 - 1 };
+        UBLOG(logINFO, " E")
+        for (int i = 0; i < 6; i++) {
+            McMatrixWrapper wrapper(matrices[i]);
+            McMarchingCubesGenerator mc(wrapper);
+
+            mc.init_all();
+            mc.run(0.5);
+
+            McVertex *mcvertices    = mc.vertices();
+            McTriangle *mctriangles = mc.triangles();
+
+            int deltaNodeNr = (int)nodes.size();
+            UBLOG(logINFO, " GbVoxelMatrix3D node tuple")
+            for (int n = 0; n < mc.nverts(); n++)
+                nodes.push_back(
+                    makeUbTuple((float)(minX1 + deltaX1 * (mcvertices[n].x +
+                                                           dx1[i])), // Anm: kein -1, da man durch manipulation der
+                                                                     // indices die dreiecke um eins versetzt bekommt
+                                (float)(minX2 + deltaX2 * (mcvertices[n].y + dx2[i])),
+                                (float)(minX3 + deltaX3 * (mcvertices[n].z + dx3[i]))));
+            for (int t = 0; t < mc.ntrigs(); t++)
+                triangles.push_back(makeUbTuple(deltaNodeNr + mctriangles[t].v1, deltaNodeNr + mctriangles[t].v2,
+                                                deltaNodeNr + mctriangles[t].v3));
+        }
+    }
+#else
+    cerr << "void GbVoxelMatrix3D.addSurfaceTriangleSet  - benoetigt MARCHING_CUBE paket aus 3rdParty" << endl;
+#endif // MC_CUBES
+
+    UBLOG(logINFO, " GbVoxelMatrix3D addSurfaceTriangleSet end")
+}
+/*=======================================================*/
+string GbVoxelMatrix3D::toString() { return "GbVoxelMatrix3D"; }
+/*=======================================================*/
+void GbVoxelMatrix3D::readMatrixFromVtiASCIIFile(std::string filename)
+
+{
+    // UBLOG(logINFO,"  - create GbVoxelMatrix3D");
+    UbFileInputASCII in(filename);
+    // ifstream in(filename.c_str(), ios::binary);
+    if (!in)
+        throw UbException(UB_EXARGS, "could not open file " + filename);
+    in.readLine();
+    in.readLine();
+    in.readLine();
+    in.readLine();
+    in.readLine();
+
+    voxelMatrix = Matrix3D(nodesX1, nodesX2, nodesX3, GbVoxelMatrix3D::FLUID);
+
+    // UBLOG(logINFO,"  - init values");
+    int val;
+    for (int x3 = 0; x3 < nodesX3; x3++)
+        for (int x2 = 0; x2 < nodesX2; x2++)
+            for (int x1 = 0; x1 < nodesX1; x1++) {
+                val = in.readInteger();
+                // if( !UbMath::equal(val, 0.0f) )
+                // if( UbMath::greater(val, threshold) )
+                if ((double)val >= lowerThreshold && (double)val <= upperThreshold) {
+                    (voxelMatrix)(x1, x2, x3) = GbVoxelMatrix3D::SOLID;
+                }
+            }
+    // UBLOG(logINFO,"  - create GbVoxelMatrix3D done");
+}
+
+//////////////////////////////////////////////////////////////////////////
+void GbVoxelMatrix3D::rotate90aroundX(double /*cX1*/, double cX2, double cX3)
+{
+    //   double tempMinPunktX1 = minX1-cX1;
+    double tempMinPunktX2 = minX2 - cX2;
+    double tempMinPunktX3 = getX3Maximum() - cX3;
+
+    //   double tempMinPunktX1tf = tempMinPunktX1;
+    double tempMinPunktX2tf = -tempMinPunktX3;
+    double tempMinPunktX3tf = tempMinPunktX2;
+
+    //   double minX1_temp = tempMinPunktX1tf+cX1;
+    double minX2_temp = tempMinPunktX2tf + cX2;
+    double minX3_temp = tempMinPunktX3tf + cX3;
+
+    minX2 = minX2_temp;
+    minX3 = minX3_temp;
+
+    int nx1 = (int)voxelMatrix.getNX1();
+    int nx2 = (int)voxelMatrix.getNX2();
+    int nx3 = (int)voxelMatrix.getNX3();
+
+    int nx1_new = nx1;
+    int nx2_new = nx3;
+    int nx3_new = nx2;
+
+    double delta_temp = deltaX2;
+    deltaX2           = deltaX3;
+    deltaX3           = delta_temp;
+
+    GbVoxelMatrix3D::Matrix3D voxelMatrix_temp(nx1_new, nx2_new, nx3_new);
+
+    for (int x3 = 0; x3 < nx3; x3++) {
+        for (int x2 = 0; x2 < nx2; x2++) {
+            for (int x1 = 0; x1 < nx1; x1++) {
+                voxelMatrix_temp(x1, nx3 - x3 - 1, x2) = this->voxelMatrix(x1, x2, x3);
+            }
+        }
+    }
+    std::swap(this->voxelMatrix, voxelMatrix_temp);
+}
+//////////////////////////////////////////////////////////////////////////
+void GbVoxelMatrix3D::rotate90aroundX()
+{
+    double cX1 = this->getX1Centroid();
+    double cX2 = this->getX2Centroid();
+    double cX3 = this->getX3Centroid();
+
+    rotate90aroundX(cX1, cX2, cX3);
+}
+//////////////////////////////////////////////////////////////////////////
+void GbVoxelMatrix3D::rotate90aroundY(double cX1, double /*cX2*/, double cX3)
+{
+    double tempMinPunktX1 = getX1Maximum() - cX1;
+    //   double tempMinPunktX2 = minX2-cX2;
+    double tempMinPunktX3 = minX3 - cX3;
+
+    double tempMinPunktX1tf = tempMinPunktX3;
+    //   double tempMinPunktX2tf = tempMinPunktX2;
+    double tempMinPunktX3tf = -tempMinPunktX1;
+
+    double minX1_temp = tempMinPunktX1tf + cX1;
+    //   double minX2_temp = tempMinPunktX2tf+cX2;
+    double minX3_temp = tempMinPunktX3tf + cX3;
+
+    minX1 = minX1_temp;
+    minX3 = minX3_temp;
+
+    int nx1 = (int)voxelMatrix.getNX1();
+    int nx2 = (int)voxelMatrix.getNX2();
+    int nx3 = (int)voxelMatrix.getNX3();
+
+    int nx1_new = nx3;
+    int nx2_new = nx2;
+    int nx3_new = nx1;
+
+    double delta_temp = deltaX1;
+    deltaX1           = deltaX3;
+    deltaX3           = delta_temp;
+
+    GbVoxelMatrix3D::Matrix3D voxelMatrix_temp(nx1_new, nx2_new, nx3_new);
+
+    for (int x3 = 0; x3 < nx3; x3++) {
+        for (int x2 = 0; x2 < nx2; x2++) {
+            for (int x1 = 0; x1 < nx1; x1++) {
+                voxelMatrix_temp(x3, x2, nx1 - x1 - 1) = this->voxelMatrix(x1, x2, x3);
+            }
+        }
+    }
+    std::swap(this->voxelMatrix, voxelMatrix_temp);
+}
+//////////////////////////////////////////////////////////////////////////
+void GbVoxelMatrix3D::rotate90aroundY()
+{
+    double cX1 = this->getX1Centroid();
+    double cX2 = this->getX2Centroid();
+    double cX3 = this->getX3Centroid();
+
+    rotate90aroundY(cX1, cX2, cX3);
+}
+//////////////////////////////////////////////////////////////////////////
+void GbVoxelMatrix3D::rotate90aroundZ(double cX1, double cX2, double /*cX3*/)
+{
+    double tempMinPunktX1 = minX1 - cX1;
+    double tempMinPunktX2 = getX2Maximum() - cX2;
+    //   double tempMinPunktX3 = minX3-cX3;
+
+    double tempMinPunktX1tf = -tempMinPunktX2;
+    double tempMinPunktX2tf = tempMinPunktX1;
+    //   double tempMinPunktX3tf = tempMinPunktX3;
+
+    double minX1_temp = tempMinPunktX1tf + cX1;
+    double minX2_temp = tempMinPunktX2tf + cX2;
+    //   double minX3_temp = tempMinPunktX3tf+cX3;
+
+    minX1 = minX1_temp;
+    minX2 = minX2_temp;
+
+    int nx1 = (int)voxelMatrix.getNX1();
+    int nx2 = (int)voxelMatrix.getNX2();
+    int nx3 = (int)voxelMatrix.getNX3();
+
+    int nx1_new = nx2;
+    int nx2_new = nx1;
+    int nx3_new = nx3;
+
+    double delta_temp = deltaX1;
+    deltaX1           = deltaX2;
+    deltaX2           = delta_temp;
+
+    GbVoxelMatrix3D::Matrix3D voxelMatrix_temp(nx1_new, nx2_new, nx3_new);
+
+    for (int x3 = 0; x3 < nx3; x3++) {
+        for (int x2 = 0; x2 < nx2; x2++) {
+            for (int x1 = 0; x1 < nx1; x1++) {
+                voxelMatrix_temp(nx2 - x2 - 1, x1, x3) = this->voxelMatrix(x1, x2, x3);
+            }
+        }
+    }
+    std::swap(this->voxelMatrix, voxelMatrix_temp);
+}
+//////////////////////////////////////////////////////////////////////////
+void GbVoxelMatrix3D::rotate90aroundZ()
+{
+    double cX1 = this->getX1Centroid();
+    double cX2 = this->getX2Centroid();
+    double cX3 = this->getX3Centroid();
+
+    rotate90aroundZ(cX1, cX2, cX3);
+}
+//////////////////////////////////////////////////////////////////////////
+void GbVoxelMatrix3D::mirrorX()
+{
+    int nx1 = (int)voxelMatrix.getNX1();
+    int nx2 = (int)voxelMatrix.getNX2();
+    int nx3 = (int)voxelMatrix.getNX3();
+
+    GbVoxelMatrix3D::Matrix3D voxelMatrix_temp(nx1, nx2, nx3);
+
+    for (int x3 = 0; x3 < nx3; x3++) {
+        for (int x2 = 0; x2 < nx2; x2++) {
+            for (int x1 = 0; x1 < nx1; x1++) {
+                voxelMatrix_temp(nx1 - x1 - 1, x2, x3) = this->voxelMatrix(x1, x2, x3);
+            }
+        }
+    }
+    std::swap(this->voxelMatrix, voxelMatrix_temp);
+}
+//////////////////////////////////////////////////////////////////////////
+void GbVoxelMatrix3D::mirrorY()
+{
+    int nx1 = (int)voxelMatrix.getNX1();
+    int nx2 = (int)voxelMatrix.getNX2();
+    int nx3 = (int)voxelMatrix.getNX3();
+
+    GbVoxelMatrix3D::Matrix3D voxelMatrix_temp(nx1, nx2, nx3);
+
+    for (int x3 = 0; x3 < nx3; x3++) {
+        for (int x2 = 0; x2 < nx2; x2++) {
+            for (int x1 = 0; x1 < nx1; x1++) {
+                voxelMatrix_temp(x1, nx2 - x2 - 1, x3) = this->voxelMatrix(x1, x2, x3);
+            }
+        }
+    }
+    std::swap(this->voxelMatrix, voxelMatrix_temp);
+}
+//////////////////////////////////////////////////////////////////////////
+void GbVoxelMatrix3D::mirrorZ()
+{
+    int nx1 = (int)voxelMatrix.getNX1();
+    int nx2 = (int)voxelMatrix.getNX2();
+    int nx3 = (int)voxelMatrix.getNX3();
+
+    GbVoxelMatrix3D::Matrix3D voxelMatrix_temp(nx1, nx2, nx3);
+
+    for (int x3 = 0; x3 < nx3; x3++) {
+        for (int x2 = 0; x2 < nx2; x2++) {
+            for (int x1 = 0; x1 < nx1; x1++) {
+                voxelMatrix_temp(x1, x2, nx3 - x3 - 1) = this->voxelMatrix(x1, x2, x3);
+            }
+        }
+    }
+    std::swap(this->voxelMatrix, voxelMatrix_temp);
+}
+//////////////////////////////////////////////////////////////////////////
+void GbVoxelMatrix3D::rotateAroundY(double theta)
+{
+    int nx1 = (int)voxelMatrix.getNX1();
+    int nx2 = (int)voxelMatrix.getNX2();
+    int nx3 = (int)voxelMatrix.getNX3();
+
+    GbVoxelMatrix3D::Matrix3D voxelMatrix_temp(nx1, nx2, nx3, FLUID);
+
+    for (int x3 = 0; x3 < nx3; x3++) {
+        for (int x2 = 0; x2 < nx2; x2++) {
+            for (int x1 = 0; x1 < nx1; x1++) {
+                if (voxelMatrix(x1, x2, x3) == SOLID) {
+                    double rcX1 = minX1 + deltaX1 * x1;
+                    double rcX3 = minX3 + deltaX3 * x3;
+
+                    double nrcX1 = cos(theta) * rcX1 + sin(theta) * rcX3;
+                    double nrcX3 = -sin(theta) * rcX1 + cos(theta) * rcX3;
+
+                    int newX1 = UbMath::integerRounding((nrcX1 - minX1) / deltaX1);
+                    int newX2 = x2;
+                    int newX3 = UbMath::integerRounding((nrcX3 - minX3) / deltaX3);
+
+                    if (newX1 > 0 && newX3 > 0 && newX1 < nx1 && newX3 < nx3) {
+                        voxelMatrix_temp(newX1, newX2, newX3) = voxelMatrix(x1, x2, x3);
+                    }
+
+                    // int ix1, ix2, ix3;
+                    // double ixx1 = (abs(nrcX1-minX1)/deltaX1);
+                    // ix2 = x2;
+                    // double ixx3 = (abs(nrcX3-minX3)/deltaX3);
+                    // if (ixx1-(int)ixx1>.9999999999) ix1 = (int)ixx1+1; else ix1 = (int)ixx1;
+                    ////if (ixx2-(int)ixx2>.9999999999) ix2 = (int)ixx2+1; else ix2 = (int)ixx2;
+                    // if (ixx3-(int)ixx3>.9999999999) ix3 = (int)ixx3+1; else ix3 = (int)ixx3;
+
+                    // if (ix1>=0 && ix3>=0 && ix1<nx1 && ix3<nx3)
+                    //{
+                    //   voxelMatrix_temp(ix1, ix2, ix3) = voxelMatrix(x1, x2, x3);
+                    //}
+                }
+            }
+        }
+    }
+    std::swap(voxelMatrix, voxelMatrix_temp);
+
+    for (int x3 = 0; x3 < nx3; x3++)
+        for (int x2 = 0; x2 < nx2; x2++)
+            for (int x1 = 0; x1 < nx1; x1++) {
+                int count = 0;
+                for (int k3 = -1; k3 <= 1; k3++)
+                    for (int k1 = -1; k1 <= 1; k1++) {
+                        int j1 = x1 + k1;
+                        int j3 = x3 + k3;
+                        if (j1 >= 0 && j3 >= 0 && j1 < nx1 && j3 < nx3) {
+                            if (voxelMatrix(j1, x2, j3) == SOLID) {
+                                count++;
+                            }
+                        }
+                    }
+                if (count == 8) {
+                    voxelMatrix(x1, x2, x3) = SOLID;
+                }
+            }
+}
+//////////////////////////////////////////////////////////////////////////
+void GbVoxelMatrix3D::writeToLegacyVTKASCII(const std::string &fileName)
+{
+    string fn = fileName + ".ascii.vtk";
+
+    FILE *file;
+    file = fopen(fn.c_str(), "w");
+
+    if (file == NULL) {
+        std::string pathf = UbSystem::getPathFromString(fn);
+        if (fn.size() > 0) {
+            UbSystem::makeDirectory(pathf);
+            file = fopen(fn.c_str(), "w");
+        }
+        if (file == NULL)
+            throw UbException(UB_EXARGS, "can not open " + fn);
+    }
+
+    if (file == NULL)
+        throw UbException(UB_EXARGS, "can not open " + fn);
+
+    int nx1 = (int)voxelMatrix.getNX1();
+    int nx2 = (int)voxelMatrix.getNX2();
+    int nx3 = (int)voxelMatrix.getNX3();
+
+    int nn = nx1 * nx2 * nx3;
+
+    fprintf(file, "# vtk DataFile Version 2.0\n");
+    fprintf(file, "vtk output\n");
+    fprintf(file, "ASCII\n");
+    fprintf(file, "DATASET STRUCTURED_POINTS\n");
+    fprintf(file, "DIMENSIONS %d %d %d\n", nx1, nx2, nx3);
+    fprintf(file, "ORIGIN %g %g %g\n", minX1, minX2, minX3);
+    fprintf(file, "SPACING %g %g %g\n", deltaX1, deltaX2, deltaX3);
+    fprintf(file, "POINT_DATA %d\n", nn);
+    fprintf(file, "SCALARS Geo float\n");
+    fprintf(file, "LOOKUP_TABLE default\n");
+
+    for (int k = 0; k < nx3; k++) {
+        for (int j = 0; j < nx2; j++) {
+            for (int i = 0; i < nx1; i++) {
+                fprintf(file, "%g ", voxelMatrix(i, j, k));
+            }
+        }
+    }
+
+    fprintf(file, "\n");
+
+    fclose(file);
+}
+//////////////////////////////////////////////////////////////////////////
+void GbVoxelMatrix3D::writeToLegacyVTKBinary(const std::string &fileName)
+{
+    string fn = fileName + ".binary.vtk";
+
+    FILE *file;
+    file = fopen(fn.c_str(), "w");
+
+    if (file == NULL) {
+        std::string pathf = UbSystem::getPathFromString(fn);
+        if (fn.size() > 0) {
+            UbSystem::makeDirectory(pathf);
+            file = fopen(fn.c_str(), "w");
+        }
+        if (file == NULL)
+            throw UbException(UB_EXARGS, "can not open " + fn);
+    }
+
+    int nx1 = (int)voxelMatrix.getNX1();
+    int nx2 = (int)voxelMatrix.getNX2();
+    int nx3 = (int)voxelMatrix.getNX3();
+
+    int nn = nx1 * nx2 * nx3;
+
+    char LF = 0x0A;
+
+    fprintf(file, "# vtk DataFile Version 3.0\n");
+    fprintf(file, "vtk output\n");
+    fprintf(file, "BINARY\n");
+    fprintf(file, "DATASET STRUCTURED_POINTS\n");
+    fprintf(file, "DIMENSIONS %d %d %d\n", nx1, nx2, nx3);
+    fprintf(file, "ORIGIN %g %g %g\n", minX1, minX2, minX3);
+    fprintf(file, "SPACING %g %g %g\n", deltaX1, deltaX2, deltaX3);
+    fprintf(file, "POINT_DATA %d\n", nn);
+    fprintf(file, "SCALARS Geo float\n");
+    fprintf(file, "LOOKUP_TABLE default");
+    fclose(file);
+
+    GbVoxelMatrix3D::Matrix3D voxelMatrix_temp(nx1, nx2, nx3);
+
+    if (UbSystem::isLittleEndian()) {
+        for (int x3 = 0; x3 < nx3; x3++) {
+            for (int x2 = 0; x2 < nx2; x2++) {
+                for (int x1 = 0; x1 < nx1; x1++) {
+                    float tmp = this->voxelMatrix(x1, x2, x3);
+                    UbSystem::swapByteOrder((unsigned char *)(&(tmp)), sizeof(float));
+                    voxelMatrix_temp(x1, x2, x3) = tmp;
+                }
+            }
+        }
+    }
+
+    file = fopen(fn.c_str(), "ab");
+
+    fwrite(&LF, sizeof(char), 1, file);
+    fwrite(voxelMatrix_temp.getStartAdressOfSortedArray(0, 0, 0), sizeof(float),
+           voxelMatrix_temp.getDataVector().size(), file);
+    fwrite(&LF, sizeof(char), 1, file);
+    fclose(file);
+}
+//////////////////////////////////////////////////////////////////////////
+void GbVoxelMatrix3D::writeToVTKImageDataASCII(const std::string &fileName)
+{
+    int nx1 = (int)voxelMatrix.getNX1();
+    int nx2 = (int)voxelMatrix.getNX2();
+    int nx3 = (int)voxelMatrix.getNX3();
+
+    string fn = fileName + ".ascii.vti";
+
+    FILE *file;
+    file = fopen(fn.c_str(), "w");
+
+    if (file == NULL) {
+        std::string pathf = UbSystem::getPathFromString(fn);
+        if (fn.size() > 0) {
+            UbSystem::makeDirectory(pathf);
+            file = fopen(fn.c_str(), "w");
+        }
+        if (file == NULL)
+            throw UbException(UB_EXARGS, "can not open " + fn);
+    }
+
+    fprintf(file,
+            "<VTKFile type=\"ImageData\" version=\"1.0\" byte_order=\"LittleEndian\" header_type=\"UInt64\">\n"); // paraview
+                                                                                                                  // 4.1
+    // fprintf(file,"<VTKFile type=\"ImageData\" version=\"0.1\" byte_order=\"LittleEndian\">\n"); //paraview 3.1
+    fprintf(file, "  <ImageData WholeExtent=\"%d %d %d %d %d %d\" Origin=\"%g %g %g\" Spacing=\"%g %g %g\">\n", 0,
+            nx1 - 1, 0, nx2 - 1, 0, nx3 - 1, minX1, minX2, minX3, deltaX1, deltaX2, deltaX3);
+    fprintf(file, "  <Piece Extent=\"%d %d %d %d %d %d\">\n", 0, nx1 - 1, 0, nx2 - 1, 0, nx3 - 1);
+    fprintf(file, "    <PointData Scalars=\"VoxelMatrix\">\n");
+    fprintf(file, "      <DataArray type=\"Float32\" Name=\"VoxelMatrix\" format=\"ascii\" RangeMin=\"0\" "
+                  "RangeMax=\"1\">\n        ");
+
+    for (int k = 0; k < nx3; k++) {
+        for (int j = 0; j < nx2; j++) {
+            for (int i = 0; i < nx1; i++) {
+                fprintf(file, "%g ", voxelMatrix(i, j, k));
+            }
+        }
+    }
+
+    fprintf(file, "\n      </DataArray>\n");
+    fprintf(file, "    </PointData>\n");
+    fprintf(file, "    <CellData>\n");
+    fprintf(file, "    </CellData>\n");
+    fprintf(file, "  </Piece>\n");
+    fprintf(file, "  </ImageData>\n");
+    fprintf(file, "</VTKFile>\n");
+
+    fclose(file);
+}
+//////////////////////////////////////////////////////////////////////////
+void GbVoxelMatrix3D::writeToVTKImageDataAppended(const std::string &fileName)
+{
+    int nx1 = (int)voxelMatrix.getNX1();
+    int nx2 = (int)voxelMatrix.getNX2();
+    int nx3 = (int)voxelMatrix.getNX3();
+
+    string fn = fileName + ".appended.vti";
+
+    FILE *file;
+    file = fopen(fn.c_str(), "w");
+
+    if (file == NULL) {
+        std::string pathf = UbSystem::getPathFromString(fn);
+        if (fn.size() > 0) {
+            UbSystem::makeDirectory(pathf);
+            file = fopen(fn.c_str(), "w");
+        }
+        if (file == NULL)
+            throw UbException(UB_EXARGS, "can not open " + fn);
+    }
+
+    fprintf(file,
+            "<VTKFile type=\"ImageData\" version=\"1.0\" byte_order=\"LittleEndian\" header_type=\"UInt64\">\n"); // paraview
+                                                                                                                  // 4.1
+    fprintf(file, "  <ImageData WholeExtent=\"%d %d %d %d %d %d\" Origin=\"%g %g %g\" Spacing=\"%g %g %g\">\n", 0,
+            nx1 - 1, 0, nx2 - 1, 0, nx3 - 1, minX1, minX2, minX3, deltaX1, deltaX2, deltaX3);
+    fprintf(file, "  <Piece Extent=\"%d %d %d %d %d %d\">\n", 0, nx1 - 1, 0, nx2 - 1, 0, nx3 - 1);
+    fprintf(file, "    <PointData Scalars=\"VoxelMatrix\">\n");
+    fprintf(file, "      <DataArray type=\"Float32\" Name=\"VoxelMatrix\" format=\"appended\" RangeMin=\"0\" "
+                  "RangeMax=\"1\" offset=\"0\" />\n");
+    fprintf(file, "    </PointData>\n");
+    fprintf(file, "    <CellData>\n");
+    fprintf(file, "    </CellData>\n");
+    fprintf(file, "  </Piece>\n");
+    fprintf(file, "  </ImageData>\n");
+    fprintf(file, "  <AppendedData encoding=\"raw\">\n");
+    fprintf(file, "   _");
+    fclose(file);
+
+    file                    = fopen(fn.c_str(), "ab");
+    unsigned long long size = (unsigned long long)voxelMatrix.getDataVector().size() * sizeof(float);
+    fwrite(&size, sizeof(unsigned long long), 1, file);
+    fwrite(voxelMatrix.getStartAdressOfSortedArray(0, 0, 0), sizeof(float), voxelMatrix.getDataVector().size(), file);
+    fclose(file);
+
+    file = fopen(fn.c_str(), "a");
+    fprintf(file, "\n");
+    fprintf(file, "  </AppendedData>\n");
+    fprintf(file, "</VTKFile>\n");
+    fclose(file);
+}
diff --git a/src/basics/geometry3d/GbVoxelMatrix3D.h b/src/basics/geometry3d/GbVoxelMatrix3D.h
new file mode 100644
index 0000000000000000000000000000000000000000..c71646e206777533fa0423ce5916c974a7124929
--- /dev/null
+++ b/src/basics/geometry3d/GbVoxelMatrix3D.h
@@ -0,0 +1,350 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file GbVoxelMatrix3D.h
+//! \ingroup geometry3D
+//! \author Konstantin Kutscher, Soeren Textor, Sebastian Geller
+//=======================================================================================
+#ifndef GBVOXELMATRIX3D_H
+#define GBVOXELMATRIX3D_H
+
+#include <cmath>
+#include <vector>
+
+#include <basics/container/CbArray3D.h>
+#include <basics/utilities/UbObserver.h>
+#include <geometry3d/GbObject3D.h>
+
+#include <PointerDefinitions.h>
+
+class GbLine3D;
+class GbTriangle3D;
+class GbObject3DCreator;
+
+class GbVoxelMatrix3D : public GbObject3D, public UbObserver
+{
+public:
+    using Matrix3D = CbArray3D<float>;
+    static const float SOLID;
+    static const float FLUID;
+    enum Endian { BigEndian, LittleEndian };
+
+    GbVoxelMatrix3D();
+    GbVoxelMatrix3D(int nx1, int nx2, int nx3, float initVal, double lowerThreshold = 0, double upperThreshold = 0);
+    GbVoxelMatrix3D(const Matrix3D &voxelMatrix, double lowerThreshold = 0, double upperThreshold = 0);
+    ~GbVoxelMatrix3D() override = default;
+
+    void finalize() override{};
+    GbVoxelMatrix3D *clone() override;
+
+    /*=======================================================================*/
+    Matrix3D::reference operator()(const Matrix3D::size_type &x1, const Matrix3D::size_type &x2,
+                                   const Matrix3D::size_type &x3)
+    {
+        return voxelMatrix(x1, x2, x3);
+    }
+    /*=======================================================================*/
+    Matrix3D::const_reference operator()(const Matrix3D::size_type &x1, const Matrix3D::size_type &x2,
+                                         const Matrix3D::size_type &x3) const
+    {
+        return voxelMatrix(x1, x2, x3);
+    }
+    /*=======================================================================*/
+    void setTransferViaFilename(bool transferViaFilename, std::string filename)
+    {
+        this->filename            = filename;
+        this->transferViaFilename = transferViaFilename;
+    }
+    void setThreshold(double lowerThreshold, double upperThreshold)
+    {
+        this->lowerThreshold = lowerThreshold;
+        this->upperThreshold = upperThreshold;
+    }
+    void setAddSurfaceTriangleSetFlag(bool flag) { this->addSurfaceTriangleSetFlag = flag; }
+
+    /*=======================================================================*/
+    void setVoxelMatrixMininum(double minX1, double minX2, double minX3)
+    {
+        this->minX1 = minX1;
+        this->minX2 = minX2;
+        this->minX3 = minX3;
+    }
+    void setVoxelMatrixMinX1(double minX1) { this->minX1 = minX1; }
+    void setVoxelMatrixMinX2(double minX2) { this->minX2 = minX2; }
+    void setVoxelMatrixMinX3(double minX3) { this->minX3 = minX3; }
+
+    /*=======================================================================*/
+    void setVoxelMatrixDelta(double deltaX1, double deltaX2, double deltaX3)
+    {
+        this->deltaX1 = deltaX1;
+        this->deltaX2 = deltaX2;
+        this->deltaX3 = deltaX3;
+    }
+    void setVoxelMatrixDeltaX1(double deltaX1) { this->deltaX1 = deltaX1; }
+    void setVoxelMatrixDeltaX2(double deltaX2) { this->deltaX2 = deltaX2; }
+    void setVoxelMatrixDeltaX3(double deltaX3) { this->deltaX3 = deltaX3; }
+
+    /*=======================================================================*/
+    double getX1Centroid() override { return 0.5 * (minX1 + this->getX1Maximum()); }
+    double getX1Minimum() override { return minX1; }
+    double getX1Maximum() override { return minX1 + deltaX1 * voxelMatrix.getNX1(); }
+
+    double getX2Centroid() override { return 0.5 * (minX2 + this->getX2Maximum()); }
+    double getX2Minimum() override { return minX2; }
+    double getX2Maximum() override { return minX2 + deltaX2 * voxelMatrix.getNX2(); }
+
+    double getX3Centroid() override { return 0.5 * (this->getX3Minimum() + this->getX3Maximum()); }
+    double getX3Minimum() override { return minX3; }
+    double getX3Maximum() override { return minX3 + deltaX3 * voxelMatrix.getNX3(); }
+
+    double getLengthX1() { return this->getX1Maximum() - minX1; }
+    double getLengthX2() { return this->getX2Maximum() - minX2; }
+    double getLengthX3() { return this->getX3Maximum() - minX3; }
+
+    void setCenterCoordinates(const double &x1, const double &x2, const double &x3) override;
+    void translate(const double &tx1, const double &tx2, const double &tx3) override;
+
+    bool isPointInGbObject3D(const double &x1p, const double &x2p, const double &x3p, bool &pointIsOnBoundary) override;
+    bool isPointInGbObject3D(const double &x1p, const double &x2p, const double &x3p) override;
+    bool isCellInsideGbObject3D(const double &x1a, const double &x2a, const double &x3a, const double &x1b,
+                                const double &x2b, const double &x3b) override;
+    bool isCellCuttingGbObject3D(const double &x1a, const double &x2a, const double &x3a, const double &x1b,
+                                 const double &x2b, const double &x3b) override;
+    bool isCellInsideOrCuttingGbObject3D(const double &x1a, const double &x2a, const double &x3a, const double &x1b,
+                                         const double &x2b, const double &x3b) override;
+    // double getCellVolumeInsideGbObject3D(const double& x1a,const double& x2a,const double& x3a,const double&
+    // x1b,const double& x2b,const double& x3b);
+
+    GbPoint3D *calculateInterSectionPoint3D(GbPoint3D & /*point1*/, GbPoint3D & /*point2*/)
+    {
+        throw UbException(__FILE__, __LINE__, UB_FUNCTION, "not implemented");
+    }
+    GbLine3D *createClippedLine3D(GbPoint3D & /*point1*/, GbPoint3D & /*point2*/) override
+    {
+        throw UbException(__FILE__, __LINE__, UB_FUNCTION, "not implemented");
+    }
+
+    std::vector<GbTriangle3D *> getSurfaceTriangleSet() override;
+    void addSurfaceTriangleSet(std::vector<UbTupleFloat3> &nodes, std::vector<UbTupleInt3> &triangles) override;
+
+    bool hasRaytracing() override { return true; }
+    /*|r| must be 1! einheitsvector!!*/
+    double getIntersectionRaytraceFactor(const double &x1, const double &x2, const double &x3, const double &rx1,
+                                         const double &rx2, const double &rx3) override;
+
+    std::string toString() override;
+
+    // virtuelle Methoden von UbObserver
+    void objectChanged(UbObservable *changedObject) override {}
+    void objectWillBeDeleted(UbObservable *objectForDeletion) override {}
+
+    template <class T>
+    void readMatrixFromRawFile(std::string filename, GbVoxelMatrix3D::Endian endian);
+    template <class T>
+    void readBufferedMatrixFromRawFile(std::string filename, GbVoxelMatrix3D::Endian endian);
+    void readMatrixFromVtiASCIIFile(std::string filename);
+
+    void rotate90aroundX();
+    void rotate90aroundY();
+    void rotate90aroundZ();
+    void rotate90aroundX(double cX1, double cX2, double cX3);
+    void rotate90aroundY(double cX1, double cX2, double cX3);
+    void rotate90aroundZ(double cX1, double cX2, double cX3);
+    void mirrorX();
+    void mirrorY();
+    void mirrorZ();
+
+    void rotateAroundY(double theta);
+
+    void writeToLegacyVTKASCII(const std::string &fileName);
+    void writeToLegacyVTKBinary(const std::string &fileName);
+    void writeToVTKImageDataASCII(const std::string &fileName);
+    void writeToVTKImageDataAppended(const std::string &fileName);
+
+    void setClosedVoidSpaceToSolid();
+
+    void calculateNumberOfSolidAndFluid();
+    long getNumberOfSolid();
+    long getNumberOfFluid();
+
+protected:
+    void findFluidNeighbor(int cx1, int cx2, int cx3);
+    Matrix3D voxelMatrixTemp;
+    CbArray3D<char> flagMatrix;
+
+    std::vector<int> x1Nbr;
+    std::vector<int> x2Nbr;
+    std::vector<int> x3Nbr;
+
+    std::vector<int> x1NbrTemp;
+    std::vector<int> x2NbrTemp;
+    std::vector<int> x3NbrTemp;
+
+    using GbObject3D::isPointInGbObject3D; // Grund: dadurch muss man hier  isPointInGbObject3D(GbPoint3D*) nicht
+                                           // ausprogrammieren, welche sonst hier "ueberdeckt" waere
+
+protected:
+    // for transfer
+    std::string filename;
+    bool transferViaFilename{ false };
+
+    bool addSurfaceTriangleSetFlag{ true };
+
+    int nodesX1{ 0 };
+    int nodesX2{ 0 };
+    int nodesX3{ 0 };
+    double lowerThreshold{ 0.0 }, upperThreshold{ 0.0 };
+
+    double minX1{ 0.0 };
+    double minX2{ 0.0 };
+    double minX3{ 0.0 };
+    double deltaX1{ 1.0 };
+    double deltaX2{ 1.0 };
+    double deltaX3{ 1.0 };
+
+    Matrix3D voxelMatrix;
+
+    long numberOfSolid;
+    long numberOfFluid;
+};
+
+//////////////////////////////////////////////////////////////////////////
+template <class T>
+void GbVoxelMatrix3D::readMatrixFromRawFile(std::string filename, GbVoxelMatrix3D::Endian endian)
+{
+    using namespace std;
+    // UBLOG(logINFO,"GbVoxelMatrix3D::readMatrixFromFile \""<<filename<<"\"
+    // nodes("<<nodesX1<<"/"<<nodesX2<<"/"<<nodesX3<<") - start");
+    ifstream in(filename.c_str(), ios::binary);
+    if (!in)
+        throw UbException(UB_EXARGS, "could not open file " + filename);
+
+    in.seekg(0, ios::end);                 // Ende springen
+    fstream::off_type length = in.tellg(); // Position abfragen
+    in.seekg(0, ios::beg);                 // An den Anfang springen
+
+    // UBLOG(logINFO,"number of nodes = "<<nodesX1*nodesX2*nodesX3*sizeof(T)<<" file size = "<<(long)length);
+    // if( (nodesX1*nodesX2*nodesX3)*sizeof(float) != (long)length )
+    unsigned long long nofn = (unsigned long long)nodesX1 * (unsigned long long)nodesX2 * (unsigned long long)nodesX3 *
+                              (unsigned long long)sizeof(T);
+    if (nofn != (unsigned long long)length) {
+        throw UbException(UB_EXARGS, "number of nodes(" + UbSystem::toString(nofn) + ") doesn't match file size(" +
+                                         UbSystem::toString((long)length) + ")");
+    }
+
+    // UBLOG(logINFO,"  - create GbVoxelMatrix3D");
+    // GbVoxelMatrix3D* voxelGeo = new GbVoxelMatrix3D(nodesX1,nodesX2,nodesX3,GbVoxelMatrix3D::FLUID);
+    voxelMatrix = Matrix3D(nodesX1, nodesX2, nodesX3, GbVoxelMatrix3D::FLUID);
+
+    // UBLOG(logINFO,"  - init values");
+    // float val;
+    T val;
+    for (int x3 = 0; x3 < nodesX3; x3++)
+        for (int x2 = 0; x2 < nodesX2; x2++)
+            for (int x1 = 0; x1 < nodesX1; x1++) {
+                // in.read((char*)&val,sizeof(float));
+                in.read((char *)&val, sizeof(T));
+                if (endian == BigEndian)
+                    UbSystem::swapByteOrder((unsigned char *)(&(val)), sizeof(T));
+                // if( UbMath::equal((double)val, threshold) )
+                // if( UbMath::greater((double)val, threshold) )
+                if ((double)val >= lowerThreshold && (double)val <= upperThreshold) {
+                    (voxelMatrix)(x1, x2, x3) = GbVoxelMatrix3D::SOLID;
+                }
+                //(voxelMatrix)(x1, x2, x3) = (float)val;
+            }
+
+    // UBLOG(logINFO,"GbVoxelMatrix3D::readMatrixFromFile \""<<filename<<"\"
+    // nodes("<<nodesX1<<"/"<<nodesX2<<"/"<<nodesX3<<") - end");
+}
+
+//////////////////////////////////////////////////////////////////////////
+template <class T>
+void GbVoxelMatrix3D::readBufferedMatrixFromRawFile(std::string filename, GbVoxelMatrix3D::Endian endian)
+{
+    using namespace std;
+    UBLOG(logINFO, "GbVoxelMatrix3D::readMatrixFromRawFile \"" << filename << "\" nodes(" << nodesX1 << "/" << nodesX2
+                                                               << "/" << nodesX3 << ") - start");
+
+    FILE *file;
+    file = fopen(filename.c_str(), "rb");
+    if (file == NULL) {
+        throw UbException(UB_EXARGS, "Could not open file " + filename);
+    }
+
+    // obtain file size:
+    fseek(file, 0, SEEK_END);
+    unsigned long int length = ftell(file);
+    rewind(file);
+
+    UBLOG(logINFO, "number of nodes = " << (long)nodesX1 * (long)nodesX2 * (long)nodesX3 << " file size = " << length);
+
+    unsigned long int nofn = (long)nodesX1 * (long)nodesX2 * (long)nodesX3 * (long)sizeof(T);
+    if (nofn != length) {
+        // throw UbException(UB_EXARGS, "number of nodes("+UbSystem::toString(nofn)+") doesn't match file
+        // size("+UbSystem::toString(length)+")");
+    }
+
+    UBLOG(logINFO, "  - create GbVoxelMatrix3D");
+    voxelMatrix = Matrix3D(nodesX1, nodesX2, nodesX3, GbVoxelMatrix3D::FLUID);
+
+    CbArray3D<T> readMatrix(nodesX1, nodesX2, nodesX3);
+
+    UBLOG(logINFO, "  - read file to matrix");
+    fread(readMatrix.getStartAdressOfSortedArray(0, 0, 0), sizeof(T), readMatrix.getDataVector().size(), file);
+    fclose(file);
+
+    UBLOG(logINFO, "  - init values");
+
+    numberOfSolid = 0;
+    T val;
+    for (int x3 = 0; x3 < nodesX3; x3++)
+        for (int x2 = 0; x2 < nodesX2; x2++)
+            for (int x1 = 0; x1 < nodesX1; x1++) {
+                val = readMatrix(x1, x2, x3);
+
+                if (endian == BigEndian) {
+                    UbSystem::swapByteOrder((unsigned char *)(&(val)), sizeof(T));
+                }
+
+                if ((double)val >= lowerThreshold && (double)val <= upperThreshold) {
+                    voxelMatrix(x1, x2, x3) = GbVoxelMatrix3D::SOLID;
+                }
+            }
+
+    UBLOG(logINFO, "GbVoxelMatrix3D::readMatrixFromRawFile \"" << filename << "\" nodes(" << nodesX1 << "/" << nodesX2
+                                                               << "/" << nodesX3 << ") - end");
+}
+
+//#if defined(RCF_USE_SF_SERIALIZATION) && !defined(SWIG)
+// UB_AUTO_RUN_NAMED(SF::registerType<GbVoxelMatrix3D>("GbVoxelMatrix3D"), SF_GbVoxelMatrix3D);
+// UB_AUTO_RUN_NAMED((SF::registerBaseAndDerived< GbObject3D, GbVoxelMatrix3D >()), SF_GbVoxelMatrix3D_BD1);
+// UB_AUTO_RUN_NAMED((SF::registerBaseAndDerived< UbObserver, GbVoxelMatrix3D>()), SF_GbVoxelMatrix3D_BD2);
+//#endif //RCF_USE_SF_SERIALIZATION
+
+#endif
diff --git a/src/basics/geometry3d/KdTree/KdNode.h b/src/basics/geometry3d/KdTree/KdNode.h
new file mode 100644
index 0000000000000000000000000000000000000000..f60de664934a79a01f1ebcdabb83a862c55ab6b2
--- /dev/null
+++ b/src/basics/geometry3d/KdTree/KdNode.h
@@ -0,0 +1,315 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file KdNode.h
+//! \ingroup KdTree
+//! \author Soeren Textor, Sebastian Bindick
+//=======================================================================================
+#ifndef KDNODE_H
+#define KDNODE_H
+
+#include <basics/memory/MbSmartPtr.h>
+
+#include <basics/utilities/UbException.h>
+#include <basics/utilities/UbKeys.h>
+#include <basics/utilities/UbMath.h>
+#include <basics/utilities/UbTuple.h>
+
+#include <geometry3d/GbTriFaceMesh3D.h>
+#include <geometry3d/KdTree/KdRay.h>
+#include <geometry3d/KdTree/KdSplitCandidate.h>
+#include <geometry3d/KdTree/KdUtilities.h>
+#include <geometry3d/KdTree/intersectionhandler/KdLineIntersectionHandler.h>
+#include <geometry3d/KdTree/intersectionhandler/KdRayIntersectionHandler.h>
+#include <geometry3d/KdTree/splitalgorithms/KdSplitAlgorithm.h>
+
+#include <string>
+#include <vector>
+
+namespace Kd
+{
+template <typename T>
+class Node
+{
+public:
+    Node(const T &x1, const T &y1, const T &z1, const T &x2, const T &y2, const T &z2,
+         const MbSmartPtr<std::vector<GbTriFaceMesh3D::TriFace>> triFaces,
+         std::vector<GbTriFaceMesh3D::Vertex> *ptrNodes)
+        : child1(NULL), child2(NULL), triFaces(triFaces), ptrNodes(ptrNodes)
+    {
+        if (x1 < x2) {
+            this->x[0] = x1;
+            this->x[1] = x2;
+        } else {
+            this->x[0] = x2;
+            this->x[1] = x1;
+        }
+
+        if (y1 < y2) {
+            this->y[0] = y1;
+            this->y[1] = y2;
+        } else {
+            this->y[0] = y2;
+            this->y[1] = y1;
+        }
+
+        if (z1 < z2) {
+            this->z[0] = z1;
+            this->z[1] = z2;
+        } else {
+            this->z[0] = z2;
+            this->z[1] = z1;
+        }
+    }
+    /* ======================================================================================= */
+    ~Node()
+    {
+        if (child1) {
+            delete child1;
+            child1 = NULL;
+        }
+        if (child2) {
+            delete child2;
+            child2 = NULL;
+        }
+    }
+    /* ======================================================================================= */
+    bool isLeaf() { return child1 == NULL && child2 == NULL; }
+    /* ======================================================================================= */
+    void deleteTriFaces() { triFaces = MbSmartPtr<std::vector<GbTriFaceMesh3D::TriFace>>(); }
+    /* ======================================================================================= */
+    const MbSmartPtr<std::vector<GbTriFaceMesh3D::TriFace>> &getTriFaces() { return triFaces; }
+    /* ======================================================================================= */
+    std::vector<GbTriFaceMesh3D::Vertex> &getNodes()
+    {
+        if (!ptrNodes)
+            throw UbException(UB_EXARGS, "ups,no nodes");
+        return *ptrNodes;
+    }
+
+    /* ======================================================================================= */
+    void buildTree(const int &level, const int &maxLevel, const SplitAlgorithm<T> &splitAlg)
+    {
+        SplitCandidate<T> splitCandidate = splitAlg.findBestSplitCandidate(level, maxLevel, *this);
+
+        if (splitCandidate.isValid) {
+
+            MbSmartPtr<std::vector<GbTriFaceMesh3D::TriFace>> triFacesForChild1(
+                new std::vector<GbTriFaceMesh3D::TriFace>);
+            MbSmartPtr<std::vector<GbTriFaceMesh3D::TriFace>> triFacesForChild2(
+                new std::vector<GbTriFaceMesh3D::TriFace>);
+
+            splitAlg.distributeTriFaces(splitCandidate, *triFacesForChild1, *triFacesForChild2, *this);
+
+            //////////////////////////////////////////////////////////////////////////
+            // calculate center points and edges of new child nodes
+            T x1_l = x[0], y1_l = y[0], z1_l = z[0];
+            T x2_l = x[1], y2_l = y[1], z2_l = z[1];
+            T x1_r = x[0], y1_r = y[0], z1_r = z[0];
+            T x2_r = x[1], y2_r = y[1], z2_r = z[1];
+
+            if (splitCandidate.axis == Axis::X) {
+                x2_l = splitCandidate.position;
+                x1_r = splitCandidate.position;
+            } else if (splitCandidate.axis == Axis::Y) {
+                y2_l = splitCandidate.position;
+                y1_r = splitCandidate.position;
+            } else {
+                z2_l = splitCandidate.position;
+                z1_r = splitCandidate.position;
+            }
+            // ----------------------------------------------------------------------
+            // ----------------------------------------------------------------------
+
+            if (triFacesForChild1->size() > 0) {
+                if (this->child1)
+                    delete this->child1;
+                this->child1 = new Node(x1_l, y1_l, z1_l, x2_l, y2_l, z2_l, triFacesForChild1, ptrNodes);
+                this->child1->buildTree(level + 1, maxLevel, splitAlg);
+            }
+
+            if (triFacesForChild2->size() > 0) {
+                if (this->child2)
+                    delete this->child2;
+                this->child2 = new Node(x1_r, y1_r, z1_r, x2_r, y2_r, z2_r, triFacesForChild2, ptrNodes);
+                this->child2->buildTree(level + 1, maxLevel, splitAlg);
+            }
+        }
+    }
+    /* ======================================================================================= */
+    int intersectLineBoundingBox(const UbTuple<T, T, T> &n1, const UbTuple<T, T, T> &n2)
+    {
+        const T &n1X = val<1>(n1);
+        const T &n1Y = val<2>(n1);
+        const T &n1Z = val<3>(n1);
+
+        const T &n2X = val<1>(n2);
+        const T &n2Y = val<2>(n2);
+        const T &n2Z = val<3>(n2);
+
+        if (UbMath::greater(UbMath::max(((n1X <= n2X ? x[0] : x[1]) - n1X) / (n2X - n1X),
+                                        ((n1Y <= n2Y ? y[0] : y[1]) - n1Y) / (n2Y - n1Y),
+                                        ((n1Z <= n2Z ? z[0] : z[1]) - n1Z) / (n2Z - n1Z)),
+                            UbMath::min(((n1X > n2X ? x[0] : x[1]) - n1X) / (n2X - n1X),
+                                        ((n1Y > n2Y ? y[0] : y[1]) - n1Y) / (n2Y - n1Y),
+                                        ((n1Z > n2Z ? z[0] : z[1]) - n1Z) / (n2Z - n1Z)))) {
+            return Intersection::NO_INTERSECTION;
+        } else {
+            return Intersection::INTERSECTION;
+        }
+    }
+    /* ======================================================================================= */
+    int intersectRayBoundingBox(const Ray<T> &ray)
+    {
+        T tmin = (x[ray.signX] - ray.originX) * ray.inv_directionX;
+        T tmax = (x[1 - ray.signX] - ray.originX) * ray.inv_directionX;
+
+        T tymin = (y[ray.signY] - ray.originY) * ray.inv_directionY;
+        T tymax = (y[1 - ray.signY] - ray.originY) * ray.inv_directionY;
+
+        if ((tmin > tymax) || (tymin > tmax)) {
+            return false;
+        }
+        if (tymin > tmin)
+            tmin = tymin;
+        if (tymax < tmax)
+            tmax = tymax;
+
+        T tzmin = (z[ray.signZ] - ray.originZ) * ray.inv_directionZ;
+        T tzmax = (z[1 - ray.signZ] - ray.originZ) * ray.inv_directionZ;
+
+        // if( (UbMath::greater( tmin, tzmax) ) || ( UbMath::greater( tzmin, tmax) ) )
+        if ((tmin > tzmax) || (tzmin > tmax)) {
+            return false;
+        }
+        // if(tzmin > tmin) tmin = tzmin;
+        if (tzmax < tmax)
+            tmax = tzmax;
+
+        // return ( (tmin =< t1) && (tmax >= t0) );
+        if (UbMath::greaterEqual(tmax, T(0.0))) {
+            return Intersection::INTERSECTION;
+        } else {
+            return Intersection::NO_INTERSECTION;
+        }
+    }
+    /* ======================================================================================= */
+    bool intersectLine(const UbTuple<T, T, T> &n1, const UbTuple<T, T, T> &n2,
+                       const LineIntersectionHandler<T> &iHandler)
+    {
+        return iHandler.intersectLine(n1, n2, *this, child1, child2);
+    }
+    /* ======================================================================================= */
+    int intersectRay(const Ray<T> &ray, const RayIntersectionHandler<T> &iHandler, std::set<UbKeys::Key3<int>> &mailbox)
+    {
+        return iHandler.intersectRay(ray, *this, child1, child2, mailbox);
+    }
+    /* ======================================================================================= */
+    int getNumOfTriFaces()
+    {
+        if (!child1 && !child2) {
+            if (triFaces)
+                return (int)triFaces->size();
+            else
+                return 0;
+        } else {
+            int sum = 0;
+
+            if (child1)
+                sum += child1->getNumOfTriFaces();
+            if (child2)
+                sum += child2->getNumOfTriFaces();
+
+            return sum;
+        }
+    }
+    /* ======================================================================================= */
+    int getNumOfNodes()
+    {
+        if (!child1 && !child2) {
+            return 1;
+        } else {
+            int sum = 0;
+            if (child1)
+                sum += child1->getNumOfNodes();
+            if (child2)
+                sum += child2->getNumOfNodes();
+
+            return 1 + sum;
+        }
+    }
+    /* ======================================================================================= */
+    std::string toString()
+    {
+        return ""; //"[" + x1 + "," + y1 + "," + z1 + "]  -" + "  [" + x2 + "," + y2 + "," + z2 + "]";
+    }
+    /* ======================================================================================= */
+    void addCubeInfo(std::vector<UbTupleFloat3> &nodes, std::vector<UbTupleInt8> &cells,
+                     std::vector<std::string> &datanames, std::vector<std::vector<double>> &celldata)
+    {
+        nodes.push_back(makeUbTuple(float(x[0]), float(y[0]), float(z[0])));
+        nodes.push_back(makeUbTuple(float(x[1]), float(y[0]), float(z[0])));
+        nodes.push_back(makeUbTuple(float(x[1]), float(y[1]), float(z[0])));
+        nodes.push_back(makeUbTuple(float(x[0]), float(y[1]), float(z[0])));
+
+        nodes.push_back(makeUbTuple(float(x[0]), float(y[0]), float(z[1])));
+        nodes.push_back(makeUbTuple(float(x[1]), float(y[0]), float(z[1])));
+        nodes.push_back(makeUbTuple(float(x[1]), float(y[1]), float(z[1])));
+        nodes.push_back(makeUbTuple(float(x[0]), float(y[1]), float(z[1])));
+
+        cells.push_back(makeUbTuple(int(nodes.size() - 8), int(nodes.size() - 7), int(nodes.size() - 6),
+                                    int(nodes.size() - 5), int(nodes.size() - 4), int(nodes.size() - 3),
+                                    int(nodes.size() - 2), int(nodes.size() - 1)));
+        datanames.resize(1);
+        datanames[0] = "childs";
+        celldata.resize(datanames.size());
+        if (child1 && child2)
+            celldata[0].push_back(2);
+        else if (child1 || child2)
+            celldata[0].push_back(1);
+        else
+            celldata[0].push_back(0);
+
+        if (child1)
+            child1->addCubeInfo(nodes, cells, datanames, celldata);
+        if (child2)
+            child2->addCubeInfo(nodes, cells, datanames, celldata);
+    }
+
+public:
+    T x[2], y[2], z[2];
+
+private:
+    Node *child1;
+    Node *child2;
+
+    MbSmartPtr<std::vector<GbTriFaceMesh3D::TriFace>> triFaces;
+    std::vector<GbTriFaceMesh3D::Vertex> *ptrNodes; // lediglich f�r Zugriff auf die Knoten!!!
+};
+} // namespace Kd
+#endif // KDNODE_H
diff --git a/src/basics/geometry3d/KdTree/KdRay.h b/src/basics/geometry3d/KdTree/KdRay.h
new file mode 100644
index 0000000000000000000000000000000000000000..43bbcd4500c98a5aa8fc4ba52993f8b62d6d1021
--- /dev/null
+++ b/src/basics/geometry3d/KdTree/KdRay.h
@@ -0,0 +1,105 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file KdRay.h
+//! \ingroup KdTree
+//! \author Soeren Textor, Sebastian Bindick
+//=======================================================================================
+#ifndef KDRAY_H
+#define KDRAY_H
+
+#include <basics/utilities/UbException.h>
+#include <basics/utilities/UbMath.h>
+
+namespace Kd
+{
+/*
+ * Ray class, for use with the optimized ray-box intersection test
+ * described in:
+ *
+ *      Amy Williams, Steve Barrus, R. Keith Morley, and Peter Shirley
+ *      "An Efficient and Robust Ray-Box Intersection Algorithm"
+ *      Journal of graphics tools, 10(1):49-54, 2005
+ *
+ */
+template <typename T>
+class Ray
+{
+public:
+    Ray(const T &originX, const T &originY, const T &originZ, const T &directionX, const T &directionY,
+        const T &directionZ)
+    {
+        this->originX = originX;
+        this->originY = originY;
+        this->originZ = originZ;
+
+        // normierung (fuer ray-triangle-intersection)
+        T oneOverLength =
+            T(1.0 / std::sqrt(directionX * directionX + directionY * directionY + directionZ * directionZ));
+
+        this->directionX = directionX * oneOverLength;
+        this->directionY = directionY * oneOverLength;
+        this->directionZ = directionZ * oneOverLength;
+
+        this->inv_directionX = T(1.0 / this->directionX); // ACHTUNG: BEWUSST KEINE ==0 Abfrage
+        this->inv_directionY = T(1.0 / this->directionY); // Alg verwendet exlitzit INF
+        this->inv_directionZ = T(1.0 / this->directionZ);
+
+        if (this->inv_directionX < 0.0)
+            this->signX = 1;
+        else
+            this->signX = 0;
+        if (this->inv_directionY < 0.0)
+            this->signY = 1;
+        else
+            this->signY = 0;
+        if (this->inv_directionZ < 0.0)
+            this->signZ = 1;
+        else
+            this->signZ = 0;
+    }
+
+    T originX;
+    T originY;
+    T originZ;
+
+    T directionX;
+    T directionY;
+    T directionZ;
+
+    T inv_directionX;
+    T inv_directionY;
+    T inv_directionZ;
+
+    int signX;
+    int signY;
+    int signZ;
+};
+} // namespace Kd
+
+#endif // KDRAY_H
diff --git a/src/basics/geometry3d/KdTree/KdSplitCandidate.h b/src/basics/geometry3d/KdTree/KdSplitCandidate.h
new file mode 100644
index 0000000000000000000000000000000000000000..cfd2fc3bca2ca1eccae8418c11ad4c69fe892954
--- /dev/null
+++ b/src/basics/geometry3d/KdTree/KdSplitCandidate.h
@@ -0,0 +1,75 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file KdSplitCandidate.h
+//! \ingroup KdTree
+//! \author Soeren Textor, Sebastian Bindick
+//=======================================================================================
+#ifndef KDSPLITCANDIDATE_H
+#define KDSPLITCANDIDATE_H
+
+#include <basics/utilities/UbMath.h>
+
+namespace Kd
+{
+template <typename T>
+class SplitCandidate
+{
+public:
+    SplitCandidate() = default;
+    /* ======================================================================================= */
+    SplitCandidate(const int &axis, const T &position, const int &starting, const int &ending, const int &insidePlane)
+        : axis(axis), position(position), starting(starting), ending(ending), np(insidePlane),
+          isValid(true) // FIXME: isValid default false is correct?
+    {
+    }
+    /* ======================================================================================= */
+    bool operator!() const { return isValid; }
+    /* ======================================================================================= */
+    friend inline bool operator<(const SplitCandidate &lhs, const SplitCandidate &rhs)
+    {
+        return lhs.position < rhs.position;
+    }
+    /* ======================================================================================= */
+
+public:
+    int axis{ 0 };
+    T Cn{ 0.0 };
+    T position{ 0.0 };
+    int nl{ 0 };
+    int nr{ 0 };
+    int np;
+    int starting{ 0 };
+    int ending{ 0 };
+    bool np_left{ false };
+    bool np_right{ false };
+    bool isValid{ false };
+};
+} // namespace Kd
+
+#endif // KDSPLITCANDIDATE_H
diff --git a/src/basics/geometry3d/KdTree/KdSplitCandidateManager.h b/src/basics/geometry3d/KdTree/KdSplitCandidateManager.h
new file mode 100644
index 0000000000000000000000000000000000000000..d7f4bdf10f141ef6358759708ef9d4fa9d5b9e11
--- /dev/null
+++ b/src/basics/geometry3d/KdTree/KdSplitCandidateManager.h
@@ -0,0 +1,100 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file KdSplitCandidateManager.h
+//! \ingroup KdTree
+//! \author Soeren Textor, Sebastian Bindick
+//=======================================================================================
+#ifndef KDSPLITCANDIDATEMANAGER_H
+#define KDSPLITCANDIDATEMANAGER_H
+
+#include <geometry3d/KdTree/KdSplitCandidate.h>
+
+#include <algorithm>
+#include <map>
+#include <vector>
+
+namespace Kd
+{
+template <typename T>
+class SplitCandidateManager
+{
+public:
+    SplitCandidateManager()
+
+        = default;
+    /* ======================================================================================= */
+    SplitCandidate<T> &operator[](const std::size_t &i)
+    {
+#ifdef DEBUG
+        return splitCandidatesVec.at(i);
+#else
+        return splitCandidatesVec[i];
+#endif
+    }
+    /* ======================================================================================= */
+    typename std::vector<SplitCandidate<T>>::size_type size() { return splitCandidatesVec.size(); }
+    /* ======================================================================================= */
+    void add(const T &pos, const int &axis, const int &starting, const int &ending, const int &np)
+    {
+        typename std::map<T, SplitCandidate<T>>::iterator it = splitCandidates.find(pos);
+        if (it != splitCandidates
+                      .end()) // split candidate is already available -> increase parameter (starting, ending and np)
+        {
+            SplitCandidate<T> &sc = it->second;
+            sc.np += np;
+            sc.starting += starting;
+            sc.ending += ending;
+        } else // split candidate is not available -> add new split candidate
+        {
+            this->splitCandidates[pos] = SplitCandidate<T>(axis, pos, starting, ending, np);
+        }
+    }
+    /* ======================================================================================= */
+    void createSortedArray()
+    {
+        splitCandidatesVec.clear();
+        typename std::map<T, SplitCandidate<T>>::iterator it;
+        for (it = splitCandidates.begin(); it != splitCandidates.end(); ++it)
+            splitCandidatesVec.push_back(it->second);
+        splitCandidates.clear();
+        std::sort(splitCandidatesVec.begin(), splitCandidatesVec.end(), std::less<SplitCandidate<T>>());
+    }
+    /* ======================================================================================= */
+
+public:
+    int objects_starting_outside_left{ 0 };
+    int objects_fully_outside_node{ 0 };
+
+private:
+    std::map<T, SplitCandidate<T>> splitCandidates;
+    std::vector<SplitCandidate<T>> splitCandidatesVec;
+};
+} // namespace Kd
+
+#endif // KDSPLITCANDIDATEMANAGER_H
diff --git a/src/basics/geometry3d/KdTree/KdTree.h b/src/basics/geometry3d/KdTree/KdTree.h
new file mode 100644
index 0000000000000000000000000000000000000000..b290c3c61a0591e04cc9358769ef3ce087192f30
--- /dev/null
+++ b/src/basics/geometry3d/KdTree/KdTree.h
@@ -0,0 +1,135 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file KdTree.h
+//! \ingroup KdTree
+//! \author Soeren Textor, Sebastian Bindick
+//=======================================================================================
+#ifndef KDTREE_H
+#define KDTREE_H
+
+#include <basics/utilities/UbKeys.h>
+#include <basics/writer/WbWriterVtkXmlBinary.h>
+#include <geometry3d/GbTriFaceMesh3D.h>
+
+#include <geometry3d/KdTree/KdNode.h>
+#include <geometry3d/KdTree/KdRay.h>
+#include <geometry3d/KdTree/KdSplitCandidate.h>
+#include <geometry3d/KdTree/splitalgorithms/KdSplitAlgorithm.h>
+
+#include <cmath>
+#include <string>
+
+namespace Kd
+{
+template <typename T>
+class Tree
+{
+public:
+    /* ======================================================================================= */
+    Tree(GbTriFaceMesh3D &mesh, const SplitAlgorithm<T> &splitAlg) : rootNode(NULL) { this->buildTree(mesh, splitAlg); }
+    /* ======================================================================================= */
+    ~Tree()
+    {
+        if (rootNode) {
+            delete rootNode;
+            rootNode = NULL;
+        }
+    }
+    /* ======================================================================================= */
+    // the IntersectionHandler specifies how to handle the intersection
+    bool intersectLine(const UbTuple<T, T, T> &n1, const UbTuple<T, T, T> &n2,
+                       const LineIntersectionHandler<T> &iHandler)
+    {
+        return rootNode->intersectLine(n1, n2, iHandler);
+    }
+    /* ======================================================================================= */
+    // the IntersectionHandler specifies how to handle the intersection
+    int intersectRay(const Ray<T> &ray, const RayIntersectionHandler<T> &iHandler)
+    {
+        std::set<UbKeys::Key3<int>> mailbox;
+        return rootNode->intersectRay(ray, iHandler, mailbox);
+    }
+    /* ======================================================================================= */
+    int getNumOfNodes()
+    {
+        if (rootNode)
+            return rootNode->getNumOfNodes();
+        return 0;
+    }
+    /* ======================================================================================= */
+    int getNumOfTriFaces()
+    {
+        if (rootNode)
+            return rootNode->getNumOfTriFaces();
+        return 0;
+    }
+    /* ======================================================================================= */
+    std::string toString()
+    {
+        return ""; // Tree:: num of nodes: " + rootNode.getNumOfNodes() + ", primitives:" +
+                   // rootNode.getNumOfPrimitives() + ", root_primitives:" + getNumOfPrimitives() + ", max_level:" +
+                   // max_level;
+    }
+    /* ======================================================================================= */
+    void buildTree(GbTriFaceMesh3D &mesh, const SplitAlgorithm<T> &splitAlg)
+    {
+        if (rootNode)
+            delete rootNode;
+
+        // create a copy of triangles
+        MbSmartPtr<std::vector<GbTriFaceMesh3D::TriFace>> triFaces(
+            new std::vector<GbTriFaceMesh3D::TriFace>(*mesh.getTriangles()));
+
+        const int maxLevel =
+            static_cast<int>(std::lround(8.0 + 1.3 * std::log((double)triFaces->size()))); // TODO: remove magic numbers
+
+        rootNode =
+            new Node<T>(T(mesh.getX1Minimum()), T(mesh.getX2Minimum()), T(mesh.getX3Minimum()), T(mesh.getX1Maximum()),
+                        T(mesh.getX2Maximum()), T(mesh.getX3Maximum()), triFaces, mesh.getNodes());
+
+        rootNode->buildTree(0, maxLevel, splitAlg);
+    }
+    void writeTree(const std::string &filename, WbWriter *writer = WbWriterVtkXmlBinary::getInstance())
+    {
+        if (rootNode) {
+            std::vector<UbTupleFloat3> nodes;
+            std::vector<UbTupleInt8> cubes;
+            std::vector<std::string> datanames;
+            std::vector<std::vector<double>> cubesdata;
+            rootNode->addCubeInfo(nodes, cubes, datanames, cubesdata);
+            writer->writeOctsWithCellData(filename, nodes, cubes, datanames, cubesdata);
+        }
+    }
+
+private:
+    Node<T> *rootNode;
+};
+} // namespace Kd
+
+#endif // KDTREE_H
diff --git a/src/basics/geometry3d/KdTree/KdUtilities.cpp b/src/basics/geometry3d/KdTree/KdUtilities.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0dca20ad16b1f2bd89a7591ffe1264e6d1098c82
--- /dev/null
+++ b/src/basics/geometry3d/KdTree/KdUtilities.cpp
@@ -0,0 +1,45 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file KdUtilities.cpp
+//! \ingroup KdTree
+//! \author Soeren Textor, Sebastian Bindick
+//=======================================================================================
+#include <geometry3d/KdTree/KdUtilities.h>
+
+namespace Kd
+{
+const int Axis::X = 0;
+const int Axis::Y = 1;
+const int Axis::Z = 2;
+
+const int Intersection::ON_BOUNDARY     = -2;
+const int Intersection::INTERSECT_EDGE  = -1;
+const int Intersection::INTERSECTION    = 1;
+const int Intersection::NO_INTERSECTION = 0;
+} // namespace Kd
diff --git a/src/basics/geometry3d/KdTree/KdUtilities.h b/src/basics/geometry3d/KdTree/KdUtilities.h
new file mode 100644
index 0000000000000000000000000000000000000000..7a304102c7effd2ce1cc487427aa712b1ada2592
--- /dev/null
+++ b/src/basics/geometry3d/KdTree/KdUtilities.h
@@ -0,0 +1,196 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file KdUtilities.h
+//! \ingroup KdTree
+//! \author Soeren Textor, Sebastian Bindick
+//=======================================================================================
+#ifndef KDUTILIES_H
+#define KDUTILIES_H
+
+#include <basics/utilities/UbException.h>
+#include <basics/utilities/UbMath.h>
+#include <basics/utilities/UbTuple.h>
+
+#include <geometry3d/GbTriFaceMesh3D.h>
+
+#include <algorithm>
+#include <vector>
+
+namespace Kd
+{
+struct Axis {
+    static const int X; // = 0;
+    static const int Y; // = 1;
+    static const int Z; // = 2;
+};
+/* ======================================================================================= */
+struct Intersection {
+    static const int ON_BOUNDARY;     // = -2;
+    static const int INTERSECT_EDGE;  // = -1;
+    static const int INTERSECTION;    // = 1;
+    static const int NO_INTERSECTION; // = 0;
+};
+/* ======================================================================================= */
+template <typename T>
+inline void project2Axis(GbTriFaceMesh3D::TriFace &triFace, std::vector<GbTriFaceMesh3D::Vertex> &nodes,
+                         const int &axis, std::vector<T> &projection)
+{
+    projection.resize(3);
+
+    if (axis == Axis::X) {
+        projection[0] = triFace.getV1x(nodes);
+        projection[1] = triFace.getV2x(nodes);
+        projection[2] = triFace.getV3x(nodes);
+    } else if (axis == Axis::Y) {
+        projection[0] = triFace.getV1y(nodes);
+        projection[1] = triFace.getV2y(nodes);
+        projection[2] = triFace.getV3y(nodes);
+    } else if (axis == Axis::Z) {
+        projection[0] = triFace.getV1z(nodes);
+        projection[1] = triFace.getV2z(nodes);
+        projection[2] = triFace.getV3z(nodes);
+    } else
+        throw UbException(UB_EXARGS, "unknown axis");
+
+    std::sort(projection.begin(), projection.end(), std::less<>());
+}
+/* ======================================================================================= */
+template <typename T>
+inline bool isPointOnPlane(const T &px, const T &py, const T &pz, const T &precision,
+                           GbTriFaceMesh3D::Vertex &pointOfTriFace, GbTriFaceMesh3D::TriFace &triFace)
+{
+    return std::fabs((px - pointOfTriFace.x) * triFace.nx + (py - pointOfTriFace.y) * triFace.ny +
+                     (pz - pointOfTriFace.z) * triFace.nz) < precision;
+}
+/* ======================================================================================= */
+template <typename T>
+inline bool isPointOnTriangle(const T &px, const T &py, const T &pz, const T &precision, GbTriFaceMesh3D::Vertex &p1,
+                              GbTriFaceMesh3D::Vertex &p2, GbTriFaceMesh3D::Vertex &p3,
+                              GbTriFaceMesh3D::TriFace &triFace)
+{
+    if (Kd::isPointOnPlane(px, py, pz, precision, p1, triFace)) {
+        T a_x = p1.x - px;
+        T a_y = p1.y - py;
+        T a_z = p1.z - pz;
+        T b_x = p2.x - px;
+        T b_y = p2.y - py;
+        T b_z = p2.z - pz;
+        T c_x = p3.x - px;
+        T c_y = p3.y - py;
+        T c_z = p3.z - pz;
+
+        const T factor = 0.5;
+        T Q1_x         = (a_y * b_z - a_z * b_y) * factor;
+        T Q1_y         = (a_z * b_x - a_x * b_z) * factor;
+        T Q1_z         = (a_x * b_y - a_y * b_x) * factor;
+
+        T Q2_x = (b_y * c_z - b_z * c_y) * factor;
+        T Q2_y = (b_z * c_x - b_x * c_z) * factor;
+        T Q2_z = (b_x * c_y - b_y * c_x) * factor;
+
+        T Q3_x = (c_y * a_z - c_z * a_y) * factor;
+        T Q3_y = (c_z * a_x - c_x * a_z) * factor;
+        T Q3_z = (c_x * a_y - c_y * a_x) * factor;
+
+        T Q_x = Q1_x + Q2_x + Q3_x;
+        T Q_y = Q1_y + Q2_y + Q3_y;
+        T Q_z = Q1_z + Q2_z + Q3_z;
+
+        if (UbMath::zero(Q_x * Q1_x + Q_y * Q1_y + Q_z * Q1_z))
+            return true;
+        else if (UbMath::zero(Q_x * Q2_x + Q_y * Q2_y + Q_z * Q2_z))
+            return true;
+        else if (UbMath::zero(Q_x * Q3_x + Q_y * Q3_y + Q_z * Q3_z))
+            return true;
+        else if (UbMath::less(Q_x * Q1_x + Q_y * Q1_y + Q_z * Q1_z, T(0.0)))
+            return false;
+        else if (UbMath::less(Q_x * Q2_x + Q_y * Q2_y + Q_z * Q2_z, T(0.0)))
+            return false;
+        else if (UbMath::less(Q_x * Q3_x + Q_y * Q3_y + Q_z * Q3_z, T(0.0)))
+            return false;
+
+        return true;
+    }
+
+    return false;
+}
+/* ======================================================================================= */
+template <typename T>
+inline bool intersectLine(const UbTuple<T, T, T> &n1, const UbTuple<T, T, T> &n2, GbTriFaceMesh3D::TriFace &triFace,
+                          std::vector<GbTriFaceMesh3D::Vertex> &nodes)
+{
+    GbTriFaceMesh3D::Vertex &p0 = triFace.getNode(0, nodes);
+
+    const T &n1X = val<1>(n1);
+    const T &n1Y = val<2>(n1);
+    const T &n1Z = val<3>(n1);
+
+    const T &n2X = val<1>(n2);
+    const T &n2Y = val<2>(n2);
+    const T &n2Z = val<3>(n2);
+
+    // if(   Kd::isPointOnPlane(n1X, n1Y, n1Z, T(1.0E-6), p0, triFace)
+    //   && Kd::isPointOnPlane(n2X, n2Y, n2Z, T(1.0E-6), p0, triFace))
+    //{
+    //   return true;
+    //}
+
+    T denom = (n2X - n1X) * triFace.nx + (n2Y - n1Y) * triFace.ny + (n2Z - n1Z) * triFace.nz;
+
+    if (UbMath::zero(denom)) // line does not intersect the plane of the triangle !
+    {
+        return false;
+    } else {
+        T d  = -triFace.nx * p0.x - triFace.ny * p0.y - triFace.nz * p0.z;
+        T mu = T(-1.0 * (d + n1X * triFace.nx + n1Y * triFace.ny + n1Z * triFace.nz) / denom);
+
+        if (!UbMath::inClosedInterval(mu, T(0.0),
+                                      T(1.0))) // Point of intersection of line and plane does not lie on the triangle
+        {
+            return false;
+        } else {
+            // intersection with plane
+
+            // Test whether Point lies inside the triangle or not
+            GbTriFaceMesh3D::Vertex &p1 = triFace.getNode(1, nodes);
+            GbTriFaceMesh3D::Vertex &p2 = triFace.getNode(2, nodes);
+
+            return Kd::isPointOnTriangle(n1X + ((n2X - n1X) * mu) // intersectionPointX
+                                         ,
+                                         n1Y + ((n2Y - n1Y) * mu) // intersectionPointY
+                                         ,
+                                         n1Z + ((n2Z - n1Z) * mu) // intersectionPointZ
+                                         ,
+                                         T(0.001), p0, p1, p2, triFace);
+        }
+    }
+}
+} // namespace Kd
+
+#endif // KDUTILIES_H
diff --git a/src/basics/geometry3d/KdTree/intersectionhandler/KdCountLineIntersectionHandler.h b/src/basics/geometry3d/KdTree/intersectionhandler/KdCountLineIntersectionHandler.h
new file mode 100644
index 0000000000000000000000000000000000000000..49b2754d6f3d6180e16c09b4d74d6dfde8dd4528
--- /dev/null
+++ b/src/basics/geometry3d/KdTree/intersectionhandler/KdCountLineIntersectionHandler.h
@@ -0,0 +1,85 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file KdCountLineIntersectionHandler.h
+//! \ingroup splitalgorithms
+//! \author Soeren Textor, Sebastian Bindick
+//=======================================================================================
+#ifndef KDCOUNTLINEINTERSECTIONHANDLER_H
+#define KDCOUNTLINEINTERSECTIONHANDLER_H
+
+#include <basics/utilities/UbKeys.h>
+#include <basics/utilities/UbTuple.h>
+
+#include <geometry3d/GbTriFaceMesh3D.h>
+
+#include <geometry3d/KdTree/KdNode.h>
+#include <geometry3d/KdTree/KdUtilities.h>
+#include <geometry3d/KdTree/intersectionhandler/KdLineIntersectionHandler.h>
+
+#include <set>
+
+namespace Kd
+{
+template <typename T>
+class CountLineIntersectionHandler : public LineIntersectionHandler<T>
+{
+public:
+    bool intersectLine(const UbTuple<T, T, T> &n1, const UbTuple<T, T, T> &n2, Node<T> &parent, Node<T> *&child1,
+                       Node<T> *&child2) const override
+    {
+        if (parent.intersectLineBoundingBox(n1, n2) == Intersection::INTERSECTION) {
+            if (parent.isLeaf()) {
+                std::vector<GbTriFaceMesh3D::TriFace> &triFaces = *parent.getTriFaces();
+                std::vector<GbTriFaceMesh3D::Vertex> &nodes     = parent.getNodes();
+
+                for (std::size_t i = 0; i < triFaces.size(); i++) {
+                    GbTriFaceMesh3D::TriFace &triFace = triFaces[i];
+
+                    if (Kd::intersectLine(n1, n2, triFace, nodes))
+                        return true;
+                }
+                return false;
+            } else {
+                if (child1) {
+                    if (child1->intersectLine(n1, n2, *this))
+                        return true;
+                }
+                if (child2) {
+                    if (child2->intersectLine(n1, n2, *this))
+                        return true;
+                }
+            }
+        }
+        return false;
+    }
+    /* ======================================================================================= */
+};
+} // namespace Kd
+
+#endif // KDCOUNTLINEINTERSECTIONHANDLER_H
diff --git a/src/basics/geometry3d/KdTree/intersectionhandler/KdCountRayIntersectionHandler.h b/src/basics/geometry3d/KdTree/intersectionhandler/KdCountRayIntersectionHandler.h
new file mode 100644
index 0000000000000000000000000000000000000000..7ca7ed3ee3e9eba80b7ee3cf090502c929df3fc9
--- /dev/null
+++ b/src/basics/geometry3d/KdTree/intersectionhandler/KdCountRayIntersectionHandler.h
@@ -0,0 +1,191 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file KdCountRayIntersectionHandler.h
+//! \ingroup splitalgorithms
+//! \author Soeren Textor, Sebastian Bindick
+//=======================================================================================
+#ifndef KDCOUNTRAYINTERSECTIONHANDLER_H
+#define KDCOUNTRAYINTERSECTIONHANDLER_H
+
+#include <basics/utilities/UbKeys.h>
+#include <basics/utilities/UbTuple.h>
+
+#include <geometry3d/GbTriFaceMesh3D.h>
+
+#include <geometry3d/KdTree/KdNode.h>
+//#include <geometry3d/KdTree/KdUtilities.h>
+#include <geometry3d/KdTree/intersectionhandler/KdRayIntersectionHandler.h>
+
+#include <set>
+
+namespace Kd
+{
+template <typename T>
+class CountRayIntersectionHandler : public RayIntersectionHandler<T>
+{
+public:
+    int intersectRay(const Ray<T> &ray, Node<T> &parent, Node<T> *&child1, Node<T> *&child2,
+                     std::set<UbKeys::Key3<int>> &mailbox) const override
+    {
+        if (parent.intersectRayBoundingBox(ray) == Intersection::INTERSECTION) {
+            if (parent.isLeaf()) {
+                return this->checkIntersectionWithTriFaces(ray, *parent.getTriFaces(), parent.getNodes(), mailbox);
+            } else {
+                int sum = 0;
+                if (child1) {
+                    int erg = child1->intersectRay(ray, *this, mailbox);
+                    if (erg < 0) {
+                        return erg;
+                    }
+                    sum += erg;
+                }
+                if (child2) {
+                    int erg = child2->intersectRay(ray, *this, mailbox);
+                    if (erg < 0) {
+                        return erg;
+                    }
+                    sum += erg;
+                }
+                return sum;
+            }
+        } else {
+            return 0;
+        }
+    }
+    /* ======================================================================================= */
+
+private:
+    int checkIntersectionWithTriFaces(const Ray<T> &ray, std::vector<GbTriFaceMesh3D::TriFace> &triFaces,
+                                      std::vector<GbTriFaceMesh3D::Vertex> &nodes,
+                                      std::set<UbKeys::Key3<int>> &mailbox) const
+    {
+        T e1x, e1y, e1z, e2x, e2y, e2z, px, py, pz, a, f, sx, sy, sz, u, qx, qy, qz, v, factor;
+
+        int counter = 0;
+
+        for (std::size_t i = 0; i < triFaces.size(); i++) {
+            GbTriFaceMesh3D::TriFace &triFace = triFaces[i];
+
+            if (mailbox.find(UbKeys::Key3<int>(triFace.getIndexVertex1(), triFace.getIndexVertex2(),
+                                               triFace.getIndexVertex3())) == mailbox.end()) {
+                mailbox.insert(
+                    UbKeys::Key3<int>(triFace.getIndexVertex1(), triFace.getIndexVertex2(),
+                                      triFace.getIndexVertex3())); // schon hier rein, ansonsten muss man es unten bei
+                                                                   // JEDEm continue und am ende des ifs machen
+
+                GbTriFaceMesh3D::Vertex &v1 = triFace.getNode(0, nodes);
+                GbTriFaceMesh3D::Vertex &v2 = triFace.getNode(1, nodes);
+                GbTriFaceMesh3D::Vertex &v3 = triFace.getNode(2, nodes);
+
+                //////////////////////////////////////////////////////////////////////////
+                // Raytracing - start(  Anm.: pr�ft NUR in Strahlrichtung
+                // Grundidee: Schnittpunkt in Baryzentrischen Koordinaten besimmten
+                // t(u,v,w) = w*v0 + u*v1 + v*v2
+                // mit w = 1.0-u-v, da fuer alle Punkte (u,v,w) im Dreick gilt u+v+w = 1
+                // wenn u, v oder w == 0 -> Punkt liegt auf Kante
+                // wenn u, v oder w == 1 -> Punkt liegt auf Eckpunkt (-> die anderen Werte muessen 0 )
+
+                // e1 = v1 - v0
+                e1x = v2.x - v1.x;
+                e1y = v2.y - v1.y;
+                e1z = v2.z - v1.z;
+
+                // e2 = v2 - v0
+                e2x = v3.x - v1.x;
+                e2y = v3.y - v1.y;
+                e2z = v3.z - v1.z;
+
+                // p = d x e2
+                px = ray.directionY * e2z - ray.directionZ * e2y;
+                py = ray.directionZ * e2x - ray.directionX * e2z;
+                pz = ray.directionX * e2y - ray.directionY * e2x;
+
+                // a = e1 dot p
+                a = e1x * px + e1y * py + e1z * pz;
+                // if( fabs(a)<1.E-10 ) continue;
+                if (fabs(a) < UbMath::Epsilon<T>::val())
+                    continue;
+                f = T(1.0 / a);
+
+                // s = o - v0
+                sx = ray.originX - v1.x;
+                sy = ray.originY - v1.y;
+                sz = ray.originZ - v1.z;
+
+                // u = f * ( s dot p)
+                u = f * (sx * px + sy * py + sz * pz);
+
+                // u ist nur gueltig in [0;1]
+                if ((UbMath::less(u, T(0.0))) || (UbMath::greater(u, T(1.0)))) {
+                    continue;
+                }
+
+                // q = s x e1
+                qx = sy * e1z - sz * e1y;
+                qy = sz * e1x - sx * e1z;
+                qz = sx * e1y - sy * e1x;
+
+                // v = f*(e2 dot q)
+                v = f * (ray.directionX * qx + ray.directionY * qy + ray.directionZ * qz);
+
+                // v ist nur gueltig in [0;1] da aber v bereits gueltig ist -> u+v darf nicht > 1.0 sein ;-)
+                if ((UbMath::less(v, T(0.0))) || (UbMath::greater(u + v, T(1.0)))) {
+                    continue;
+                }
+
+                // t = f * (e2 dot q)
+                factor = f * (e2x * qx + e2y * qy + e2z * qz);
+                // Raytracing - end
+                //////////////////////////////////////////////////////////////////////////
+
+                if (UbMath::zero(factor)) {
+                    return Intersection::ON_BOUNDARY; // ray.Org liegt direkt auf einem dreieck --> boundary
+                }
+                if (factor < 0.0) {
+                    continue; // Schnittpunkt liegt in entgegengesetzter Strahlrichtung
+                }
+
+                // edge tests
+                // wenn u, v oder w ==0 -> Punkt liegt auf Kante bzw. Eckpunkt
+                if (UbMath::zero(u))
+                    return Intersection::INTERSECT_EDGE;
+                if (UbMath::zero(v))
+                    return Intersection::INTERSECT_EDGE;
+                if (UbMath::zero(T(1.0) - u - v))
+                    return Intersection::INTERSECT_EDGE;
+
+                counter++;
+            }
+        }
+        return counter;
+    }
+};
+} // namespace Kd
+
+#endif // KDCOUNTRAYLINEINTERSECTIONHANDLER_H
diff --git a/src/basics/geometry3d/KdTree/intersectionhandler/KdLineIntersectionHandler.h b/src/basics/geometry3d/KdTree/intersectionhandler/KdLineIntersectionHandler.h
new file mode 100644
index 0000000000000000000000000000000000000000..0895f740894341b8cf5b3d340b114eb76b88a58e
--- /dev/null
+++ b/src/basics/geometry3d/KdTree/intersectionhandler/KdLineIntersectionHandler.h
@@ -0,0 +1,63 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file KdLineIntersectionHandler.h
+//! \ingroup splitalgorithms
+//! \author Soeren Textor, Sebastian Bindick
+//=======================================================================================
+#ifndef KDLINEINTERSECTIONHANDLER_H
+#define KDLINEINTERSECTIONHANDLER_H
+
+#include <basics/utilities/UbTuple.h>
+//#include <geometry3d/GbTriFaceMesh3D.h>
+
+#include <set>
+
+// #ifdef CAB_RCF
+// #  include <3rdParty/rcf/RcfSerializationIncludes.h>
+// #end
+namespace Kd
+{
+template <typename T>
+class Node;
+
+template <typename T>
+class LineIntersectionHandler
+{
+public:
+    virtual bool intersectLine(const UbTuple<T, T, T> &n1, const UbTuple<T, T, T> &n2, Node<T> &parent,
+                               Node<T> *&child1, Node<T> *&child2) const = 0;
+    virtual ~LineIntersectionHandler()                                   = default;
+};
+} // namespace Kd
+
+// #if defined(RCF_USE_SF_SERIALIZATION) && !defined(SWIG)
+//    SF_NO_CTOR(Kd::LineIntersectionHandler<float>);
+//    SF_NO_CTOR(Kd::LineIntersectionHandler<double>);
+// #endif //RCF_USE_SF_SERIALIZATI
+#endif // KDLINEINTERSECTIONHANDLER_H
diff --git a/src/basics/geometry3d/KdTree/intersectionhandler/KdRayIntersectionHandler.h b/src/basics/geometry3d/KdTree/intersectionhandler/KdRayIntersectionHandler.h
new file mode 100644
index 0000000000000000000000000000000000000000..e38fcd5340a94200b961c27f092aec1258722c13
--- /dev/null
+++ b/src/basics/geometry3d/KdTree/intersectionhandler/KdRayIntersectionHandler.h
@@ -0,0 +1,53 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file KdRayIntersectionHandler.h
+//! \ingroup splitalgorithms
+//! \author Soeren Textor, Sebastian Bindick
+//=======================================================================================
+#ifndef KDRAYINTERSECTIONHANDLER_H
+#define KDRAYINTERSECTIONHANDLER_H
+
+#include <basics/utilities/UbTuple.h>
+#include <geometry3d/KdTree/KdRay.h>
+
+#include <set>
+
+namespace Kd
+{
+template <typename T>
+class RayIntersectionHandler
+{
+public:
+    virtual int intersectRay(const Ray<T> &ray, Node<T> &parent, Node<T> *&child1, Node<T> *&child2,
+                             std::set<UbKeys::Key3<int>> &mailbox) const = 0;
+    virtual ~RayIntersectionHandler()                                    = default;
+};
+} // namespace Kd
+
+#endif // KDRAYINTERSECTIONHANDLER_H
diff --git a/src/basics/geometry3d/KdTree/splitalgorithms/KdSAHSplit.cpp b/src/basics/geometry3d/KdTree/splitalgorithms/KdSAHSplit.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b1437df34892146645692691894ace02b509871b
--- /dev/null
+++ b/src/basics/geometry3d/KdTree/splitalgorithms/KdSAHSplit.cpp
@@ -0,0 +1,39 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file KdSAHSplit.cpp
+//! \ingroup splitalgorithms
+//! \author Soeren Textor, Sebastian Bindick
+//=======================================================================================
+//#include <geometry3d/KdTree/SAHSplit.h>
+
+// namespace Kd
+// {
+//    const double SAHSplit::Ct = 3.0; //traversal cost
+//    const double SAHSplit::Ci = 4.0; //ray-patch-intersection-cost
+// }
diff --git a/src/basics/geometry3d/KdTree/splitalgorithms/KdSAHSplit.h b/src/basics/geometry3d/KdTree/splitalgorithms/KdSAHSplit.h
new file mode 100644
index 0000000000000000000000000000000000000000..334c911fb8fc68bf3b1c82a9757d026320edcf8e
--- /dev/null
+++ b/src/basics/geometry3d/KdTree/splitalgorithms/KdSAHSplit.h
@@ -0,0 +1,287 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file KdSAHSplit.h
+//! \ingroup splitalgorithms
+//! \author Soeren Textor, Sebastian Bindick
+//=======================================================================================
+#ifndef KDSAHSPLIT_H
+#define KDSAHSPLIT_H
+
+#include <basics/utilities/UbException.h>
+#include <basics/utilities/UbInfinity.h>
+#include <basics/utilities/UbMath.h>
+#include <geometry3d/GbTriFaceMesh3D.h>
+
+#include <geometry3d/KdTree/KdNode.h>
+#include <geometry3d/KdTree/KdSplitCandidateManager.h>
+#include <geometry3d/KdTree/KdUtilities.h>
+#include <geometry3d/KdTree/splitalgorithms/KdSplitAlgorithm.h>
+
+#include <cmath>
+#include <vector>
+
+namespace Kd
+{
+template <typename T>
+class SAHSplit : public SplitAlgorithm<T>
+{
+public:
+    /* ======================================================================================= */
+    SplitCandidate<T> findBestSplitCandidate(const int &level, const int &maxLevel, Node<T> &node) const override
+    {
+        if (!node.getTriFaces())
+            throw UbException(UB_EXARGS, "triFace NULL pointer");
+
+        if (node.getTriFaces()->size() <= 1 // max triangles in node
+            || level >= maxLevel) {
+            return SplitCandidate<T>();
+        }
+
+        SplitCandidate<T> bestSplitCandidate;
+        T minCN = Ub::inf;
+
+        for (int splitAxis = 0; splitAxis < 3; splitAxis++) {
+            SplitCandidateManager<T> sc;
+            findPossibleSplitCandidates(splitAxis, node, sc);
+
+            // incremental sweep to find best split position
+            for (std::size_t i = 0; i < sc.size(); i++) {
+                if (i == 0) {
+                    sc[i].nl = sc.objects_starting_outside_left + sc.objects_fully_outside_node;
+                    sc[i].nr = int(node.getTriFaces()->size()) - sc[0].np - sc[0].ending;
+                } else {
+                    sc[i].nl = sc[i - 1].nl + sc[i - 1].starting + sc[i - 1].np;
+                    sc[i].nr = sc[i - 1].nr - sc[i].ending - sc[i].np;
+                }
+
+                this->calcSAH(sc[i], node);
+
+                if (sc[i].Cn < minCN) {
+                    minCN              = sc[i].Cn;
+                    bestSplitCandidate = sc[i];
+                }
+            }
+        }
+
+        // automatic termination criterion (SAH)
+        if (bestSplitCandidate.isValid && bestSplitCandidate.Cn >= node.getTriFaces()->size() * Ci) {
+            return SplitCandidate<T>();
+        }
+
+        return bestSplitCandidate;
+    }
+    /* ======================================================================================= */
+    void distributeTriFaces(const SplitCandidate<T> &candidate,
+                            std::vector<GbTriFaceMesh3D::TriFace> &triFacesForChild1,
+                            std::vector<GbTriFaceMesh3D::TriFace> &triFacesForChild2, Node<T> &node) const override
+    {
+        if (!node.getTriFaces())
+            throw UbException(UB_EXARGS, "null pointer at triface list");
+
+        std::vector<GbTriFaceMesh3D::TriFace> &srcTriFaces = *node.getTriFaces();
+        std::vector<GbTriFaceMesh3D::Vertex> &srcNodes     = node.getNodes();
+        std::vector<T> projection;
+
+        for (std::size_t i = 0; i < srcTriFaces.size(); i++) {
+            GbTriFaceMesh3D::TriFace &triFace = srcTriFaces[i];
+            Kd::project2Axis(triFace, srcNodes, candidate.axis, projection);
+
+            T &min = projection[0];
+            T &max = projection[2];
+            // --------------------------------------------------- //
+            // case 1 : object inside plane
+            if (UbMath::equal(min, max)) {
+                if (UbMath::equal(min, candidate.position)) {
+                    if (candidate.np_left) {
+                        triFacesForChild1.push_back(triFace);
+                    } else if (candidate.np_right) {
+                        triFacesForChild2.push_back(triFace);
+                    }
+                } else if (UbMath::less(min, candidate.position)) {
+                    triFacesForChild1.push_back(triFace);
+                } else // if( UbMath::greater(min, candidate.position)
+                {
+                    triFacesForChild2.push_back(triFace);
+                }
+            } //
+            // --------------------------------------------------- //
+            // case 2 : object on left side of plane
+            else if (UbMath::lessEqual(max, candidate.position)) {
+                triFacesForChild1.push_back(triFace);
+            } // --------------------------------------------------- //
+            // case 3 : object on right side of plane
+            else if (UbMath::greaterEqual(min, candidate.position)) {
+                triFacesForChild2.push_back(triFace);
+            } //
+            // --------------------------------------------------- //
+            // case 4 : object in both nodes
+            else {
+                triFacesForChild1.push_back(triFace);
+                triFacesForChild2.push_back(triFace);
+            } //
+              // --------------------------------------------------- //
+        }
+
+        node.deleteTriFaces();
+    }
+
+private:
+    /* ======================================================================================= */
+    // cost function
+    inline T calcCosts(const int &nl, const int &nr, const T &SA_VL, const T &SA_VR, const T &SA_V) const
+    {
+        return Ct + Ci * (nl * SA_VL / SA_V + nr * SA_VR / SA_V);
+    }
+    /* ======================================================================================= */
+    void findPossibleSplitCandidates(const int &splitAxis, Node<T> &node,
+                                     SplitCandidateManager<T> &splitCandidateManager) const
+    {
+        T p1_node = (splitAxis == Axis::X ? node.x[0] : splitAxis == Axis::Y ? node.y[0] : node.z[0]);
+        T p2_node = (splitAxis == Axis::X ? node.x[1] : splitAxis == Axis::Y ? node.y[1] : node.z[1]);
+
+        if (!node.getTriFaces())
+            throw UbException(UB_EXARGS, "null pointer");
+
+        std::vector<GbTriFaceMesh3D::TriFace> &srcTriFaces = *node.getTriFaces();
+        std::vector<GbTriFaceMesh3D::Vertex> &srcNodes     = node.getNodes();
+        std::vector<T> projection;
+
+        for (std::size_t i = 0; i < srcTriFaces.size(); i++) {
+            GbTriFaceMesh3D::TriFace &triFace = srcTriFaces[i];
+
+            // project object to axis
+            Kd::project2Axis(triFace, srcNodes, splitAxis, projection);
+            // left point
+            T &p1 = projection[0];
+            // right point
+            T &p2 = projection[2];
+
+            // --------------------------------------------------- //
+            // --------------------------------------------------- //
+            // case 1 : object is fully inside the current node
+            if (UbMath::greaterEqual(p1, p1_node) && UbMath::lessEqual(p2, p2_node)) {
+                if (UbMath::equal(p1, p2)) {
+                    // object is inside the plane
+                    splitCandidateManager.add(p1, splitAxis, 0, 0, 1);
+                } else {
+                    splitCandidateManager.add(p1, splitAxis, 1, 0, 0);
+                    splitCandidateManager.add(p2, splitAxis, 0, 1, 0);
+                }
+            } //
+            // --------------------------------------------------- //
+            // --------------------------------------------------- //
+            // case 2 : just the right point (p2) is inside the current node
+            else if (UbMath::less(p1, p1_node) && UbMath::lessEqual(p2, p2_node) && UbMath::greaterEqual(p2, p1_node)) {
+                splitCandidateManager.add(p2, splitAxis, 0, 1, 0);
+                splitCandidateManager.objects_starting_outside_left++;
+            } //
+            // --------------------------------------------------- //
+            // --------------------------------------------------- //
+            // case 3 : just the left point (p1) is inside the current node
+            else if (UbMath::greaterEqual(p1, p1_node) && UbMath::greater(p2, p2_node) &&
+                     UbMath::lessEqual(p1, p2_node)) {
+                splitCandidateManager.add(p1, splitAxis, 1, 0, 0);
+            } //
+            // --------------------------------------------------- //
+            // --------------------------------------------------- //
+            // case 4 : left and right point are outside the current node
+            else if (UbMath::less(p1, p1_node) && UbMath::greater(p2, p2_node)) {
+                splitCandidateManager.objects_fully_outside_node++;
+            } //
+              // --------------------------------------------------- //
+              // --------------------------------------------------- //
+        }
+
+        splitCandidateManager.createSortedArray();
+    }
+
+    /* ======================================================================================= */
+    // calculates the costs for a given splitCandidate based on the Surface Area Heuristic (SAH)
+    void calcSAH(SplitCandidate<T> &candidate, Node<T> &node) const
+    {
+        T p1_node = (candidate.axis == Axis::X ? node.x[0] : candidate.axis == Axis::Y ? node.y[0] : node.z[0]);
+
+        // edges of (root) voxel
+        T dx = std::fabs(node.x[1] - node.x[0]);
+        T dy = std::fabs(node.y[1] - node.y[0]);
+        T dz = std::fabs(node.z[1] - node.z[0]);
+
+        // surface area (root) voxel
+        T SA_V = T((2.0 * dx * dy) + (2.0 * dx * dz) + (2.0 * dy * dz));
+
+        T delta  = (candidate.axis == Axis::X ? dx : candidate.axis == Axis::Y ? dy : dz);
+        T deltaL = std::fabs(candidate.position - p1_node);
+        T deltaR = std::fabs(delta - deltaL);
+
+        // edges of sub voxel left
+        T dx_l = (candidate.axis == Axis::X ? deltaL : dx), dy_l = (candidate.axis == Axis::Y ? deltaL : dy),
+          dz_l = (candidate.axis == Axis::Z ? deltaL : dz);
+
+        // surface area sub voxel left
+        T SA_VL = T((2.0 * dx_l * dy_l) + (2.0 * dx_l * dz_l) + (2.0 * dy_l * dz_l));
+
+        // edges of sub voxel right
+        T dx_r = (candidate.axis == Axis::X ? deltaR : dx), dy_r = (candidate.axis == Axis::Y ? deltaR : dy),
+          dz_r = (candidate.axis == Axis::Z ? deltaR : dz);
+
+        // surface area sub voxel right
+        T SA_VR = T((2.0 * dx_r * dy_r) + (2.0 * dx_r * dz_r) + (2.0 * dy_r * dz_r));
+
+        if (candidate.np == 0) {
+            candidate.Cn = calcCosts(candidate.nl, candidate.nr, SA_VL, SA_VR, SA_V);
+            return;
+        }
+
+        // once putting np with nl, and once with nr - and select the one with lowest cost
+        // see: Wald, Havran: "On building fast kd-Trees for Ray Tracing, and doing that in O(N log N)", 2006
+        T CP_L = calcCosts(candidate.nl + candidate.np, candidate.nr, SA_VL, SA_VR, SA_V);
+        T CP_R = calcCosts(candidate.nl, candidate.nr + candidate.np, SA_VL, SA_VR, SA_V);
+
+        if (CP_L < CP_R) {
+            candidate.Cn       = CP_L;
+            candidate.np_right = true;
+        } else {
+            candidate.Cn      = CP_R;
+            candidate.np_left = true;
+        }
+    }
+    /* ======================================================================================= */
+
+protected:
+    static const T Ct; // = 3.0; traversal cost
+    static const T Ci; // = 4.0; ray-patch-intersection-cost
+};
+
+template <typename T>
+const T SAHSplit<T>::Ct = 3.0; // traversal cost
+template <typename T>
+const T SAHSplit<T>::Ci = 4.0; // ray-patch-intersection-cost
+} // namespace Kd
+
+#endif // KDSAHSPLIT_H
diff --git a/src/basics/geometry3d/KdTree/splitalgorithms/KdSpatiallMedianSplit.h b/src/basics/geometry3d/KdTree/splitalgorithms/KdSpatiallMedianSplit.h
new file mode 100644
index 0000000000000000000000000000000000000000..57a3eef3b9e2d2698b307fcac124f932b8b0b148
--- /dev/null
+++ b/src/basics/geometry3d/KdTree/splitalgorithms/KdSpatiallMedianSplit.h
@@ -0,0 +1,115 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file KdSpacialMedianSplit.h
+//! \ingroup splitalgorithms
+//! \author Soeren Textor, Sebastian Bindick
+//=======================================================================================
+#ifndef SPATIALLMEDIANSPLIT_H
+#define SPATIALLMEDIANSPLIT_H
+
+#include <basics/utilities/UbMath.h>
+#include <geometry3d/GbTriFaceMesh3D.h>
+
+#include <geometry3d/KdTree/splitalgorithms/KdSplitAlgorithm.h>
+
+namespace Kd
+{
+template <typename T>
+class SpatialMedianSplit : public SplitAlgorithm<T>
+{
+    /* ======================================================================================= */
+    SplitCandidate<T> findBestSplitCandidate(const int &level, const int &maxLevel, Node<T> &node) const override
+    {
+        if (node.getTriFaces()->size() <= 24 // max triangles in node
+            || level >= maxLevel) {
+            return SplitCandidate<T>();
+        }
+
+        T dx = std::fabs(node.x[1] - node.x[0]);
+        T dy = std::fabs(node.y[1] - node.y[0]);
+        T dz = std::fabs(node.z[1] - node.z[0]);
+
+        if (UbMath::equal(dx, UbMath::max(dx, dy, dz)))
+            return SplitCandidate<T>(Axis::X, node.x[0] + 0.5 * dx, 0, 0, 0);
+        else if (UbMath::equal(dy, UbMath::max(dy, dz)))
+            return SplitCandidate<T>(Axis::Y, node.y[0] + 0.5 * dy, 0, 0, 0);
+
+        return SplitCandidate<T>(Axis::Z, node.z[0] + 0.5 * dz, 0, 0, 0);
+    }
+    /* ======================================================================================= */
+    void distributeTriFaces(const SplitCandidate<T> &candidate,
+                            std::vector<GbTriFaceMesh3D::TriFace> &primitives_child1,
+                            std::vector<GbTriFaceMesh3D::TriFace> &primitives_child2, Node<T> &node) const override
+    {
+        if (!node.getTriFaces())
+            throw UbException(UB_EXARGS, "null pointer");
+
+        std::vector<GbTriFaceMesh3D::TriFace> &srcTriFaces = *node.getTriFaces();
+        std::vector<GbTriFaceMesh3D::Vertex> &srcNodes     = node.getNodes();
+        std::vector<T> projection;
+
+        for (std::size_t i = 0; i < srcTriFaces.size(); i++) {
+            GbTriFaceMesh3D::TriFace &triFace = srcTriFaces[i];
+            Kd::project2Axis(triFace, srcNodes, candidate.axis, projection);
+
+            T &min = projection[0];
+            T &max = projection[2];
+
+            // case 1 : object inside plane
+            if (UbMath::equal(min, max)) {
+                if (UbMath::equal(min, candidate.position)) {
+                    primitives_child1.push_back(triFace);
+                    primitives_child2.push_back(triFace);
+                } else if (UbMath::less(min, candidate.position)) {
+                    primitives_child1.push_back(triFace);
+                } else if (UbMath::greater(min, candidate.position)) {
+                    primitives_child2.push_back(triFace);
+                }
+            }
+            // case 2 : object on left side of plane
+            else if (UbMath::lessEqual(max, candidate.position)) {
+                primitives_child1.push_back(triFace);
+            }
+            // case 3 : object on right side of plane
+            else if (UbMath::greaterEqual(min, candidate.position)) {
+                primitives_child2.push_back(triFace);
+            }
+            // case 4 : object in both nodes
+            else {
+                primitives_child1.push_back(triFace);
+                primitives_child2.push_back(triFace);
+            }
+        }
+
+        node.deleteTriFaces();
+    }
+};
+} // namespace Kd
+
+#endif // SPATIALLMEDIANSPLIT_H
diff --git a/src/basics/geometry3d/KdTree/splitalgorithms/KdSplitAlgorithm.h b/src/basics/geometry3d/KdTree/splitalgorithms/KdSplitAlgorithm.h
new file mode 100644
index 0000000000000000000000000000000000000000..b6901241e9dd36a1f687ff87a9a292ef95daa1b8
--- /dev/null
+++ b/src/basics/geometry3d/KdTree/splitalgorithms/KdSplitAlgorithm.h
@@ -0,0 +1,59 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file KdSplitAlgorithm.h
+//! \ingroup splitalgorithms
+//! \author Soeren Textor, Sebastian Bindick
+//=======================================================================================
+#ifndef KDSPLITALGORITHM_H
+#define KDSPLITALGORITHM_H
+
+#include <geometry3d/GbTriFaceMesh3D.h>
+//#include <geometry3d/KdTree/Node.h>
+#include <geometry3d/KdTree/KdSplitCandidate.h>
+
+#include <vector>
+
+namespace Kd
+{
+template <typename T>
+class Node;
+
+template <typename T>
+class SplitAlgorithm
+{
+public:
+    virtual SplitCandidate<T> findBestSplitCandidate(const int &level, const int &maxLevel, Node<T> &node) const   = 0;
+    virtual void distributeTriFaces(const SplitCandidate<T> &candidate,
+                                    std::vector<GbTriFaceMesh3D::TriFace> &triFacesForChild1,
+                                    std::vector<GbTriFaceMesh3D::TriFace> &triFacesForChild2, Node<T> &node) const = 0;
+    virtual ~SplitAlgorithm() = default;
+};
+} // namespace Kd
+
+#endif // KDSPLITALGORITHM_H
diff --git a/src/gpu/GksGpu/BoundaryConditions/BoundaryCondition.cpp b/src/gpu/GksGpu/BoundaryConditions/BoundaryCondition.cpp
index 781ba46d26df995446312199a805f6c8d499998e..b9abb50130e18df11062c144a53e21461dae7fbf 100644
--- a/src/gpu/GksGpu/BoundaryConditions/BoundaryCondition.cpp
+++ b/src/gpu/GksGpu/BoundaryConditions/BoundaryCondition.cpp
@@ -43,6 +43,8 @@
 #include "DataBase/DataBaseAllocator.h"
 #include "DataBase/DataBaseStruct.h"
 
+using namespace vf::gpu;
+
 BoundaryCondition::BoundaryCondition( SPtr<DataBase> dataBase )
     : myAllocator ( dataBase->myAllocator )
 {
diff --git a/src/gpu/GksMeshAdapter/GksMeshAdapter.cpp b/src/gpu/GksMeshAdapter/GksMeshAdapter.cpp
index fcff658b3662bf5ce55bdc42c0a8d07e8e7c872d..28a0b87d12e9de452a3a42b8ddfa0fe3e5add8e7 100644
--- a/src/gpu/GksMeshAdapter/GksMeshAdapter.cpp
+++ b/src/gpu/GksMeshAdapter/GksMeshAdapter.cpp
@@ -53,6 +53,8 @@
 #include "MeshCell.h"
 #include "MeshFace.h"
 
+using namespace vf::gpu;
+
 GksMeshAdapter::GksMeshAdapter(SPtr<MultipleGridBuilder> gridBuilder)
     : gridBuilder(gridBuilder)
 {}
diff --git a/src/gpu/GksMeshAdapter/MeshCell.cpp b/src/gpu/GksMeshAdapter/MeshCell.cpp
index 65a931c84deca244abf78e100bb838dd9c1870f3..349d308ee498e89f9705091c72d3ca7013bf3d4e 100644
--- a/src/gpu/GksMeshAdapter/MeshCell.cpp
+++ b/src/gpu/GksMeshAdapter/MeshCell.cpp
@@ -34,6 +34,8 @@
 
 #include "GridGenerator/grid/NodeValues.h"
 
+using namespace vf::gpu;
+
 MeshCell::MeshCell(){
 
     level   = INVALID_INDEX;
diff --git a/src/gpu/GridGenerator/CMakeLists.txt b/src/gpu/GridGenerator/CMakeLists.txt
index 9168222045a58a498b23f69ff4dce1a9e9ee5ac5..07b6125d6ecd83dca59e20e7c286ebc2b8d14715 100644
--- a/src/gpu/GridGenerator/CMakeLists.txt
+++ b/src/gpu/GridGenerator/CMakeLists.txt
@@ -1,16 +1,7 @@
-project(GridGenerator LANGUAGES CUDA CXX)
-
+project(GridGenerator LANGUAGES CXX)
 
 vf_add_library(PRIVATE_LINK basics OpenMP::OpenMP_CXX)
 
-vf_get_library_name(library_name)
-set_target_properties(${library_name} PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
-
-# according to linker error when building static libraries.
-# https://stackoverflow.com/questions/50033435/cmake-cuda-separate-compilation-static-lib-link-error-on-windows-but-not-on-ubun
-if (NOT BUILD_SHARED_LIBRARY)
-    set_target_properties(${library_name} PROPERTIES CUDA_RESOLVE_DEVICE_SYMBOLS ON)
-endif()
-
-# we want to suppress all cuda warnings so far for this library.
-target_compile_options(${library_name} PUBLIC $<$<COMPILE_LANGUAGE:CUDA>:-Xcudafe "-w" >)
\ No newline at end of file
+if(NOT MSVC) 
+   target_compile_options(GridGenerator PRIVATE "-Wno-strict-aliasing")
+endif()
\ No newline at end of file
diff --git a/src/gpu/GridGenerator/StreetPointFinder/JunctionReader.cpp b/src/gpu/GridGenerator/StreetPointFinder/JunctionReader.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..bac17264d1c00389bbefacc4063d7801e8f5baa7
--- /dev/null
+++ b/src/gpu/GridGenerator/StreetPointFinder/JunctionReader.cpp
@@ -0,0 +1,145 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file JunctionReader.cpp
+//! \ingroup StreetPointFinder
+//! \author Stephan Lenz
+//=======================================================================================
+#include "JunctionReader.h"
+
+#include <fstream>
+#include <iostream>
+#include <string>
+
+
+JunctionReaderData::JunctionReaderData(std::vector<uint> inCells, std::vector<uint> outCells, std::vector<int> carCanNotEnterThisOutCell, uint trafficLightSwitchTime = 0) :
+	inCells{ inCells }, outCells{ outCells }, carCanNotEnterThisOutCell{ carCanNotEnterThisOutCell }, trafficLightSwitchTime{ trafficLightSwitchTime }
+{}
+
+void JunctionReader::readJunctions(std::string filename, StreetPointFinder* streetPointFinder)
+{
+	*logging::out << logging::Logger::INFO_INTERMEDIATE << "StreetPointFinder::readJunctions( " << filename << " )" << "\n";
+
+	std::ifstream file;
+	file.open(filename.c_str());
+	if (!file.is_open()) std::cerr << "File not found" << std::endl;
+	this->streetPointFinder = streetPointFinder;
+
+	uint numberOfJunctions;
+	file >> numberOfJunctions;
+
+	std::string inOutDummy;
+	int streetIndex = 0;
+	uint trafficLightTime = 0;
+	bool onlyNeighbors = false;
+
+	file >> inOutDummy;
+
+	for (uint i = 0; i < numberOfJunctions; i++) {
+		std::vector<uint> inCells, outCells;
+		std::vector<int> carCanNotEnterThisOutCell;
+
+		//inCells
+		file >> inOutDummy;
+		while (inOutDummy.compare("out") != 0) {
+			streetIndex = std::stoi(inOutDummy);
+
+			if (streetIndex >= 0)
+				inCells.push_back(getCellIndex(streetIndex, 'e'));
+
+			file >> inOutDummy;
+		}
+
+		//outCells
+		file >> inOutDummy;
+		while (inOutDummy.compare("in") != 0 && inOutDummy.compare("end") != 0 && inOutDummy.compare("t") != 0 && inOutDummy.compare("c") != 0) {
+			streetIndex = std::stoi(inOutDummy);
+
+			if (streetIndex >= 0) {
+				outCells.push_back(getCellIndex(streetIndex, 's'));
+				if (carCanNotEnterThisOutCell.size() < inCells.size())
+					carCanNotEnterThisOutCell.push_back(getCellIndex(streetIndex, 's'));
+			}
+			else if (streetIndex == -2) //no prohibited outCell
+				carCanNotEnterThisOutCell.push_back(-2);
+
+			file >> inOutDummy;
+		}
+
+		//trafficLightTime
+		if (inOutDummy.compare("t") == 0) {
+			file >> inOutDummy;
+			trafficLightTime = std::stoi(inOutDummy);
+			file >> inOutDummy;
+		}
+		else
+			trafficLightTime = 0;
+
+		// only neighbors (used for curves)
+		if (inOutDummy.compare("c") == 0) {
+			onlyNeighbors = true;
+			file >> inOutDummy;
+		}
+
+
+		//make Junction or neighbors
+		if (onlyNeighbors) {
+			if (inCells.size() == 2 && outCells.size() == 2) {
+				specialNeighbors.cells.insert(specialNeighbors.cells.end(), inCells.begin(), inCells.end());
+				specialNeighbors.neighbors.push_back(outCells[1]);     
+				specialNeighbors.neighbors.push_back(outCells[0]);
+
+				onlyNeighbors = false;
+			}
+			else 
+            { 
+                // TODO: this could be a bug, as before this change "continue" was not guarded by the "else"
+                // https://git.rz.tu-bs.de/irmb/VirtualFluids_dev/-/issues/11
+                std::cerr << "can't add curve" << std::endl; 
+                continue;
+            }
+		}
+		else
+			junctions.push_back(JunctionReaderData(inCells, outCells, carCanNotEnterThisOutCell, trafficLightTime));
+
+	}
+}
+
+
+unsigned int JunctionReader::getCellIndex(unsigned int streetIndex, char startOrEnd)
+{
+	uint i = 0;
+	unsigned int cellIndex = 0;
+	while (i < streetIndex) {
+		cellIndex += streetPointFinder->streets[i].numberOfCells;
+		++i;
+	}
+	if (startOrEnd == 's') 	return cellIndex;
+	return cellIndex + streetPointFinder->streets[streetIndex].numberOfCells - 1;
+}
+
diff --git a/src/gpu/GridGenerator/StreetPointFinder/JunctionReader.h b/src/gpu/GridGenerator/StreetPointFinder/JunctionReader.h
new file mode 100644
index 0000000000000000000000000000000000000000..5b68b0357ea2432dfde6d167b27908fe1aa4348a
--- /dev/null
+++ b/src/gpu/GridGenerator/StreetPointFinder/JunctionReader.h
@@ -0,0 +1,78 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file JunctionReader.h
+//! \ingroup StreetPointFinder
+//! \author Stephan Lenz
+//=======================================================================================
+#ifndef JUNCTIONREADER_H
+#define JUNCTIONREADER_H
+
+#include <vector>
+
+#include "GridGenerator_export.h"
+
+#include "Core/DataTypes.h"
+#include "Core/Logger/Logger.h"
+
+#include "StreetPointFinder.h"
+
+
+
+struct GRIDGENERATOR_EXPORT JunctionReaderData
+{
+	std::vector<uint> inCells;
+	std::vector<uint> outCells;
+	std::vector<int> carCanNotEnterThisOutCell;
+	uint trafficLightSwitchTime;
+
+	JunctionReaderData(std::vector<uint> inCells, std::vector<uint> outCells, std::vector<int> carCanNotEnterThisOutCell, uint trafficLightSwitchTime);
+};
+
+
+struct GRIDGENERATOR_EXPORT Neighbors
+{
+	std::vector<int> cells;
+	std::vector<int> neighbors;
+};
+
+
+
+struct GRIDGENERATOR_EXPORT JunctionReader
+{
+	std::vector<JunctionReaderData> junctions;
+	Neighbors specialNeighbors;
+	StreetPointFinder* streetPointFinder;
+
+	void readJunctions(std::string filename, StreetPointFinder* streetPointFinder);
+
+
+private:
+	unsigned int getCellIndex(unsigned int streetIndex, char startOrEnd);
+};
+#endif
diff --git a/src/gpu/GridGenerator/StreetPointFinder/SinkReader.cpp b/src/gpu/GridGenerator/StreetPointFinder/SinkReader.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1224f1bf7cad8e535e842426406aacc619dad314
--- /dev/null
+++ b/src/gpu/GridGenerator/StreetPointFinder/SinkReader.cpp
@@ -0,0 +1,75 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file SinkReader.cpp
+//! \ingroup StreetPointFinder
+//! \author Stephan Lenz
+//=======================================================================================
+#include "SinkReader.h"
+
+#include <fstream>
+#include <iostream>
+
+SinkReaderData::SinkReaderData(uint sinkIndex, float sinkBlockedPossibility) :
+	sinkIndex{ sinkIndex }, sinkBlockedPossibility{ sinkBlockedPossibility }
+{}
+
+void SinkReader::readSinks(std::string filename, StreetPointFinder* streetPointFinder)
+{
+	*logging::out << logging::Logger::INFO_INTERMEDIATE << "StreetPointFinder::readSinks( " << filename << " )" << "\n";
+
+	this->streetPointFinder = streetPointFinder;
+
+	std::ifstream file;
+	file.open(filename.c_str());
+	if (!file.is_open()) std::cerr << "File not found" << std::endl;
+
+	uint numberOfSinks;
+	file >> numberOfSinks;
+
+	uint streetIndex;
+	float sinkBlockedPossibility;
+
+
+	for (uint i = 0; i < numberOfSinks; i++) {
+		file >> streetIndex >> sinkBlockedPossibility;
+		sinks.push_back(SinkReaderData(getCellIndexEnd(streetIndex), sinkBlockedPossibility));
+	}
+}
+
+unsigned int SinkReader::getCellIndexEnd(unsigned int streetIndex)
+{
+	uint i = 0;
+	unsigned int cellIndex = 0;
+	while (i < streetIndex) {
+		cellIndex += streetPointFinder->streets[i].numberOfCells;
+		++i;
+	}
+	
+	return cellIndex + streetPointFinder->streets[streetIndex].numberOfCells - 1;
+}
diff --git a/src/gpu/GridGenerator/StreetPointFinder/SinkReader.h b/src/gpu/GridGenerator/StreetPointFinder/SinkReader.h
new file mode 100644
index 0000000000000000000000000000000000000000..ba28596b0eb63954eb5f7162c4849f863e15f657
--- /dev/null
+++ b/src/gpu/GridGenerator/StreetPointFinder/SinkReader.h
@@ -0,0 +1,65 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file SinkReader.h
+//! \ingroup StreetPointFinder
+//! \author Stephan Lenz
+//=======================================================================================
+#ifndef SINKREADER_H
+#define  SINKREADER_H
+
+#include <vector>
+
+#include "GridGenerator_export.h"
+
+#include "Core/DataTypes.h"
+#include "Core/Logger/Logger.h"
+
+#include "StreetPointFinder.h"
+
+
+
+struct GRIDGENERATOR_EXPORT SinkReaderData{
+	uint sinkIndex;
+	float sinkBlockedPossibility;
+	SinkReaderData(uint sinkIndex, float sinkBlockedPossibility);
+};
+
+struct GRIDGENERATOR_EXPORT SinkReader
+{
+	std::vector<SinkReaderData> sinks;
+	StreetPointFinder* streetPointFinder;
+
+	void readSinks(std::string filename, StreetPointFinder* streetPointFinder);
+
+private:
+	unsigned int getCellIndexEnd(unsigned int streetIndex);
+};
+
+
+#endif
\ No newline at end of file
diff --git a/src/gpu/GridGenerator/StreetPointFinder/SourceReader.cpp b/src/gpu/GridGenerator/StreetPointFinder/SourceReader.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a3a62f942f96fa1faf9e49448ed3ae627d985273
--- /dev/null
+++ b/src/gpu/GridGenerator/StreetPointFinder/SourceReader.cpp
@@ -0,0 +1,78 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file SourceReader.cpp
+//! \ingroup StreetPointFinder
+//! \author Stephan Lenz
+//=======================================================================================
+#include "SourceReader.h"
+
+#include <fstream>
+#include <iostream>
+
+SourceReaderData::SourceReaderData(unsigned int sourceIndex, float sourcePossibility):
+	sourceIndex{sourceIndex}, sourcePossibility{sourcePossibility}
+{}
+
+
+void SourceReader::readSources(std::string filename, StreetPointFinder* streetPointFinder)
+{
+	*logging::out << logging::Logger::INFO_INTERMEDIATE << "StreetPointFinder::readSources( " << filename << " )" << "\n";
+
+	this->streetPointFinder = streetPointFinder;
+
+	std::ifstream file;
+	file.open(filename.c_str());
+	if (!file.is_open()) std::cerr << "File not found" << std::endl;
+
+	uint numberOfSources;
+	file >> numberOfSources;
+
+	uint streetIndex;
+	float sourcePossibility;
+
+
+	for (uint i = 0; i < numberOfSources; i++) {
+		file >> streetIndex  >> sourcePossibility;
+		sources.push_back(SourceReaderData(getCellIndexStart(streetIndex), sourcePossibility));
+	}
+}
+
+
+unsigned int SourceReader::getCellIndexStart(unsigned int streetIndex)
+{
+	uint i = 0;
+	unsigned int cellIndex = 0;
+	while (i < streetIndex) {
+		cellIndex += streetPointFinder->streets[i].numberOfCells;
+		++i;
+	}
+	return cellIndex;
+}
+	
+	
diff --git a/src/gpu/GridGenerator/StreetPointFinder/SourceReader.h b/src/gpu/GridGenerator/StreetPointFinder/SourceReader.h
new file mode 100644
index 0000000000000000000000000000000000000000..f79c618d06ff9f72738c7b69767a8dd3c5443fac
--- /dev/null
+++ b/src/gpu/GridGenerator/StreetPointFinder/SourceReader.h
@@ -0,0 +1,63 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file SourceReader.h
+//! \ingroup StreetPointFinder
+//! \author Stephan Lenz
+//=======================================================================================
+#ifndef SOURCEREADER_H
+#define  SOURCEREADER_H
+
+#include <vector>
+
+#include "Core/DataTypes.h"
+#include "Core/Logger/Logger.h"
+
+#include "StreetPointFinder.h"
+
+
+
+struct GRIDGENERATOR_EXPORT SourceReaderData {
+	unsigned int sourceIndex;
+	float sourcePossibility;
+	SourceReaderData(unsigned int sourceIndex, float sourcePossibility);
+};
+
+struct GRIDGENERATOR_EXPORT SourceReader
+{
+	std::vector<SourceReaderData> sources;
+	StreetPointFinder* streetPointFinder;
+
+	void readSources(std::string filename, StreetPointFinder* streetPointFinder);
+
+private:
+	unsigned int getCellIndexStart(unsigned int streetIndex);
+};
+
+
+#endif
\ No newline at end of file
diff --git a/src/gpu/GridGenerator/StreetPointFinder/StreetPointFinder.cpp b/src/gpu/GridGenerator/StreetPointFinder/StreetPointFinder.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9fbd3933a5457e96d2d1aa01f1fadcf675be1980
--- /dev/null
+++ b/src/gpu/GridGenerator/StreetPointFinder/StreetPointFinder.cpp
@@ -0,0 +1,790 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file StreetPointFinder.cpp
+//! \ingroup StreetPointFinder
+//! \author Stephan Lenz
+//=======================================================================================
+#include "StreetPointFinder.h"
+
+#include "Core/Logger/Logger.h"
+
+#include <string>
+#include <sstream>
+#include <fstream>
+#include <iostream>
+#include <cmath>
+#include <algorithm>
+#include <numeric>
+
+#include "grid/Grid.h"
+#include "grid/NodeValues.h"
+
+using namespace vf::gpu;
+
+Street::Street(real xStartCell, real yStartCell, real xEndCell, real yEndCell, real dx)
+{
+	real length = std::sqrt((xEndCell - xStartCell)*(xEndCell - xStartCell)
+		+ (yEndCell - yStartCell)*(yEndCell - yStartCell));
+
+	this->numberOfCells = std::floor(length / dx);
+
+	real realLength = dx * (this->numberOfCells);
+
+	real vectorX = (xEndCell - xStartCell) / length;
+	real vectorY = (yEndCell - yStartCell) / length;
+
+	this->xStart = xStartCell - 0.5 * (realLength - length) * vectorX + 0.5 * dx  * vectorX;
+	this->yStart = yStartCell - 0.5 * (realLength - length) * vectorY + 0.5 * dx  * vectorY;
+
+	this->xEnd = xEndCell + 0.5 * (realLength - length) * vectorX - 0.5 * dx  * vectorX;
+	this->yEnd = yEndCell + 0.5 * (realLength - length) * vectorY - 0.5 * dx  * vectorY;
+
+	//this->xStart = xStart + dx * (xEnd - xStart) / length;
+	//this->yStart = yStart + dx * (yEnd - yStart) / length;
+	//
+	//this->xEnd   = xEnd   - dx * (xEnd - xStart) / length;
+	//this->yEnd   = yEnd   - dx * (yEnd - yStart) / length;
+
+	//this->numberOfCells = std::lround( length / dx ) + 1;
+}
+
+real Street::getCoordinateX(int cellIndex)
+{
+	return xStart + real(cellIndex) / real(numberOfCells - 1) * (xEnd - xStart);
+}
+
+real Street::getCoordinateY(int cellIndex)
+{
+	return yStart + real(cellIndex) / real(numberOfCells - 1) * (yEnd - yStart);
+}
+
+real Street::getVectorX()
+{
+	real vecX = this->xEnd - this->xStart;
+	real vecY = this->yEnd - this->yStart;
+
+	real length = sqrt(vecX*vecX + vecY*vecY);
+
+	return vecX / length;
+}
+
+real Street::getVectorY()
+{
+	real vecX = this->xEnd - this->xStart;
+	real vecY = this->yEnd - this->yStart;
+
+	real length = sqrt(vecX*vecX + vecY*vecY);
+
+	return vecY / length;
+}
+
+void Street::findIndicesLB(SPtr<Grid> grid, real initialSearchHeight)
+{
+	for (uint i = 0; i < numberOfCells; i++)
+	{
+		real x = getCoordinateX(i);
+		real y = getCoordinateY(i);
+
+		uint matrixIndex = grid->transCoordToIndex(x, y, initialSearchHeight);
+
+		real xLB, yLB, zLB;
+		grid->transIndexToCoords(matrixIndex, xLB, yLB, zLB);
+
+		while (grid->getFieldEntry(matrixIndex) != BC_SOLID ||
+			   grid->getFieldEntry(grid->transCoordToIndex(xLB, yLB, zLB-grid->getDelta())) != STOPPER_SOLID)
+		{
+			zLB -= grid->getDelta();
+			matrixIndex = grid->transCoordToIndex(xLB, yLB, zLB);
+		}
+
+		std::stringstream msg;
+
+
+		msg << "( " << x << ", " << y << " )" << "  ==>  ";
+		msg << "( " << xLB << ", " << yLB << ", " << zLB << " ), type = [" << (int)grid->getFieldEntry(matrixIndex) << "], z = " << zLB << " \n";
+
+		*logging::out << logging::Logger::INFO_LOW << msg.str();
+
+		this->matrixIndicesLB.push_back(matrixIndex);
+		this->sparseIndicesLB.push_back(grid->getSparseIndex(matrixIndex));
+	}
+}
+
+void StreetPointFinder::prepareSimulationFileData()
+{
+	//////////////////////////////////////////////////////////////////////////
+	// Concatenate sparseIndicesLB
+
+	for (auto& street : this->streets) this->sparseIndicesLB.insert(this->sparseIndicesLB.end(), street.sparseIndicesLB.begin(), street.sparseIndicesLB.end());
+
+	//////////////////////////////////////////////////////////////////////////
+	// prepare vectors
+
+	uint numberOfCells = (uint)this->sparseIndicesLB.size();
+
+	mapNashToConc.resize(numberOfCells);
+
+	std::vector<uint> indexMap(numberOfCells);
+	std::iota(indexMap.begin(), indexMap.end(), 0);
+
+	//////////////////////////////////////////////////////////////////////////
+	// sort vectors
+
+	std::stable_sort(indexMap.begin(),
+		indexMap.end(),
+		[&](uint lhs, uint rhs) {
+		return this->sparseIndicesLB[lhs] <= this->sparseIndicesLB[rhs];
+	});
+
+	std::stable_sort(this->sparseIndicesLB.begin(),
+		this->sparseIndicesLB.end(),
+		[](uint lhs, uint rhs) {
+		return lhs <= rhs;
+	});
+	//////////////////////////////////////////////////////////////////////////
+	// invert idxMap
+
+	{
+		std::vector<uint> buffer = indexMap;
+		for (uint idx = 0; idx < indexMap.size(); idx++)
+			indexMap[buffer[idx]] = idx;
+	}
+
+	//////////////////////////////////////////////////////////////////////////
+	// identify duplicates and find correct mapping indices
+
+	std::vector<uint> reducedIndexMap(numberOfCells);
+
+	uint currentSparseIndex = this->sparseIndicesLB[0];
+	uint reducedIndex = 0;
+	for (uint index = 1; index < numberOfCells; index++)
+	{
+		if (this->sparseIndicesLB[index] == currentSparseIndex)
+		{
+			reducedIndexMap[index] = reducedIndex;
+		}
+		else
+		{
+			currentSparseIndex = this->sparseIndicesLB[index];
+			reducedIndexMap[index] = ++reducedIndex;
+		}
+	}
+
+	for (uint index = 0; index < numberOfCells; index++)
+	{
+		mapNashToConc[index] = reducedIndexMap[indexMap[index]];
+	}
+
+	//////////////////////////////////////////////////////////////////////////
+	// erase duplicated
+
+	auto newEnd = std::unique(this->sparseIndicesLB.begin(), this->sparseIndicesLB.end());
+
+	this->sparseIndicesLB.resize(std::distance(this->sparseIndicesLB.begin(), newEnd));
+
+	//////////////////////////////////////////////////////////////////////////
+}
+
+void StreetPointFinder::readStreets(std::string filename)
+{
+	*logging::out << logging::Logger::INFO_INTERMEDIATE << "StreetPointFinder::readStreets( " << filename << " )" << "\n";
+
+	uint numberOfStreets;
+
+	std::ifstream file;
+
+	file.open(filename.c_str());
+
+	file >> numberOfStreets;
+
+	for (uint i = 0; i < numberOfStreets; i++)
+	{
+		real xStart, yStart, xEnd, yEnd;
+
+		real dx;
+
+		file >> xStart >> yStart >> xEnd >> yEnd >> dx;
+
+		streets.push_back(Street(xStart, yStart, xEnd, yEnd, dx));
+	}
+
+	file.close();
+
+	*logging::out << logging::Logger::INFO_INTERMEDIATE << "done!\n";
+}
+
+void StreetPointFinder::findIndicesLB(SPtr<Grid> grid, real initialSearchHeight)
+{
+	*logging::out << logging::Logger::INFO_INTERMEDIATE << "StreetPointFinder::findIndicesLB()\n";
+
+	for (auto& street : streets) street.findIndicesLB(grid, initialSearchHeight);
+
+	*logging::out << logging::Logger::INFO_INTERMEDIATE << "done!\n";
+}
+
+void StreetPointFinder::writeVTK(std::string filename, const std::vector<int>& cars)
+{
+	uint numberOfCells = 0;
+
+	*logging::out << logging::Logger::INFO_INTERMEDIATE << "StreetPointFinder::writeVTK( " << filename << " )" << "\n";
+
+	std::ofstream file;
+
+	file.open(filename);
+
+	prepareWriteVTK(file, numberOfCells);
+
+	//////////////////////////////////////////////////////////////////////////
+
+	file << "FIELD Label " << 3 << std::endl;
+
+	//////////////////////////////////////////////////////////////////////////
+
+	writeStreetsVTK(file, numberOfCells);
+
+	writeLengthsVTK(file, numberOfCells);
+
+	writeCarsVTK(file, numberOfCells, cars);
+
+	////////////////////////////////////////////////////////////////////////////
+
+	file.close();
+
+	*logging::out << logging::Logger::INFO_INTERMEDIATE << "done!\n";
+}
+
+
+void StreetPointFinder::writeReducedVTK(std::string filename, const std::vector<int>& cars)
+{
+	uint numberOfCells = 0;
+
+	*logging::out << logging::Logger::INFO_INTERMEDIATE << "StreetPointFinder::writeVTK( " << filename << " )" << "\n";
+
+	std::ofstream file;
+
+	file.open(filename);
+
+	prepareWriteVTK(file, numberOfCells);
+
+	//////////////////////////////////////////////////////////////////////////
+
+	file << "FIELD Label " << 1 << std::endl;
+
+	//////////////////////////////////////////////////////////////////////////
+
+	writeCarsVTK(file, numberOfCells, cars);
+
+	////////////////////////////////////////////////////////////////////////////
+
+	file.close();
+
+	*logging::out << logging::Logger::INFO_INTERMEDIATE << "done!\n";
+}
+
+void StreetPointFinder::prepareWriteVTK(std::ofstream & file, uint & numberOfCells)
+{
+
+	uint numberOfNodes = 0;
+
+	for (auto& street : streets)
+	{
+		numberOfCells += street.numberOfCells;
+		numberOfNodes += street.numberOfCells + 1;
+	}	
+
+	file << "# vtk DataFile Version 3.0\n";
+	file << "by MeshGenerator\n";
+	file << "ASCII\n";
+	file << "DATASET UNSTRUCTURED_GRID\n";
+
+	file << "POINTS " << numberOfNodes << " float" << std::endl;
+
+	for (auto& street : streets)
+	{
+		for (uint i = 0; i <= street.numberOfCells; i++)
+		{
+			file << 0.5 * (street.getCoordinateX(i - 1) + street.getCoordinateX(i)) << " "
+				<< 0.5 * (street.getCoordinateY(i - 1) + street.getCoordinateY(i)) << " " << 0.0 << std::endl;
+		}
+	}
+
+	//////////////////////////////////////////////////////////////////////////
+
+	file << "CELLS " << numberOfCells << " " << 3 * numberOfCells << std::endl;
+
+
+	uint nodeIndex = 0;
+	for (auto& street : streets)
+	{
+		for (uint i = 0; i < street.numberOfCells; i++)
+		{
+			file << "2 " << nodeIndex << " " << nodeIndex + 1 << std::endl;
+			nodeIndex++;
+		}
+		nodeIndex++;
+	}
+
+	//////////////////////////////////////////////////////////////////////////
+
+	file << "CELL_TYPES " << numberOfCells << std::endl;
+
+	for (uint i = 0; i < numberOfCells; i++) {
+		file << "3" << std::endl;
+	}
+	//////////////////////////////////////////////////////////////////////////
+
+	file << "\nCELL_DATA " << numberOfCells << std::endl;
+}
+
+
+void StreetPointFinder::writeStreetsVTK(std::ofstream & file, uint numberOfCells)
+{
+	file << "StreetIndex 1 " << numberOfCells << " int" << std::endl;
+
+	uint streetIndex = 0;
+	for (auto& street : streets)
+	{
+		for (uint i = 0; i < street.numberOfCells; i++)
+		{
+			file << streetIndex << std::endl;
+		}
+		streetIndex++;
+	}
+}
+
+
+
+void StreetPointFinder::writeCarsVTK(std::ofstream& file, uint numberOfCells, const std::vector<int>& cars)
+{
+	file << "Cars 1 " << numberOfCells << " float" << std::endl;
+
+	uint index = 0;
+	for (auto& street : streets)
+	{
+		for (uint i = 0; i < street.numberOfCells; i++)
+		{
+			if (index < cars.size())
+				file << cars[index] << std::endl;
+			else
+				file << -1 << std::endl;
+			index++;
+		}
+	}
+}
+
+
+void StreetPointFinder::writeLengthsVTK(std::ofstream & file, uint numberOfCells)
+{
+	file << "StreetLength 1 " << numberOfCells << " float" << std::endl;
+
+	for (auto& street : streets)
+	{
+		for (uint i = 0; i < street.numberOfCells; i++)
+		{
+			real length = std::sqrt((street.getCoordinateX(i) - street.getCoordinateX(0)) * (street.getCoordinateX(i) - street.getCoordinateX(0))
+				+ (street.getCoordinateY(i) - street.getCoordinateY(0)) * (street.getCoordinateY(i) - street.getCoordinateY(0)));
+
+			file << length << std::endl;
+		}
+	}
+}
+
+
+void StreetPointFinder::writeConnectionVTK(std::string filename, SPtr<Grid> grid)
+{
+	uint numberOfCells = 0;
+
+	for (auto& street : streets)
+	{
+		numberOfCells += street.numberOfCells;
+	}
+
+	*logging::out << logging::Logger::INFO_INTERMEDIATE << "StreetPointFinder::writeConnectionVTK( " << filename << " )" << "\n";
+
+	std::ofstream file;
+
+	file.open(filename);
+
+	file << "# vtk DataFile Version 3.0\n";
+	file << "by MeshGenerator\n";
+	file << "ASCII\n";
+	file << "DATASET UNSTRUCTURED_GRID\n";
+
+	file << "POINTS " << 2 * numberOfCells << " float" << std::endl;
+
+	for (auto& street : streets)
+	{
+		for (uint i = 0; i < street.numberOfCells; i++)
+		{
+			real xLB, yLB, zLB;
+			grid->transIndexToCoords(street.matrixIndicesLB[i], xLB, yLB, zLB);
+
+			file << street.getCoordinateX(i) << " " << street.getCoordinateY(i) << " " << 5.0 << std::endl;
+			file << xLB << " " << yLB << " " << zLB << std::endl;
+		}
+	}
+
+	//////////////////////////////////////////////////////////////////////////
+
+	file << "CELLS " << numberOfCells << " " << 3 * numberOfCells << std::endl;
+
+
+	uint nodeIndex = 0;
+	for (auto& street : streets)
+	{
+		for (uint i = 0; i < street.numberOfCells; i++)
+		{
+			file << "2 " << nodeIndex << " " << nodeIndex + 1 << std::endl;
+			nodeIndex += 2;
+		}
+	}
+
+	//////////////////////////////////////////////////////////////////////////
+
+	file << "CELL_TYPES " << numberOfCells << std::endl;
+
+	for (uint i = 0; i < numberOfCells; i++) {
+		file << "3" << std::endl;
+	}
+
+	//////////////////////////////////////////////////////////////////////////
+
+	file.close();
+
+	*logging::out << logging::Logger::INFO_INTERMEDIATE << "done!\n";
+}
+
+void StreetPointFinder::writeSimulationFile(std::string gridPath, real concentration, uint numberOfLevels, uint level)
+{
+	*logging::out << logging::Logger::INFO_INTERMEDIATE << "StreetPointFinder::writeSimulationFile( " << gridPath << "conc.dat )" << "\n";
+
+	std::ofstream file;
+
+	file.open(gridPath + "conc.dat");
+
+	file << "concentration\n";
+
+	file << numberOfLevels - 1 << "\n";
+
+	for (uint currentLevel = 0; currentLevel < numberOfLevels; currentLevel++)
+	{
+		if (currentLevel == level)
+		{
+			uint numberOfCells = 0;
+			for (auto& street : streets)
+			{
+				numberOfCells += street.numberOfCells;
+			}
+
+			file << numberOfCells << "\n";
+
+			for (auto& street : streets)
+			{
+				for (auto& sparseIndexLB : street.sparseIndicesLB)
+				{
+					// + 1 for numbering shift between GridGenerator and VF_GPU
+					file << sparseIndexLB + 1 << "\n";
+				}
+			}
+		}
+		else
+		{
+			file << "0\n";
+		}
+	}
+
+	file.close();
+
+	*logging::out << logging::Logger::INFO_INTERMEDIATE << "done!\n";
+}
+
+void StreetPointFinder::writeStreetVectorFile(std::string gridPath, real concentration, uint numberOfLevels, uint level)
+{
+	*logging::out << logging::Logger::INFO_INTERMEDIATE << "StreetPointFinder::writeStreetVectorFile( " << gridPath << "streetVector.dat )" << "\n";
+
+	std::ofstream file;
+
+	file.open(gridPath + "streetVector.dat");
+
+	file << "streetVector\n";
+
+	file << numberOfLevels - 1 << "\n";
+
+	for (uint currentLevel = 0; currentLevel < numberOfLevels; currentLevel++)
+	{
+		if (currentLevel == level)
+		{
+			uint numberOfCells = 0;
+			for (auto& street : streets)
+			{
+				numberOfCells += street.numberOfCells;
+			}
+
+			file << numberOfCells << "\n";
+
+			for (auto& street : streets)
+			{
+				for (auto& sparseIndexLB : street.sparseIndicesLB)
+				{
+                    (void) sparseIndexLB;
+ 					// + 1 for numbering shift between GridGenerator and VF_GPU
+					file << street.getVectorX() << " " << street.getVectorY() << "\n";
+				}
+			}
+		}
+		else
+		{
+			file << "0\n";
+		}
+	}
+
+	file.close();
+
+	*logging::out << logging::Logger::INFO_INTERMEDIATE << "done!\n";
+}
+
+void StreetPointFinder::writeSimulationFileSorted(std::string gridPath, real concentration, uint numberOfLevels, uint level)
+{
+	*logging::out << logging::Logger::INFO_INTERMEDIATE << "StreetPointFinder::writeSimulationFile( " << gridPath << "concSorted.dat )" << "\n";
+
+	std::ofstream file;
+
+	file.open(gridPath + "concSorted.dat");
+
+	file << "concentration\n";
+
+	file << numberOfLevels - 1 << "\n";
+
+	for (uint currentLevel = 0; currentLevel < numberOfLevels; currentLevel++)
+	{
+		if (currentLevel == level)
+		{
+			file << this->sparseIndicesLB.size() << "\n";
+
+			for (auto& sparseIndexLB : this->sparseIndicesLB)
+			{
+				// + 1 for numbering shift between GridGenerator and VF_GPU
+				file << sparseIndexLB + 1 << "\n";
+			}
+		}
+		else
+		{
+			file << "0\n";
+		}
+	}
+
+	file.close();
+
+	*logging::out << logging::Logger::INFO_INTERMEDIATE << "done!\n";
+}
+
+void StreetPointFinder::writeMappingFile(std::string gridPath)
+{
+	*logging::out << logging::Logger::INFO_INTERMEDIATE << "StreetPointFinder::writeMappingFile( " << gridPath << "mappingNashToConc.dat )" << "\n";
+
+	std::ofstream file;
+
+	file.open(gridPath + "mappingNashToConc.dat");
+
+	file << this->mapNashToConc.size() << "\n";
+
+	for (auto& index : this->mapNashToConc)
+	{
+		file << index << "\n";
+	}
+
+	file.close();
+
+	*logging::out << logging::Logger::INFO_INTERMEDIATE << "done!\n";
+}
+
+
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+// Speed hackend by Stephan Lenz, not tested
+
+void StreetPointFinder::write3DVTK(std::string filename, const std::vector<int>& cars)
+{
+	uint numberOfCells = 0;
+
+	*logging::out << logging::Logger::INFO_INTERMEDIATE << "StreetPointFinder::writeVTK( " << filename << " )" << "\n";
+
+	std::ofstream file;
+
+	file.open(filename);
+
+	prepareWrite3DVTK(file, numberOfCells, cars);
+
+	////////////////////////////////////////////////////////////////////////////
+
+	file.close();
+
+	*logging::out << logging::Logger::INFO_INTERMEDIATE << "done!\n";
+}
+
+void StreetPointFinder::prepareWrite3DVTK(std::ofstream & file, uint & numberOfCells, const std::vector<int>& cars)
+{
+
+	uint numberOfNodes = 0;
+
+	for (auto& street : streets)
+	{
+		numberOfCells += street.numberOfCells;
+		numberOfNodes += street.numberOfCells + 1;
+	}
+
+	file << "# vtk DataFile Version 3.0\n";
+	file << "by MeshGenerator\n";
+	file << "ASCII\n";
+	file << "DATASET UNSTRUCTURED_GRID\n";
+
+	uint index = 0;
+	uint numberOfCars = 0;
+
+	for (auto& street : streets)
+	{
+		for (uint i = 0; i < street.numberOfCells; i++)
+		{
+			if (index < cars.size() && cars[index] != -1)
+			{
+				numberOfCars++;
+			}
+
+			index++;
+		}
+	}
+
+	file << "POINTS " << 8 * numberOfCars << " float" << std::endl;
+
+	index = 0;
+	for (auto& street : streets)
+	{
+		for (uint i = 0; i < street.numberOfCells; i++)
+		{
+			if(index < cars.size() && cars[index] != -1 )
+			{
+				real xStart = 0.5 * (street.getCoordinateX(i - 1) + street.getCoordinateX(i));
+				real yStart = 0.5 * (street.getCoordinateY(i - 1) + street.getCoordinateY(i));
+
+				real xEnd = 0.5 * (street.getCoordinateX(i) + street.getCoordinateX(i + 1));
+				real yEnd = 0.5 * (street.getCoordinateY(i) + street.getCoordinateY(i + 1));
+
+				real vecX = xEnd - xStart;
+				real vecY = yEnd - yStart;
+
+				file << xStart + vecY << " " << yStart - vecX << " " << 0.0 << std::endl;
+				file << xStart - vecY << " " << yStart + vecX << " " << 0.0 << std::endl;
+
+				file << xEnd + vecY << " " << yEnd - vecX << " " << 0.0 << std::endl;
+				file << xEnd - vecY << " " << yEnd + vecX << " " << 0.0 << std::endl;
+
+				file << xStart + vecY << " " << yStart - vecX << " " << 1.5 << std::endl;
+				file << xStart - vecY << " " << yStart + vecX << " " << 1.5 << std::endl;
+
+				file << xEnd + vecY << " " << yEnd - vecX << " " << 1.5 << std::endl;
+				file << xEnd - vecY << " " << yEnd + vecX << " " << 1.5 << std::endl;
+			}
+
+			index++;
+		}
+	}
+
+	//////////////////////////////////////////////////////////////////////////
+
+	file << "CELLS " << numberOfCars << " " << 9 * numberOfCars << std::endl;
+
+	index = 0;
+	uint carIndex = 0;
+	for (auto& street : streets)
+	{
+		for (uint i = 0; i < street.numberOfCells; i++)
+		{
+			if (index < cars.size() && cars[index] != -1)
+			{
+				file << "8 " 
+					 << 8 * carIndex + 0 << " "
+					 << 8 * carIndex + 1 << " "
+					 << 8 * carIndex + 3 << " "
+					 << 8 * carIndex + 2 << " "
+					 << 8 * carIndex + 4 << " "
+					 << 8 * carIndex + 5 << " "
+					 << 8 * carIndex + 7 << " "
+					 << 8 * carIndex + 6 << " "
+					 << std::endl;
+
+				carIndex++;
+			}
+			index++;
+		}
+	}
+
+	//////////////////////////////////////////////////////////////////////////
+
+	file << "CELL_TYPES " << numberOfCars << std::endl;
+
+	for (uint i = 0; i < numberOfCars; i++) {
+		file << "12" << std::endl;
+	}
+
+	//////////////////////////////////////////////////////////////////////////
+
+	file << "\nCELL_DATA " << numberOfCars << std::endl;
+
+	//////////////////////////////////////////////////////////////////////////
+
+	file << "FIELD Label " << 1 << std::endl;
+
+	//////////////////////////////////////////////////////////////////////////
+
+	file << "Cars 1 " << numberOfCars << " float" << std::endl;
+
+	index = 0;
+	for (auto& street : streets)
+	{
+		for (uint i = 0; i < street.numberOfCells; i++)
+		{
+			if (index < cars.size() && cars[index] != -1)
+				file << cars[index] << std::endl;
+			
+			index++;
+		}
+	}
+}
+
+
+
+
diff --git a/src/gpu/GridGenerator/StreetPointFinder/StreetPointFinder.h b/src/gpu/GridGenerator/StreetPointFinder/StreetPointFinder.h
new file mode 100644
index 0000000000000000000000000000000000000000..feb3618f64b0a6f757930772594878a6ca7c0144
--- /dev/null
+++ b/src/gpu/GridGenerator/StreetPointFinder/StreetPointFinder.h
@@ -0,0 +1,120 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file StreetPointFinder.h
+//! \ingroup StreetPointFinder
+//! \author Stephan Lenz
+//=======================================================================================
+#ifndef StreetPointFinder_H
+#define StreetPointFinder_H
+
+#include <vector>
+#include <string>
+
+#include "GridGenerator_export.h"
+
+#include "PointerDefinitions.h"
+#include "Core/DataTypes.h"
+
+
+
+class Grid;
+
+struct GRIDGENERATOR_EXPORT Street
+{
+    // The start and end coordinates are stored for cell centers!
+    //
+    //     |---x---|---x---|---x---|---x---|---x---|---x---|---x---|---x---|---x---|---x---|
+    //         |--->                       |<----->|                               <---|
+    //         xStart                          dx                                   xEnd
+    //
+    // dx = (xStart - xEnd) / (numberOfCells - 1)
+
+    uint numberOfCells;
+    real xStart, yStart, xEnd, yEnd;
+
+    std::vector<uint> matrixIndicesLB;
+    std::vector<uint> sparseIndicesLB;
+
+    // The constructor expect start and end for cells
+    Street( real xStartCell, real yStartCell, real xEndCell, real yEndCell, real dx );
+
+    real getCoordinateX( int cellIndex );
+    real getCoordinateY( int cellIndex );
+
+	real getVectorX();
+	real getVectorY();
+
+    void findIndicesLB( SPtr<Grid> grid, real initialSearchHeight);
+};
+
+struct GRIDGENERATOR_EXPORT StreetPointFinder
+{
+    std::vector<Street> streets;
+
+    std::vector<uint> sparseIndicesLB;
+    std::vector<uint> mapNashToConc;
+
+    void prepareSimulationFileData();
+
+    void readStreets(std::string filename);
+
+    void findIndicesLB( SPtr<Grid> grid, real initialSearchHeight );
+
+	void writeVTK(std::string filename, const std::vector<int>& cars = std::vector<int>());
+
+	void writeReducedVTK(std::string filename, const std::vector<int>& cars = std::vector<int>());
+
+	void prepareWriteVTK(std::ofstream& file, uint & numberOfCells);
+
+	void writeCarsVTK(std::ofstream& file, uint numberOfCells, const std::vector<int>& cars);
+
+	void writeLengthsVTK(std::ofstream& file, uint numberOfCells);
+
+	void writeStreetsVTK(std::ofstream& file, uint numberOfCells);
+
+    void writeConnectionVTK(std::string filename, SPtr<Grid> grid);
+
+	void writeSimulationFile(std::string gridPath, real concentration, uint numberOfLevels, uint level);
+
+	void writeStreetVectorFile(std::string gridPath, real concentration, uint numberOfLevels, uint level);
+
+    void writeSimulationFileSorted( std::string gridPath, real concentration, uint numberOfLevels, uint level );
+
+    void writeMappingFile( std::string gridPath );
+
+	//////////////////////////////////////////////////////////////////////////
+	// 3D cars writer hacked by Stephan L.
+
+	void write3DVTK(std::string filename, const std::vector<int>& cars = std::vector<int>());
+
+	void prepareWrite3DVTK(std::ofstream& file, uint & numberOfCells, const std::vector<int>& cars);
+};
+
+
+#endif
\ No newline at end of file
diff --git a/src/gpu/GridGenerator/geometries/Arrow/Arrow.h b/src/gpu/GridGenerator/geometries/Arrow/Arrow.h
new file mode 100644
index 0000000000000000000000000000000000000000..945f1e3a8af7bd14fb9c3a8d5d9d26ab7405a7b7
--- /dev/null
+++ b/src/gpu/GridGenerator/geometries/Arrow/Arrow.h
@@ -0,0 +1,55 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file Arrow.h
+//! \ingroup geometries
+//! \author Soeren Peters, Stephan Lenz
+//=======================================================================================
+#ifndef Arrow_H
+#define Arrow_H
+
+#include <memory>
+
+struct Vertex;
+
+class Arrow 
+{
+public:
+	virtual ~Arrow() {};
+protected:
+	Arrow() {};
+
+public:
+	virtual std::shared_ptr<Vertex> getStart() const = 0;
+	virtual std::shared_ptr<Vertex> getEnd() const = 0;
+	virtual void print() const = 0;
+};
+
+
+
+#endif
diff --git a/src/gpu/GridGenerator/geometries/Arrow/ArrowImp.cpp b/src/gpu/GridGenerator/geometries/Arrow/ArrowImp.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f7ee7330c6c57f076fd4f45c8bf7a3f0749df6a1
--- /dev/null
+++ b/src/gpu/GridGenerator/geometries/Arrow/ArrowImp.cpp
@@ -0,0 +1,69 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file ArrowImp.cpp
+//! \ingroup geometries
+//! \author Soeren Peters, Stephan Lenz
+//=======================================================================================
+#include "ArrowImp.h"
+
+#include "../Vertex/Vertex.h"
+
+ std::shared_ptr<Arrow> ArrowImp::make(const Vertex &start, const Vertex &end)
+{
+	return std::shared_ptr<ArrowImp>(new ArrowImp(start, end));
+}
+
+ArrowImp::ArrowImp(const Vertex &start, const Vertex &end) : start(std::make_shared<Vertex>(start)), end(std::make_shared<Vertex>(end))
+{
+
+}
+
+ArrowImp::~ArrowImp()
+{
+
+}
+
+std::shared_ptr<Vertex> ArrowImp::getStart() const
+{
+	return this->start;
+}
+
+std::shared_ptr<Vertex> ArrowImp::getEnd() const
+{
+	return this->end;
+}
+
+void ArrowImp::print() const
+{
+	printf("v1: ");
+	start->print();
+	printf("v2: ");
+	end->print();
+}
+
diff --git a/src/gpu/GridGenerator/grid/GridStrategy/GridStrategy.h b/src/gpu/GridGenerator/geometries/Arrow/ArrowImp.h
similarity index 60%
rename from src/gpu/GridGenerator/grid/GridStrategy/GridStrategy.h
rename to src/gpu/GridGenerator/geometries/Arrow/ArrowImp.h
index 6d7f0f2c0aa83b1155db10df5b49729bd157a195..ef145b7def48803b7e2d043f7a5862ee21f954c4 100644
--- a/src/gpu/GridGenerator/grid/GridStrategy/GridStrategy.h
+++ b/src/gpu/GridGenerator/geometries/Arrow/ArrowImp.h
@@ -1,67 +1,64 @@
 //=======================================================================================
-// ____          ____    __    ______     __________   __      __       __        __         
-// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |        
-//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |        
-//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |        
-//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____    
-//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|   
-//      \    \  |    |   ________________________________________________________________    
-//       \    \ |    |  |  ______________________________________________________________|   
-//        \    \|    |  |  |         __          __     __     __     ______      _______    
-//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)   
-//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______    
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
 //           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
-//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/   
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
 //
-//  This file is part of VirtualFluids. VirtualFluids is free software: you can 
+//  This file is part of VirtualFluids. VirtualFluids 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 
+//  License as published by the Free Software Foundation, either version 3 of
 //  the License, or (at your option) any later version.
-//  
-//  VirtualFluids 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 
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
 //
-//! \file GridStrategy.h
-//! \ingroup grid
+//! \file ArrowImp.h
+//! \ingroup geometries
 //! \author Soeren Peters, Stephan Lenz
 //=======================================================================================
-#ifndef GRID_STRATEGY_H
-#define GRID_STRATEGY_H
+#ifndef ArrowImp_H
+#define ArrowImp_H
 
-#include "Core/LbmOrGks.h"
+#include <memory>
 
 #include "global.h"
+#include "GridGenerator_export.h"
 
-#include "grid/Field.h"
+#include "Arrow.h"
 
 struct Vertex;
-class GridImp;
 
-class GRIDGENERATOR_EXPORT GridStrategy
+class ArrowImp : public Arrow 
 {
 public:
-    virtual ~GridStrategy() {}
-
-    virtual void allocateFieldMemory(Field* field) = 0;
-    virtual void freeFieldMemory(Field* field) = 0;
-
-    virtual void allocateGridMemory(SPtr<GridImp> grid) = 0;
+	GRIDGENERATOR_EXPORT virtual ~ArrowImp();
+	GRIDGENERATOR_EXPORT static std::shared_ptr<Arrow> make(const Vertex &start, const Vertex &end);
 
-    virtual void initalNodesToOutOfGrid(SPtr<GridImp> grid) = 0;
-    virtual void findInnerNodes(SPtr<GridImp> grid) = 0;
+	GRIDGENERATOR_EXPORT std::shared_ptr<Vertex> getStart() const;
+	GRIDGENERATOR_EXPORT std::shared_ptr<Vertex> getEnd() const;
 
-	virtual void findEndOfGridStopperNodes(SPtr<GridImp> grid) = 0;
-
-    virtual void findSparseIndices(SPtr<GridImp> coarseGrid, SPtr<GridImp> fineGrid) = 0;
+	GRIDGENERATOR_EXPORT void print() const;
+private:
+	ArrowImp(const Vertex &start, const Vertex &end);
 
+	std::shared_ptr<Vertex> start;
+	std::shared_ptr<Vertex> end;
+};
 
-    virtual void freeMemory(SPtr<GridImp> grid) = 0;
 
-};
 
 #endif
diff --git a/src/gpu/GridGenerator/geometries/BoundingBox/BoundingBox.cu b/src/gpu/GridGenerator/geometries/BoundingBox/BoundingBox.cpp
similarity index 88%
rename from src/gpu/GridGenerator/geometries/BoundingBox/BoundingBox.cu
rename to src/gpu/GridGenerator/geometries/BoundingBox/BoundingBox.cpp
index 52295a1501720b260b75199cce4fad229246b256..1532e57e8cc4b0db93ed79c03074d7845ff9c87f 100644
--- a/src/gpu/GridGenerator/geometries/BoundingBox/BoundingBox.cu
+++ b/src/gpu/GridGenerator/geometries/BoundingBox/BoundingBox.cpp
@@ -26,12 +26,13 @@
 //  You should have received a copy of the GNU General Public License along
 //  with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
 //
-//! \file BoundingBox.cu
+//! \file BoundingBox.cpp
 //! \ingroup geometries
 //! \author Soeren Peters, Stephan Lenz
 //=======================================================================================
 #include "BoundingBox.h"
 
+#include "../Triangle/Triangle.h"
 #include "../Vertex/Vertex.h"
 #include <GridGenerator/utilities/math/Math.h>
 
@@ -41,17 +42,6 @@
 
  BoundingBox::BoundingBox(real minX, real maxX, real minY, real maxY, real minZ, real maxZ) : minX(minX), maxX(maxX), minY(minY), maxY(maxY), minZ(minZ), maxZ(maxZ) {}
 
- BoundingBox::BoundingBox() :
-     minX(0),
-     maxX(0),
-     minY(0),
-     maxY(0),
-     minZ(0),
-     maxZ(0) {}
-
- BoundingBox::BoundingBox(const BoundingBox &t) : minX(t.minX), maxX(t.maxX), minY(t.minY), maxY(t.maxY), minZ(t.minZ), maxZ(t.maxZ) {}
-
-
  BoundingBox BoundingBox::makeInvalidMinMaxBox()
  {
      BoundingBox box = BoundingBox(std::numeric_limits<real>::max(),
@@ -63,6 +53,39 @@
      return box;
  }
 
+ void BoundingBox::setMinMax(const Triangle &t)
+ {
+     real minX, maxX, minY, maxY, minZ, maxZ;
+     t.setMinMax(minX, maxX, minY, maxY, minZ, maxZ);
+     if (minX < this->minX)
+         this->minX = minX;
+     if (minY < this->minY)
+         this->minY = minY;
+     if (minZ < this->minZ)
+         this->minZ = minZ;
+
+     if (maxX > this->maxX)
+         this->maxX = maxX;
+     if (maxY > this->maxY)
+         this->maxY = maxY;
+     if (maxZ > this->maxZ)
+         this->maxZ = maxZ;
+ }
+
+ bool BoundingBox::intersect(const Triangle &t) const
+ {
+     if (isInside(t.v1) || isInside(t.v2) || isInside(t.v3))
+         return true;
+     return false;
+ }
+
+ bool BoundingBox::isInside(const Triangle &t) const
+ {
+     if (isInside(t.v1) && isInside(t.v2) && isInside(t.v3))
+         return true;
+     return false;
+ }
+
  bool BoundingBox::isInside(const real x, const real y, const real z) const
  {
      return this->isInside(Vertex(x,y,z));
diff --git a/src/gpu/GridGenerator/geometries/BoundingBox/BoundingBox.h b/src/gpu/GridGenerator/geometries/BoundingBox/BoundingBox.h
index 161db459bf4ef7cc8b86a08c28948860fd9cf5f6..2a495d3a4b7a4854079b62ba979baaea0d7db5f0 100644
--- a/src/gpu/GridGenerator/geometries/BoundingBox/BoundingBox.h
+++ b/src/gpu/GridGenerator/geometries/BoundingBox/BoundingBox.h
@@ -34,7 +34,6 @@
 #define BoundingBox_h
 
 #include <vector>
-#include <cuda_runtime.h>
 
 #include "global.h"
 
@@ -53,15 +52,17 @@ public:
 	real maxZ;
 
 	BoundingBox(real minX, real maxX, real minY, real maxY, real minZ, real maxZ);
-    BoundingBox();
-	BoundingBox(const BoundingBox &t);
+    BoundingBox() = default;
 
 public:
     static BoundingBox makeInvalidMinMaxBox();
 
-	void print() const;
+    void setMinMax(const Triangle &t);
+    void print() const;
 
-	bool isInside(const real x, const real y, const real z) const;
+	bool isInside(const Triangle &t) const;
+    bool isInside(const real x, const real y, const real z) const;
+    bool intersect(const Triangle &t) const;
 
 	std::vector<std::vector<Vertex> > getIntersectionPoints(const BoundingBox &b) const;
 	bool intersect(const BoundingBox &box) const;
diff --git a/src/gpu/GridGenerator/geometries/Conglomerate/Conglomerate.cpp b/src/gpu/GridGenerator/geometries/Conglomerate/Conglomerate.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..331b928c6f5542584cffdcc1b17df7207981b8f8
--- /dev/null
+++ b/src/gpu/GridGenerator/geometries/Conglomerate/Conglomerate.cpp
@@ -0,0 +1,197 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file Conglomerate.cpp
+//! \ingroup geometries
+//! \author Soeren Peters, Stephan Lenz
+//=======================================================================================
+#include "Conglomerate.h"
+
+Conglomerate::Conglomerate()
+{
+    addObjects = new Object*[MAX_NUMBER_OF_OBJECTS];
+    subtractObjects = new Object*[MAX_NUMBER_OF_OBJECTS];
+}
+
+Conglomerate::~Conglomerate()
+{
+    for (uint i = 0; i < numberOfAddObjects; i++)
+        delete addObjects[i];
+
+    for (uint i = 0; i < numberOfSubtractObjects; i++)
+        delete subtractObjects[i];
+
+    delete[] addObjects;
+    delete[] subtractObjects;
+}
+
+SPtr<Conglomerate> Conglomerate::makeShared()
+{
+    return SPtr<Conglomerate>(new Conglomerate());
+}
+
+void Conglomerate::add(Object* object)
+{
+    if (numberOfAddObjects < MAX_NUMBER_OF_OBJECTS)
+    {
+        addObjects[numberOfAddObjects] = object;
+        numberOfAddObjects++;
+    } else
+        printf("[WARNING] max numbers of %d reached! Object was not added.\n", MAX_NUMBER_OF_OBJECTS);
+}
+
+void Conglomerate::subtract(Object* object)
+{
+    if (numberOfSubtractObjects < MAX_NUMBER_OF_OBJECTS)
+    {
+        subtractObjects[numberOfSubtractObjects] = object;
+        numberOfSubtractObjects++;
+    }
+    else
+        printf("[WARNING] max numbers of %d reached! Object was not added.\n", MAX_NUMBER_OF_OBJECTS);
+}
+
+Object* Conglomerate::clone() const
+{
+    auto conglomerate = new Conglomerate();
+    for (uint i = 0; i < numberOfAddObjects; i++)
+        conglomerate->add(addObjects[i]->clone());
+
+    for (uint i = 0; i < numberOfSubtractObjects; i++)
+        conglomerate->subtract(subtractObjects[i]->clone());
+
+    return conglomerate;
+}
+
+double Conglomerate::getX1Centroid()
+{
+    return (getX1Minimum() + getX1Maximum()) * 0.5;
+}
+
+double Conglomerate::getX1Minimum()
+{
+    double minimum = addObjects[0]->getX1Minimum();
+    for(uint i = 1; i < numberOfAddObjects; i++)
+        minimum = getMinimum(minimum, addObjects[i]->getX1Minimum());
+    return minimum;
+}
+
+double Conglomerate::getX1Maximum()
+{
+    double maximum = addObjects[0]->getX1Maximum();
+    for (uint i = 1; i < numberOfAddObjects; i++)
+        maximum = getMaximum(maximum, addObjects[i]->getX1Maximum());
+    return maximum;
+}
+
+double Conglomerate::getX2Centroid()
+{
+    return (getX2Minimum() + getX2Maximum()) * 0.5;
+}
+
+double Conglomerate::getX2Minimum()
+{
+    double minimum = addObjects[0]->getX2Minimum();
+    for (uint i = 1; i < numberOfAddObjects; i++)
+        minimum = getMinimum(minimum, addObjects[i]->getX2Minimum());
+    return minimum;
+}	
+
+double Conglomerate::getX2Maximum()
+{
+    double maximum = addObjects[0]->getX2Maximum();
+    for (uint i = 1; i < numberOfAddObjects; i++)
+        maximum = getMaximum(maximum, addObjects[i]->getX2Maximum());
+    return maximum;
+}
+
+double Conglomerate::getX3Centroid()
+{
+    return (getX3Minimum() + getX3Maximum()) * 0.5;
+}
+
+double Conglomerate::getX3Minimum()
+{
+    double minimum = addObjects[0]->getX3Minimum();
+    for (uint i = 1; i < numberOfAddObjects; i++)
+        minimum = getMinimum(minimum, addObjects[i]->getX3Minimum());
+    return minimum;
+}	
+
+double Conglomerate::getX3Maximum()
+{
+    double maximum = addObjects[0]->getX3Maximum();
+    for (uint i = 1; i < numberOfAddObjects; i++)
+        maximum = getMaximum(maximum, addObjects[i]->getX3Maximum());
+    return maximum;
+}
+
+double Conglomerate::getMinimum(double val1, double val2)
+{
+    if (val1 > val2)
+        return val2;
+    return val1;
+}
+
+double Conglomerate::getMaximum(double val1, double val2)
+{
+    if (val1 < val2)
+        return val2;
+    return val1;
+}
+
+bool Conglomerate::isPointInObject(const double& x1, const double& x2, const double& x3, const double& minOffset, const double& maxOffset)
+{
+    for (uint i = 0; i < numberOfSubtractObjects; i++)
+        if (subtractObjects[i]->isPointInObject(x1, x2, x3, minOffset, maxOffset))
+            return false;
+
+    for (uint i = 0; i < numberOfAddObjects; i++)
+        if (addObjects[i]->isPointInObject(x1, x2, x3, minOffset, maxOffset))
+            return true;
+
+    return false;
+}
+
+void Conglomerate::scale(double delta)
+{
+    for (uint i = 0; i < numberOfAddObjects; i++)
+        addObjects[i]->scale(delta);
+
+    for (uint i = 0; i < numberOfSubtractObjects; i++)
+        subtractObjects[i]->scale(delta);
+}
+
+void Conglomerate::findInnerNodes(SPtr<GridImp> grid)
+{
+    for (uint i = 0; i < numberOfAddObjects; i++)
+        addObjects[i]->findInnerNodes(grid);
+
+    if( numberOfSubtractObjects > 0 )
+        *logging::out << logging::Logger::INFO_INTERMEDIATE << "Warning: Conglomerate::substract() is currently nut fully implemented!\n";
+}
diff --git a/src/gpu/GridGenerator/geometries/Conglomerate/Conglomerate.h b/src/gpu/GridGenerator/geometries/Conglomerate/Conglomerate.h
new file mode 100644
index 0000000000000000000000000000000000000000..8cb26137d6ab4e4c52bed34aa1d044121ac4bf3d
--- /dev/null
+++ b/src/gpu/GridGenerator/geometries/Conglomerate/Conglomerate.h
@@ -0,0 +1,85 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file Conglomerate.h
+//! \ingroup geometries
+//! \author Soeren Peters, Stephan Lenz
+//=======================================================================================
+#ifndef CONGLOMERATE_H
+#define CONGLOMERATE_H
+
+#include "global.h"
+
+#include "geometries/Object.h"
+
+#define MAX_NUMBER_OF_OBJECTS 20
+
+class GRIDGENERATOR_EXPORT Conglomerate : public Object
+{
+public:              
+    Conglomerate();
+    virtual ~Conglomerate();
+
+    static SPtr<Conglomerate> makeShared();
+
+    void add(Object* object);
+    void subtract(Object* objectStub);
+
+
+    Object* clone() const override;
+
+    double getX1Centroid() override;
+    double getX1Minimum() override;
+    double getX1Maximum() override;
+    double getX2Centroid() override;
+    double getX2Minimum() override;
+    double getX2Maximum() override;
+    double getX3Centroid() override;
+    double getX3Minimum() override;
+    double getX3Maximum() override;
+
+    void scale(double delta) override;
+
+    bool isPointInObject(const double& x1, const double& x2, const double& x3, const double& minOffset, const double& maxOffset) override;
+
+    void findInnerNodes(SPtr<GridImp> grid) override;
+
+protected:
+    static double getMinimum(double val1, double val2);
+    static double getMaximum(double val1, double val2);
+
+
+    Object** addObjects;
+    Object** subtractObjects;
+    uint numberOfAddObjects = 0;
+    uint numberOfSubtractObjects = 0;
+};
+
+
+
+#endif   
diff --git a/src/gpu/GridGenerator/geometries/Cuboid/Cuboid.cu b/src/gpu/GridGenerator/geometries/Cuboid/Cuboid.cpp
similarity index 99%
rename from src/gpu/GridGenerator/geometries/Cuboid/Cuboid.cu
rename to src/gpu/GridGenerator/geometries/Cuboid/Cuboid.cpp
index 7636c2bafd03be5bd18cb7dcd8546fbd09b42c96..e64a202ca9bcd5a33fcc9ba85e7bd35fa67a1d4e 100644
--- a/src/gpu/GridGenerator/geometries/Cuboid/Cuboid.cu
+++ b/src/gpu/GridGenerator/geometries/Cuboid/Cuboid.cpp
@@ -26,7 +26,7 @@
 //  You should have received a copy of the GNU General Public License along
 //  with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
 //
-//! \file Cuboid.cu
+//! \file Cuboid.cpp
 //! \ingroup geometries
 //! \author Soeren Peters, Stephan Lenz
 //=======================================================================================
diff --git a/src/gpu/GridGenerator/geometries/Object.cu b/src/gpu/GridGenerator/geometries/Object.cpp
similarity index 92%
rename from src/gpu/GridGenerator/geometries/Object.cu
rename to src/gpu/GridGenerator/geometries/Object.cpp
index 1b369d708fe6dc527fdee3e45c93a80de38bb4c7..c162b3b1db8654f36a0fe6f3c20f79b34a157338 100644
--- a/src/gpu/GridGenerator/geometries/Object.cu
+++ b/src/gpu/GridGenerator/geometries/Object.cpp
@@ -26,15 +26,19 @@
 //  You should have received a copy of the GNU General Public License along
 //  with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
 //
-//! \file Object.cu
+//! \file Object.cpp
 //! \ingroup geometries
 //! \author Soeren Peters, Stephan Lenz
 //=======================================================================================
 #include "Object.h"
 #include "grid/GridImp.h"
-#include "grid/GridStrategy/GridStrategy.h"
 
 void Object::findInnerNodes(SPtr<GridImp> grid)
 {
-    grid->getGridStrategy()->findInnerNodes( grid );
+    grid->findInnerNodes();
+}
+
+int Object::getIntersection(const Vertex &P, const Vertex &direction, Vertex &pointOnObject, real &qVal)
+{
+    return 1;
 }
diff --git a/src/gpu/GridGenerator/geometries/Object.h b/src/gpu/GridGenerator/geometries/Object.h
index 88f09253612c4d1d73cb2ecdb8112b504702b0ad..b92cca7992dcb06c1f230da8d8c9ce46bb7a3416 100644
--- a/src/gpu/GridGenerator/geometries/Object.h
+++ b/src/gpu/GridGenerator/geometries/Object.h
@@ -38,6 +38,7 @@
 #include "global.h"
 
 class GridImp;
+struct Vertex;
 
 class GRIDGENERATOR_EXPORT Object
 {
@@ -74,6 +75,8 @@ public:
     }
 
     virtual void findInnerNodes(SPtr<GridImp> grid);
+
+    virtual int getIntersection(const Vertex &P, const Vertex &direction, Vertex &pointOnObject, real &qVal);
 };
 
 
diff --git a/src/gpu/GridGenerator/geometries/Sphere/Sphere.cpp b/src/gpu/GridGenerator/geometries/Sphere/Sphere.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..fa460bc021cdca1159f272e3bcb4d4dad50fc352
--- /dev/null
+++ b/src/gpu/GridGenerator/geometries/Sphere/Sphere.cpp
@@ -0,0 +1,173 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file Sphere.cpp
+//! \ingroup geometries
+//! \author Soeren Peters, Stephan Lenz
+//=======================================================================================
+#include "Sphere.h"
+
+#include <algorithm>    // std::min
+#include <float.h>
+#include <cmath>
+
+#include "geometries/Vertex/Vertex.h"
+
+Sphere::Sphere(const double& centerX, const double& centerY, const double& centerZ, const double& radius)
+    : centerX(centerX), centerY(centerY), centerZ(centerZ), radius(radius)
+{
+
+}
+
+Sphere::~Sphere()
+{
+}
+
+SPtr<Sphere> Sphere::makeShared(double centerX, double centerY, double centerZ, double radius)
+{
+    return SPtr<Sphere>(new Sphere(centerX, centerY, centerZ, radius));
+}
+
+Object* Sphere::clone() const
+{
+    return new Sphere(centerX, centerY, centerZ, radius);
+}
+
+double Sphere::getX1Centroid()
+{
+    return centerX;
+}
+
+double Sphere::getX1Minimum()
+{
+    return centerX - radius;
+}
+
+double Sphere::getX1Maximum()
+{
+    return centerX + radius;
+}
+
+double Sphere::getX2Centroid()
+{
+    return centerY;
+}
+
+double Sphere::getX2Minimum()
+{
+    return centerY - radius;
+}
+
+double Sphere::getX2Maximum()
+{
+    return centerY + radius;
+}
+
+double Sphere::getX3Centroid()
+{
+    return centerZ;
+}
+
+double Sphere::getX3Minimum()
+{
+    return centerZ - radius;
+}
+
+double Sphere::getX3Maximum()
+{
+    return centerZ + radius;
+}
+
+bool Sphere::isPointInObject(const double& x1, const double& x2, const double& x3, const double& minOffset,
+    const double& maxOffset)
+{
+    double offset = maxOffset;
+    if (x1 < centerX || x2 < centerY || x3 < centerZ)
+        offset = minOffset;
+        
+
+    const double deltaX1 = x1 - centerX;
+    const double deltaX2 = x2 - centerY;
+    const double deltaX3 = x3 - centerZ;
+
+    return (deltaX1*deltaX1 + deltaX2*deltaX2 + deltaX3*deltaX3) < ((this->radius - offset) * (this->radius - offset));
+}
+
+
+void Sphere::scale(double delta)
+{
+    this->radius += delta;
+}
+
+int Sphere::getIntersection(const Vertex & point, const Vertex & direction, Vertex & pointOnObject, real & qVal)
+{
+    
+    Vertex relativePoint( point.x - this->centerX, 
+                          point.y - this->centerY, 
+                          point.z - this->centerZ );
+
+    real directionSquare = direction.x * direction.x
+                         + direction.y * direction.y
+                         + direction.z * direction.z;
+
+    real p = 2* ( relativePoint.x * direction.x
+                + relativePoint.y * direction.y
+                + relativePoint.z * direction.z )
+                / directionSquare;
+
+    real q = ( relativePoint.x * relativePoint.x
+             + relativePoint.y * relativePoint.y
+             + relativePoint.z * relativePoint.z
+             - (real)this->radius * (real)this->radius )
+           / directionSquare;
+
+    real discriminant = 0.25 * p * p - q;
+
+
+    if( discriminant < 0.0 ) return 1;
+
+    real result1 = - 0.5 * p + std::sqrt( discriminant );
+    real result2 = - 0.5 * p - std::sqrt( discriminant );
+
+    if( result1 < 0.0 && result2 < 0.0 ) return 1;
+
+    if (result1 < 0.0)
+        result1 = (real)FLT_MAX;
+    if (result2 < 0.0)
+        result2 = (real)FLT_MAX;
+
+    real t = std::min( result1, result2 );
+
+    pointOnObject.x = point.x + t * direction.x;
+    pointOnObject.y = point.y + t * direction.y;
+    pointOnObject.z = point.z + t * direction.z;
+
+    qVal = t;
+
+    return 0;
+}
diff --git a/src/gpu/GridGenerator/geometries/Sphere/Sphere.h b/src/gpu/GridGenerator/geometries/Sphere/Sphere.h
new file mode 100644
index 0000000000000000000000000000000000000000..ba5821f5bfed5b4d25c1ee3c5abecb168db462e7
--- /dev/null
+++ b/src/gpu/GridGenerator/geometries/Sphere/Sphere.h
@@ -0,0 +1,78 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file Sphere.h
+//! \ingroup geometries
+//! \author Soeren Peters, Stephan Lenz
+//=======================================================================================
+#ifndef SPHERE_H
+#define SPHERE_H
+
+#include "global.h"
+#include "GridGenerator_export.h"
+#include "geometries/Object.h"
+
+class GRIDGENERATOR_EXPORT Sphere : public Object
+{
+public:
+    Sphere(const double& centerX, const double& centerY, const double& centerZ, const double& radius);
+    virtual ~Sphere();
+
+    static SPtr<Sphere> makeShared(double centerX, double centerY, double centerZ, double radius);
+
+    Object* clone() const override;
+
+    double getX1Centroid() override;
+    double getX1Minimum() override;
+    double getX1Maximum() override;
+    double getX2Centroid() override;
+    double getX2Minimum() override;
+    double getX2Maximum() override;
+    double getX3Centroid() override;
+    double getX3Minimum() override;
+    double getX3Maximum() override;
+
+    bool isPointInObject(const double& x1, const double& x2, const double& x3, const double& minOffset, const double& maxOffset) override;
+
+
+    void scale(double delta) override;
+    
+    int getIntersection(const Vertex &P, const Vertex &direction, Vertex &pointOnObject, real &qVal) override;
+
+
+protected:
+    double centerX;
+    double centerY;
+    double centerZ;
+
+    double radius;
+};
+
+
+
+#endif   
diff --git a/src/gpu/GridGenerator/geometries/Triangle/Triangle.cpp b/src/gpu/GridGenerator/geometries/Triangle/Triangle.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..bf272b9e7f46c413ae6edce62c05d1be20d327de
--- /dev/null
+++ b/src/gpu/GridGenerator/geometries/Triangle/Triangle.cpp
@@ -0,0 +1,356 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file Triangle.cpp
+//! \ingroup geometries
+//! \author Soeren Peters, Stephan Lenz
+//=======================================================================================
+#include "Triangle.h"
+
+#include "utilities/math/Math.h"
+
+#include "grid/NodeValues.h"
+
+using namespace vf::gpu;
+
+Triangle::Triangle(Vertex &v1, Vertex &v2, Vertex &v3, Vertex &normal) : v1(v1), v2(v2), v3(v3), normal(normal), patchIndex(INVALID_INDEX) {}
+Triangle::Triangle(Vertex &v1, Vertex &v2, Vertex &v3) : v1(v1), v2(v2), v3(v3), patchIndex(INVALID_INDEX) { calcNormal(); }
+Triangle::Triangle(){}
+
+void Triangle::set(const Vertex &v1, const Vertex &v2, const Vertex &v3)
+{
+    this->v1 = v1;
+    this->v2 = v2;
+    this->v3 = v3;
+    this->calcNormal();
+}
+
+void Triangle::set(int index, Vertex value)
+{
+    if (index == 0)
+        v1 = value;
+    if (index == 1)
+        v2 = value;
+    if (index == 2)
+        v3 = value;
+}
+
+Vertex Triangle::get(int index)
+{
+    if (index == 0)
+        return v1;
+    if (index == 1)
+        return v2;
+    if (index == 2)
+        return v3;
+    else
+        return Vertex((real)-999999999999999, (real)-99999999999999, (real)-9999999999999);
+}
+
+void Triangle::calcNormal()
+{
+    Vertex edge1 = v2 - v1;
+    Vertex edge2 = v3 - v1;
+    normal = edge1.crossProduct(edge2);
+    normal.normalize();
+}
+
+void Triangle::initalLayerThickness(real delta)
+{
+    this->layerThickness = delta * (std::abs(this->normal.x) + std::abs(this->normal.y) + std::abs(this->normal.z));
+}
+
+
+char Triangle::isUnderFace(const Vertex &point) const
+{
+    real s;
+
+    if (this->isUnterExtendedFace(point, s)) {
+        if (this->isNotNextToFace(point)) {
+            if (this->isUnderAngleToNeighbors(point)) {
+                if (this->isNegativeDirectionBorder(point)) {
+                    return NEGATIVE_DIRECTION_BORDER;
+                } else {
+                    return INSIDE;
+                }
+            } else {
+                return 4;
+            }
+        } else {
+            return 3;
+        }
+    }
+
+
+    if (this->isQNode(point, s))
+        return Q_DEPRECATED;
+    
+    return FLUID;
+}
+
+bool Triangle::isUnterExtendedFace(const Vertex & point, real &s) const
+{
+    s = this->getPerpedicularDistanceFrom(point);
+    return ((vf::Math::greaterEqual(s, 0.0f)) && s < this->layerThickness);
+}
+
+real Triangle::getPerpedicularDistanceFrom(const Vertex &P) const
+{
+    Vertex v = P - v1;
+    return  (v * -1.0f) * normal;
+}
+
+Vertex Triangle::getPerpedicularPointFrom(const Vertex &P) const
+{
+    return P + normal * getPerpedicularDistanceFrom(P);
+}
+
+bool Triangle::isQNode(const Vertex & point, const real &s) const
+{
+    return (s < 0 && vf::Math::lessEqual(-s, this->layerThickness));
+    //calculateQs(actualPoint, actualTriangle);
+}
+
+bool Triangle::isNegativeDirectionBorder(const Vertex &point) const
+{
+    return normal.x < 0.0f || normal.y < 0.0f || normal.z < 0.0f;
+    //return (sVector.x < 0.0f && sVector.y < 0.0f && sVector.z < 0.0f);
+}
+
+bool Triangle::isNotNextToFace(const Vertex &point) const
+{
+    Vertex Pb = getPerpedicularPointFrom(point);
+
+    Vertex w1 = Pb - v1;
+    Vertex w2 = Pb - v2;
+    Vertex w3 = Pb - v3;
+
+    Vertex t1 = w1.crossProduct(v2 - v1);
+    Vertex t2 = w2.crossProduct(v3 - v2);
+    Vertex t3 = w3.crossProduct(v1 - v3);
+
+    real g1 = t1 * normal;
+    real g2 = t2 * normal;
+    real g3 = t3 * normal;
+
+    return vf::Math::lessEqual(g1, 0.0f) && vf::Math::lessEqual(g2, 0.0f) && vf::Math::lessEqual(g3, 0.0f);
+}
+
+bool Triangle::isUnderAngleToNeighbors(const Vertex &point) const
+{
+    Vertex Pci[3];
+    this->getClosestPointsOnEdges(Pci, point);
+    Vertex Pb = this->getPerpedicularPointFrom(point);
+
+    Vertex q[3];
+    Vertex r[3];
+
+    real betaAngles[3];
+    for (int i = 0; i < 3; i++)
+    {
+        q[i] = point - Pci[i];
+        r[i] = Pb - Pci[i];
+        betaAngles[i] = q[i].getInnerAngle(r[i]);
+    }
+
+    real eps = EPSILON * 100.0f;
+    return (vf::Math::lessEqual(betaAngles[0], alphaAngles[0], eps) && vf::Math::lessEqual(betaAngles[1], alphaAngles[1], eps) && vf::Math::lessEqual(betaAngles[2], alphaAngles[2], eps));
+}
+
+void Triangle::getClosestPointsOnEdges(Vertex arr[], const Vertex &P) const
+{
+    Vertex Pc1, Pc2, Pc3;
+    Vertex v4 = P - v1;
+    Vertex v5 = P - v2;
+    Vertex v6 = P - v3;
+
+    Vertex d1 = v2 - v1;
+    Vertex d2 = v3 - v2;
+    Vertex d3 = v1 - v3;
+
+    real temp = (v4 * d1) / (d1 * d1);
+    Vertex tempV = d1 * temp;
+    Pc1 = v1 + tempV;
+
+    temp = (v5 * d2) / (d2 * d2);
+    tempV = d2 * temp;
+    Pc2 = v2 + tempV;
+
+    temp = (v6 * d3) / (d3 * d3);
+    tempV = d3 * temp;
+    Pc3 = v3 + tempV;
+
+    arr[0] = Pc1;
+    arr[1] = Pc2;
+    arr[2] = Pc3;
+}
+
+Vertex Triangle::getCenterOfMass() const 
+{
+    return (v1 + v2 + v3) * (1.0f / 3.0f);
+}
+
+real Triangle::getHalfAngleBetweenToAdjacentTriangle(const Triangle &t2) const
+{
+    if (isEqual(t2)) return 0.0f;
+
+    real alpha = normal.getInnerAngle(t2.normal);
+	if (alpha == 0.0f)
+		return 90.0f;
+
+    if(doesNormalsShowToEachOther(t2))
+        return (180.0f + alpha) / 2.0f;
+    else
+        return (180.0f - alpha) / 2.0f;
+}
+
+int Triangle::isEqual(const Triangle &t2) const
+{
+    return getNumberOfCommonEdge(t2) == 3;
+}
+
+bool Triangle::doesNormalsShowToEachOther(const  Triangle &t2) const
+{
+    Vertex s1 = getCenterOfMass();
+    Vertex s2 = t2.getCenterOfMass();
+
+    Vertex s1s2 = s1 - s2;
+    real X = s1s2 * t2.normal;
+    return X > 0 ? true : false;
+}
+
+int Triangle::getCommonEdge(const Triangle &t2) const 
+{
+    bool edgeOneCommon = false;
+	bool edgeTwoCommon = false;
+	bool edgeThreeCommon = false;
+
+	edgeOneCommon = t2.contains(v1);
+	edgeTwoCommon = t2.contains(v2);
+	edgeThreeCommon = t2.contains(v3);
+
+    if (edgeOneCommon && edgeTwoCommon)
+        return 0;
+    else if (edgeTwoCommon && edgeThreeCommon)
+        return 1;
+    else if (edgeThreeCommon && edgeOneCommon)
+        return 2;
+    else
+        return -1;
+}
+
+bool Triangle::contains(const Vertex& v) const 
+{
+	return (v == v1 || v == v2 || v == v3);
+}
+
+
+int Triangle::getNumberOfCommonEdge(const Triangle &t2) const
+{
+	int commonEdge = 0;
+	if (t2.contains(v1))
+		commonEdge++;
+	if (t2.contains(v2))
+		commonEdge++;
+	if (t2.contains(v3))
+		commonEdge++;
+
+    if (commonEdge == 2 || commonEdge == 3) return commonEdge;
+    return 0;
+}
+
+
+int Triangle::getTriangleIntersection(const Vertex &P, const Vertex &direction, Vertex &pointOnTri, real &qVal) const
+{
+	///// taken from /////
+	//http://www.scratchapixel.com/lessons/3d-basic-rendering/ray-tracing-rendering-a-triangle/moller-trumbore-ray-triangle-intersection
+
+
+    Vertex edge1, edge2, tvec, pvec, qvec, tuv;
+    float det, inv_det;
+
+    edge1 = v2 - v1;
+    edge2 = v3 - v1;
+
+    pvec = direction.crossProduct(edge2);
+    det = edge1 * pvec;
+
+    if (det < EPSILON)
+        return 3;
+
+    inv_det = 1.0 / det;
+
+    tvec = P - v1;
+    tuv.y = (tvec * pvec) * inv_det;
+
+	if (!vf::Math::greaterEqual(tuv.y, 0.0) || !vf::Math::lessEqual(tuv.y, 1.0))
+	//if (tuv.y < 0.0 || tuv.y > 1.0)
+        return 1;
+
+    qvec = tvec.crossProduct(edge1);
+    tuv.z = (direction * qvec) * inv_det;
+
+	if ( !vf::Math::greaterEqual(tuv.z, 0.0) || !vf::Math::lessEqual((tuv.y + tuv.z), 1.0))
+    //if (tuv.z < 0.0 || (tuv.y + tuv.z) > 1.0)
+        return 2;
+
+    tuv.x = (edge2 * qvec) * inv_det;
+
+    pointOnTri.x = (1.0 - tuv.y - tuv.z) * v1.x + tuv.y * v2.x + tuv.z * v3.x;
+    pointOnTri.y = (1.0 - tuv.y - tuv.z) * v1.y + tuv.y * v2.y + tuv.z * v3.y;
+    pointOnTri.z = (1.0 - tuv.y - tuv.z) * v1.z + tuv.y * v2.z + tuv.z * v3.z;
+
+    qVal = tuv.x;
+
+    return 0;
+}
+
+void Triangle::print() const
+{
+    printf("v1: ");
+    v1.print();
+    printf("v2: ");
+    v2.print();
+    printf("v3: ");
+    v3.print();
+    printf("normal: ");
+    normal.print();
+}
+
+bool Triangle::operator==(const Triangle &t) const
+{
+    return v1 == t.v1 && v2 == t.v2 && v3 == t.v3
+        && vf::Math::equal(alphaAngles[0], t.alphaAngles[0]) && vf::Math::equal(alphaAngles[1], t.alphaAngles[1]) && vf::Math::equal(alphaAngles[2], t.alphaAngles[2]);
+}
+
+
+void Triangle::setMinMax(real &minX, real &maxX, real &minY, real &maxY, real &minZ, real &maxZ) const
+{
+    Vertex::setMinMax(minX, maxX, minY, maxY, minZ, maxZ, v1, v2, v3);
+}
+
diff --git a/src/gpu/GridGenerator/geometries/Triangle/Triangle.h b/src/gpu/GridGenerator/geometries/Triangle/Triangle.h
new file mode 100644
index 0000000000000000000000000000000000000000..0017d2f71145f2608976a95018816bf81cef44b7
--- /dev/null
+++ b/src/gpu/GridGenerator/geometries/Triangle/Triangle.h
@@ -0,0 +1,95 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file Triangle.h
+//! \ingroup geometries
+//! \author Soeren Peters, Stephan Lenz
+//=======================================================================================
+#ifndef Triangle_h
+#define Triangle_h
+
+#include <memory>
+
+#include "global.h"
+#include "GridGenerator_export.h"
+#include "geometries/Vertex/Vertex.h"
+
+class TriangleMemento;
+
+struct GRIDGENERATOR_EXPORT Triangle
+{
+    Vertex v1, v2, v3, normal;
+    real alphaAngles[3];
+    real layerThickness;
+    
+    uint patchIndex;
+
+	Triangle(Vertex &v1, Vertex &v2, Vertex &v3, Vertex &normal);
+	Triangle(Vertex &v1, Vertex &v2, Vertex &v3);
+	Triangle();
+
+	void set(const Vertex &v1, const Vertex &v2, const Vertex &v3);
+    void set(int index, Vertex value);
+    Vertex get(int index);
+	void calcNormal();
+
+    void initalLayerThickness(real delta);
+
+
+	Vertex getCenterOfMass() const;
+	real getHalfAngleBetweenToAdjacentTriangle(const Triangle &t2) const;
+	int isEqual(const Triangle &t2) const;
+	bool doesNormalsShowToEachOther(const  Triangle &t2) const;
+	int getCommonEdge(const Triangle &t2) const;
+
+	bool contains(const Vertex& v)const;
+	int getNumberOfCommonEdge(const Triangle &t2) const;
+	int getTriangleIntersection(const Vertex &P, const Vertex &direction, Vertex &pointOnTri, real &qVal) const;
+	void print() const;
+
+    char isUnderFace(const Vertex &point) const;
+
+    bool isUnterExtendedFace(const Vertex & point, real &s) const;
+    bool isNotNextToFace(const Vertex &point) const;
+    bool isUnderAngleToNeighbors(const Vertex &point) const;
+    void getClosestPointsOnEdges(Vertex arr[], const Vertex &P) const;
+    real getPerpedicularDistanceFrom(const Vertex &P) const;
+    Vertex getPerpedicularPointFrom(const Vertex &P) const;
+    bool isQNode(const Vertex & point, const real &s) const;
+    bool isNegativeDirectionBorder(const Vertex & point) const;
+
+    bool operator==(const Triangle &t) const;
+
+    TriangleMemento getState() const;
+    void setState(const TriangleMemento &memento);
+
+
+    void setMinMax(real &minX, real &maxX, real &minY, real &maxY, real &minZ, real &maxZ) const;
+};
+
+#endif
diff --git a/src/gpu/GridGenerator/geometries/TriangularMesh/TriangularMesh.cpp b/src/gpu/GridGenerator/geometries/TriangularMesh/TriangularMesh.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a11384887074aa6b42bff77dd8b7ee1ade8fc9e0
--- /dev/null
+++ b/src/gpu/GridGenerator/geometries/TriangularMesh/TriangularMesh.cpp
@@ -0,0 +1,290 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file TriangularMesh.cpp
+//! \ingroup geometries
+//! \author Soeren Peters, Stephan Lenz
+//=======================================================================================
+#include "TriangularMesh.h"
+
+#include "Core/Timer/Timer.h"
+
+#include "basics/geometry3d/GbTriFaceMesh3D.h"
+
+#include "geometries/TriangularMesh/triangleNeighborFinder/TriangleNeighborFinder.h"
+#include "geometries/TriangularMesh/TriangularMeshStrategy.h"
+
+#include "io/STLReaderWriter/STLWriter.h"
+#include "io/STLReaderWriter/STLReader.h"
+
+#include "grid/GridImp.h"
+#include "grid/NodeValues.h"
+
+#include "utilities/transformator/TransformatorImp.h"
+
+using namespace vf::gpu;
+
+
+TriangularMesh* TriangularMesh::make(const std::string& fileName, const std::vector<uint> ignorePatches)
+{
+    TriangularMesh* triangularMesh = new TriangularMesh(fileName, ignorePatches);
+    return triangularMesh;
+}
+
+TriangularMesh::TriangularMesh(const std::string& input, const BoundingBox& box)
+{
+	this->triangleVec = STLReader::readSTL(box, input);
+	initalizeDataFromTriangles();
+	this->findNeighbors();
+}
+
+TriangularMesh::TriangularMesh(const std::string& inputPath, const std::vector<uint> ignorePatches)
+{
+    this->minmax = BoundingBox::makeInvalidMinMaxBox();
+
+    this->triangleVec = STLReader::readSTL(inputPath, STLReader::ascii, ignorePatches);
+    //this->triangleVec = STLReader::readSTL(inputPath);
+    initalizeDataFromTriangles();
+    this->findNeighbors();
+}
+
+
+TriangularMesh::TriangularMesh()
+{
+	this->minmax = BoundingBox::makeInvalidMinMaxBox();  // blame Lenz
+}
+
+TriangularMesh::~TriangularMesh()
+{
+
+}
+
+Object* TriangularMesh::clone() const
+{
+    auto mesh = new TriangularMesh();
+    mesh->setTriangles(this->triangleVec);
+    return mesh;
+}
+
+
+uint TriangularMesh::getNumberOfTriangles() const
+{
+    return (uint)triangleVec.size();
+}
+
+
+void TriangularMesh::findNeighbors()
+{
+	*logging::out << logging::Logger::INFO_INTERMEDIATE << "start finding neighbors ...\n";
+
+    auto t = Timer::makeStart();
+
+	TriangleNeighborFinder finder(triangles, size);
+	finder.fillWithNeighborAngles(this);
+
+    t->end();
+
+    *logging::out << logging::Logger::INFO_INTERMEDIATE << "time finding neighbors: " << t->getTimeInSeconds() << "s\n";
+}
+
+void TriangularMesh::setTriangles(std::vector<Triangle> triangles)
+{
+	this->triangleVec = triangles;
+	initalizeDataFromTriangles();
+}
+
+void TriangularMesh::setMinMax(BoundingBox minmax)
+{
+	this->minmax = minmax;
+}
+
+void TriangularMesh::initalizeDataFromTriangles()
+{
+	this->triangles = triangleVec.data();
+	this->size = long(triangleVec.size());
+
+    for (std::size_t i = 0; i < (size_t)this->size; i++) {
+        this->minmax.setMinMax(this->triangleVec[i]);
+    }
+}
+
+bool TriangularMesh::operator==(const TriangularMesh &geometry) const
+{
+    if (!(minmax == geometry.minmax))
+        return false;
+
+    if (size != geometry.size)
+        return false;
+
+    for (int i = 0; i < size ; i++)
+        if (!(triangleVec[i] == geometry.triangleVec[i]))
+            return false;
+    return true;
+}
+
+
+GbTriFaceMesh3D* TriangularMesh::getGbTriFaceMesh3D() const
+{
+    return this->VF_GbTriFaceMesh3D.get();
+}
+
+GRIDGENERATOR_EXPORT void TriangularMesh::generateGbTriFaceMesh3D()
+{
+    if( this->VF_GbTriFaceMesh3D ) return;
+
+    *logging::out << logging::Logger::INFO_INTERMEDIATE << "Start generating GbTriFaceMesh3D:\n";
+
+    std::vector<GbTriFaceMesh3D::Vertex>  *gbVertices = new std::vector<GbTriFaceMesh3D::Vertex>(this->triangleVec.size() * 3);
+    std::vector<GbTriFaceMesh3D::TriFace> *gbTriangles = new std::vector<GbTriFaceMesh3D::TriFace>(this->triangleVec.size());
+
+    for (int i = 0; i < (int)this->triangleVec.size(); i++)
+    {
+        (*gbVertices)[i * 3] = GbTriFaceMesh3D::Vertex(triangles[i].v1.x, triangles[i].v1.y, triangles[i].v1.z);
+        (*gbVertices)[i * 3 + 1] = GbTriFaceMesh3D::Vertex(triangles[i].v2.x, triangles[i].v2.y, triangles[i].v2.z);
+        (*gbVertices)[i * 3 + 2] = GbTriFaceMesh3D::Vertex(triangles[i].v3.x, triangles[i].v3.y, triangles[i].v3.z);
+
+        (*gbTriangles)[i] = GbTriFaceMesh3D::TriFace(i * 3, i * 3 + 1, i * 3 + 2);
+    }
+
+    this->VF_GbTriFaceMesh3D = std::make_shared<GbTriFaceMesh3D>( "stl", gbVertices, gbTriangles, GbTriFaceMesh3D::KDTREE_SAHPLIT, false );
+
+    *logging::out << logging::Logger::INFO_INTERMEDIATE << "Done generating GbTriFaceMesh3D\n";
+}
+
+
+bool intersectPlane(const Vertex &normal, const Vertex &pointOnPlane, const Vertex &originLine, const Vertex &directionLine, Vertex &intersectionPoint)
+{
+    // assuming vectors are all normalized
+    real denom = normal * directionLine;
+    if (denom > 1e-6) {
+        Vertex p0l0 = pointOnPlane - originLine;
+        real distance = p0l0 * normal / denom;
+        intersectionPoint = originLine + directionLine * distance;
+        return (distance >= 0);
+    }
+
+    return false;
+}
+
+void TriangularMesh::scale(double offset)
+{
+    std::vector<Triangle> triangles = this->triangleVec;
+
+    TriangleNeighborFinder finder(this->triangles, this->size);
+
+    auto trianglesPerVertex = finder.getTrianglesPerVertex();
+    auto averrageNormals = getAverrageNormalsPerVertex(trianglesPerVertex);
+
+
+    for (std::size_t vertexID = 0; vertexID < this->getNumberOfTriangles() * 3; vertexID++)
+    {
+        int coordinatedID = finder.sortedToTriangles[vertexID][IDS::coordinateID];
+        Vertex averrageNormal = averrageNormals[coordinatedID];
+
+        //auto triangleIds = finder.getTriangleIDsWithCommonVertex(vertexID);
+        //for(auto index : triangleIds)
+        //{
+        //    auto triangle = origin->triangleVec[index];
+        //    Vertex intersection;
+        //    real d = 10;
+        //    triangle.normal.normalize();
+        //    Vertex p = triangle.v2 + triangle.normal * d;
+        //    // p.normalize();
+        //    Vertex lineOrigin = origin->triangleVec[triangleID].get(vertexTriangleID);
+        //    // lineOrigin.normalize();
+        //    //averrageNormal.normalize();
+        //    //triangle.print();
+
+        //    //printf("average: \n");
+        //    //averrageNormal.print();
+
+        //    //printf("line origin: \n");
+        //    //lineOrigin.print();
+
+        //    //printf("plane normal: \n");
+        //    //triangle.normal.print();
+
+        //    //printf("plane point: \n");
+        //    //p.print();
+
+        //    bool b = intersectPlane(triangle.normal, p, lineOrigin, averrageNormal, intersection);
+        //    //intersection.print();
+        //    //printf("\n");
+        //}
+        //printf("\n\n");
+
+        averrageNormal.normalize();
+        const int triangleID = (int)vertexID / 3;
+        const int vertexTriangleID = (int)vertexID % 3;
+
+        Vertex intersection;
+        Vertex p = this->triangleVec[triangleID].v1 + this->triangleVec[triangleID].normal * offset;
+        Vertex lineOrigin = this->triangleVec[triangleID].get(vertexTriangleID);
+        //bool b = intersectPlane(this->triangleVec[triangleID].normal, p, lineOrigin, averrageNormal, intersection);
+        triangles[triangleID].set(vertexTriangleID, intersection);
+        triangles[triangleID].calcNormal();
+
+        triangles[triangleID].set(vertexTriangleID, lineOrigin + averrageNormal * offset);
+    }
+
+    this->setTriangles(triangles);
+}
+
+std::vector<Vertex> TriangularMesh::getAverrageNormalsPerVertex(std::vector<std::vector<Triangle>> trianglesPerVertex)
+{
+    std::vector<Vertex> averrageNormals;
+    for (auto triangles : trianglesPerVertex)
+    {
+        eliminateTriangleswithIdenticialNormal(triangles);
+
+        Vertex sumNormal;
+        for (auto triangle : triangles)
+        {
+            triangle.calcNormal();
+            sumNormal = sumNormal + triangle.normal;
+        }
+        real magnitude = sumNormal.getMagnitude();
+        averrageNormals.push_back(Vertex(sumNormal / magnitude));
+    }
+    return averrageNormals;
+}
+
+void TriangularMesh::eliminateTriangleswithIdenticialNormal(std::vector<Triangle> &triangles)
+{
+    for (std::size_t i = 0; i < triangles.size() - 1; i++) {
+        for (std::size_t j = i + 1; j < triangles.size(); j++) {
+            if (triangles[i].normal == triangles[j].normal)
+                triangles.erase(triangles.begin() + i);
+        }
+    }
+}
+
+void TriangularMesh::findInnerNodes(SPtr<GridImp> grid)
+{
+    grid->getTriangularMeshDiscretizationStrategy()->discretize(this, grid.get(), FLUID, INVALID_OUT_OF_GRID);
+}
diff --git a/src/gpu/GridGenerator/geometries/TriangularMesh/TriangularMesh.h b/src/gpu/GridGenerator/geometries/TriangularMesh/TriangularMesh.h
new file mode 100644
index 0000000000000000000000000000000000000000..2d31de98bf1f5530ada555e548ac6bb40e5e51b7
--- /dev/null
+++ b/src/gpu/GridGenerator/geometries/TriangularMesh/TriangularMesh.h
@@ -0,0 +1,114 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file TriangularMesh.h
+//! \ingroup geometries
+//! \author Soeren Peters, Stephan Lenz, Martin Schoenherr
+//=======================================================================================
+#ifndef TriangularMesh_h
+#define TriangularMesh_h
+
+#include <stdio.h>
+#include <vector>
+#include <string>
+#include <memory>
+#include "GridGenerator_export.h"
+#include "global.h"
+
+#include "geometries/Triangle/Triangle.h"
+#include "geometries/BoundingBox/BoundingBox.h"
+
+#include "geometries/Object.h"
+
+class GeometryMemento;
+class GbTriFaceMesh3D;
+
+enum class DiscretizationMethod { RAYCASTING, POINT_IN_OBJECT, POINT_UNDER_TRIANGLE };
+
+
+class TriangularMesh : public Object
+{
+public:
+
+    GRIDGENERATOR_EXPORT static TriangularMesh* make(const std::string& fileName, const std::vector<uint> ignorePatches = std::vector<uint>());
+	GRIDGENERATOR_EXPORT TriangularMesh();
+    GRIDGENERATOR_EXPORT TriangularMesh(const std::string& inputPath, const std::vector<uint> ignorePatches = std::vector<uint>());
+	GRIDGENERATOR_EXPORT TriangularMesh(const std::string& inputPath, const BoundingBox &box);
+	GRIDGENERATOR_EXPORT ~TriangularMesh();
+
+    GRIDGENERATOR_EXPORT uint getNumberOfTriangles() const;
+
+	GRIDGENERATOR_EXPORT void setTriangles(std::vector<Triangle> triangles);
+	GRIDGENERATOR_EXPORT void setMinMax(BoundingBox minmax);
+
+	std::vector<Triangle> triangleVec;
+	Triangle *triangles;
+	long size;
+	BoundingBox minmax;
+
+    SPtr<GbTriFaceMesh3D> VF_GbTriFaceMesh3D;
+
+    GRIDGENERATOR_EXPORT bool operator==(const TriangularMesh &geometry) const;
+
+    GRIDGENERATOR_EXPORT void findNeighbors();
+
+    GRIDGENERATOR_EXPORT GbTriFaceMesh3D* getGbTriFaceMesh3D() const;
+
+    GRIDGENERATOR_EXPORT void generateGbTriFaceMesh3D();
+
+private:
+	
+	void initalizeDataFromTriangles();
+
+    static std::vector<Vertex> getAverrageNormalsPerVertex(std::vector<std::vector<Triangle> > trianglesPerVertex);
+    static void eliminateTriangleswithIdenticialNormal(std::vector<Triangle> &triangles);
+
+public:
+    Object* clone() const override;
+    double getX1Centroid() override { throw "Not implemented in TriangularMesh"; }
+    double getX1Minimum() override { return minmax.minX; }
+    double getX1Maximum() override { return minmax.maxX; }
+    double getX2Centroid() override { throw "Not implemented in TriangularMesh"; }
+    double getX2Minimum() override { return minmax.minY; }
+    double getX2Maximum() override { return minmax.maxY; }
+    double getX3Centroid() override { throw "Not implemented in TriangularMesh"; }
+    double getX3Minimum() override { return minmax.minZ; }
+    double getX3Maximum() override { return minmax.maxZ; }
+    void scale(double delta) override;
+    bool isPointInObject(const double& x1, const double& x2, const double& x3, const double& minOffset,
+        const double& maxOffset) override {
+        return false;
+    }
+    
+    void findInnerNodes(SPtr<GridImp> grid) override;
+};
+
+
+
+#endif
+
diff --git a/src/gpu/GridGenerator/geometries/TriangularMesh/TriangularMeshStrategy.cpp b/src/gpu/GridGenerator/geometries/TriangularMesh/TriangularMeshStrategy.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d9c1486e2ca9469d55174eca673f22f180a78294
--- /dev/null
+++ b/src/gpu/GridGenerator/geometries/TriangularMesh/TriangularMeshStrategy.cpp
@@ -0,0 +1,310 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file TriangularMeshStrategy.cpp
+//! \ingroup geometries
+//! \author Soeren Peters, Stephan Lenz
+//=======================================================================================
+#include "TriangularMeshStrategy.h"
+
+#include "Core/Timer/Timer.h"
+
+#include "basics/geometry3d/GbTriFaceMesh3D.h"
+
+#include "geometries/Triangle/Triangle.h"
+#include "geometries/TriangularMesh/TriangularMesh.h"
+
+#include "grid/GridImp.h"
+#include "grid/NodeValues.h"
+
+using namespace vf::gpu;
+
+void TriangularMeshDiscretizationStrategy::removeOddBoundaryCellNodes(GridImp* grid)
+{
+#pragma omp parallel for
+    for (int index = 0; index < (int)grid->getSize(); index++)
+        grid->fixOddCell(index);
+}
+
+
+void PointInObjectDiscretizationStrategy::doDiscretize(TriangularMesh* triangularMesh, GridImp* grid, char InnerType, char OuterType)
+{
+    triangularMesh->generateGbTriFaceMesh3D();
+
+    *logging::out << logging::Logger::INFO_INTERMEDIATE << "Start Point-In-Object Test:\n";
+
+    // trigger the GbTriFaceMesh3D to generate a kd-tree
+    triangularMesh->getGbTriFaceMesh3D()->isPointInGbObject3D(0.0, 0.0, 0.0);
+
+    auto timer = Timer::makeStart();
+
+    real outputTime = 60.0;
+    
+#pragma omp parallel for
+    for (int index = 0; index < (int)grid->getSize(); index++)
+    {
+        if( grid->getFieldEntry(index) == InnerType ) continue;
+
+        real x, y, z;
+        grid->transIndexToCoords(index, x, y, z);
+
+        if (triangularMesh->getGbTriFaceMesh3D()->isPointInGbObject3D(x, y, z))
+            grid->setNodeTo(index, InnerType);
+        //else
+        //    grid->setNodeTo(i, OuterType);
+
+        if( timer->getCurrentRuntimeInSeconds() > outputTime ){
+            *logging::out << logging::Logger::INFO_INTERMEDIATE << "    " << index << "/" << grid->getSize() <<" nodes tested!\n";
+            timer->start();
+        }
+    }
+
+    *logging::out << logging::Logger::INFO_INTERMEDIATE << "Done Point-In-Object Test\n";
+}
+
+
+void RayCastingDiscretizationStrategy::doDiscretize(TriangularMesh* triangularMesh, GridImp* grid, char InnerType, char OuterType)
+{
+        auto mesh = triangularMesh->getGbTriFaceMesh3D();
+
+        const real minXExact = triangularMesh->minmax.minX;
+        const real minYExact = triangularMesh->minmax.minY;
+        const real minZExact = triangularMesh->minmax.minZ;
+
+        const real maxXExact = triangularMesh->minmax.maxX;
+        const real maxYExact = triangularMesh->minmax.maxY;
+        const real maxZExact = triangularMesh->minmax.maxZ;
+
+        const auto min = grid->getMinimumOnNode(Vertex(minXExact, minYExact, minZExact));
+
+        const real minX = min.x;
+        const real minY = min.y;
+        const real minZ = min.z;
+
+        const auto max = grid->getMaximumOnNode(Vertex(maxXExact, maxYExact, maxZExact));
+
+        const real maxX = max.x;
+        const real maxY = max.y;
+        const real maxZ = max.z;
+
+
+        real x, y, z;
+        for (z = minZ; z <= maxZ; z += grid->getDelta())
+        {
+            for (y = minY; y <= maxY; y += grid->getDelta())
+            {
+                for (x = minX; x <= maxX; x += grid->getDelta())
+                {
+                    grid->setNodeTo(grid->transCoordToIndex(x, y, z), InnerType);
+                }
+            }
+        }
+
+
+
+        int counter = 0;
+
+        // Test line intersection
+        for (z = minZ; z <= maxZ; z += grid->getDelta())
+        {
+            for (y = minY; y <= maxY; y += grid->getDelta())
+            {
+                for (x = minX; x <= maxX; x += grid->getDelta())
+                {
+                    counter++;
+                    if (mesh->intersectLine((x - grid->getDelta()), y, z, x, y, z)) 
+                        break;
+                    grid->setNodeTo(grid->transCoordToIndex(x, y, z), OuterType);
+                }
+            }
+        }
+
+        // Test line intersection from opposite direction
+        for (z = minZ; z <= maxZ; z += grid->getDelta())
+        {
+            for (y = minY; y <= maxY; y += grid->getDelta())
+            {
+                for (x = maxX; x >= minX; x -= grid->getDelta())
+                {
+                    if (!grid->isNode(grid->transCoordToIndex(x, y, z), OuterType))
+                    {
+                        counter++;
+                        if (mesh->intersectLine((x + grid->getDelta()), y, z, x, y, z))
+                            break;
+                        grid->setNodeTo(grid->transCoordToIndex(x, y, z), OuterType);
+                    }
+                }
+            }
+        }
+
+        // Test line intersection
+        for (z = minZ; z <= maxZ; z += grid->getDelta())
+        {
+            for (x = minX; x <= maxX; x += grid->getDelta())
+            {
+                for (y = minY; y <= maxY; y += grid->getDelta())
+                {
+                    if (!grid->isNode(grid->transCoordToIndex(x, y, z), OuterType))
+                    {
+                        counter++;
+                        if (mesh->intersectLine(x, (y - grid->getDelta()), z, x, y, z)) 
+                            break;
+                        grid->setNodeTo(grid->transCoordToIndex(x, y, z), OuterType);
+                    }
+                }
+            }
+        }
+
+        // Test line intersection from opposite direction
+        for (z = minZ; z <= maxZ; z += grid->getDelta())
+        {
+            for (x = minX; x <= maxX; x += grid->getDelta())
+            {
+                for (y = maxY; y >= minY; y -= grid->getDelta())
+                {
+                    if (!grid->isNode(grid->transCoordToIndex(x, y, z), OuterType))
+                    {
+                        counter++;
+                        if (mesh->intersectLine(x, (y + grid->getDelta()), z, x, y, z))
+                            break;
+                        grid->setNodeTo(grid->transCoordToIndex(x, y, z), OuterType);
+                    }
+                }
+            }
+        }
+
+        // Test line intersection
+        for (x = minX; x <= maxX; x += grid->getDelta())
+        {
+            for (y = minY; y <= maxY; y += grid->getDelta())
+            {
+                for (z = minZ; z <= maxZ; z += grid->getDelta())
+                {
+                    if (!grid->isNode(grid->transCoordToIndex(x, y, z), OuterType))
+                    {
+                        counter++;
+                        if (mesh->intersectLine(x, y, (z - grid->getDelta()), x, y, z)) 
+                            break;
+                        grid->setNodeTo(grid->transCoordToIndex(x, y, z), OuterType);
+                    }
+                }
+            }
+        }
+
+        // Test line intersection from opposite direction
+        for (x = minX; x <= maxX; x += grid->getDelta())
+        {
+            for (y = minY; y <= maxY; y += grid->getDelta())
+            {
+                for (z = maxZ; z >= minZ; z -= grid->getDelta())
+                {
+                    if (!grid->isNode(grid->transCoordToIndex(x, y, z), OuterType))
+                    {
+                        counter++;
+                        if (mesh->intersectLine(x, y, (z + grid->getDelta()), x, y, z)) 
+                            break;
+                        grid->setNodeTo(grid->transCoordToIndex(x, y, z), OuterType);
+                    }
+                }
+            }
+        }
+
+        delete mesh;
+}
+
+
+
+void PointUnderTriangleStrategy::doDiscretize(TriangularMesh* triangularMesh, GridImp* grid, char innerType, char outerType)
+{
+#pragma omp parallel for
+    for (long i = 0; i < triangularMesh->size; i++)
+        this->meshReverse(triangularMesh->triangles[i], grid, innerType);
+
+    this->findInsideNodes(grid, innerType);
+
+#pragma omp parallel for
+    for (int i = 0; i < (int)grid->getSize(); i++)
+        this->setNegativeDirBorderTo(grid, i, innerType);
+}
+
+void PointUnderTriangleStrategy::meshReverse(Triangle& triangle, GridImp* grid, char innerType)
+{
+    auto box = grid->getBoundingBoxOnNodes(triangle);
+
+    const real delta = grid->getDelta();
+    triangle.initalLayerThickness(delta);
+
+    for (real x = box.minX; x <= box.maxX; x += delta)
+    {
+        for (real y = box.minY; y <= box.maxY; y += delta)
+        {
+            for (real z = box.minZ; z <= box.maxZ; z += delta)
+            {
+                const uint index = grid->transCoordToIndex(x, y, z);
+
+                const Vertex point(x, y, z);
+
+                const char pointValue = triangle.isUnderFace(point);
+
+                if (pointValue == NEGATIVE_DIRECTION_BORDER)
+                    grid->setNodeTo(index, NEGATIVE_DIRECTION_BORDER);
+                else if (pointValue == INSIDE)
+                    grid->setNodeTo(index, innerType);
+            }
+        }
+    }
+}
+
+void PointUnderTriangleStrategy::findInsideNodes(GridImp* grid, char innerType)
+{
+    bool foundInsideNode = true;
+    while (foundInsideNode)
+    {
+        foundInsideNode = false;
+        for (uint index = 0; index < grid->getSize(); index++)
+            this->setInsideNode(grid, index, foundInsideNode, innerType);
+    }
+}
+
+void PointUnderTriangleStrategy::setInsideNode(GridImp* grid, const uint &index, bool &insideNodeFound, char innerType)
+{
+    if (grid->isNode(index, NEGATIVE_DIRECTION_BORDER))
+        return;
+
+    if (!grid->isNode(index, innerType) && grid->nodeInNextCellIs(index, innerType))
+    {
+        grid->setNodeTo(index, innerType);
+        insideNodeFound = true;
+    }
+}
+
+void PointUnderTriangleStrategy::setNegativeDirBorderTo(GridImp* grid, const uint &index, char innerType)
+{
+    if (grid->isNode(index, NEGATIVE_DIRECTION_BORDER))
+        grid->setNodeTo(index, innerType);
+}
\ No newline at end of file
diff --git a/src/gpu/GridGenerator/geometries/TriangularMesh/TriangularMeshStrategy.h b/src/gpu/GridGenerator/geometries/TriangularMesh/TriangularMeshStrategy.h
new file mode 100644
index 0000000000000000000000000000000000000000..573a464844ac769ebd1127c666481b87f363099f
--- /dev/null
+++ b/src/gpu/GridGenerator/geometries/TriangularMesh/TriangularMeshStrategy.h
@@ -0,0 +1,101 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file TriangularMeshStrategy.h
+//! \ingroup geometries
+//! \author Soeren Peters, Stephan Lenz
+//=======================================================================================
+#ifndef TriangularMeshStrategy_H
+#define TriangularMeshStrategy_H
+
+#include "global.h"
+#include "GridGenerator_export.h"
+
+class GridImp;
+class TriangularMesh;
+struct Triangle;
+
+class GRIDGENERATOR_EXPORT TriangularMeshDiscretizationStrategy
+{
+public:
+    TriangularMeshDiscretizationStrategy() {}
+    virtual ~TriangularMeshDiscretizationStrategy() {}
+
+
+    void discretize(TriangularMesh* triangularMesh, GridImp* grid, char InnerType, char OuterType)
+    {  
+        this->doDiscretize(triangularMesh, grid, InnerType, OuterType);
+    }
+
+private:
+    virtual void doDiscretize(TriangularMesh* triangularMesh, GridImp* grid, char InnerType, char OuterType) = 0;
+    void removeOddBoundaryCellNodes(GridImp* grid);
+};
+
+
+
+class GRIDGENERATOR_EXPORT PointInObjectDiscretizationStrategy : public TriangularMeshDiscretizationStrategy
+{
+public:
+    PointInObjectDiscretizationStrategy() {}
+    virtual ~PointInObjectDiscretizationStrategy() {}
+
+    virtual void doDiscretize(TriangularMesh* triangularMesh, GridImp* grid, char InnerType, char OuterType);
+};
+
+class GRIDGENERATOR_EXPORT RayCastingDiscretizationStrategy : public TriangularMeshDiscretizationStrategy
+{
+public:
+    RayCastingDiscretizationStrategy() {}
+    virtual ~RayCastingDiscretizationStrategy() {}
+
+    virtual void doDiscretize(TriangularMesh* triangularMesh, GridImp* grid, char InnerType, char OuterType);
+};
+
+class GRIDGENERATOR_EXPORT PointUnderTriangleStrategy : public TriangularMeshDiscretizationStrategy
+{
+public:
+    PointUnderTriangleStrategy() {}
+    virtual ~PointUnderTriangleStrategy() {}
+    void doDiscretize(TriangularMesh* triangularMesh, GridImp* grid, char innerType, char outerType) override;
+
+private:
+    void meshReverse(Triangle& triangle, GridImp* grid, char innerType);
+
+    void findInsideNodes(GridImp* grid, char innerType);
+
+    void setInsideNode(GridImp* grid, const uint &index, bool &insideNodeFound, char innerType);
+
+    void setNegativeDirBorderTo(GridImp* grid, const uint &index, char innerType);
+
+};
+
+
+
+#endif
+
diff --git a/src/gpu/GridGenerator/geometries/TriangularMesh/triangleNeighborFinder/TriangleNeighborFinder.cpp b/src/gpu/GridGenerator/geometries/TriangularMesh/triangleNeighborFinder/TriangleNeighborFinder.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..08984d872ebf07cbe1d88658b48a7850077f188f
--- /dev/null
+++ b/src/gpu/GridGenerator/geometries/TriangularMesh/triangleNeighborFinder/TriangleNeighborFinder.cpp
@@ -0,0 +1,356 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file TriangleNeighborFinder.cpp
+//! \ingroup geometries
+//! \author Soeren Peters, Stephan Lenz
+//=======================================================================================
+#include "TriangleNeighborFinder.h"
+#include <omp.h>
+
+#include <GridGenerator/geometries/Triangle/Triangle.h>
+#include <GridGenerator/geometries/TriangularMesh/TriangularMesh.h>
+
+
+
+
+int compare2DArrayAccordingToXYZ(const void *pa, const void *pb) {
+
+    real *a = *((real **)pa);
+    real *b = *((real **)pb);
+
+    //compare X
+    if (a[IDS::x] < b[IDS::x]) return -1;
+    else if (a[IDS::x] > b[IDS::x]) return +1;
+    //compare Y
+    else if (a[IDS::y] < b[IDS::y]) return -1;
+    else if (a[IDS::y] > b[IDS::y]) return +1;
+    //compare Z
+    else if (a[IDS::z] < b[IDS::z]) return -1;
+    else if (a[IDS::z] > b[IDS::z]) return +1;
+    //compare Index
+    else if (a[IDS::vertexID] < b[IDS::vertexID]) return -1;
+    else if (a[IDS::vertexID] > b[IDS::vertexID]) return +1;
+
+    return 0;
+}
+
+int compare2DArrayAccordingToIndex(const void *pa, const void *pb) {
+
+    real *a = *((real **)pa);
+    real *b = *((real **)pb);
+
+    if (a[IDS::vertexID] < b[IDS::vertexID]) return -1;
+    else if (a[IDS::vertexID] > b[IDS::vertexID]) return +1;
+    return 0;
+}
+
+TriangleNeighborFinder::TriangleNeighborFinder(Triangle *triangles, int size) : triangles(triangles)
+{
+    numberOfRows = size * DIMENSION;
+
+    this->initalSortedInSpaceWithCoords(triangles, size);
+
+    qsort(sortedInSpace, numberOfRows, sizeof sortedInSpace[0], compare2DArrayAccordingToXYZ);
+
+    this->fillSortedInSpaceWithFirstVertexAndCoordinateIDs(numberOfRows);
+
+    //copy the array:
+    sortedToTriangles = new real*[numberOfRows];
+    for (int i = 0; i < numberOfRows; i++) {
+        sortedToTriangles[i] = new real[4];
+        sortedToTriangles[i][IDS::vertexID] = sortedInSpace[i][IDS::vertexID];
+        sortedToTriangles[i][IDS::firstVertexID] = sortedInSpace[i][IDS::firstVertexID];
+        sortedToTriangles[i][IDS::coordinateID] = sortedInSpace[i][IDS::coordinateID];
+        sortedToTriangles[i][IDS::uniqueCoordID] = (real)i;
+    }
+
+    qsort(sortedToTriangles, numberOfRows, sizeof sortedToTriangles[0], compare2DArrayAccordingToIndex);
+
+    indicesOfTriangleNeighbors.resize(size);
+
+    this->fillVectorWithIndicesOfTriangleNeighbors();
+}
+
+
+void TriangleNeighborFinder::initalSortedInSpaceWithCoords(Triangle *triangles, int size)
+{
+    sortedInSpace = new real*[numberOfRows];
+
+    int vertexCounter = 0;
+    const int numberOfColumns = 6;
+    for (int i = 0; i < size; i++){
+        sortedInSpace[vertexCounter] = new real[numberOfColumns];
+        sortedInSpace[vertexCounter][IDS::vertexID] = (real)vertexCounter;
+        sortedInSpace[vertexCounter][IDS::firstVertexID] = 0.0f;                  
+        sortedInSpace[vertexCounter][IDS::coordinateID]  = 0.0f;                   
+        sortedInSpace[vertexCounter][IDS::x] = triangles[i].v1.x;
+        sortedInSpace[vertexCounter][IDS::y] = triangles[i].v1.y;
+        sortedInSpace[vertexCounter][IDS::z] = triangles[i].v1.z;
+
+        vertexCounter++;
+        sortedInSpace[vertexCounter] = new real[numberOfColumns];
+        sortedInSpace[vertexCounter][IDS::vertexID]      = (real)vertexCounter;
+        sortedInSpace[vertexCounter][IDS::firstVertexID] = 0.0f;
+        sortedInSpace[vertexCounter][IDS::coordinateID]  = 0.0f;
+        sortedInSpace[vertexCounter][IDS::x] = triangles[i].v2.x;
+        sortedInSpace[vertexCounter][IDS::y] = triangles[i].v2.y;
+        sortedInSpace[vertexCounter][IDS::z] = triangles[i].v2.z;
+
+        vertexCounter++;
+        sortedInSpace[vertexCounter] = new real[numberOfColumns];
+        sortedInSpace[vertexCounter][IDS::vertexID]      = (real)vertexCounter;
+        sortedInSpace[vertexCounter][IDS::firstVertexID] = 0.0f;
+        sortedInSpace[vertexCounter][IDS::coordinateID]  = 0.0f;
+        sortedInSpace[vertexCounter][IDS::x] = triangles[i].v3.x;
+        sortedInSpace[vertexCounter][IDS::y] = triangles[i].v3.y;
+        sortedInSpace[vertexCounter][IDS::z] = triangles[i].v3.z;
+        vertexCounter++;
+    }
+}
+
+TriangleNeighborFinder::~TriangleNeighborFinder()
+{
+    for (int i = 0; i < numberOfRows; i++){
+        delete[] sortedToTriangles[i];
+        delete[] sortedInSpace[i];
+    }
+    delete[] sortedToTriangles;
+    delete[] sortedInSpace;
+}
+
+void TriangleNeighborFinder::fillSortedInSpaceWithFirstVertexAndCoordinateIDs(int numberOfRows)
+{
+    int firstVertexID = 0;
+    int compareID = 0;
+    int coordinateID = 0;
+    int duplicates = 0;
+    
+    while (firstVertexID < numberOfRows) {
+        Vertex a = Vertex(sortedInSpace[firstVertexID][IDS::x], sortedInSpace[firstVertexID][IDS::y], sortedInSpace[firstVertexID][IDS::z]);
+        Vertex b = Vertex(sortedInSpace[compareID][IDS::x], sortedInSpace[compareID][IDS::y], sortedInSpace[compareID][IDS::z]);
+        while (a.getEuclideanDistanceTo(b) < 1e-7)
+        {
+            sortedInSpace[compareID][IDS::firstVertexID] = sortedInSpace[firstVertexID][0];
+            sortedInSpace[compareID][IDS::coordinateID] = (real)coordinateID;
+            duplicates++;
+            
+            compareID++;
+            if (compareID == numberOfRows)
+                break;
+            b = Vertex(sortedInSpace[compareID][IDS::x], sortedInSpace[compareID][IDS::y], sortedInSpace[compareID][IDS::z]);
+        }
+        firstVertexID += duplicates;
+        duplicates = 0;
+        coordinateID++;
+    }
+}
+
+void TriangleNeighborFinder::fillVectorWithIndicesOfTriangleNeighbors()
+{
+    for (unsigned int triangleID = 0; triangleID < indicesOfTriangleNeighbors.size(); triangleID++){
+
+        Vertex coordinateIDsFromTriangle = getCoordinatesIDfromTriangle(triangleID);
+
+        for (unsigned int vertex = 0; vertex < DIMENSION; vertex++){
+            unsigned int vertexID = triangleID * DIMENSION + vertex;
+            unsigned int firstVertexID = (int)sortedToTriangles[vertexID][IDS::firstVertexID];
+            unsigned int uniqueCoordID = (int)sortedToTriangles[firstVertexID][IDS::uniqueCoordID];
+
+            while (firstVertexID == sortedInSpace[uniqueCoordID][IDS::firstVertexID]){
+                unsigned int jTriangle = findTriangleID(uniqueCoordID);
+
+                uniqueCoordID++;
+                if (uniqueCoordID >= indicesOfTriangleNeighbors.size()*DIMENSION)
+                    break;
+                if (jTriangle == triangleID)
+                    continue;
+
+                Vertex coordinateIDsFromTriangleNeighbor = getCoordinatesIDfromTriangle(jTriangle);
+
+                if (isTriangleNeighborOfParentTriangle(coordinateIDsFromTriangle, coordinateIDsFromTriangleNeighbor)
+                    &&  isNeighborNotAlreadyInside(triangleID, jTriangle))
+                    indicesOfTriangleNeighbors[triangleID].push_back(jTriangle);
+            }
+
+        }
+    }
+}
+
+unsigned int TriangleNeighborFinder::findTriangleID(unsigned int uniqueCoordID)
+{
+    return (int)sortedInSpace[uniqueCoordID][IDS::vertexID] / DIMENSION;
+}
+
+Vertex TriangleNeighborFinder::getCoordinatesIDfromTriangle(int triangleID)
+{
+    real coordinateID1 = sortedToTriangles[triangleID * DIMENSION + 0][IDS::coordinateID];
+    real coordinateID2 = sortedToTriangles[triangleID * DIMENSION + 1][IDS::coordinateID];
+    real coordinateID3 = sortedToTriangles[triangleID * DIMENSION + 2][IDS::coordinateID];
+    return Vertex(coordinateID1, coordinateID2, coordinateID3);
+}
+
+
+bool TriangleNeighborFinder::isTriangleNeighborOfParentTriangle(Vertex v1, Vertex v2)
+{
+    int countSameID = 0;
+    if (v1.x == v2.x)
+        countSameID++;
+    else if (v1.x == v2.y)
+        countSameID++;
+    else if (v1.x == v2.z)
+        countSameID++;
+
+    if (v1.y == v2.x)
+        countSameID++;
+    else if (v1.y == v2.y)
+        countSameID++;
+    else if (v1.y == v2.z)
+        countSameID++;
+
+    if (v1.z == v2.x)
+        countSameID++;
+    else if (v1.z == v2.y)
+        countSameID++;
+    else if (v1.z == v2.z)
+        countSameID++;
+
+    if (countSameID == 2 || countSameID == 3)
+        return true;
+
+    return false;
+}
+
+bool TriangleNeighborFinder::isNeighborNotAlreadyInside(unsigned int iTriangle, unsigned int jTriangle)
+{
+    for (unsigned int i = 0; i < indicesOfTriangleNeighbors[iTriangle].size(); i++){
+        if (indicesOfTriangleNeighbors[iTriangle][i] == jTriangle)
+            return false;
+    }
+    return true;
+}
+
+void TriangleNeighborFinder::fillWithNeighborIndices(IntegerPtr2D *neighborIndices, Triangle *triangles)
+{
+    for (unsigned int i = 0; i < indicesOfTriangleNeighbors.size(); i++){
+        int row = i * neighborIndices->DIM;
+        neighborIndices->ptr[row + 0] = neighborIndices->ptr[row + 1] = neighborIndices->ptr[row + 2] = -1;
+        for (unsigned int j = 0; j < indicesOfTriangleNeighbors[i].size(); j++){
+            int index = triangles[i].getCommonEdge(triangles[indicesOfTriangleNeighbors[i][j]]);
+            neighborIndices->ptr[row + index] = indicesOfTriangleNeighbors[i][j];
+        }
+    }
+}
+
+void TriangleNeighborFinder::fillWithNeighborAngles(TriangularMesh *geom) const
+{
+    int j, index, indexNeighbor;
+    //#pragma omp parallel for private(j, row, index, indexNeighbor) shared(neighborAngles->ptr)
+    for (int i = 0; i < (int)indicesOfTriangleNeighbors.size(); i++){
+        geom->triangles[i].alphaAngles[0] = geom->triangles[i].alphaAngles[1] = geom->triangles[i].alphaAngles[2] = 90.0f;
+        for (j = 0; j < (int)indicesOfTriangleNeighbors[i].size(); j++){
+            indexNeighbor = indicesOfTriangleNeighbors[i][j];
+            index = geom->triangles[i].getCommonEdge(geom->triangles[indexNeighbor]);
+            geom->triangles[i].alphaAngles[index] = geom->triangles[i].getHalfAngleBetweenToAdjacentTriangle(geom->triangles[indexNeighbor]);
+        }
+    }
+
+    //for (size_t i = 0; i < neighborAngles->size; i++)
+    //{
+    //    int row = i * 3;
+    //    printf("triangle : %d\n", i);
+    //    for (size_t j = 0; j < 3; j++)
+    //    {
+    //        printf(" %d ", neighborAngles->ptr[row + j]);
+    //    }
+    //    printf("\n");
+    //}
+}
+
+std::vector<int> TriangleNeighborFinder::getTriangleIDsWithCommonVertex(int vertexID) const
+{
+    std::vector<int> triangleIDs;
+
+    const int firstVertexId = sortedToTriangles[vertexID][IDS::firstVertexID];
+    int uniqueCoordID = sortedToTriangles[firstVertexId][IDS::uniqueCoordID]; 
+    const int coordinateID = sortedInSpace[uniqueCoordID][IDS::coordinateID];
+    while (coordinateID == sortedInSpace[uniqueCoordID][IDS::coordinateID])
+    {
+        int triangleID = sortedInSpace[uniqueCoordID][IDS::vertexID] / 3;
+        triangleIDs.push_back(triangleID);
+        uniqueCoordID++;
+        if (uniqueCoordID == numberOfRows)
+            break;
+    }
+
+    return triangleIDs;
+}
+
+std::vector< std::vector<Triangle> > TriangleNeighborFinder::getTrianglesPerVertex() const
+{
+    std::vector< std::vector<Triangle> > connected;
+    int uniqueCoordID = 0;
+    while (uniqueCoordID < numberOfRows)
+    {
+        std::vector<Triangle> triangles;
+
+        int nextCoordinateID = this->sortedInSpace[uniqueCoordID][IDS::coordinateID];
+        int currentCoordinateID = this->sortedInSpace[uniqueCoordID][IDS::coordinateID];
+        while (nextCoordinateID == currentCoordinateID)
+        {
+            const int vertexID = this->sortedInSpace[uniqueCoordID][IDS::vertexID];
+            const int triangleID = vertexID / 3;
+            triangles.push_back(this->triangles[triangleID]);
+
+            uniqueCoordID++;
+            if (uniqueCoordID >= numberOfRows)
+                break;
+            currentCoordinateID = nextCoordinateID;
+            nextCoordinateID = this->sortedInSpace[uniqueCoordID][IDS::coordinateID];
+        }
+        connected.push_back(triangles);
+    }
+    return connected;
+}
+
+
+void TriangleNeighborFinder::printSortedToTriangles() const
+{
+    printf("VertexID | FirstVertexID | CoordID | UniqueCoordID\n");
+    for (int row = 0; row < numberOfRows; row++) {
+        printf("%d \t %d \t %d \t %d\n", int(sortedToTriangles[row][IDS::vertexID]), int(sortedToTriangles[row][IDS::firstVertexID]), int(sortedToTriangles[row][IDS::coordinateID]), int(sortedToTriangles[row][IDS::uniqueCoordID]));
+    }
+}
+
+void TriangleNeighborFinder::printSortedInSpace() const
+{
+    printf("VertexID | X | Y | Z | FirstVertexID | CoordID | UniqueCoordID\n");
+    for (int row = 0; row < numberOfRows; row++) {
+        printf("%d \t %2.2f \t %2.2f \t %2.2f \t %d \t %d \t %d\n", int(sortedInSpace[row][IDS::vertexID]), sortedInSpace[row][IDS::x], sortedInSpace[row][IDS::y], sortedInSpace[row][IDS::z], int(sortedInSpace[row][IDS::firstVertexID]), int(sortedInSpace[row][IDS::coordinateID]), int(sortedInSpace[row][IDS::uniqueCoordID]));
+    }
+}
diff --git a/src/gpu/GridGenerator/geometries/TriangularMesh/triangleNeighborFinder/TriangleNeighborFinder.h b/src/gpu/GridGenerator/geometries/TriangularMesh/triangleNeighborFinder/TriangleNeighborFinder.h
new file mode 100644
index 0000000000000000000000000000000000000000..b0dda279c5f95a621b5875e78b5cdb7479b98a54
--- /dev/null
+++ b/src/gpu/GridGenerator/geometries/TriangularMesh/triangleNeighborFinder/TriangleNeighborFinder.h
@@ -0,0 +1,88 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file TriangleNeighborFinder.h
+//! \ingroup geometries
+//! \author Soeren Peters, Stephan Lenz
+//=======================================================================================
+#ifndef TriangleNeighborFinder_h
+#define TriangleNeighborFinder_h
+
+#include "GridGenerator/global.h"
+#include "GridGenerator_export.h"
+#include <vector>
+
+struct IDS {
+    enum IDs { vertexID = 0, firstVertexID = 1, coordinateID = 2, uniqueCoordID = 3, x = 3, y = 4, z = 5 };
+};
+
+struct Triangle;
+struct Vertex;
+class TriangularMesh;
+
+struct IntegerPtr2D {
+    int *ptr;
+    int size;
+    int DIM;
+};
+
+class TriangleNeighborFinder
+{
+public:
+    GRIDGENERATOR_EXPORT TriangleNeighborFinder(Triangle *triangles, int size);
+    GRIDGENERATOR_EXPORT ~TriangleNeighborFinder();
+    
+    std::vector<int> getTriangleIDsWithCommonVertex(int vertexID) const;
+    std::vector< std::vector<Triangle> > getTrianglesPerVertex() const;
+
+    void GRIDGENERATOR_EXPORT fillWithNeighborIndices(IntegerPtr2D *indices, Triangle *triangles);
+	void GRIDGENERATOR_EXPORT fillWithNeighborAngles(TriangularMesh *geom) const;
+
+    void printSortedToTriangles() const;
+    void printSortedInSpace() const;
+
+private:
+    void initalSortedInSpaceWithCoords(Triangle *triangles_ptr, int size);
+    void fillSortedInSpaceWithFirstVertexAndCoordinateIDs(int numberOfRows);
+    void fillVectorWithIndicesOfTriangleNeighbors();
+    unsigned int findTriangleID(unsigned int uniqueCoordID);
+    Vertex getCoordinatesIDfromTriangle(int triangleID);
+    bool isNeighborNotAlreadyInside(unsigned int iTriangle, unsigned int jTriangle);
+
+    bool isTriangleNeighborOfParentTriangle(Vertex, Vertex);
+
+    int numberOfRows;
+    Triangle *triangles;
+
+public:
+    std::vector<std::vector<uint> > indicesOfTriangleNeighbors;
+    real **sortedToTriangles;
+    real **sortedInSpace;
+};
+
+#endif
diff --git a/src/gpu/GridGenerator/geometries/TriangularMesh/triangleRefinement/TriangleRefinement.cpp b/src/gpu/GridGenerator/geometries/TriangularMesh/triangleRefinement/TriangleRefinement.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c1babac2324e80362c62c2b448cd1e309d7c5adf
--- /dev/null
+++ b/src/gpu/GridGenerator/geometries/TriangularMesh/triangleRefinement/TriangleRefinement.cpp
@@ -0,0 +1,249 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file TriangleRefinement.cpp
+//! \ingroup geometries
+//! \author Soeren Peters, Stephan Lenz
+//=======================================================================================
+#include "TriangleRefinement.h"
+
+#include <GridGenerator/geometries/Triangle/Triangle.h>
+
+TriangleRefinement::TriangleRefinement(std::vector<Triangle> *triangles)
+{
+    this->triangles = triangles;
+}
+
+TriangleRefinement::~TriangleRefinement()
+{
+
+}
+
+void TriangleRefinement::redoubleTriangles()
+{
+    int counter = 0;
+    for (size_t i = 0; i < triangles->size(); i++)
+    {
+        refine((int)i);
+        counter++;
+        if (counter % 50 == 0)
+            printf("triangle refine: %d\n", (counter / 2));
+    }
+}
+
+void TriangleRefinement::refineUntilMinDistance(double d_min)
+{
+    double d = 10e9;
+	int counter = 0;
+
+	while (d > d_min) {
+        int triangleToRefine = findIndexFromTriangleWithLongestEdge(&d);
+        refine(triangleToRefine);
+
+        counter++;
+		if (counter % 50 == 0)
+            printf("triangle refine: %d, actual dMAX = %2.6f, d_min = %2.6f\n", counter, d, d_min);
+
+    }
+}
+
+void TriangleRefinement::refineUntilcountTriangle(int countTri)
+{
+    double d = 10e9;
+    int counter = 0;
+
+    while (counter < countTri) {
+        int triangleToRefine = findIndexFromTriangleWithLongestEdge(&d);
+        refine(triangleToRefine);
+
+        counter++;
+        if (counter % 100 == 0)
+            printf("triangle refine: %d, countTri = %d\n", counter, countTri);
+    }
+}
+
+int TriangleRefinement::findIndexFromTriangleWithLongestEdge(double *d)
+{
+    *d = 0;
+    double dTemp;
+    int triangleToRefine = 0;
+    for (size_t i = 0; i < triangles->size(); i++)
+    {
+        dTemp = getLongestEdgeDistance((*triangles)[i]);
+        if (*d < dTemp) {
+            *d = dTemp;
+            triangleToRefine = (int)i;
+        }
+    }
+    return triangleToRefine;
+}
+
+
+void TriangleRefinement::refine(int iTriangle)
+{
+    sortNeighborIndices();
+
+    Triangle t = (*triangles)[iTriangle];
+    int edge = getEdgeWithLongestDistance(t);
+
+    std::vector<Vertex> v = getVertexArray(iTriangle);
+    Vertex newVertex = getNewhalfVertexFromTrianglesEdge(v, edge);
+
+    createTwoTriangles(v, edge, newVertex);
+
+    int indexNeighbor = this->indices.ptr[iTriangle * indices.DIM + edge];
+    v = getVertexArray(indexNeighbor);
+    int commonEdgeNeigbor = findCommonEdgeFromTriangles(indexNeighbor, iTriangle);
+    createTwoTriangles(v, commonEdgeNeigbor, newVertex);
+
+    eraseOldTrianglesFromVector(iTriangle, indexNeighbor);
+}
+
+void TriangleRefinement::sortNeighborIndices()
+{
+    indices.DIM = 3;
+    indices.size = (int)triangles->size();
+    indices.ptr = new int[indices.DIM * indices.size];
+    TriangleNeighborFinder neighbors((*triangles).data(), indices.size);
+    neighbors.fillWithNeighborIndices(&indices, (*triangles).data());
+}
+
+std::vector<Vertex> TriangleRefinement::getVertexArray(int iTriangle)
+{
+    Triangle t = (*triangles)[iTriangle];
+
+    std::vector<Vertex> v;
+    v.resize(4);
+    v[0] = t.v1;
+    v[1] = t.v2;
+    v[2] = t.v3;
+    v[3] = t.normal;
+    return v;
+}
+
+Vertex TriangleRefinement::getNewhalfVertexFromTrianglesEdge(std::vector<Vertex>  v, int edge)
+{
+    return getHalfVertex(v[edge], v[edge == 2 ? 0 : edge + 1]);
+}
+
+void TriangleRefinement::createTwoTriangles(std::vector<Vertex> v, int edge, Vertex newEdge)
+{
+    Vertex againstNewEdge = v[edge - 1 < 0 ? 2 : edge - 1];
+    Vertex firstOldVertex = v[edge];
+    Vertex secondOldVertex = v[edge + 1 > 2 ? 0 : edge + 1];
+
+    Triangle firstNewTriangle(newEdge, againstNewEdge, firstOldVertex, v[3]);
+    Triangle secondNewTriangle(newEdge, secondOldVertex, againstNewEdge, v[3]);
+
+    (*triangles).push_back(firstNewTriangle);
+    (*triangles).push_back(secondNewTriangle);
+}
+
+int TriangleRefinement::findCommonEdgeFromTriangles(int indexNeighbor, int iTriangle)
+{
+    int commonEdgeNeigbor = -1;
+    for (int i = 0; i < indices.DIM; i++) {
+        if (indices.ptr[indexNeighbor * indices.DIM + i] == iTriangle)
+            commonEdgeNeigbor = i;
+    }
+    return commonEdgeNeigbor;
+}
+
+void TriangleRefinement::eraseOldTrianglesFromVector(int iTriangle, int indexNeighbor)
+{
+    (*triangles).erase((*triangles).begin() + iTriangle);
+    if (iTriangle < indexNeighbor)
+        indexNeighbor--;
+    (*triangles).erase((*triangles).begin() + indexNeighbor);
+}
+
+void TriangleRefinement::refine(Triangle t, Triangle &firstNewTriangle, Triangle &secondNewTriangle) 
+{
+    int edge = getEdgeWithLongestDistance(t);
+
+    std::vector<Vertex> v;
+    v.resize(4);
+    v[0] = t.v1;
+    v[1] = t.v2;
+    v[2] = t.v3;
+    v[3] = t.normal;
+    Vertex newEdge = getHalfVertex(v[edge], v[edge == 2 ? 0 : edge + 1]);
+
+    Vertex againstNewEdge = v[edge - 1 < 0 ? 2 : edge - 1];
+    Vertex firstOldVertex = v[edge];
+    Vertex secondOldVertex = v[edge + 1 > 2 ? 0 : edge + 1];
+
+    firstNewTriangle = Triangle(newEdge, againstNewEdge, firstOldVertex, v[3]);
+    secondNewTriangle = Triangle(newEdge, secondOldVertex, againstNewEdge, v[3]);
+}
+
+
+int TriangleRefinement::getEdgeWithLongestDistance(Triangle &t)
+{
+    real d1 = t.v2.getEuclideanDistanceTo(t.v1);
+    real d2 = t.v3.getEuclideanDistanceTo(t.v2);
+    real d3 = t.v1.getEuclideanDistanceTo(t.v3);
+
+    real max = d1;
+    int edge = 0;
+
+    if (d2 > d1) {
+        edge = 1;
+        max = d2;
+    }
+
+    if (d3 > max){
+        edge = 2;
+        max = d3;
+    }
+
+    return edge;
+}
+
+real TriangleRefinement::getLongestEdgeDistance(Triangle &t) {
+
+    int edge = getEdgeWithLongestDistance(t);
+    Vertex v[3];
+    v[0] = t.v1;
+    v[1] = t.v2;
+    v[2] = t.v3;
+
+    if (edge == 2)
+        return v[0].getEuclideanDistanceTo(v[2]);
+
+    return v[edge + 1].getEuclideanDistanceTo(v[edge]);
+}
+
+Vertex TriangleRefinement::getHalfVertex(const Vertex &v, const Vertex &w)
+{
+    Vertex r;
+    r.x = (v.x + w.x) / 2.0f;
+    r.y = (v.y + w.y) / 2.0f;
+    r.z = (v.z + w.z) / 2.0f;
+    return r;
+}
diff --git a/src/gpu/GridGenerator/geometries/TriangularMesh/triangleRefinement/TriangleRefinement.h b/src/gpu/GridGenerator/geometries/TriangularMesh/triangleRefinement/TriangleRefinement.h
new file mode 100644
index 0000000000000000000000000000000000000000..a9c5262fbf0ee701e26885fb54d96cd079038a87
--- /dev/null
+++ b/src/gpu/GridGenerator/geometries/TriangularMesh/triangleRefinement/TriangleRefinement.h
@@ -0,0 +1,79 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file TriangleRefinement.h
+//! \ingroup geometries
+//! \author Soeren Peters, Stephan Lenz
+//=======================================================================================
+#ifndef TriangleRefinement_h
+#define TriangleRefinement_h
+
+#include <vector>
+
+#include "global.h"
+
+#include "geometries/TriangularMesh/triangleNeighborFinder/TriangleNeighborFinder.h"
+
+struct Triangle;
+struct Vertex;
+struct IntegerPtr2D;
+
+class  TriangleRefinement
+{
+public:
+    GRIDGENERATOR_EXPORT TriangleRefinement(std::vector<Triangle> *triangles);
+    GRIDGENERATOR_EXPORT ~TriangleRefinement();
+
+    void GRIDGENERATOR_EXPORT refine(int iTriangle);
+    static void GRIDGENERATOR_EXPORT refine(Triangle t, Triangle &firstNewTriangle, Triangle &secondNewTriangle);
+    
+    void GRIDGENERATOR_EXPORT refineUntilMinDistance(double d_min);
+    void GRIDGENERATOR_EXPORT refineUntilcountTriangle(int countTri);
+    void GRIDGENERATOR_EXPORT redoubleTriangles();
+
+    static GRIDGENERATOR_EXPORT Vertex getHalfVertex(const Vertex &v, const Vertex &w);
+
+private:
+    std::vector<Triangle> *triangles;
+    IntegerPtr2D indices;
+
+    int findIndexFromTriangleWithLongestEdge(double *d);
+    std::vector<Vertex> getVertexArray(int iTriangle);
+    Vertex getNewhalfVertexFromTrianglesEdge(std::vector<Vertex> v, int edge);
+    void sortNeighborIndices();
+    void createTwoTriangles(std::vector<Vertex> v, int edge, Vertex newEdge);
+    void eraseOldTrianglesFromVector(int iTriangle, int indexNeighbor);
+    int findCommonEdgeFromTriangles(int indexNeighbor, int iTriangle);
+
+public:
+    static int GRIDGENERATOR_EXPORT getEdgeWithLongestDistance(Triangle &t);
+    static real GRIDGENERATOR_EXPORT getLongestEdgeDistance(Triangle &t);
+};
+
+
+#endif
diff --git a/src/gpu/GridGenerator/geometries/Vertex/Vertex.cu b/src/gpu/GridGenerator/geometries/Vertex/Vertex.cpp
similarity index 96%
rename from src/gpu/GridGenerator/geometries/Vertex/Vertex.cu
rename to src/gpu/GridGenerator/geometries/Vertex/Vertex.cpp
index 23d49efa9d350a3a56ff754f33c0a7eb2351a974..5fe27a28b8833a3f7a5bdcc73b9863e82b3ea973 100644
--- a/src/gpu/GridGenerator/geometries/Vertex/Vertex.cu
+++ b/src/gpu/GridGenerator/geometries/Vertex/Vertex.cpp
@@ -26,7 +26,7 @@
 //  You should have received a copy of the GNU General Public License along
 //  with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
 //
-//! \file Vertex.cu
+//! \file Vertex.cpp
 //! \ingroup geometries
 //! \author Soeren Peters, Stephan Lenz
 //=======================================================================================
@@ -37,14 +37,7 @@
 Vertex::Vertex(real x, real y, real z) : x(x), y(y), z(z){}
 Vertex::Vertex() { x = 0.0f; y = 0.0f; z = 0.0f; }
 
-Vertex::Vertex(const Vertex& v)
-{
-	this->x = v.x;
-	this->y = v.y;
-	this->z = v.z;
-}
-
- real Vertex::getEuclideanDistanceTo(const Vertex &w) const
+real Vertex::getEuclideanDistanceTo(const Vertex &w) const
 {
     return vf::Math::sqrtReal((x - w.x)*(x - w.x) + (y - w.y)*(y - w.y) + (z - w.z)*(z - w.z));
 }
@@ -120,7 +113,7 @@ real Vertex::getInnerAngle(const Vertex &w) const
 
     real mag = this->getMagnitude() * w.getMagnitude();
     real skal = *this * w;
-    if (mag - fabs(skal) < 0.0001)
+    if (mag - std::abs(skal) < 0.0001)
         return 0.0f;
     return  vf::Math::acosReal(skal / mag) * 180.0f / vf::Math::acosReal(-1.0f); // acos(-1.0f) = PI 
 }
diff --git a/src/gpu/GridGenerator/geometries/Vertex/Vertex.h b/src/gpu/GridGenerator/geometries/Vertex/Vertex.h
index 824f89c77a630ef8e12dd5332bf462afa96ec342..7b27d853f652459143699204c59a5843de6eaf39 100644
--- a/src/gpu/GridGenerator/geometries/Vertex/Vertex.h
+++ b/src/gpu/GridGenerator/geometries/Vertex/Vertex.h
@@ -34,7 +34,6 @@
 #define VERTEX_H
 
 #include <stdio.h>
-#include <cuda_runtime.h>
 #include <memory>
 #include <ostream>
 
@@ -47,7 +46,6 @@ public:
 
 	Vertex(real x, real y, real z);
 	Vertex();
-	Vertex(const Vertex& v);
 	~Vertex() {}
 
 	real getEuclideanDistanceTo(const Vertex &w) const;
diff --git a/src/gpu/GridGenerator/geometries/VerticalCylinder/VerticalCylinder.cpp b/src/gpu/GridGenerator/geometries/VerticalCylinder/VerticalCylinder.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..89bcd50349fe1a7591c5a873b5924a0c8ce8c2f3
--- /dev/null
+++ b/src/gpu/GridGenerator/geometries/VerticalCylinder/VerticalCylinder.cpp
@@ -0,0 +1,122 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __         
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |        
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |        
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |        
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____    
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|   
+//      \    \  |    |   ________________________________________________________________    
+//       \    \ |    |  |  ______________________________________________________________|   
+//        \    \|    |  |  |         __          __     __     __     ______      _______    
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)   
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______    
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/   
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//  
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file VerticalCylinder.cpp
+//! \ingroup geometries
+//! \author Soeren Peters, Stephan Lenz
+//=======================================================================================
+#include "VerticalCylinder.h"
+
+VerticalCylinder::VerticalCylinder(const double& centerX, const double& centerY, const double& centerZ, const double& radius, const double& height)
+    : centerX(centerX), centerY(centerY), centerZ(centerZ), radius(radius), height(height)
+{
+
+}
+
+VerticalCylinder::~VerticalCylinder()
+{
+}
+
+SPtr<VerticalCylinder> VerticalCylinder::makeShared(double centerX, double centerY, double centerZ, double radius, double height)
+{
+    return SPtr<VerticalCylinder>(new VerticalCylinder(centerX, centerY, centerZ, radius, height));
+}
+
+Object* VerticalCylinder::clone() const
+{
+    return new VerticalCylinder(centerX, centerY, centerZ, radius, height);
+}
+
+double VerticalCylinder::getX1Centroid()
+{
+    return centerX;
+}
+
+double VerticalCylinder::getX1Minimum()
+{
+    return centerX - radius;
+}
+
+double VerticalCylinder::getX1Maximum()
+{
+    return centerX + radius;
+}
+
+double VerticalCylinder::getX2Centroid()
+{
+    return centerY;
+}
+
+double VerticalCylinder::getX2Minimum()
+{
+    return centerY - radius;
+}
+
+double VerticalCylinder::getX2Maximum()
+{
+    return centerY + radius;
+}
+
+double VerticalCylinder::getX3Centroid()
+{
+    return centerZ;
+}
+
+double VerticalCylinder::getX3Minimum()
+{
+    return centerZ - 0.5 * height;
+}
+
+double VerticalCylinder::getX3Maximum()
+{
+    return centerZ + 0.5 * height;
+}
+
+bool VerticalCylinder::isPointInObject(const double& x1, const double& x2, const double& x3, const double& minOffset, const double& maxOffset)
+{
+    double offset = maxOffset;
+    if (x1 < centerX || x2 < centerY || x3 < centerZ)
+        offset = minOffset;
+        
+
+    const double deltaX1 = x1 - centerX;
+    const double deltaX2 = x2 - centerY;
+    const double deltaX3 = x3 - centerZ;
+
+    if( deltaX3 > 0.5 * height || deltaX3 < - 0.5 * height )
+        return false;
+
+    return (deltaX1*deltaX1 + deltaX2*deltaX2) < ((this->radius - offset) * (this->radius - offset));
+}
+
+
+void VerticalCylinder::scale(double delta)
+{
+    this->radius += delta;
+    this->height += delta;
+}
diff --git a/src/gpu/GridGenerator/geometries/VerticalCylinder/VerticalCylinder.h b/src/gpu/GridGenerator/geometries/VerticalCylinder/VerticalCylinder.h
new file mode 100644
index 0000000000000000000000000000000000000000..24d9383bf5628e46b1d634874f79ceb73eaa6cae
--- /dev/null
+++ b/src/gpu/GridGenerator/geometries/VerticalCylinder/VerticalCylinder.h
@@ -0,0 +1,76 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file VerticalCylinder.h
+//! \ingroup geometries
+//! \author Soeren Peters, Stephan Lenz
+//=======================================================================================
+#ifndef VERTICAL_CYLINDER_H
+#define VERTICAL_CYLINDER_H
+
+#include "global.h"
+#include "GridGenerator_export.h"
+#include "geometries/Object.h"
+
+class GRIDGENERATOR_EXPORT VerticalCylinder : public Object
+{
+public:
+    VerticalCylinder(const double& centerX, const double& centerY, const double& centerZ, const double& radius, const double& height);
+    virtual ~VerticalCylinder();
+
+    static SPtr<VerticalCylinder> makeShared(double centerX, double centerY, double centerZ, double radius, double height);
+
+    Object* clone() const override;
+
+    double getX1Centroid() override;
+    double getX1Minimum() override;
+    double getX1Maximum() override;
+    double getX2Centroid() override;
+    double getX2Minimum() override;
+    double getX2Maximum() override;
+    double getX3Centroid() override;
+    double getX3Minimum() override;
+    double getX3Maximum() override;
+
+    bool isPointInObject(const double& x1, const double& x2, const double& x3, const double& minOffset, const double& maxOffset) override;
+
+
+    void scale(double delta) override;
+   
+protected:
+    double centerX;
+    double centerY;
+    double centerZ;
+
+    double radius;
+    double height;
+};
+
+
+
+#endif   
diff --git a/src/gpu/GridGenerator/grid/BoundaryConditions/BoundaryCondition.cpp b/src/gpu/GridGenerator/grid/BoundaryConditions/BoundaryCondition.cpp
index 4081aeffd9165e838959c78e39c9b51d6082c4a7..8930bdf3b165b4e0dbb497773fd0b6cf6ec6f8f7 100644
--- a/src/gpu/GridGenerator/grid/BoundaryConditions/BoundaryCondition.cpp
+++ b/src/gpu/GridGenerator/grid/BoundaryConditions/BoundaryCondition.cpp
@@ -42,6 +42,19 @@ bool gg::BoundaryCondition::isSide( SideType side ) const
     return this->side->whoAmI() == side;
 }
 
+void VelocityBoundaryCondition::setVelocityProfile(
+    SPtr<Grid> grid, std::function<void(real, real, real, real &, real &, real &)> velocityProfile)
+{
+    for (uint index = 0; index < this->indices.size(); index++) {
+
+        real x, y, z;
+
+        grid->transIndexToCoords(this->indices[index], x, y, z);
+
+        velocityProfile(x, y, z, this->vxList[index], this->vyList[index], this->vzList[index]);
+    }
+}
+
 void GeometryBoundaryCondition::setTangentialVelocityForPatch(SPtr<Grid> grid, uint patch, 
                                                               real p1x, real p1y, real p1z, 
                                                               real p2x, real p2y, real p2z, 
diff --git a/src/gpu/GridGenerator/grid/BoundaryConditions/BoundaryCondition.h b/src/gpu/GridGenerator/grid/BoundaryConditions/BoundaryCondition.h
index 28570b46e2bdf92f88cb7696cc7748c767957afb..9ae5f09e208e92213ca90ff75f095eddd5dbeaf1 100644
--- a/src/gpu/GridGenerator/grid/BoundaryConditions/BoundaryCondition.h
+++ b/src/gpu/GridGenerator/grid/BoundaryConditions/BoundaryCondition.h
@@ -28,12 +28,13 @@
 //
 //! \file BoundaryCondition.h
 //! \ingroup grid
-//! \author Soeren Peters, Stephan Lenz
+//! \author Soeren Peters, Stephan Lenz, Martin Schoenherr
 //=======================================================================================
 #ifndef BoundaryCondition_H
 #define BoundaryCondition_H
 
 #include <vector>
+#include <functional>
 
 #include "global.h"
 
@@ -86,7 +87,7 @@ protected:
 public:
     char getType() const override
     {
-        return BC_PRESSURE;
+        return vf::gpu::BC_PRESSURE;
     }
 
     real getRho()
@@ -113,7 +114,7 @@ protected:
 public:
     virtual char getType() const override
     {
-        return BC_SLIP;
+        return vf::gpu::BC_SLIP;
     }
 
     void fillSlipNormalLists()
@@ -153,7 +154,7 @@ protected:
 public:
     virtual char getType() const override
     {
-        return BC_VELOCITY;
+        return vf::gpu::BC_VELOCITY;
     }
 
     void fillVelocityLists()
@@ -173,6 +174,8 @@ public:
     real getVx(uint index) { return this->vxList[index]; }
     real getVy(uint index) { return this->vyList[index]; }
     real getVz(uint index) { return this->vzList[index]; }
+
+    void setVelocityProfile( SPtr<Grid> grid, std::function<void(real,real,real,real&,real&,real&)> velocityProfile );
 };
 
 //////////////////////////////////////////////////////////////////////////
@@ -192,7 +195,7 @@ private:
 public:
     char getType() const override
     {
-        return BC_SOLID;
+        return vf::gpu::BC_SOLID;
     }
 
     void setVelocityForPatch( uint patch, real vx, real vy, real vz ){
diff --git a/src/gpu/GridGenerator/grid/BoundaryConditions/Side.cpp b/src/gpu/GridGenerator/grid/BoundaryConditions/Side.cpp
index 99097a393735a31abad0dd717a2dcfc2b1d35326..02d61a83456090a3b96b207de5761b70d9b30fca 100644
--- a/src/gpu/GridGenerator/grid/BoundaryConditions/Side.cpp
+++ b/src/gpu/GridGenerator/grid/BoundaryConditions/Side.cpp
@@ -49,11 +49,11 @@ void Side::addIndices(SPtr<Grid> grid, SPtr<BoundaryCondition> boundaryCondition
         {
             const uint index = getIndex(grid, coord, constant, v1, v2);
 
-            if ((index != INVALID_INDEX) && (  grid->getFieldEntry(index) == FLUID
-                                            || grid->getFieldEntry(index) == FLUID_CFC
-                                            || grid->getFieldEntry(index) == FLUID_CFF
-                                            || grid->getFieldEntry(index) == FLUID_FCC
-                                            || grid->getFieldEntry(index) == FLUID_FCF ) )
+            if ((index != INVALID_INDEX) && (  grid->getFieldEntry(index) == vf::gpu::FLUID
+                                            || grid->getFieldEntry(index) == vf::gpu::FLUID_CFC
+                                            || grid->getFieldEntry(index) == vf::gpu::FLUID_CFF
+                                            || grid->getFieldEntry(index) == vf::gpu::FLUID_FCC
+                                            || grid->getFieldEntry(index) == vf::gpu::FLUID_FCF ) )
             {
                 grid->setFieldEntry(index, boundaryCondition->getType());
                 boundaryCondition->indices.push_back(index);
@@ -107,9 +107,9 @@ void Side::setQs(SPtr<Grid> grid, SPtr<BoundaryCondition> boundaryCondition, uin
 
         uint neighborIndex = grid->transCoordToIndex( x, y, z );
 
-        if( grid->getFieldEntry(neighborIndex) == STOPPER_OUT_OF_GRID_BOUNDARY ||
-            grid->getFieldEntry(neighborIndex) == STOPPER_OUT_OF_GRID ||
-            grid->getFieldEntry(neighborIndex) == STOPPER_SOLID )
+        if( grid->getFieldEntry(neighborIndex) == vf::gpu::STOPPER_OUT_OF_GRID_BOUNDARY ||
+            grid->getFieldEntry(neighborIndex) == vf::gpu::STOPPER_OUT_OF_GRID ||
+            grid->getFieldEntry(neighborIndex) == vf::gpu::STOPPER_SOLID )
             qNode[dir] = 0.5;
         else
             qNode[dir] = -1.0;
diff --git a/src/gpu/GridGenerator/grid/Field.cu b/src/gpu/GridGenerator/grid/Field.cpp
similarity index 94%
rename from src/gpu/GridGenerator/grid/Field.cu
rename to src/gpu/GridGenerator/grid/Field.cpp
index 6067cb66e7e56ff7fa5a4aae0ec197298d9172ca..d8ac2a80ea6fc5da879c5378aac2eab70016ff72 100644
--- a/src/gpu/GridGenerator/grid/Field.cu
+++ b/src/gpu/GridGenerator/grid/Field.cpp
@@ -26,38 +26,29 @@
 //  You should have received a copy of the GNU General Public License along
 //  with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
 //
-//! \file Field.cu
+//! \file Field.cpp
 //! \ingroup grid
-//! \author Soeren Peters, Stephan Lenz
+//! \author Soeren Peters, Stephan Lenz, Martin Schoenherr
 //=======================================================================================
 #include "Field.h"
 
 #include "grid/NodeValues.h"
-#include "grid/GridStrategy/GridStrategy.h"
 
-Field::Field(SPtr<GridStrategy> gridStrategy, uint size) : gridStrategy(gridStrategy), size(size)
-{
-    
-}
-
-Field::Field()
-{
-    
-}
+using namespace vf::gpu;
 
-Field::~Field()
+Field::Field(uint size) : size(size)
 {
     
 }
 
 void Field::allocateMemory()
 {
-    gridStrategy->allocateFieldMemory(this);
+    this->field = new char[this->size];
 }
 
 void Field::freeMemory()
 {
-    gridStrategy->freeFieldMemory(this);
+    delete[] this->field;
 }
 
 // --------------------------------------------------------- //
@@ -132,6 +123,11 @@ bool Field::isStopper(uint index) const
     return isStopperOutOfGrid(index) || isStopperCoarseUnderFine(index) || isStopperSolid(index) || is(index, STOPPER_OUT_OF_GRID_BOUNDARY);
 }
 
+bool Field::isQ(uint index) const
+{
+    return field[index] == Q_DEPRECATED;
+}
+
 bool Field::isBoundaryConditionNode(uint index) const
 {
     return  field[index] == BC_SOLID || field[index] == BC_OUTFLOW || field[index] == BC_VELOCITY || field[index] == BC_PRESSURE || field[index] == BC_SLIP;
diff --git a/src/gpu/GridGenerator/grid/Field.h b/src/gpu/GridGenerator/grid/Field.h
index 8b66c56d8fc50f4b7caa99f43a1e4ab73451305b..002c8c108bd405f4077cd2779f5e59232135ace9 100644
--- a/src/gpu/GridGenerator/grid/Field.h
+++ b/src/gpu/GridGenerator/grid/Field.h
@@ -28,7 +28,7 @@
 //
 //! \file Field.h
 //! \ingroup grid
-//! \author Soeren Peters, Stephan Lenz
+//! \author Soeren Peters, Stephan Lenz, Martin Schoenherr
 //=======================================================================================
 #ifndef FIELD_H
 #define FIELD_H
@@ -36,14 +36,12 @@
 #include "global.h"
 
 struct Vertex;
-class GridStrategy;
 
 class GRIDGENERATOR_EXPORT Field : public enableSharedFromThis<Field>
 {
 public:
-    Field(SPtr<GridStrategy> gridStrategy, uint size);
-    Field();
-    ~Field();
+    Field(uint size);
+    Field() = default;
     void allocateMemory();
     void freeMemory();
 
@@ -55,6 +53,7 @@ public:
     bool isFineToCoarseNode(uint index) const;
 	bool isFluid(uint index) const;
 	bool isInvalidSolid(uint index) const;
+    bool isQ(uint index) const;
     bool isBoundaryConditionNode(uint index) const;
     bool isInvalidCoarseUnderFine(uint index) const;
     bool isStopperOutOfGrid(uint index) const;
@@ -73,13 +72,8 @@ public:
     void setFieldEntryToInvalidOutOfGrid(uint index);
 
 private:
-    SPtr<GridStrategy> gridStrategy;
-
     char *field;
     uint size;
-
-    friend class GridGpuStrategy;
-    friend class GridCpuStrategy;
 };
 
 #endif
diff --git a/src/gpu/GridGenerator/grid/Grid.h b/src/gpu/GridGenerator/grid/Grid.h
index 1582c0bb6c1243d8f162c4240d498ca0e46e6a48..3407b23c1efbb4143d06ded7880c26d7c0eb6599 100644
--- a/src/gpu/GridGenerator/grid/Grid.h
+++ b/src/gpu/GridGenerator/grid/Grid.h
@@ -28,7 +28,7 @@
 //
 //! \file Grid.h
 //! \ingroup grid
-//! \author Soeren Peters, Stephan Lenz
+//! \author Soeren Peters, Stephan Lenz, Martin Schönherr
 //=======================================================================================
 #ifndef GRID_H
 #define GRID_H
@@ -41,9 +41,9 @@
 
 #include "grid/Cell.h"
 
+class TriangularMesh;
 struct Vertex;
 struct Triangle;
-class GridStrategy;
 class GridInterface;
 class Object;
 class BoundingBox;
@@ -51,7 +51,7 @@ class BoundingBox;
 class GRIDGENERATOR_EXPORT Grid
 {
 public:
-    virtual ~Grid() {}
+    virtual ~Grid() = default;
 
     virtual const Object* getObject() const = 0;
 
@@ -67,32 +67,66 @@ public:
     virtual real getEndY() const = 0;
     virtual real getEndZ() const = 0;
 
+    virtual Vertex getMinimumOnNode(Vertex exact) const = 0;
+    virtual Vertex getMaximumOnNode(Vertex exact) const = 0;
+
     virtual uint getNumberOfNodesX() const = 0;
     virtual uint getNumberOfNodesY() const = 0;
     virtual uint getNumberOfNodesZ() const = 0;
 
-    virtual int getSparseIndex(uint matrixIndex) const = 0;
+    virtual uint getNumberOfNodesCF() const = 0;
+    virtual uint getNumberOfNodesFC() const = 0;
+
+    virtual int getSparseIndex(uint matrixIndex) const      = 0;
     virtual char getFieldEntry(uint matrixIndex) const = 0;
     virtual void setFieldEntry(uint matrixIndex, char type) = 0;
 
+    virtual void getGridInterfaceIndices(uint* iCellCfc, uint* iCellCff, uint* iCellFcc, uint* iCellFcf) const = 0;
+
     virtual int *getNeighborsX() const = 0;
     virtual int *getNeighborsY() const = 0;
     virtual int *getNeighborsZ() const = 0;
     virtual int *getNeighborsNegative() const = 0;
 
-    virtual real* getDistribution() const = 0;
+    virtual uint *getCF_coarse() const = 0;
+    virtual uint *getCF_fine() const   = 0;
+    virtual uint *getCF_offset() const = 0;
+
+    virtual uint *getFC_coarse() const = 0;
+    virtual uint *getFC_fine() const   = 0;
+    virtual uint *getFC_offset() const = 0;
+
+    virtual real *getDistribution() const = 0;
     virtual int* getDirection() const = 0;
     virtual int getStartDirection() const = 0;
     virtual int getEndDirection() const = 0;
 
     virtual void getNodeValues(real *xCoords, real *yCoords, real *zCoords, uint *neighborX, uint *neighborY, uint *neighborZ, uint *neighborNegative, uint *geo) const = 0;
 
-    virtual SPtr<GridStrategy> getGridStrategy() const = 0;
     virtual void transIndexToCoords(uint index, real &x, real &y, real &z) const = 0;
     virtual uint transCoordToIndex(const real &x, const real &y, const real &z) const = 0;
 
     virtual void inital(const SPtr<Grid> fineGrid, uint numberOfLayers) = 0;
     
+    virtual void setOddStart(bool xOddStart, bool yOddStart, bool zOddStart) = 0;
+
+    virtual void findGridInterface(SPtr<Grid> grid, LbmOrGks lbmOrGks) = 0;
+
+    virtual void repairGridInterfaceOnMultiGPU(SPtr<Grid> fineGrid) = 0;
+
+    virtual void limitToSubDomain(SPtr<BoundingBox> subDomainBox, LbmOrGks lbmOrGks) = 0;
+
+    virtual void enableFindSolidBoundaryNodes() = 0;
+    virtual void enableComputeQs()              = 0;
+
+    virtual void mesh(TriangularMesh &geometry) = 0;
+    virtual void mesh(Object *object)           = 0;
+
+    virtual void closeNeedleCells()         = 0;
+    virtual void closeNeedleCellsThinWall() = 0;
+
+    virtual void findQs(Object *object) = 0;
+
     virtual void setPeriodicity(bool periodicityX, bool periodicityY, bool periodicityZ) = 0;
     virtual void setPeriodicityX(bool periodicity) = 0;
     virtual void setPeriodicityY(bool periodicity) = 0;
@@ -102,6 +136,8 @@ public:
     virtual bool getPeriodicityY() = 0;
     virtual bool getPeriodicityZ() = 0;
 
+    virtual void setEnableFixRefinementIntoTheWall(bool enableFixRefinementIntoTheWall) = 0;
+
     virtual void freeMemory() = 0;
 
     virtual bool nodeInCellIs(Cell& cell, char type) const = 0;
@@ -110,6 +146,27 @@ public:
 
     virtual real getFirstFluidNode(real coords[3], int direction, real startCoord) const = 0;
     virtual real getLastFluidNode(real coords[3], int direction, real startCoord) const = 0;
+
+    virtual uint getNumberOfSolidBoundaryNodes() const                          = 0;
+    virtual void setNumberOfSolidBoundaryNodes(uint numberOfSolidBoundaryNodes) = 0;
+
+    virtual real getQValue(const uint index, const uint dir) const = 0;
+    virtual uint getQPatch(const uint index) const                 = 0;
+
+    virtual void setInnerRegionFromFinerGrid(bool innerRegionFromFinerGrid) = 0;
+
+    virtual void setNumberOfLayers(uint numberOfLayers) = 0;
+
+    virtual void findCommunicationIndices(int direction, SPtr<BoundingBox> subDomainBox, LbmOrGks lbmOrGks) = 0;
+
+    virtual uint getNumberOfSendNodes(int direction)    = 0;
+    virtual uint getNumberOfReceiveNodes(int direction) = 0;
+
+    virtual uint getSendIndex(int direction, uint index)    = 0;
+    virtual uint getReceiveIndex(int direction, uint index) = 0;
+
+    virtual void repairCommunicationInices(int direction) = 0;
+
 };
 
 #endif
diff --git a/src/gpu/GridGenerator/grid/GridBuilder/GridBuilder.h b/src/gpu/GridGenerator/grid/GridBuilder/GridBuilder.h
index 63ea9b188cc5559e55cf7e7bddb611e6672004dd..57290025c3f6e48554e1dafe9bd101ae237b3288 100644
--- a/src/gpu/GridGenerator/grid/GridBuilder/GridBuilder.h
+++ b/src/gpu/GridGenerator/grid/GridBuilder/GridBuilder.h
@@ -28,7 +28,7 @@
 //
 //! \file GridBuilder.h
 //! \ingroup grid
-//! \author Soeren Peters, Stephan Lenz
+//! \author Soeren Peters, Stephan Lenz, Martin Schönherr
 //=======================================================================================
 #ifndef GridBuilder_H
 #define GridBuilder_H
@@ -78,7 +78,9 @@ public:
     virtual void getGridInformations(std::vector<int>& gridX, std::vector<int>& gridY, std::vector<int>& gridZ, std::vector<int>& distX, std::vector<int>& distY, std::vector<int>& distZ) = 0;
     virtual GRIDGENERATOR_EXPORT uint getNumberOfGridLevels() const = 0;
 
-	virtual SPtr<Grid> getGrid(uint level) = 0;
+    virtual void writeArrows(std::string fileName) const = 0;
+
+    virtual SPtr<Grid> getGrid(uint level) = 0;
 
     virtual unsigned int getNumberOfNodes(unsigned int level) const = 0;
     virtual void getNodeValues(real *xCoords, real *yCoords, real *zCoords, 
@@ -100,8 +102,26 @@ public:
     virtual void getVelocityValues(real* vx, real* vy, real* vz, int* indices, int level) const = 0;
     virtual void getVelocityQs(real* qs[27], int level) const = 0;
 
-    virtual SPtr<gg::BoundaryCondition> getBoundaryCondition( SideType side, uint level ) const = 0;
+    virtual uint getPressureSize(int level) const                                                  = 0;
+    virtual void getPressureValues(real *rho, int *indices, int *neighborIndices, int level) const = 0;
+    virtual void getPressureQs(real *qs[27], int level) const                                      = 0;
+
+    virtual uint getGeometrySize(int level) const                                 = 0;
+    virtual void getGeometryIndices(int *indices, int level) const                = 0;
+    virtual void getGeometryQs(real *qs[27], int level) const                     = 0;
+    virtual bool hasGeometryValues() const                                        = 0;
+    virtual void getGeometryValues(real *vx, real *vy, real *vz, int level) const = 0;
+
+    virtual SPtr<gg::BoundaryCondition> getBoundaryCondition(SideType side, uint level) const = 0;
+
+    virtual SPtr<GeometryBoundaryCondition> getGeometryBoundaryCondition(uint level) const = 0;
+
+    virtual uint getCommunicationProcess(int direction) = 0;
 
+    virtual uint getNumberOfSendIndices(int direction, uint level)             = 0;
+    virtual uint getNumberOfReceiveIndices(int direction, uint level)          = 0;
+    virtual void getSendIndices(int *sendIndices, int direction, int level)    = 0;
+    virtual void getReceiveIndices(int *sendIndices, int direction, int level) = 0;
 };
 
 #endif
diff --git a/src/gpu/GridGenerator/grid/GridBuilder/LevelGridBuilder.cpp b/src/gpu/GridGenerator/grid/GridBuilder/LevelGridBuilder.cpp
index 73bcbdf2b7ee5956236842771e6d8891f6226de9..20c285c13aa2c7644fc1ac6ea6a87b5d8dc7f72c 100644
--- a/src/gpu/GridGenerator/grid/GridBuilder/LevelGridBuilder.cpp
+++ b/src/gpu/GridGenerator/grid/GridBuilder/LevelGridBuilder.cpp
@@ -28,33 +28,50 @@
 //
 //! \file LevelGridBuilder.cpp
 //! \ingroup grid
-//! \author Soeren Peters, Stephan Lenz
+//! \author Soeren Peters, Stephan Lenz, Martin Schönherr
 //=======================================================================================
 #include "LevelGridBuilder.h"
 
 #include <stdio.h>
 #include <iostream>
 
+#include "geometries/Arrow/ArrowImp.h"
 #include "geometries/BoundingBox/BoundingBox.h"
+#include "geometries/Triangle/Triangle.h"
+#include "geometries/TriangularMesh/TriangularMesh.h"
 
 #include "grid/BoundaryConditions/BoundaryCondition.h"
 #include "grid/BoundaryConditions/Side.h"
-#include "grid/GridStrategy/GridCpuStrategy/GridCpuStrategy.h"
-#include "grid/NodeValues.h"
-#include "grid/GridFactory.h"
 #include "grid/Grid.h"
+#include "grid/GridFactory.h"
+#include "grid/GridInterface.h"
+#include "grid/NodeValues.h"
+
+#include "io/GridVTKWriter/GridVTKWriter.h"
+#include "io/QLineWriter.h"
+#include "io/SimulationFileWriter/SimulationFileWriter.h"
+
+#include "utilities/communication.h"
+#include "utilities/transformator/ArrowTransformator.h"
 
 #define GEOFLUID 19
 #define GEOSOLID 16
 
-LevelGridBuilder::LevelGridBuilder(Device device, const std::string& d3qxx) : d3qxx(d3qxx)
+using namespace vf::gpu;
+
+LevelGridBuilder::LevelGridBuilder()
 {
-    (void)device;
+    this->communicationProcesses[CommunicationDirections::MX] = INVALID_INDEX;
+    this->communicationProcesses[CommunicationDirections::PX] = INVALID_INDEX;
+    this->communicationProcesses[CommunicationDirections::MY] = INVALID_INDEX;
+    this->communicationProcesses[CommunicationDirections::PY] = INVALID_INDEX;
+    this->communicationProcesses[CommunicationDirections::MZ] = INVALID_INDEX;
+    this->communicationProcesses[CommunicationDirections::PZ] = INVALID_INDEX;
 }
 
-std::shared_ptr<LevelGridBuilder> LevelGridBuilder::makeShared(Device device, const std::string& d3qxx)
+std::shared_ptr<LevelGridBuilder> LevelGridBuilder::makeShared()
 {
-    return SPtr<LevelGridBuilder>(new LevelGridBuilder(device, d3qxx));
+    return SPtr<LevelGridBuilder>(new LevelGridBuilder());
 }
 
 void LevelGridBuilder::setSlipBoundaryCondition(SideType sideType, real nomalX, real normalY, real normalZ)
@@ -89,6 +106,42 @@ void LevelGridBuilder::setVelocityBoundaryCondition(SideType sideType, real vx,
     *logging::out << logging::Logger::INFO_INTERMEDIATE << "Set Velocity BC on level " << 0 << " with " << (int)velocityBoundaryCondition->indices.size() <<"\n";
 }
 
+void LevelGridBuilder::setVelocityGeometryBoundaryCondition(real vx, real vy, real vz)
+{
+    geometryHasValues = true;
+
+    for (uint level = 0; level < getNumberOfGridLevels(); level++)
+    {
+		if (boundaryConditions[level]->geometryBoundaryCondition != nullptr)
+		{
+			boundaryConditions[level]->geometryBoundaryCondition->vx = vx;
+			boundaryConditions[level]->geometryBoundaryCondition->vy = vy;
+			boundaryConditions[level]->geometryBoundaryCondition->vz = vz;
+			boundaryConditions[level]->geometryBoundaryCondition->side->addIndices(grids, level, boundaryConditions[level]->geometryBoundaryCondition);
+
+            boundaryConditions[level]->geometryBoundaryCondition->fillVelocityLists();
+
+            *logging::out << logging::Logger::INFO_INTERMEDIATE << "Set Geometry Velocity BC on level " << level << " with " << (int)boundaryConditions[level]->geometryBoundaryCondition->indices.size() <<"\n";
+		}
+    }
+}
+
+void LevelGridBuilder::setPressureBoundaryCondition(SideType sideType, real rho)
+{
+    for (uint level = 0; level < getNumberOfGridLevels(); level++)
+    {
+        SPtr<PressureBoundaryCondition> pressureBoundaryCondition = PressureBoundaryCondition::make(rho);
+
+        auto side = SideFactory::make(sideType);
+        pressureBoundaryCondition->side = side;
+        pressureBoundaryCondition->side->addIndices(grids, level, pressureBoundaryCondition);
+
+        boundaryConditions[level]->pressureBoundaryConditions.push_back(pressureBoundaryCondition);
+
+        *logging::out << logging::Logger::INFO_INTERMEDIATE << "Set Pressure BC on level " << level << " with " << (int)pressureBoundaryCondition->indices.size() <<"\n";
+    }
+}
+
 void LevelGridBuilder::setPeriodicBoundaryCondition(bool periodic_X, bool periodic_Y, bool periodic_Z)
 {
     for( uint level = 0; level < this->grids.size(); level++ )
@@ -110,6 +163,22 @@ void LevelGridBuilder::setNoSlipBoundaryCondition(SideType sideType)
     }
 }
 
+GRIDGENERATOR_EXPORT void LevelGridBuilder::setEnableFixRefinementIntoTheWall(bool enableFixRefinementIntoTheWall)
+{
+    for (uint level = 0; level < this->grids.size(); level++)
+        grids[level]->setEnableFixRefinementIntoTheWall(enableFixRefinementIntoTheWall);
+}
+
+GRIDGENERATOR_EXPORT void LevelGridBuilder::setCommunicationProcess(int direction, uint process)
+{
+    this->communicationProcesses[direction] = process;
+}
+
+GRIDGENERATOR_EXPORT uint LevelGridBuilder::getCommunicationProcess(int direction)
+{
+    return this->communicationProcesses[direction];
+}
+
 LevelGridBuilder::~LevelGridBuilder()
 {
     for (const auto& grid : grids)
@@ -146,24 +215,69 @@ uint LevelGridBuilder::getNumberOfGridLevels() const
 
 uint LevelGridBuilder::getNumberOfNodesCF(int level)
 {
-    return 0;
+    return this->grids[level]->getNumberOfNodesCF();
 }
 
 uint LevelGridBuilder::getNumberOfNodesFC(int level)
 {
-    return 0;
+    return this->grids[level]->getNumberOfNodesFC();
 }
 
 void LevelGridBuilder::getGridInterfaceIndices(uint* iCellCfc, uint* iCellCff, uint* iCellFcc, uint* iCellFcf, int level) const
 {
+    this->grids[level]->getGridInterfaceIndices(iCellCfc, iCellCff, iCellFcc, iCellFcf);
 }
 
 void LevelGridBuilder::getOffsetFC(real * xOffFC, real * yOffFC, real * zOffFC, int level)
 {
+    for (uint i = 0; i < getNumberOfNodesFC(level); i++)
+    {
+        uint offset = this->grids[level]->getFC_offset()[i];
+
+        xOffFC[i] = - this->grids[level]->getDirection()[ 3*offset + 0 ];
+        yOffFC[i] = - this->grids[level]->getDirection()[ 3*offset + 1 ];
+        zOffFC[i] = - this->grids[level]->getDirection()[ 3*offset + 2 ];
+    }
 }
 
 void LevelGridBuilder::getOffsetCF(real * xOffCF, real * yOffCF, real * zOffCF, int level)
 {
+    for (uint i = 0; i < getNumberOfNodesCF(level); i++)
+    {
+        uint offset = this->grids[level]->getCF_offset()[i];
+
+        xOffCF[i] = - this->grids[level]->getDirection()[ 3*offset + 0 ];
+        yOffCF[i] = - this->grids[level]->getDirection()[ 3*offset + 1 ];
+        zOffCF[i] = - this->grids[level]->getDirection()[ 3*offset + 2 ];
+    }
+}
+
+GRIDGENERATOR_EXPORT uint LevelGridBuilder::getNumberOfSendIndices(int direction, uint level)
+{
+    return this->grids[level]->getNumberOfSendNodes(direction);
+}
+
+GRIDGENERATOR_EXPORT uint LevelGridBuilder::getNumberOfReceiveIndices(int direction, uint level)
+{
+    return this->grids[level]->getNumberOfReceiveNodes(direction);
+}
+
+GRIDGENERATOR_EXPORT void LevelGridBuilder::getSendIndices(int * sendIndices, int direction, int level)
+{
+    SPtr<Grid> grid = this->grids[level];
+    for( uint i = 0; i < getNumberOfSendIndices(direction, level); i++ )
+    {
+        sendIndices[i] = grid->getSparseIndex( grid->getSendIndex(direction, i) ) + 1;
+    }
+}
+
+GRIDGENERATOR_EXPORT void LevelGridBuilder::getReceiveIndices(int * receiveIndices, int direction, int level)
+{
+    SPtr<Grid> grid = this->grids[level];
+    for( uint i = 0; i < getNumberOfReceiveIndices(direction, level); i++ )
+    {
+        receiveIndices[i] = grid->getSparseIndex( grid->getReceiveIndex(direction, i) ) + 1;
+    }
 }
 
 uint LevelGridBuilder::getNumberOfNodes(unsigned int level) const
@@ -287,12 +401,119 @@ void LevelGridBuilder::getVelocityQs(real* qs[27], int level) const
     }
 }
 
+uint LevelGridBuilder::getPressureSize(int level) const
+{
+    uint size = 0;
+    for (auto boundaryCondition : boundaryConditions[level]->pressureBoundaryConditions)
+    {
+        size += uint(boundaryCondition->indices.size());
+    }
+    return size;
+}
+
+void LevelGridBuilder::getPressureValues(real* rho, int* indices, int* neighborIndices, int level) const
+{
+    int allIndicesCounter = 0;
+    for (auto boundaryCondition : boundaryConditions[level]->pressureBoundaryConditions)
+    {
+        for (std::size_t i = 0; i < boundaryCondition->indices.size(); i++)
+        {
+            indices[allIndicesCounter] = grids[level]->getSparseIndex(boundaryCondition->indices[i]) + 1;
+
+            neighborIndices[allIndicesCounter] = grids[level]->getSparseIndex(boundaryCondition->neighborIndices[i]) + 1;
+
+            rho[allIndicesCounter] = boundaryCondition->rho;
+            allIndicesCounter++;
+        }
+    }
+}
+
+void LevelGridBuilder::getPressureQs(real* qs[27], int level) const
+{
+    int allIndicesCounter = 0;
+    for (auto boundaryCondition : boundaryConditions[level]->pressureBoundaryConditions)
+    {
+        for ( uint index = 0; index < boundaryCondition->indices.size(); index++ )
+        {
+            for (int dir = 0; dir <= grids[level]->getEndDirection(); dir++)
+            {
+                qs[dir][allIndicesCounter] = boundaryCondition->qs[index][dir];
+            }
+            allIndicesCounter++;
+        }
+    }
+}
+
+uint LevelGridBuilder::getGeometrySize(int level) const
+{
+    if (boundaryConditions[level]->geometryBoundaryCondition)
+        return  (uint)boundaryConditions[level]->geometryBoundaryCondition->indices.size();
+    
+    return 0;
+}
+
+void LevelGridBuilder::getGeometryIndices(int* indices, int level) const
+{
+    for (uint i = 0; i <  boundaryConditions[level]->geometryBoundaryCondition->indices.size(); i++)
+    {
+        indices[i] = grids[level]->getSparseIndex(boundaryConditions[level]->geometryBoundaryCondition->indices[i]) + 1;
+    }
+}
+
+bool LevelGridBuilder::hasGeometryValues() const
+{
+    return geometryHasValues;
+}
+
+void LevelGridBuilder::getGeometryValues(real* vx, real* vy, real* vz, int level) const
+{
+    for (uint i = 0; i < boundaryConditions[level]->geometryBoundaryCondition->indices.size(); i++)
+    {
+		vx[i] = boundaryConditions[level]->geometryBoundaryCondition->getVx(i);
+		vy[i] = boundaryConditions[level]->geometryBoundaryCondition->getVy(i);
+		vz[i] = boundaryConditions[level]->geometryBoundaryCondition->getVz(i);
+    }
+}
+
+void LevelGridBuilder::getGeometryQs(real* qs[27], int level) const
+{
+    for (std::size_t i = 0; i < boundaryConditions[level]->geometryBoundaryCondition->indices.size(); i++)
+    {
+        for (int dir = 0; dir <= grids[level]->getEndDirection(); dir++)
+        {
+            qs[dir][i] = boundaryConditions[level]->geometryBoundaryCondition->qs[i][dir];
+        }
+    }
+}
+
+void LevelGridBuilder::writeArrows(std::string fileName) const 
+{
+    QLineWriter::writeArrows(fileName, boundaryConditions[getNumberOfGridLevels() - 1]->geometryBoundaryCondition, grids[getNumberOfGridLevels() - 1]);
+}
+
 GRIDGENERATOR_EXPORT SPtr<gg::BoundaryCondition> LevelGridBuilder::getBoundaryCondition(SideType side, uint level) const
 {
-    for( auto bc : this->boundaryConditions[level]->velocityBoundaryConditions )
+    for (auto bc : this->boundaryConditions[level]->slipBoundaryConditions)
+        if (bc->isSide(side))
+            return bc;
+
+    for (auto bc : this->boundaryConditions[level]->velocityBoundaryConditions)
         if( bc->isSide(side) )
             return bc;
 
+    for (auto bc : this->boundaryConditions[level]->pressureBoundaryConditions)
+        if (bc->isSide(side))
+            return bc;
+
+    auto bc = this->boundaryConditions[level]->geometryBoundaryCondition;
+
+    if (bc && bc->isSide(side))
+        return bc;
+
     return nullptr;
 }
 
+GRIDGENERATOR_EXPORT SPtr<GeometryBoundaryCondition> LevelGridBuilder::getGeometryBoundaryCondition(uint level) const
+{
+    return this->boundaryConditions[level]->geometryBoundaryCondition;
+}
diff --git a/src/gpu/GridGenerator/grid/GridBuilder/LevelGridBuilder.h b/src/gpu/GridGenerator/grid/GridBuilder/LevelGridBuilder.h
index 8e0f79a7aa833af59b0eb5e74a70aaaefdd5a7aa..f2325435d99140f33eee9844c13908de87788558 100644
--- a/src/gpu/GridGenerator/grid/GridBuilder/LevelGridBuilder.h
+++ b/src/gpu/GridGenerator/grid/GridBuilder/LevelGridBuilder.h
@@ -28,7 +28,7 @@
 //
 //! \file LevelGridBuilder.h
 //! \ingroup grid
-//! \author Soeren Peters, Stephan Lenz
+//! \author Soeren Peters, Stephan Lenz, Martin Schönherr
 //=======================================================================================
 #ifndef LEVEL_GRID_BUILDER_H
 #define LEVEL_GRID_BUILDER_H
@@ -46,13 +46,16 @@
 
 struct Vertex;
 class  Grid;
+class Transformator;
+class ArrowTransformator;
 class PolyDataWriterWrapper;
 class BoundingBox;
-enum class Device;
 
 class Side;
 class VelocityBoundaryCondition;
 class SlipBoundaryCondition;
+class PressureBoundaryCondition;
+class GeometryBoundaryCondition;
 enum class SideType;
 
 
@@ -60,10 +63,10 @@ enum class SideType;
 class LevelGridBuilder : public GridBuilder
 {
 protected:
-    GRIDGENERATOR_EXPORT LevelGridBuilder(Device device, const std::string& d3qxx);
+    GRIDGENERATOR_EXPORT LevelGridBuilder();
 
 public:
-    GRIDGENERATOR_EXPORT static std::shared_ptr<LevelGridBuilder> makeShared(Device device, const std::string& d3qxx);
+    GRIDGENERATOR_EXPORT static std::shared_ptr<LevelGridBuilder> makeShared();
 
     GRIDGENERATOR_EXPORT SPtr<Grid> getGrid(uint level) override;
 
@@ -71,9 +74,16 @@ public:
 
     GRIDGENERATOR_EXPORT void setSlipBoundaryCondition(SideType sideType, real nomalX, real normalY, real normalZ);
     GRIDGENERATOR_EXPORT void setVelocityBoundaryCondition(SideType sideType, real vx, real vy, real vz);
+    GRIDGENERATOR_EXPORT void setPressureBoundaryCondition(SideType sideType, real rho);
     GRIDGENERATOR_EXPORT void setPeriodicBoundaryCondition(bool periodic_X, bool periodic_Y, bool periodic_Z);
     GRIDGENERATOR_EXPORT void setNoSlipBoundaryCondition(SideType sideType);
 
+    GRIDGENERATOR_EXPORT void setEnableFixRefinementIntoTheWall(bool enableFixRefinementIntoTheWall);
+
+    GRIDGENERATOR_EXPORT void setCommunicationProcess(int direction, uint process);
+
+    GRIDGENERATOR_EXPORT uint getCommunicationProcess(int direction) override;
+
     GRIDGENERATOR_EXPORT virtual std::shared_ptr<Grid> getGrid(int level, int box);
 
     GRIDGENERATOR_EXPORT virtual unsigned int getNumberOfNodes(unsigned int level) const override;
@@ -93,7 +103,20 @@ public:
     GRIDGENERATOR_EXPORT virtual void getVelocityValues(real* vx, real* vy, real* vz, int* indices, int level) const override;
     GRIDGENERATOR_EXPORT virtual void getVelocityQs(real* qs[27], int level) const override;
 
+    GRIDGENERATOR_EXPORT uint getPressureSize(int level) const override;
+    GRIDGENERATOR_EXPORT void getPressureValues(real* rho, int* indices, int* neighborIndices, int level) const override;
+    GRIDGENERATOR_EXPORT virtual void getPressureQs(real* qs[27], int level) const override;
+
+    GRIDGENERATOR_EXPORT virtual void getGeometryQs(real *qs[27], int level) const override;
+    GRIDGENERATOR_EXPORT virtual uint getGeometrySize(int level) const override;
+    GRIDGENERATOR_EXPORT virtual void getGeometryIndices(int *indices, int level) const override;
+    GRIDGENERATOR_EXPORT virtual bool hasGeometryValues() const override;
+    GRIDGENERATOR_EXPORT virtual void getGeometryValues(real *vx, real *vy, real *vz, int level) const override;
+
+    GRIDGENERATOR_EXPORT void writeArrows(std::string fileName) const override;
+
     GRIDGENERATOR_EXPORT SPtr<gg::BoundaryCondition> getBoundaryCondition( SideType side, uint level ) const override;
+    GRIDGENERATOR_EXPORT SPtr<GeometryBoundaryCondition> getGeometryBoundaryCondition(uint level) const override;
 
 protected:
     
@@ -106,17 +129,30 @@ protected:
 
         std::vector<SPtr<VelocityBoundaryCondition>> velocityBoundaryConditions;
 
+        std::vector<SPtr<PressureBoundaryCondition>> pressureBoundaryConditions;
+
         std::vector<SPtr<VelocityBoundaryCondition> > noSlipBoundaryConditions;
+
+        SPtr<GeometryBoundaryCondition> geometryBoundaryCondition;
     };
     bool geometryHasValues = false;
 
     std::vector<std::shared_ptr<Grid> > grids;
     std::vector<SPtr<BoundaryConditions> > boundaryConditions;
     
+    std::array<uint, 6> communicationProcesses;
+
     void checkLevel(int level);
 
-private:
-    std::string d3qxx;
+protected:
+    void setVelocityGeometryBoundaryCondition(real vx, real vy, real vz);
+
+    void createBCVectors();
+    void addShortQsToVector(int index);
+    void addQsToVector(int index);
+    void fillRBForNode(int index, int direction, int directionSign, int rb);
+
+    Vertex getVertex(const int matrixIndex) const;
 
 public:
     GRIDGENERATOR_EXPORT void getGridInformations(std::vector<int>& gridX, std::vector<int>& gridY,
@@ -132,6 +168,10 @@ public:
     GRIDGENERATOR_EXPORT void getOffsetFC(real* xOffCf, real* yOffCf, real* zOffCf, int level) override;
     GRIDGENERATOR_EXPORT void getOffsetCF(real* xOffFc, real* yOffFc, real* zOffFc, int level) override;
 
+    GRIDGENERATOR_EXPORT uint getNumberOfSendIndices(int direction, uint level) override;
+    GRIDGENERATOR_EXPORT uint getNumberOfReceiveIndices(int direction, uint level) override;
+    GRIDGENERATOR_EXPORT void getSendIndices(int *sendIndices, int direction, int level) override;
+    GRIDGENERATOR_EXPORT void getReceiveIndices(int *sendIndices, int direction, int level) override;
 };
 
 #endif
diff --git a/src/gpu/GridGenerator/grid/GridBuilder/MultipleGridBuilder.cpp b/src/gpu/GridGenerator/grid/GridBuilder/MultipleGridBuilder.cpp
index f3fdaa25d1eca3c60f0bd6c477b0a3984089b46f..565a02a2807ef15679bf08fa001ea9a03f78ca4e 100644
--- a/src/gpu/GridGenerator/grid/GridBuilder/MultipleGridBuilder.cpp
+++ b/src/gpu/GridGenerator/grid/GridBuilder/MultipleGridBuilder.cpp
@@ -28,7 +28,7 @@
 //
 //! \file MultipleGridBuilder.cpp
 //! \ingroup grid
-//! \author Soeren Peters, Stephan Lenz
+//! \author Soeren Peters, Stephan Lenz, Martin Schönherr
 //=======================================================================================
 #include "MultipleGridBuilder.h"
 
@@ -46,15 +46,17 @@
 #include "grid/Grid.h"
 #include "grid/GridFactory.h"
 
-MultipleGridBuilder::MultipleGridBuilder(SPtr<GridFactory> gridFactory, Device device, const std::string &d3qxx) :
-    LevelGridBuilder(device, d3qxx), gridFactory(gridFactory), numberOfLayersFine(12), numberOfLayersBetweenLevels(8), subDomainBox(nullptr)
+#include "io/GridVTKWriter/GridVTKWriter.h"
+#include "io/STLReaderWriter/STLWriter.h"
+
+MultipleGridBuilder::MultipleGridBuilder() : LevelGridBuilder(), numberOfLayersFine(12), numberOfLayersBetweenLevels(8), subDomainBox(nullptr)
 {
 
 }
 
-SPtr<MultipleGridBuilder> MultipleGridBuilder::makeShared(SPtr<GridFactory> gridFactory)
+SPtr<MultipleGridBuilder> MultipleGridBuilder::makeShared()
 {
-    return SPtr<MultipleGridBuilder>(new MultipleGridBuilder(gridFactory));
+    return SPtr<MultipleGridBuilder>(new MultipleGridBuilder());
 }
 
 void MultipleGridBuilder::addCoarseGrid(real startX, real startY, real startZ, real endX, real endY, real endZ, real delta)
@@ -72,9 +74,128 @@ void MultipleGridBuilder::addCoarseGrid(real startX, real startY, real startZ, r
     addGridToList(grid);
 }
 
+void MultipleGridBuilder::addGeometry(Object* solidObject)
+{
+    this->solidObject = solidObject;
+
+    for(auto bcs : boundaryConditions)
+    {
+        bcs->geometryBoundaryCondition = GeometryBoundaryCondition::make();
+        bcs->geometryBoundaryCondition->side = SideFactory::make(SideType::GEOMETRY);
+    }
+}
+
+void MultipleGridBuilder::addGeometry(Object* solidObject, uint level)
+{
+    this->solidObject = solidObject;
+    auto gridShape = solidObject->clone();
+    gridShape->scale(4.0);
+
+    this->addGrid(gridShape, level);
+}
+
+void MultipleGridBuilder::addGrid(Object* gridShape)
+{
+    if (!coarseGridExists())
+        return emitNoCoarseGridExistsWarning();
+
+    const auto grid = makeGrid(gridShape, getNumberOfLevels(), 0);
+
+    addGridToListIfValid(grid);
+}
+
+void MultipleGridBuilder::addGrid(Object* gridShape, uint levelFine)
+{
+    if (!coarseGridExists())
+        return emitNoCoarseGridExistsWarning();
+
+    for( uint level = this->getNumberOfLevels(); level <= levelFine; level++ ){
+        const auto grid = makeGrid(gridShape, level, levelFine);
+
+
+        if(level != levelFine){
+            grid->setInnerRegionFromFinerGrid(true);
+            grid->setNumberOfLayers( this->numberOfLayersBetweenLevels );
+        }
+        else{
+            grid->setNumberOfLayers( this->numberOfLayersFine );
+        }
+
+        grids.push_back(grid);
+    }
+
+    //////////////////////////////////////////////////////////////////////////
+    // this old code by Soeren P. scaled the object
+    // this did not work for concave geometries
+    //////////////////////////////////////////////////////////////////////////
+
+    //const uint nodesBetweenGrids = 12;
+    //const uint levelDifference = levelFine - getNumberOfLevels();
+    //const uint oldGridSize = this->getNumberOfLevels();
+
+    //addIntermediateGridsToList(levelDifference, levelFine, nodesBetweenGrids, gridShape);
+    //addFineGridToList(levelFine, gridShape->clone());
+
+
+    //eraseGridsFromListIfInvalid(oldGridSize);
+}
+
+void MultipleGridBuilder::addFineGridToList(uint level, Object* gridShape)
+{
+    const auto grid = makeGrid(gridShape, level, 0);
+    grids.push_back(grid);
+}
+
+void MultipleGridBuilder::addIntermediateGridsToList(uint levelDifference, uint levelFine, uint nodesBetweenGrids, Object* gridShape)
+{
+    if (levelDifference > 0)
+    {
+        auto spacings = getSpacingFactors(levelDifference);
+
+        uint level = getNumberOfLevels();
+        for (int i = levelDifference - 1; i >= 0; i--)
+        {
+            const real scalingFactor = nodesBetweenGrids * spacings[i] * calculateDelta(levelFine);
+            Object* gridShapeClone = gridShape->clone();
+            gridShapeClone->scale(scalingFactor);
+
+            const auto grid = makeGrid(gridShapeClone, level++, 0);
+            grids.push_back(grid);
+        }
+    }
+}
+
+std::vector<uint> MultipleGridBuilder::getSpacingFactors(uint levelDifference) const
+{
+    std::vector<uint> spacings(levelDifference);
+
+    spacings[0] = uint(std::pow(2, 1));
+    for (uint i = 1; i < levelDifference; i++)
+        spacings[i] = spacings[i - 1] + uint(std::pow(2, i + 1));
+
+    return spacings;
+}
+
+void MultipleGridBuilder::eraseGridsFromListIfInvalid(uint oldSize)
+{
+    if (!isGridInCoarseGrid(grids[oldSize]))
+    {
+        this->grids.erase(grids.begin() + oldSize, grids.end());
+        emitGridIsNotInCoarseGridWarning();
+    }
+}
+
+void MultipleGridBuilder::addGridToListIfValid(SPtr<Grid> grid)
+{
+    if (!isGridInCoarseGrid(grid))
+        return emitGridIsNotInCoarseGridWarning();
+
+    addGridToList(grid);
+}
+
 SPtr<Grid> MultipleGridBuilder::makeGrid(Object* gridShape, real startX, real startY, real startZ, real endX, real endY, real endZ, real delta, uint level) const
 {
-    return gridFactory->makeGrid(gridShape, startX, startY, startZ, endX, endY, endZ, delta, level);
+    return GridImp::makeShared(gridShape, startX, startY, startZ, endX, endY, endZ, delta, "D3Q27", level);
 }
 
 bool MultipleGridBuilder::coarseGridExists() const
@@ -82,6 +203,196 @@ bool MultipleGridBuilder::coarseGridExists() const
     return !grids.empty();
 }
 
+SPtr<Grid> MultipleGridBuilder::makeGrid(Object* gridShape, uint level, uint levelFine)
+{
+    boundaryConditions.push_back(SPtr<BoundaryConditions>(new BoundaryConditions));
+
+    const real delta = calculateDelta(level);
+
+    bool xOddStart = false, yOddStart = false, zOddStart = false;
+
+	auto staggeredCoordinates = getStaggeredCoordinates(gridShape, level, levelFine, xOddStart, yOddStart, zOddStart);
+
+	SPtr<Grid> newGrid = this->makeGrid(gridShape, staggeredCoordinates[0], 
+                                                   staggeredCoordinates[1], 
+                                                   staggeredCoordinates[2], 
+                                                   staggeredCoordinates[3], 
+                                                   staggeredCoordinates[4], 
+                                                   staggeredCoordinates[5], delta, level);
+
+    newGrid->setOddStart( xOddStart, yOddStart, zOddStart );
+
+    return newGrid;
+}
+
+real MultipleGridBuilder::calculateDelta(uint level) const
+{
+    real delta = this->getDelta(0);
+    for (uint i = 0; i < level; i++)
+        delta *= 0.5;
+    return delta;
+}
+
+std::array<real, 6> MultipleGridBuilder::getStaggeredCoordinates(Object* gridShape, uint level, uint levelFine, bool& xOddStart, bool& yOddStart, bool& zOddStart) const
+{
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    //
+    // This method computes the start and end coordinates with respect to the coarse grid
+    // The following sketch visualizes this procedure for level 2:
+    //
+    //                          /----------------------- domain --------------------------------/ 
+    //                          |                      /----------------- refinement region ------------------------/
+    //                          |                      |                                        |                   |
+    //                          |                      |                                        |                   |
+    // Level 2:                 |                 2   2|  2   2   2   2   2   2   2   2   2   2 | 2  (2) (2) (2)    |
+    // Level 1:             1   |   1       1       1  |    1       1       1       1       1   |   1      (1)      |
+    // Level 0:         0       |       0              |0               0               0       |       0           |
+    //                          |                      |                                        |                   |
+    //                          |  out of refinement   |             inside refinement          |   out of domain   |   out of refinement
+    //                          |                      |                                        |                   |
+    //  Step  1) ------------------>x                  |                                        |   x<-------------------------------------------
+    //  Step  2)                |    ------>x------>x------>x                                   |                   |
+    //  Step  3)                |                      |  x<                                    |    >x             |
+    //  Step  4)                |                 x<------                                      |      ------>x     |
+    //  Step  5)                |                      |                                        | x<--x<--x<--      |
+    //
+	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+	const real deltaCoarse = this->grids[level-1]->getDelta();
+    const real delta = 0.5 * deltaCoarse;
+
+
+	std::array<real, 6> staggeredCoordinates;
+
+    real X1Minimum = gridShape->getX1Minimum();
+    real X2Minimum = gridShape->getX2Minimum();
+    real X3Minimum = gridShape->getX3Minimum();
+    real X1Maximum = gridShape->getX1Maximum();
+    real X2Maximum = gridShape->getX2Maximum();
+    real X3Maximum = gridShape->getX3Maximum();
+
+    if( levelFine >= level ){
+        real overlap = 0.0;
+        
+        if(level != levelFine)
+        {
+            overlap += ( this->numberOfLayersBetweenLevels + 1 ) * delta;
+
+            // use geometric series to account for overlap of higher levels:
+            // overlap + overlap/2 + overlap/4 + ...
+            overlap *= 2.0 * ( 1.0 - pow(0.5, levelFine - level ) );
+        }
+
+        // add overlap for finest level
+        overlap += this->numberOfLayersFine * delta * pow(0.5, levelFine - level);
+
+        X1Minimum -= overlap;
+        X2Minimum -= overlap;
+        X3Minimum -= overlap;
+        X1Maximum += overlap;
+        X2Maximum += overlap;
+        X3Maximum += overlap;
+    }
+
+	// Step 1
+    // go to boundary of coarse grid
+	staggeredCoordinates[0] = this->grids[level-1]->getStartX();
+	staggeredCoordinates[1] = this->grids[level-1]->getStartY();
+	staggeredCoordinates[2] = this->grids[level-1]->getStartZ();
+	staggeredCoordinates[3] = this->grids[level-1]->getEndX();
+	staggeredCoordinates[4] = this->grids[level-1]->getEndY();
+	staggeredCoordinates[5] = this->grids[level-1]->getEndZ();
+
+	// Step 2
+    // move to first coarse node in refinement region
+	while (staggeredCoordinates[0] < X1Minimum) staggeredCoordinates[0] += deltaCoarse;
+	while (staggeredCoordinates[1] < X2Minimum) staggeredCoordinates[1] += deltaCoarse;
+	while (staggeredCoordinates[2] < X3Minimum) staggeredCoordinates[2] += deltaCoarse;
+	while (staggeredCoordinates[3] > X1Maximum) staggeredCoordinates[3] -= deltaCoarse;
+	while (staggeredCoordinates[4] > X2Maximum) staggeredCoordinates[4] -= deltaCoarse;
+	while (staggeredCoordinates[5] > X3Maximum) staggeredCoordinates[5] -= deltaCoarse;
+
+	// Step 3
+    // make the grid staggered with one layer of stopper nodes on the outside
+	staggeredCoordinates[0] -= 0.25 * deltaCoarse;
+	staggeredCoordinates[1] -= 0.25 * deltaCoarse;
+	staggeredCoordinates[2] -= 0.25 * deltaCoarse;
+	staggeredCoordinates[3] += 0.25 * deltaCoarse;
+	staggeredCoordinates[4] += 0.25 * deltaCoarse;
+	staggeredCoordinates[5] += 0.25 * deltaCoarse;
+
+	// Step 4
+    // add two layers until the refinement region is completely inside the fine grid
+	if (staggeredCoordinates[0] > X1Minimum) staggeredCoordinates[0] -= deltaCoarse;
+	if (staggeredCoordinates[1] > X2Minimum) staggeredCoordinates[1] -= deltaCoarse;
+	if (staggeredCoordinates[2] > X3Minimum) staggeredCoordinates[2] -= deltaCoarse;
+	if (staggeredCoordinates[3] < X1Maximum) staggeredCoordinates[3] += deltaCoarse;
+	if (staggeredCoordinates[4] < X2Maximum) staggeredCoordinates[4] += deltaCoarse;
+	if (staggeredCoordinates[5] < X3Maximum) staggeredCoordinates[5] += deltaCoarse;
+
+    // Step 5
+
+    // if the mesh is bigger than the domain then it has an odd start
+    if (staggeredCoordinates[0] < this->grids[level - 1]->getStartX()) xOddStart = true;
+    if (staggeredCoordinates[1] < this->grids[level - 1]->getStartY()) yOddStart = true;
+    if (staggeredCoordinates[2] < this->grids[level - 1]->getStartZ()) zOddStart = true;
+
+    // if the refinement region is larger than the domain, then the start and end points are moved inwards again
+    while (staggeredCoordinates[0] < this->grids[level - 1]->getStartX()) staggeredCoordinates[0] += delta;
+    while (staggeredCoordinates[1] < this->grids[level - 1]->getStartY()) staggeredCoordinates[1] += delta;
+    while (staggeredCoordinates[2] < this->grids[level - 1]->getStartZ()) staggeredCoordinates[2] += delta;
+    while (staggeredCoordinates[3] > this->grids[level - 1]->getEndX()  ) staggeredCoordinates[3] -= delta;
+    while (staggeredCoordinates[4] > this->grids[level - 1]->getEndY()  ) staggeredCoordinates[4] -= delta;
+    while (staggeredCoordinates[5] > this->grids[level - 1]->getEndZ()  ) staggeredCoordinates[5] -= delta;
+
+	return staggeredCoordinates;
+}
+
+std::array<real, 6> MultipleGridBuilder::getStaggeredCoordinates(real startX, real startY, real startZ, real endX, real endY, real endZ, real delta, uint level) const
+{
+	//previous version of Soeren P.	
+	auto offset = getOffset(delta);
+
+    const real startXStaggered = std::floor(startX) - offset[0];
+    const real startYStaggered = std::floor(startY) - offset[1];
+    const real startZStaggered = std::floor(startZ) - offset[2];
+
+    const real endXStaggered = std::ceil(endX) + offset[0];
+    const real endYStaggered = std::ceil(endY) + offset[1];
+    const real endZStaggered = std::ceil(endZ) + offset[2];
+
+    auto temporaryGrid = this->makeGrid(nullptr, startXStaggered, startYStaggered, startZStaggered, endXStaggered, endYStaggered, endZStaggered, delta, level);
+    auto startStaggered = temporaryGrid->getMinimumOnNode(Vertex(startX, startY, startZ));
+    auto endStaggered = temporaryGrid->getMaximumOnNode(Vertex(endX, endY, endZ));
+
+    return std::array<real, 6>{startStaggered.x, startStaggered.y, startStaggered.z, endStaggered.x, endStaggered.y, endStaggered.z};
+}
+
+std::array<real, 3> MultipleGridBuilder::getOffset(real delta) const
+{
+    real offsetToNullStart = delta * 0.5;
+
+    for (uint level = 1; level < getNumberOfLevels(); level++)
+        offsetToNullStart += getDelta(level) * 0.5;
+
+    const real offsetX = getStartX(0) - int(getStartX(0)) + offsetToNullStart;
+    const real offsetY = getStartY(0) - int(getStartY(0)) + offsetToNullStart;
+    const real offsetZ = getStartZ(0) - int(getStartZ(0)) + offsetToNullStart;
+    return std::array<real, 3>{offsetX, offsetY, offsetZ};
+}
+
+bool MultipleGridBuilder::isGridInCoarseGrid(SPtr<Grid> grid) const
+{
+    return
+        vf::Math::greaterEqual(grid->getStartX(), grids[0]->getStartX()) &&
+        vf::Math::greaterEqual(grid->getStartY(), grids[0]->getStartY()) &&
+        vf::Math::greaterEqual(grid->getStartZ(), grids[0]->getStartZ()) &&
+        vf::Math::lessEqual(grid->getEndX(), grids[0]->getEndX()) &&
+        vf::Math::lessEqual(grid->getEndY(), grids[0]->getEndY()) &&
+        vf::Math::lessEqual(grid->getEndZ(), grids[0]->getEndZ());
+}
+
+
 uint MultipleGridBuilder::getNumberOfLevels() const
 {
     return uint(grids.size());
@@ -134,18 +445,157 @@ std::vector<SPtr<Grid> > MultipleGridBuilder::getGrids() const
     return this->grids;
 }
 
+// this method initiates the actual grid generation
+//
+//  => before calling this MultipleGridBuilder::buildGrids(...), several options 
+//     parameters and similar have to be set for the grid generation:
+//      => MultipleGridBuilder::addCoarseGrid(...)                      => background grid
+//      => MultipleGridBuilder::setNumberOfLayers(...)                  => additional layers outside refinement region
+//      => MultipleGridBuilder::addGrid(..)                             => refinement region
+//      => MultipleGridBuilder::setSubDomainBox(...)                    => sub domain for Multi GPU
+//      => MultipleGridBuilder::addGeometry(...)                        => object for solid domain
+//      => MultipleGridBuilder::setPeriodicBoundaryCondition(...)       => periodicity
+//
+//  => LBM boundary conditions are set after MultipleGridBuilder::buildGrids(...):
+//      => LevelGridBuilder::setVelocityBoundaryCondition(...)
+//      => LevelGridBuilder::setPressureBoundaryCondition(...)
+//      => GeometryBoundaryCondition::setTangentialVelocityForPatch(...)
+//      => VelocityBoundaryCondition::setVelocityProfile(...)
+//
+//  => Multi GPU connectivity is set after MultipleGridBuilder::buildGrids(...):
+//      => MultipleGridBuilder::findCommunicationIndices(...)
+//      => LevelGridBuilder::setCommunicationProcess(...)
+//
 void MultipleGridBuilder::buildGrids( LbmOrGks lbmOrGks, bool enableThinWalls )
 {
-    *logging::out << logging::Logger::INFO_INTERMEDIATE << "Start initializing level " << 0 << "\n";
+    //////////////////////////////////////////////////////////////////////////
+
+    // initialize the grids:
+    //      => allocate memory
+    //      => set everything to INVALID_OUT_OF_GRID
+    //      => find nodes inside the refinement region, either based on 
+    //         an object or on the shape of the underlying fine grid
+    //      => add overlap as specified by MultipleGridBuilder::setNumberOfLayers
+    //      => fix odd cells, such that we obtain steps of size on the 
+    //         boundary of the grid (for complete cells for interpolation)
+    //      => fix refinement into the wall, i.e. make sure the refinement 
+    //         goes straight into the walls
+    //      => set stopper nodes to STOPPER_OUT_OF_GRID and STOPPER_OUT_OF_GRID_BOUNDARY
+    //
+    // the number of layers is passed to the Grid::initial(...) method as argument
+    //
+    // For further documentation of the grid initialization see Section 5.2.2 and
+    // Figure 5.2 in the Dissertation of Stephan Lenz:
+    // https://publikationsserver.tu-braunschweig.de/receive/dbbs_mods_00068716
+    //
+    for( int level = (int)grids.size()-1; level >= 0; level-- ) {
 
-    grids[0]->inital( nullptr, 0 );
+        *logging::out << logging::Logger::INFO_INTERMEDIATE << "Start initializing level " << level << "\n";
 
-    *logging::out << logging::Logger::INFO_INTERMEDIATE << "Done initializing level " << 0 << "\n";
+        // On the coarse grid every thing is Fluid (w.r.t. the refinement)
+        // On the finest grid the Fluid region is defined by the Object
+        // On the intermediate levels the Fluid region is defined by the fluid region of the finer level
+        if(level == 0)
+            grids[level]->inital( nullptr, 0 );
+        else if(level == (int)grids.size() - 1)
+            grids[level]->inital( nullptr, this->numberOfLayersFine );
+        else
+            grids[level]->inital( grids[level+1], this->numberOfLayersBetweenLevels );
+
+        *logging::out << logging::Logger::INFO_INTERMEDIATE << "Done initializing level " << level << "\n";
+    }
 
     //////////////////////////////////////////////////////////////////////////
 
-	if (lbmOrGks == LBM)
-		grids[0]->findSparseIndices(nullptr);
+    // set the solid region and find Qs
+    // this is only done if a solid object was added to the GridBuilder
+    //
+    // For further documentation of the treatment of solid objects see Section 5.2.3
+    // and figure 5.3 in the Dissertation of Stephan Lenz:
+    // https://publikationsserver.tu-braunschweig.de/receive/dbbs_mods_00068716
+    //
+    if (solidObject)
+    {
+
+        *logging::out << logging::Logger::INFO_INTERMEDIATE << "Start with Q Computation\n";
+
+        // Currently the solid object is only used on the finest grid,
+        // because refinement into solid objects is not yet implemented.
+        // If the solid object does not intersect the interfaces, it 
+        // might be possible to have a solid object on more than the finest
+        // level (See Bachelor thesis of Lennard Lux). To enable this, 
+        // change the following two lines. This is not tested though!
+
+        //for( uint level = 0; level < grids.size(); level++ )
+        uint level = (uint)grids.size() - 1;
+        {
+            // the Grid::mesh(...) method distinguishes inside and ouside regions
+            // of the solid domain.:
+            //      => set inner nodes to INVALID_SOLID
+            //      => close needle sells
+            //      => set one layer of STOPPER_SOLID nodes in the solid domain
+            //      => set one layer of BC_SOLID nodes in the fluid domain
+            grids[level]->mesh(solidObject);
+
+            // if thin walls are enables additional BC_SOLID nodes are found by
+            // Grid::findOs(...). To prevent the actual Q computation, 
+            // Grid::enableFindSolidBoundaryNodes() and Grid::enableComputeQs()
+            // set a flag that changes the behavior of Grid::findOs(...);
+            // additionally some needle cells are closed in this process.
+            if (enableThinWalls) {
+                grids[level]->enableFindSolidBoundaryNodes();
+                grids[level]->findQs(solidObject);
+                grids[level]->closeNeedleCellsThinWall();
+                grids[level]->enableComputeQs();
+            }
+
+            // compute the sub grid distances 
+            // this works for STL and Sphere objects, but not yet for other primitives!
+            if( lbmOrGks == LBM )
+                grids[level]->findQs(solidObject);
+        }
+
+        *logging::out << logging::Logger::INFO_INTERMEDIATE << "Done with Q Computation\n";
+    }
+
+    //////////////////////////////////////////////////////////////////////////
+
+    // find the interface interpolations cells
+    // For further documentation see Section 5.2.4 and Figure 5.3 in the dissertation
+    // of Stephan Lenz:
+    // https://publikationsserver.tu-braunschweig.de/receive/dbbs_mods_00068716
+    //
+    for (size_t i = 0; i < grids.size() - 1; i++)
+        grids[i]->findGridInterface(grids[i + 1], lbmOrGks);
+
+    //////////////////////////////////////////////////////////////////////////
+
+    // set all points outside the sub domain to STOPPER_OUT_OF_GRID_BOUNDARY
+    // and INVALID_OUT_OF_GRID
+    if( this->subDomainBox )
+        for (size_t i = 0; i < grids.size(); i++)
+            grids[i]->limitToSubDomain( this->subDomainBox, lbmOrGks );
+
+    //////////////////////////////////////////////////////////////////////////
+
+    // shrinks the interface cell lists to the correct size
+    for (size_t i = 0; i < grids.size() - 1; i++)
+        grids[i]->repairGridInterfaceOnMultiGPU(grids[i + 1]);
+
+    //////////////////////////////////////////////////////////////////////////
+
+    // unrolls the matrix
+    //      => computes the sparse indices
+    //      => generates neighbor connectivity taking into account periodic boundaries
+    //      => undates the interface connectivity to sparse indices (overwrites matrix indices!)
+    if (lbmOrGks == LBM) {
+        for (size_t i = 0; i < grids.size() - 1; i++)
+           grids[i]->findSparseIndices(grids[i + 1]);
+
+        grids[grids.size() - 1]->findSparseIndices(nullptr);
+    }
+
+    //////////////////////////////////////////////////////////////////////////
 }
 
 GRIDGENERATOR_EXPORT void MultipleGridBuilder::setNumberOfLayers(uint numberOfLayersFine, uint numberOfLayersBetweenLevels)
@@ -154,3 +604,42 @@ GRIDGENERATOR_EXPORT void MultipleGridBuilder::setNumberOfLayers(uint numberOfLa
     this->numberOfLayersBetweenLevels = numberOfLayersBetweenLevels;
 }
 
+void MultipleGridBuilder::emitNoCoarseGridExistsWarning()
+{
+    *logging::out << logging::Logger::WARNING << "No Coarse grid was added before. Actual Grid is not added, please create coarse grid before.\n";
+}
+
+
+void MultipleGridBuilder::emitGridIsNotInCoarseGridWarning()
+{
+    *logging::out << logging::Logger::WARNING << "Grid lies not inside of coarse grid. Actual Grid is not added.\n";
+}
+
+void MultipleGridBuilder::findCommunicationIndices(int direction, LbmOrGks lbmOrGks)
+{
+    *logging::out << logging::Logger::INFO_HIGH << "Start findCommunicationIndices()\n";
+
+    if( this->subDomainBox )
+        for (size_t i = 0; i < grids.size(); i++)
+            grids[i]->findCommunicationIndices(direction, this->subDomainBox, lbmOrGks);
+
+    *logging::out << logging::Logger::INFO_HIGH << "Done with findCommunicationIndices()\n";
+}
+
+void MultipleGridBuilder::writeGridsToVtk(const std::string& path) const
+{
+    for(uint level = 0; level < grids.size(); level++)
+    {
+        std::stringstream ss;
+        ss << path << level << ".vtk";
+
+        GridVTKWriter::writeGridToVTKXML(grids[level], ss.str());
+
+    }
+}
+
+GRIDGENERATOR_EXPORT void MultipleGridBuilder::setSubDomainBox(SPtr<BoundingBox> subDomainBox)
+{
+    this->subDomainBox = subDomainBox;
+}
+
diff --git a/src/gpu/GridGenerator/grid/GridBuilder/MultipleGridBuilder.h b/src/gpu/GridGenerator/grid/GridBuilder/MultipleGridBuilder.h
index df13fa31f14d88546df08e9b68549b82bed42bf3..839e0036bbc6b0f5d28bec5da3a0abe637b7adca 100644
--- a/src/gpu/GridGenerator/grid/GridBuilder/MultipleGridBuilder.h
+++ b/src/gpu/GridGenerator/grid/GridBuilder/MultipleGridBuilder.h
@@ -28,20 +28,20 @@
 //
 //! \file MultipleGridBuilder.h
 //! \ingroup grid
-//! \author Soeren Peters, Stephan Lenz
+//! \author Soeren Peters, Stephan Lenz, Martin Schoenherr
 //=======================================================================================
 #ifndef MULTIPLE_GRID_BUILDER_H
 #define MULTIPLE_GRID_BUILDER_H
 
 #include <vector>
 #include <array>
-
+#include "GridGenerator_export.h"
 #include "Core/LbmOrGks.h"
 
 #include "global.h"
 
 #include "grid/GridBuilder/LevelGridBuilder.h"
-#include "grid/GridFactory.h"
+#include "grid/distributions/Distribution.h"
 
 class Object;
 class BoundingBox;
@@ -49,12 +49,17 @@ class BoundingBox;
 class MultipleGridBuilder : public LevelGridBuilder
 {
 private:
-    GRIDGENERATOR_EXPORT MultipleGridBuilder(SPtr<GridFactory> gridFactory, Device device = Device::CPU, const std::string &d3qxx = "D3Q27");
+    GRIDGENERATOR_EXPORT MultipleGridBuilder();
 
 public:
-    GRIDGENERATOR_EXPORT static SPtr<MultipleGridBuilder> makeShared(SPtr<GridFactory> gridFactory);
+    GRIDGENERATOR_EXPORT static SPtr<MultipleGridBuilder> makeShared();
 
     GRIDGENERATOR_EXPORT void addCoarseGrid(real startX, real startY, real startZ, real endX, real endY, real endZ, real delta);
+    GRIDGENERATOR_EXPORT void addGrid(Object *gridShape);
+    GRIDGENERATOR_EXPORT void addGrid(Object *gridShape, uint levelFine);
+
+    GRIDGENERATOR_EXPORT void addGeometry(Object *gridShape);
+    GRIDGENERATOR_EXPORT void addGeometry(Object *solidObject, uint level);
 
     GRIDGENERATOR_EXPORT uint getNumberOfLevels() const;
     GRIDGENERATOR_EXPORT real getDelta(uint level) const;
@@ -72,21 +77,41 @@ public:
 
     GRIDGENERATOR_EXPORT void setNumberOfLayers( uint numberOfLayersFine, uint numberOfLayersBetweenLevels );
 
+    GRIDGENERATOR_EXPORT void writeGridsToVtk(const std::string &path) const;
+
+    GRIDGENERATOR_EXPORT void setSubDomainBox(SPtr<BoundingBox> subDomainBox);
 
 private:
     void addGridToList(SPtr<Grid> grid);
+    real calculateDelta(uint level) const;
     bool coarseGridExists() const;
+    bool isGridInCoarseGrid(SPtr<Grid> grid) const;
 
-    SPtr<Grid> makeGrid(Object* gridShape, real startX, real startY, real startZ, real endX, real endY, real endZ, real delta, uint level) const;
+    void addFineGridToList(uint level, Object *gridShape);
+    void addIntermediateGridsToList(uint levelDifference, uint levelFine, uint nodesBetweenGrids, Object *gridShape);
+    void eraseGridsFromListIfInvalid(uint oldSize);
+    void addGridToListIfValid(SPtr<Grid> grid);
 
+    std::array<real, 6> getStaggeredCoordinates(Object *gridShape, uint level, uint levelFine, bool &xOddStart, bool &yOddStart, bool &zOddStart) const;
+    std::array<real, 6> getStaggeredCoordinates(real startX, real startY, real startZ, real endX, real endY, real endZ, real delta, uint level) const;
+    std::array<real, 3> getOffset(real delta) const;
+    std::vector<uint> getSpacingFactors(uint levelDifference) const;
 
-    SPtr<GridFactory> gridFactory;
+    SPtr<Grid> makeGrid(Object *gridShape, uint level, uint levelFine);
+    SPtr<Grid> makeGrid(Object *gridShape, real startX, real startY, real startZ, real endX, real endY, real endZ, real delta, uint level) const;
+
+    static void emitNoCoarseGridExistsWarning();
+    static void emitGridIsNotInCoarseGridWarning();
+
+    Object *solidObject = nullptr;
 
     uint numberOfLayersFine;
     uint numberOfLayersBetweenLevels;
 
     SPtr<BoundingBox> subDomainBox;
 
+public:
+    GRIDGENERATOR_EXPORT void findCommunicationIndices(int direction, LbmOrGks lbmOrGks);
 };
 
 #endif
diff --git a/src/gpu/GridGenerator/grid/GridFactory.h b/src/gpu/GridGenerator/grid/GridFactory.h
index 9ebf1e3a13184a9b3aea75694c74e039fc987ad5..b525596fa670a026d60b1297c75ef69c46b23498 100644
--- a/src/gpu/GridGenerator/grid/GridFactory.h
+++ b/src/gpu/GridGenerator/grid/GridFactory.h
@@ -37,15 +37,8 @@
 
 #include "geometries/Cuboid/Cuboid.h"
 
-#include "grid/GridStrategy/GridCpuStrategy/GridCpuStrategy.h"
-#include "grid/distributions/Distribution.h"
 #include "grid/GridImp.h"
 
-enum class Device
-{
-    CPU, GPU
-};
-
 enum class TriangularMeshDiscretizationMethod
 {
     RAYCASTING, POINT_IN_OBJECT, POINT_UNDER_TRIANGLE
@@ -59,43 +52,10 @@ public:
         return SPtr<GridFactory>(new GridFactory());
     }
 
-private:
-    GridFactory()
-    {
-        gridStrategy = SPtr<GridStrategy>(new GridCpuStrategy());
-    }
-
-public:
     SPtr<Grid> makeGrid(Object* gridShape, real startX, real startY, real startZ, real endX, real endY, real endZ, real delta, uint level, const std::string& d3Qxx = "D3Q27")
     {
-        Distribution distribution = DistributionHelper::getDistribution(d3Qxx);
-
-        SPtr<GridImp> grid;
-
-        grid = GridImp::makeShared(gridShape, startX, startY, startZ, endX, endY, endZ, delta, gridStrategy, distribution, level);
-
-        return grid;
-    }
-
-
-    void setGridStrategy(Device device)
-    {
-        switch (device)
-        {
-        case Device::CPU:
-            gridStrategy = SPtr<GridStrategy>(new GridCpuStrategy()); break;
-        case Device::GPU:
-            throw std::runtime_error("GPU Device for GridGenerator not supported.");
-        }
+        return GridImp::makeShared(gridShape, startX, startY, startZ, endX, endY, endZ, delta, d3Qxx, level);
     }
-
-    void setGridStrategy(SPtr<GridStrategy> gridStrategy)
-    {
-        this->gridStrategy = gridStrategy;
-    }
-
-private:
-    SPtr<GridStrategy> gridStrategy;
 };
 
 
diff --git a/src/gpu/GridGenerator/grid/GridImp.cpp b/src/gpu/GridGenerator/grid/GridImp.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9b64d8260a69226a5481405b0f33f91de4dbf09d
--- /dev/null
+++ b/src/gpu/GridGenerator/grid/GridImp.cpp
@@ -0,0 +1,1983 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __         
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |        
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |        
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |        
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____    
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|   
+//      \    \  |    |   ________________________________________________________________    
+//       \    \ |    |  |  ______________________________________________________________|   
+//        \    \|    |  |  |         __          __     __     __     ______      _______    
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)   
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______    
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/   
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//  
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file GridImp.cpp
+//! \ingroup grid
+//! \author Soeren Peters, Stephan Lenz, Martin Schoenherr
+//=======================================================================================
+#include "GridImp.h"
+
+#include <stdio.h>
+#include <time.h>
+#include <iostream>
+#include <omp.h>
+#include <sstream>
+#include <cmath>
+
+#include "global.h"
+
+#include "geometries/Object.h"
+#include "geometries/Vertex/Vertex.h"
+#include "geometries/Triangle/Triangle.h"
+#include "geometries/TriangularMesh/TriangularMesh.h"
+#include "geometries/TriangularMesh/TriangularMeshStrategy.h"
+#include "geometries/BoundingBox/BoundingBox.h"
+
+#include "grid/distributions/Distribution.h"
+#include "grid/Field.h"
+#include "grid/GridInterface.h"
+#include "grid/NodeValues.h"
+
+#include "io/GridVTKWriter/GridVTKWriter.h"
+
+#include "utilities/communication.h"
+#include "utilities/math/Math.h"
+
+int DIRECTIONS[DIR_END_MAX][DIMENSION];
+
+using namespace vf::gpu;
+
+GridImp::GridImp(Object* object, real startX, real startY, real startZ, real endX, real endY, real endZ, real delta, Distribution distribution, uint level) 
+            : object(object), 
+    startX(startX),
+    startY(startY),
+    startZ(startZ),
+    endX(endX),
+    endY(endY),
+    endZ(endZ),
+    delta(delta),
+    distribution(distribution),
+    level(level),
+    periodicityX(false),
+    periodicityY(false),
+    periodicityZ(false),
+    enableFixRefinementIntoTheWall(false),
+    gridInterface(nullptr),
+    neighborIndexX(nullptr),
+    neighborIndexY(nullptr),
+    neighborIndexZ(nullptr),
+    neighborIndexNegative(nullptr),
+    sparseIndices(nullptr),
+    qIndices(nullptr),
+    qValues(nullptr),
+    qPatches(nullptr),
+    innerRegionFromFinerGrid(false),
+    numberOfLayers(0),
+    qComputationStage(qComputationStageType::ComputeQs)
+{
+    initalNumberOfNodesAndSize();
+}
+
+SPtr<GridImp> GridImp::makeShared(Object* object, real startX, real startY, real startZ, real endX, real endY, real endZ, real delta, std::string d3Qxx, uint level)
+{
+    Distribution distribution = DistributionHelper::getDistribution(d3Qxx);
+    SPtr<GridImp> grid(new GridImp(object, startX, startY, startZ, endX, endY, endZ, delta, distribution, level));
+    return grid;
+}
+
+
+void GridImp::initalNumberOfNodesAndSize()
+{
+    const real length = endX - startX;
+    const real width = endY - startY;
+    const real height = endZ - startZ;
+
+    nx = std::lround((length + delta) / delta);
+    ny = std::lround((width + delta) / delta);
+    nz = std::lround((height + delta) / delta);
+
+    this->size = nx * ny * nz;
+    this->sparseSize = size;
+    distribution.setSize(size);
+}
+
+void GridImp::inital(const SPtr<Grid> fineGrid, uint numberOfLayers)
+{
+    field = Field(size);
+    field.allocateMemory();
+
+    this->neighborIndexX        = new int[this->size];
+    this->neighborIndexY        = new int[this->size];
+    this->neighborIndexZ        = new int[this->size];
+    this->neighborIndexNegative = new int[this->size];
+
+    this->sparseIndices = new int[this->size];
+
+    this->qIndices = new uint[this->size];
+    for (uint i = 0; i < this->size; i++)
+        this->qIndices[i] = INVALID_INDEX;
+
+    *logging::out << logging::Logger::INFO_INTERMEDIATE << "Start initalNodesToOutOfGrid()\n";
+#pragma omp parallel for
+    for (int index = 0; index < (int)this->size; index++)
+        this->initalNodeToOutOfGrid(index);
+    
+    if( this->innerRegionFromFinerGrid ){
+        *logging::out << logging::Logger::INFO_INTERMEDIATE << "Start setInnerBasedOnFinerGrid()\n";
+        this->setInnerBasedOnFinerGrid(fineGrid);
+    }
+    else{
+        *logging::out << logging::Logger::INFO_INTERMEDIATE << "Start findInnerNodes()\n";
+        this->object->findInnerNodes( shared_from_this() );
+    }
+
+    *logging::out << logging::Logger::INFO_INTERMEDIATE << "Start addOverlap()\n";
+    this->addOverlap();
+    
+    *logging::out << logging::Logger::INFO_INTERMEDIATE << "Start fixOddCells()\n";
+#pragma omp parallel for
+    for (int index = 0; index < (int)this->size; index++)
+        this->fixOddCell(index);
+    
+    if( enableFixRefinementIntoTheWall )
+    {
+        *logging::out << logging::Logger::INFO_INTERMEDIATE << "Start fixRefinementIntoWall()\n";
+#pragma omp parallel for
+        for (int xIdx = 0; xIdx < (int)this->nx; xIdx++) {
+            for (uint yIdx = 0; yIdx < this->ny; yIdx++) {
+                this->fixRefinementIntoWall(xIdx, yIdx, 0, 3);
+                this->fixRefinementIntoWall(xIdx, yIdx, this->nz - 1, -3);
+            }
+        }
+
+#pragma omp parallel for
+        for (int xIdx = 0; xIdx < (int)this->nx; xIdx++) {
+            for (uint zIdx = 0; zIdx < this->nz; zIdx++) {
+                this->fixRefinementIntoWall(xIdx, 0, zIdx, 2);
+                this->fixRefinementIntoWall(xIdx, this->ny - 1, zIdx, -2);
+            }
+        }
+
+#pragma omp parallel for
+        for (int yIdx = 0; yIdx < (int)this->ny; yIdx++) {
+            for (uint zIdx = 0; zIdx < this->nz; zIdx++) {
+                this->fixRefinementIntoWall(0, yIdx, zIdx, 1);
+                this->fixRefinementIntoWall(this->nx - 1, yIdx, zIdx, -1);
+            }
+        }
+    }
+    
+    *logging::out << logging::Logger::INFO_INTERMEDIATE << "Start findEndOfGridStopperNodes()\n";
+#pragma omp parallel for
+    for (int index = 0; index < (int)this->size; index++)
+        this->findEndOfGridStopperNode(index);
+
+    *logging::out << logging::Logger::INFO_INTERMEDIATE
+        << "Grid created: " << "from (" << this->startX << ", " << this->startY << ", " << this->startZ << ") to (" << this->endX << ", " << this->endY << ", " << this->endZ << ")\n"
+        << "nodes: " << this->nx << " x " << this->ny << " x " << this->nz << " = " << this->size << "\n";
+}
+
+void GridImp::setOddStart(bool xOddStart, bool yOddStart, bool zOddStart)
+{
+    this->xOddStart = xOddStart;
+    this->yOddStart = yOddStart;
+    this->zOddStart = zOddStart;
+}
+
+void GridImp::initalNodeToOutOfGrid(uint index) {
+    this->field.setFieldEntryToInvalidOutOfGrid(index);
+}
+
+void GridImp::freeMemory()
+{
+    if( this->neighborIndexX        != nullptr ) { delete[] this->neighborIndexX;        this->neighborIndexX        = nullptr; }
+    if( this->neighborIndexY        != nullptr ) { delete[] this->neighborIndexY;        this->neighborIndexY        = nullptr; }
+    if( this->neighborIndexZ        != nullptr ) { delete[] this->neighborIndexZ;        this->neighborIndexZ        = nullptr; }
+    if( this->neighborIndexNegative != nullptr ) { delete[] this->neighborIndexNegative; this->neighborIndexNegative = nullptr; }
+    if( this->sparseIndices         != nullptr ) { delete[] this->sparseIndices;         this->sparseIndices         = nullptr; }
+	if( this->qIndices              != nullptr ) { delete[] this->qIndices;              this->qIndices              = nullptr; }
+	if( this->qValues               != nullptr ) { delete[] this->qValues;               this->qValues               = nullptr; }
+	if( this->qPatches              != nullptr ) { delete[] this->qPatches;              this->qPatches              = nullptr; }
+
+    field.freeMemory();
+}
+
+void GridImp::findInnerNodes()
+{
+#pragma omp parallel for
+    for (int index = 0; index < (int)this->size; index++)
+        this->findInnerNode(index);
+}
+
+void GridImp::findInnerNode(uint index)
+{
+    this->sparseIndices[index] = index;
+
+    if( this->level != 0 ){
+        const Cell cell = getOddCellFromIndex(index);
+        if (isInside(cell))
+            this->field.setFieldEntryToFluid(index);
+    }
+    else{
+        real x, y, z;
+        this->transIndexToCoords(index, x, y, z);
+        const uint xIndex = getXIndex(x);
+        const uint yIndex = getYIndex(y);
+        const uint zIndex = getZIndex(z);
+
+        if( xIndex != 0 && xIndex != this->nx-1 &&
+            yIndex != 0 && yIndex != this->ny-1 &&
+            zIndex != 0 && zIndex != this->nz-1 )
+            this->field.setFieldEntryToFluid(index);
+    }
+}
+
+void GridImp::discretize(Object* solidObject, char innerType, char outerType)
+{
+#pragma omp parallel for
+    for (int index = 0; index < (int)this->size; index++)
+    {
+        this->sparseIndices[index] = index;
+
+        if( this->getFieldEntry(index) == innerType ) continue;
+        
+        real x, y, z;
+        this->transIndexToCoords(index, x, y, z);
+
+        if( solidObject->isPointInObject(x, y, z, 0.0, 0.0) )
+            this->setFieldEntry(index, innerType);
+        //else
+        //    this->setFieldEntry(index, outerType);
+    }
+}
+
+bool GridImp::isInside(const Cell& cell) const
+{
+    return object->isCellInObject(cell);
+}
+
+////TODO: check where the fine grid starts (0.25 or 0.75) and if even or odd-cell is needed
+// Cell numbering:
+//       even start                            odd start
+//    +---------+                           +---------+
+//    |       +-----+-----+-----+           | +-----+-----+-----+
+//    |       | |   |     |     |           | |     | |   |     |
+//    |       +-----+-----+-----+           | +-----+-----+-----+
+//    +---------+                           +---------+
+//               0     1     2                   0     1     2
+//              even      even                        even     
+//                   odd                        odd         odd
+//
+Cell GridImp::getOddCellFromIndex(uint index) const
+{
+    real x, y, z;
+    this->transIndexToCoords(index, x, y, z);
+
+    const uint xIndex = getXIndex(x);
+    const uint yIndex = getYIndex(y);
+    const uint zIndex = getZIndex(z);
+
+    real xCellStart;
+    if( this->xOddStart ) xCellStart = xIndex % 2 != 0 ? x - this->delta : x;
+    else                  xCellStart = xIndex % 2 != 0 ? x               : x - this->delta;
+
+    real yCellStart;
+    if( this->yOddStart ) yCellStart = yIndex % 2 != 0 ? y - this->delta : y;
+    else                  yCellStart = yIndex % 2 != 0 ? y               : y - this->delta;
+
+    real zCellStart;
+    if( this->zOddStart ) zCellStart = zIndex % 2 != 0 ? z - this->delta : z;
+    else                  zCellStart = zIndex % 2 != 0 ? z               : z - this->delta;
+
+    return Cell(xCellStart, yCellStart, zCellStart, delta);
+}
+
+void GridImp::setInnerBasedOnFinerGrid(const SPtr<Grid> fineGrid)
+{
+    for( uint index = 0; index < this->size; index++ ){
+
+        real x, y, z;
+        this->transIndexToCoords(index, x, y, z);
+
+        uint childIndex[8];
+
+        childIndex[0] = fineGrid->transCoordToIndex( x + 0.25 * this->delta, y + 0.25 * this->delta, z + 0.25 * this->delta );
+        childIndex[1] = fineGrid->transCoordToIndex( x + 0.25 * this->delta, y + 0.25 * this->delta, z - 0.25 * this->delta );
+        childIndex[2] = fineGrid->transCoordToIndex( x + 0.25 * this->delta, y - 0.25 * this->delta, z + 0.25 * this->delta );
+        childIndex[3] = fineGrid->transCoordToIndex( x + 0.25 * this->delta, y - 0.25 * this->delta, z - 0.25 * this->delta );
+        childIndex[4] = fineGrid->transCoordToIndex( x - 0.25 * this->delta, y + 0.25 * this->delta, z + 0.25 * this->delta );
+        childIndex[5] = fineGrid->transCoordToIndex( x - 0.25 * this->delta, y + 0.25 * this->delta, z - 0.25 * this->delta );
+        childIndex[6] = fineGrid->transCoordToIndex( x - 0.25 * this->delta, y - 0.25 * this->delta, z + 0.25 * this->delta );
+        childIndex[7] = fineGrid->transCoordToIndex( x - 0.25 * this->delta, y - 0.25 * this->delta, z - 0.25 * this->delta );
+
+        for( uint i = 0; i < 8; i++ ){
+            if( childIndex[i] != INVALID_INDEX && fineGrid->getFieldEntry( childIndex[i] ) == FLUID ){
+                this->setFieldEntry(index, FLUID);
+                break;
+            }
+        }
+    }
+}
+
+void GridImp::addOverlap()
+{
+    for( uint layer = 0; layer < this->numberOfLayers; layer++ ){
+#pragma omp parallel for
+        for (int index = 0; index < (int)this->size; index++)
+            this->setOverlapTmp(index);
+
+#pragma omp parallel for
+        for (int index = 0; index < (int)this->size; index++)
+            this->setOverlapFluid(index);
+    }
+}
+
+void GridImp::setOverlapTmp( uint index )
+{
+    if( this->field.is( index, INVALID_OUT_OF_GRID ) ){
+        
+        if( this->hasNeighborOfType(index, FLUID) ){
+            this->field.setFieldEntry( index, OVERLAP_TMP );
+        }
+    }
+}
+
+void GridImp::setOverlapFluid( uint index )
+{
+    if( this->field.is( index, OVERLAP_TMP ) ){
+        this->field.setFieldEntry( index, FLUID );
+    }
+}
+
+void GridImp::fixRefinementIntoWall(uint xIndex, uint yIndex, uint zIndex, int dir)
+{
+
+    real x = this->startX + this->delta * xIndex;
+    real y = this->startY + this->delta * yIndex;
+    real z = this->startZ + this->delta * zIndex;
+
+    uint index = this->transCoordToIndex(x, y, z);
+
+    if( !this->xOddStart && ( dir == 1 || dir == -1 ) && ( xIndex % 2 == 1 || xIndex == 0 ) ) return;
+    if( !this->yOddStart && ( dir == 2 || dir == -2 ) && ( yIndex % 2 == 1 || yIndex == 0 ) ) return;
+    if( !this->zOddStart && ( dir == 3 || dir == -3 ) && ( zIndex % 2 == 1 || zIndex == 0 ) ) return;
+
+    // Dont do this if inside of the domain
+    if(  this->xOddStart && ( dir == 1 || dir == -1 ) && ( xIndex % 2 == 0 && xIndex != 0 ) ) return;
+    if(  this->yOddStart && ( dir == 2 || dir == -2 ) && ( yIndex % 2 == 0 && yIndex != 0 ) ) return;
+    if(  this->zOddStart && ( dir == 3 || dir == -3 ) && ( zIndex % 2 == 0 && zIndex != 0 ) ) return;
+    
+    //////////////////////////////////////////////////////////////////////////
+
+    real dx{ 0.0 }, dy{ 0.0 }, dz{ 0.0 };
+
+    if      ( dir ==  1 ){ dx =   this->delta; dy = 0.0;           dz = 0.0;           }
+    else if ( dir == -1 ){ dx = - this->delta; dy = 0.0;           dz = 0.0;           }
+    else if ( dir ==  2 ){ dx = 0.0;           dy =   this->delta; dz = 0.0;           }
+    else if ( dir == -2 ){ dx = 0.0;           dy = - this->delta; dz = 0.0;           }
+    else if ( dir ==  3 ){ dx = 0.0;           dy = 0.0;           dz =   this->delta; }
+    else if ( dir == -3 ){ dx = 0.0;           dy = 0.0;           dz = - this->delta; }
+
+    //////////////////////////////////////////////////////////////////////////
+
+    char type = this->field.getFieldEntry(index);
+
+    char type2    = ( type == FLUID ) ? ( INVALID_OUT_OF_GRID ) : ( FLUID );
+    uint distance = ( type == FLUID ) ? ( 9                   ) : ( 5     );
+
+    bool allTypesAreTheSame = true;
+
+    for( uint i = 1; i <= distance; i++ ){
+        uint neighborIndex = this->transCoordToIndex(x + i * dx, y + i * dy, z + i * dz);
+
+        if( neighborIndex != INVALID_INDEX && !this->field.is( neighborIndex, type ) )
+            allTypesAreTheSame = false;
+    }
+
+    //////////////////////////////////////////////////////////////////////////
+
+    if( allTypesAreTheSame )
+        return;
+
+    this->setFieldEntry(index, type2);
+
+    for( uint i = 1; i <= distance; i++ ){
+        uint neighborIndex = this->transCoordToIndex(x + i * dx, y + i * dy, z + i * dz);
+
+        this->setFieldEntry(neighborIndex, type2);
+    }
+}
+
+void GridImp::findStopperNode(uint index) // deprecated
+{
+    if(isValidEndOfGridStopper(index))
+        this->field.setFieldEntryToStopperOutOfGrid(index);
+
+    if (isValidSolidStopper(index))
+        this->field.setFieldEntry(index, STOPPER_SOLID);
+}
+
+void GridImp::findEndOfGridStopperNode(uint index)
+{
+	if (isValidEndOfGridStopper(index)){
+        if( this->level != 0 )
+		    this->field.setFieldEntryToStopperOutOfGrid(index);
+        else
+            this->field.setFieldEntryToStopperOutOfGridBoundary(index);
+    }
+
+	if (isValidEndOfGridBoundaryStopper(index))
+		this->field.setFieldEntryToStopperOutOfGridBoundary(index);
+}
+
+void GridImp::findSolidStopperNode(uint index)
+{
+	if (isValidSolidStopper(index))
+		this->field.setFieldEntry(index, STOPPER_SOLID);
+}
+
+void GridImp::findBoundarySolidNode(uint index)
+{
+	if (shouldBeBoundarySolidNode(index)) 
+	{
+		this->field.setFieldEntry(index, BC_SOLID);
+		this->qIndices[index] = this->numberOfSolidBoundaryNodes++;
+		//grid->setNumberOfSolidBoundaryNodes(grid->getNumberOfSolidBoundaryNodes() + 1);
+	}
+}
+
+void GridImp::fixOddCell(uint index)
+{
+    Cell cell = getOddCellFromIndex(index);
+    if (isOutSideOfGrid(cell))
+        return;
+    if (contains(cell, FLUID))
+        setNodeTo(cell, FLUID);
+}
+
+bool GridImp::isOutSideOfGrid(Cell &cell) const
+{
+    for (const auto point : cell) {
+        if (point.x < startX || point.x > endX
+            || point.y < startY || point.y > endY
+            || point.z < startZ || point.z > endZ)
+            return true;
+    }
+    return false;
+}
+
+bool GridImp::contains(Cell &cell, char type) const
+{
+    for (const auto point : cell) {
+		uint index = transCoordToIndex(point.x, point.y, point.z);
+		if (index == INVALID_INDEX)
+			continue;
+        if (field.is(index, type))
+            return true;
+    }
+    return false;
+}
+
+bool GridImp::cellContainsOnly(Cell &cell, char type) const
+{
+    for (const auto point : cell) {
+		uint index = transCoordToIndex(point.x, point.y, point.z);
+		if (index == INVALID_INDEX)
+            return false;
+        if (!field.is(index, type))
+            return false;
+    }
+    return true;
+}
+
+bool GridImp::cellContainsOnly(Cell &cell, char typeA, char typeB) const
+{
+    for (const auto point : cell) {
+		uint index = transCoordToIndex(point.x, point.y, point.z);
+		if (index == INVALID_INDEX)
+            return false;
+        if (!field.is(index, typeA) && !field.is(index, typeB))
+            return false;
+    }
+    return true;
+}
+
+const Object * GridImp::getObject() const
+{
+    return this->object;
+}
+
+void GridImp::setNodeTo(Cell &cell, char type)
+{
+    for (const auto point : cell) {
+		uint index = transCoordToIndex(point.x, point.y, point.z);
+		if (index == INVALID_INDEX)
+			continue;
+		field.setFieldEntry(index, type);
+    }
+}
+
+void GridImp::setNodeTo(uint index, char type)
+{
+	if( index != INVALID_INDEX )
+		field.setFieldEntry(index, type);
+}
+
+bool GridImp::isNode(uint index, char type) const
+{
+    if( index != INVALID_INDEX )
+		return field.is(index, type);
+
+    throw std::runtime_error("GridImp::isNode() -> index == INVALID_INDEX not supported.");
+}
+
+bool GridImp::isValidEndOfGridStopper(uint index) const
+{
+	// Lenz: also includes corner stopper nodes
+	if (!this->field.is(index, INVALID_OUT_OF_GRID))
+		return false;
+
+	return hasNeighborOfType(index, FLUID);
+}
+
+bool GridImp::isValidEndOfGridBoundaryStopper(uint index) const
+{
+	// Lenz: also includes corner stopper nodes
+	if (!this->field.is(index, FLUID))
+		return false;
+
+	return ! hasAllNeighbors(index);
+}
+
+bool GridImp::isValidSolidStopper(uint index) const
+{
+	// Lenz: also includes corner stopper nodes
+	if (!this->field.is(index, INVALID_SOLID))
+		return false;
+
+	return hasNeighborOfType(index, FLUID);
+}
+
+bool GridImp::shouldBeBoundarySolidNode(uint index) const
+{
+	if (!this->field.is(index, FLUID))
+		return false;
+
+	return hasNeighborOfType(index, STOPPER_SOLID);
+}
+
+bool GridImp::hasAllNeighbors(uint index) const
+{
+	// new version by Lenz, utilizes the range based for loop for all directions
+	real x, y, z;
+	this->transIndexToCoords(index, x, y, z);
+	for (const auto dir : this->distribution) {
+		const uint neighborIndex = this->transCoordToIndex(x + dir[0] * this->getDelta(), y + dir[1] * this->getDelta(), z + dir[2] * this->getDelta());
+
+		if (neighborIndex == INVALID_INDEX) return false;
+	}
+
+	return true;
+}
+
+bool GridImp::hasNeighborOfType(uint index, char type) const
+{
+	// new version by Lenz, utilizes the range based for loop for all directions
+	real x, y, z;
+	this->transIndexToCoords(index, x, y, z);
+	for (const auto dir : this->distribution) {
+		const uint neighborIndex = this->transCoordToIndex(x + dir[0] * this->getDelta(), y + dir[1] * this->getDelta(), z + dir[2] * this->getDelta());
+
+		if (neighborIndex == INVALID_INDEX) continue;
+
+		if (this->field.is(neighborIndex, type))
+			return true;
+	}
+
+	return false;
+}
+
+bool GridImp::nodeInNextCellIs(int index, char type) const
+{
+    real x, y, z;
+    this->transIndexToCoords(index, x, y, z);
+
+    const real neighborX = x + this->delta > endX ? endX : x + this->delta;
+    const real neighborY = y + this->delta > endY ? endY : y + this->delta;
+    const real neighborZ = z + this->delta > endZ ? endZ : z + this->delta;
+
+    const uint indexX = transCoordToIndex(neighborX, y, z);
+    const uint indexY = transCoordToIndex(x, neighborY, z);
+    const uint indexZ = transCoordToIndex(x, y, neighborZ);
+
+    const uint indexXY = transCoordToIndex(neighborX, neighborY, z);
+    const uint indexYZ = transCoordToIndex(x, neighborY, neighborZ);
+    const uint indexXZ = transCoordToIndex(neighborX, y, neighborZ);
+
+    const uint indexXYZ = transCoordToIndex(neighborX, neighborY, neighborZ);
+
+	const bool typeX   = indexX   == INVALID_INDEX ? false : this->field.is(indexX, type);
+	const bool typeY   = indexY   == INVALID_INDEX ? false : this->field.is(indexY, type);
+	const bool typeXY  = indexXY  == INVALID_INDEX ? false : this->field.is(indexXY, type);
+	const bool typeZ   = indexZ   == INVALID_INDEX ? false : this->field.is(indexZ, type);
+	const bool typeYZ  = indexYZ  == INVALID_INDEX ? false : this->field.is(indexYZ, type);
+	const bool typeXZ  = indexXZ  == INVALID_INDEX ? false : this->field.is(indexXZ, type);
+	const bool typeXYZ = indexXYZ == INVALID_INDEX ? false : this->field.is(indexXYZ, type);
+
+    return typeX || typeY || typeXY || typeZ || typeYZ
+        || typeXZ || typeXYZ;
+}
+
+bool GridImp::nodeInPreviousCellIs(int index, char type) const
+{
+    real x, y, z;
+    this->transIndexToCoords(index, x, y, z);
+
+    const real neighborX = x - this->delta < startX ? startX : x - this->delta;
+    const real neighborY = y - this->delta < startY ? startY : y - this->delta;
+    const real neighborZ = z - this->delta < startZ ? startZ : z - this->delta;
+
+    const uint indexX = transCoordToIndex(neighborX, y, z);
+    const uint indexY = transCoordToIndex(x, neighborY, z);
+    const uint indexZ = transCoordToIndex(x, y, neighborZ);
+
+    const uint indexXY = transCoordToIndex(neighborX, neighborY, z);
+    const uint indexYZ = transCoordToIndex(x, neighborY, neighborZ);
+    const uint indexXZ = transCoordToIndex(neighborX, y, neighborZ);
+
+    const uint indexXYZ = transCoordToIndex(neighborX, neighborY, neighborZ);
+
+	const bool typeX   = indexX   == INVALID_INDEX ? false : this->field.is(indexX  , type);
+	const bool typeY   = indexY   == INVALID_INDEX ? false : this->field.is(indexY  , type);
+	const bool typeXY  = indexXY  == INVALID_INDEX ? false : this->field.is(indexXY , type);
+	const bool typeZ   = indexZ   == INVALID_INDEX ? false : this->field.is(indexZ  , type);
+	const bool typeYZ  = indexYZ  == INVALID_INDEX ? false : this->field.is(indexYZ , type);
+	const bool typeXZ  = indexXZ  == INVALID_INDEX ? false : this->field.is(indexXZ , type);
+	const bool typeXYZ = indexXYZ == INVALID_INDEX ? false : this->field.is(indexXYZ, type);
+
+    return typeX || typeY || typeXY || typeZ || typeYZ
+        || typeXZ || typeXYZ;
+}
+
+bool GridImp::nodeInCellIs(Cell& cell, char type) const
+{
+    for (const auto node : cell)
+    {
+        const uint index = transCoordToIndex(node.x, node.y, node.z);
+		if (index == INVALID_INDEX)
+			continue;
+        if (field.is(index, type))
+            return true;
+    }
+    return false;
+}
+
+
+void GridImp::setCellTo(uint index, char type)
+{
+    real x, y, z;
+    this->transIndexToCoords(index, x, y, z);
+
+    Cell cell(x, y, z, this->delta);
+    for (const auto node : cell)
+    {
+        const uint nodeIndex = transCoordToIndex(node.x, node.y, node.z);
+		if (nodeIndex == INVALID_INDEX)
+			continue;
+		this->field.setFieldEntry(nodeIndex, type);
+    }
+}
+
+
+void GridImp::setNonStopperOutOfGridCellTo(uint index, char type)
+{
+    real x, y, z;
+    this->transIndexToCoords(index, x, y, z);
+
+    Cell cell(x, y, z, this->delta);
+    for (const auto node : cell)
+    {
+        const uint nodeIndex = transCoordToIndex(node.x, node.y, node.z);
+		if (nodeIndex == INVALID_INDEX)
+			continue;
+
+        if( this->getFieldEntry( nodeIndex ) != STOPPER_OUT_OF_GRID && 
+            this->getFieldEntry( nodeIndex ) != STOPPER_OUT_OF_GRID_BOUNDARY )
+            this->field.setFieldEntry(nodeIndex, type);
+    }
+}
+
+
+void GridImp::setPeriodicity(bool periodicityX, bool periodicityY, bool periodicityZ)
+{
+    this->periodicityX = periodicityX;
+    this->periodicityY = periodicityY;
+    this->periodicityZ = periodicityZ;
+}
+
+void GridImp::setPeriodicityX(bool periodicity)
+{
+    this->periodicityX = periodicity;
+}
+
+void GridImp::setPeriodicityY(bool periodicity)
+{
+    this->periodicityY = periodicity;
+}
+
+void GridImp::setPeriodicityZ(bool periodicity)
+{
+    this->periodicityZ = periodicity;
+}
+
+bool GridImp::getPeriodicityX()
+{
+    return this->periodicityX;
+}
+
+bool GridImp::getPeriodicityY()
+{
+    return this->periodicityY;
+}
+
+bool GridImp::getPeriodicityZ()
+{
+    return this->periodicityZ;
+}
+
+void GridImp::setEnableFixRefinementIntoTheWall(bool enableFixRefinementIntoTheWall)
+{
+    this->enableFixRefinementIntoTheWall = enableFixRefinementIntoTheWall;
+}
+
+uint GridImp::transCoordToIndex(const real &x, const real &y, const real &z) const
+{
+    const uint xIndex = getXIndex(x);
+    const uint yIndex = getYIndex(y);
+    const uint zIndex = getZIndex(z);
+
+	if (xIndex >= nx || yIndex >= ny || zIndex >= nz)
+        return INVALID_INDEX;
+
+    return xIndex + nx * (yIndex + ny * zIndex);
+}
+
+void GridImp::transIndexToCoords(uint index, real &x, real &y, real &z) const
+{
+    if (index == INVALID_INDEX)
+        printf("Function: transIndexToCoords. GridImp Index: %d, size: %d. Exit Program!\n", index, size);
+
+    x = (real)(index % nx);
+    y = (real)((index / nx) % ny);
+    z = (real)(((index / nx) / ny) % nz);
+
+    x = (x * delta) + startX;
+    y = (y * delta) + startY;
+    z = (z * delta) + startZ;
+}
+
+uint GridImp::getLevel(real startDelta) const
+{
+    uint level = 0;
+    real delta = this->delta;
+    while(!vf::Math::equal(delta, startDelta))
+    {
+        delta *= 2;
+        level++;
+    }
+    return level;
+}
+
+uint GridImp::getLevel() const
+{
+    return this->level;
+}
+
+void GridImp::setTriangularMeshDiscretizationStrategy(TriangularMeshDiscretizationStrategy* triangularMeshDiscretizationStrategy)
+{
+    this->triangularMeshDiscretizationStrategy = triangularMeshDiscretizationStrategy;
+}
+
+TriangularMeshDiscretizationStrategy * GridImp::getTriangularMeshDiscretizationStrategy()
+{
+    return this->triangularMeshDiscretizationStrategy;
+}
+
+uint GridImp::getNumberOfSolidBoundaryNodes() const
+{
+	return this->numberOfSolidBoundaryNodes;
+}
+
+void GridImp::setNumberOfSolidBoundaryNodes(uint numberOfSolidBoundaryNodes)
+{
+	if (numberOfSolidBoundaryNodes < INVALID_INDEX)
+		this->numberOfSolidBoundaryNodes = numberOfSolidBoundaryNodes;
+}
+
+real GridImp::getQValue(const uint index, const uint dir) const
+{
+	const int qIndex = dir * this->numberOfSolidBoundaryNodes + this->qIndices[index];
+
+	return this->qValues[qIndex];
+}
+
+uint GridImp::getQPatch(const uint index) const
+{
+    return this->qPatches[ this->qIndices[index] ];
+}
+
+void GridImp::setInnerRegionFromFinerGrid(bool innerRegionFromFinerGrid)
+{
+   this->innerRegionFromFinerGrid = innerRegionFromFinerGrid;
+}
+
+void GridImp::setNumberOfLayers(uint numberOfLayers)
+{
+    this->numberOfLayers = numberOfLayers;
+}
+
+// --------------------------------------------------------- //
+//                  Set Sparse Indices                       //
+// --------------------------------------------------------- //
+
+void GridImp::findSparseIndices(SPtr<Grid> finerGrid)
+{
+    *logging::out << logging::Logger::INFO_INTERMEDIATE << "Find sparse indices...";
+    auto fineGrid = std::static_pointer_cast<GridImp>(finerGrid);
+    
+    this->updateSparseIndices();
+
+#pragma omp parallel for
+    for (int index = 0; index < (int)this->getSize(); index++)
+        this->setNeighborIndices(index);
+
+    if (fineGrid) {
+        fineGrid->updateSparseIndices();
+    }
+
+    const uint newGridSize = this->getSparseSize();
+    *logging::out << logging::Logger::INFO_INTERMEDIATE << "... done. new size: " << newGridSize
+                  << ", delete nodes:" << this->getSize() - newGridSize << "\n";
+}
+
+
+void GridImp::updateSparseIndices()
+{
+    int removedNodes = 0;
+    int newIndex = 0;
+    for (uint index = 0; index < size; index++)
+    {
+        if (this->field.isInvalidCoarseUnderFine(index) || this->field.isInvalidOutOfGrid(index) || this->field.isInvalidSolid(index))
+        {
+            sparseIndices[index] = -1;
+            removedNodes++;
+        }
+        else
+        {
+            sparseIndices[index] = newIndex;
+            newIndex++;
+        }
+    }
+    sparseSize = size - removedNodes;
+}
+
+void GridImp::setNeighborIndices(uint index)
+{
+    real x, y, z;
+    this->transIndexToCoords(index, x, y, z);
+
+    this->neighborIndexX[index]        = -1;
+    this->neighborIndexY[index]        = -1;
+    this->neighborIndexZ[index]        = -1;
+    this->neighborIndexNegative[index] = -1;
+
+    if (this->field.isStopper(index) || this->field.is(index, STOPPER_OUT_OF_GRID_BOUNDARY))
+    {
+        this->setStopperNeighborCoords(index);
+        return;
+    }
+     
+    if (this->sparseIndices[index] == -1)
+        return;
+
+
+    real neighborXCoord, neighborYCoord, neighborZCoord;
+    this->getNeighborCoords(neighborXCoord, neighborYCoord, neighborZCoord, x, y, z);
+    const int neighborX = getSparseIndex(neighborXCoord, y, z);
+    const int neighborY = getSparseIndex(x, neighborYCoord, z);
+    const int neighborZ = getSparseIndex(x, y, neighborZCoord);
+
+    this->getNegativeNeighborCoords(neighborXCoord, neighborYCoord, neighborZCoord, x, y, z);
+    const int neighborNegative = getSparseIndex(neighborXCoord, neighborYCoord, neighborZCoord);
+
+    this->neighborIndexX[index]        = neighborX;
+    this->neighborIndexY[index]        = neighborY;
+    this->neighborIndexZ[index]        = neighborZ;
+    this->neighborIndexNegative[index] = neighborNegative;
+}
+
+void GridImp::setStopperNeighborCoords(uint index)
+{
+    real x, y, z;
+    this->transIndexToCoords(index, x, y, z);
+
+    if (vf::Math::lessEqual(x + delta, endX) && !this->field.isInvalidOutOfGrid(this->transCoordToIndex(x + delta, y, z)))
+        neighborIndexX[index] = getSparseIndex(x + delta, y, z);
+
+    if (vf::Math::lessEqual(y + delta, endY) && !this->field.isInvalidOutOfGrid(this->transCoordToIndex(x, y + delta, z)))
+        neighborIndexY[index] = getSparseIndex(x, y + delta, z);
+
+    if (vf::Math::lessEqual(z + delta, endZ) && !this->field.isInvalidOutOfGrid(this->transCoordToIndex(x, y, z + delta)))
+        neighborIndexZ[index] = getSparseIndex(x, y, z + delta);
+
+    if (vf::Math::greaterEqual(x - delta, endX) && 
+        vf::Math::greaterEqual(y - delta, endY) && 
+        vf::Math::greaterEqual(z - delta, endZ) && 
+        !this->field.isInvalidOutOfGrid(this->transCoordToIndex(x - delta, y - delta, z - delta)))
+    {
+        neighborIndexNegative[index] = getSparseIndex(x - delta, y - delta, z - delta);
+    }
+}
+
+void GridImp::getNeighborCoords(real &neighborX, real &neighborY, real &neighborZ, real x, real y, real z) const
+{
+    real coords[3] = { x, y, z };
+    neighborX = getNeighborCoord(periodicityX, startX, coords, 0);
+    neighborY = getNeighborCoord(periodicityY, startY, coords, 1);
+    neighborZ = getNeighborCoord(periodicityZ, startZ, coords, 2);
+}
+
+real GridImp::getNeighborCoord(bool periodicity, real startCoord, real coords[3], int direction) const
+{
+    if (periodicity)
+    {
+        real neighborCoords[3] = {coords[0], coords[1] , coords[2] };
+        neighborCoords[direction] = neighborCoords[direction] + delta;
+        const int neighborIndex = this->transCoordToIndex(neighborCoords[0], neighborCoords[1], neighborCoords[2]);
+
+        //////////////////////////////////////////////////////////////////////////
+
+        if( field.is(neighborIndex, STOPPER_OUT_OF_GRID_BOUNDARY) )
+            return getFirstFluidNode(coords, direction, startCoord);
+        else
+            return coords[direction] + delta;
+
+    }
+    
+    return coords[direction] + delta;
+}
+
+void GridImp::getNegativeNeighborCoords(real &neighborX, real &neighborY, real &neighborZ, real x, real y, real z) const
+{
+    real coords[3] = { x, y, z };
+
+    neighborX = getNegativeNeighborCoord(periodicityX, endX, coords, 0);
+    neighborY = getNegativeNeighborCoord(periodicityY, endY, coords, 1);
+    neighborZ = getNegativeNeighborCoord(periodicityZ, endZ, coords, 2);
+}
+
+real GridImp::getNegativeNeighborCoord(bool periodicity, real startCoord, real coords[3], int direction) const
+{
+    if (periodicity)
+    {
+        real neighborCoords[3] = {coords[0], coords[1] , coords[2] };
+        neighborCoords[direction] = neighborCoords[direction] - delta;
+        const uint neighborIndex = this->transCoordToIndex(neighborCoords[0], neighborCoords[1], neighborCoords[2]);
+
+        if(neighborIndex != INVALID_INDEX && !field.isStopperOutOfGrid(neighborIndex) && !field.is(neighborIndex, STOPPER_OUT_OF_GRID_BOUNDARY) )
+            return coords[direction] - delta;
+
+        return getLastFluidNode(coords, direction, startCoord);
+    }
+    
+    return coords[direction] - delta;
+}
+
+
+real GridImp::getLastFluidNode(real coords[3], int direction, real startCoord) const
+{
+    coords[direction] = startCoord;
+    uint index = this->transCoordToIndex(coords[0], coords[1], coords[2]);
+    while (index != INVALID_INDEX && !field.isFluid(index))
+    {
+        coords[direction] -= delta;
+        index = this->transCoordToIndex(coords[0], coords[1], coords[2]);
+    }
+    return coords[direction];
+}
+
+real GridImp::getFirstFluidNode(real coords[3], int direction, real startCoord) const
+{
+    coords[direction] = startCoord;
+    uint index = this->transCoordToIndex(coords[0], coords[1], coords[2]);
+    while (!field.isFluid(index))
+    {
+        coords[direction] += delta;
+        index = this->transCoordToIndex(coords[0], coords[1], coords[2]);
+    }
+    return coords[direction];
+}
+
+
+int GridImp::getSparseIndex(const real &x, const real &y, const real &z) const
+{
+    const int matrixIndex = transCoordToIndex(x, y, z);
+    return sparseIndices[matrixIndex];
+}
+
+// --------------------------------------------------------- //
+//                    Find Interface                         //
+// --------------------------------------------------------- //
+void GridImp::findGridInterface(SPtr<Grid> finerGrid, LbmOrGks lbmOrGks)
+{
+    auto fineGrid          = std::static_pointer_cast<GridImp>(finerGrid);
+    const auto coarseLevel = this->getLevel();
+    const auto fineLevel   = fineGrid->getLevel();
+
+    *logging::out << logging::Logger::INFO_INTERMEDIATE << "find interface level " << coarseLevel << " -> "
+                  << fineLevel;
+
+    this->gridInterface = new GridInterface();
+    // TODO: this is stupid! concave refinements can easily have many more interface cells
+    const uint sizeCF = 10 * (fineGrid->nx * fineGrid->ny + fineGrid->ny * fineGrid->nz + fineGrid->nx * fineGrid->nz);
+    this->gridInterface->cf.coarse = new uint[sizeCF];
+    this->gridInterface->cf.fine   = new uint[sizeCF];
+    this->gridInterface->cf.offset = new uint[sizeCF];
+    this->gridInterface->fc.coarse = new uint[sizeCF];
+    this->gridInterface->fc.fine   = new uint[sizeCF];
+    this->gridInterface->fc.offset = new uint[sizeCF];
+
+    for (uint index = 0; index < this->getSize(); index++)
+        this->findGridInterfaceCF(index, *fineGrid, lbmOrGks);
+
+    for (uint index = 0; index < this->getSize(); index++)
+        this->findGridInterfaceFC(index, *fineGrid);
+
+    for (uint index = 0; index < this->getSize(); index++)
+        this->findOverlapStopper(index, *fineGrid);
+
+    if (lbmOrGks == GKS) {
+        for (uint index = 0; index < this->getSize(); index++)
+            this->findInvalidBoundaryNodes(index);
+    }
+
+    *logging::out << logging::Logger::INFO_INTERMEDIATE << "  ... done. \n";
+}
+
+void GridImp::repairGridInterfaceOnMultiGPU(SPtr<Grid> fineGrid)
+{
+    this->gridInterface->repairGridInterfaceOnMultiGPU( shared_from_this(), std::static_pointer_cast<GridImp>(fineGrid) );
+}
+
+void GridImp::limitToSubDomain(SPtr<BoundingBox> subDomainBox, LbmOrGks lbmOrGks)
+{
+    for( uint index = 0; index < this->size; index++ ){
+
+        real x, y, z;
+        this->transIndexToCoords( index, x, y, z );
+
+        {
+            BoundingBox tmpSubDomainBox = *subDomainBox;
+
+            // one layer for receive nodes and one for stoppers
+            if( lbmOrGks == LBM )
+                tmpSubDomainBox.extend(this->delta);
+
+            if (!tmpSubDomainBox.isInside(x, y, z) 
+                && ( this->getFieldEntry(index) == FLUID ||
+                     this->getFieldEntry(index) == FLUID_CFC ||
+                     this->getFieldEntry(index) == FLUID_CFF ||
+                     this->getFieldEntry(index) == FLUID_FCC ||
+                     this->getFieldEntry(index) == FLUID_FCF ||
+                     this->getFieldEntry(index) == BC_SOLID ) )
+            {
+                this->setFieldEntry(index, STOPPER_OUT_OF_GRID_BOUNDARY);
+            }
+        }
+
+        {
+            BoundingBox tmpSubDomainBox = *subDomainBox;
+
+            // one layer for receive nodes and one for stoppers
+            if( lbmOrGks == LBM )
+                tmpSubDomainBox.extend(2.0 * this->delta);
+            else
+                tmpSubDomainBox.extend(1.0 * this->delta);
+
+            if (!tmpSubDomainBox.isInside(x, y, z))
+                this->setFieldEntry(index, INVALID_OUT_OF_GRID);
+        }
+    }
+}
+
+void GridImp::findGridInterfaceCF(uint index, GridImp& finerGrid, LbmOrGks lbmOrGks)
+{
+	if (lbmOrGks == LBM)
+	{
+		gridInterface->findInterfaceCF            (index, this, &finerGrid);
+		gridInterface->findBoundaryGridInterfaceCF(index, this, &finerGrid);
+	}
+	else if (lbmOrGks == GKS)
+		gridInterface->findInterfaceCF_GKS(index, this, &finerGrid);
+}
+
+void GridImp::findGridInterfaceFC(uint index, GridImp& finerGrid)
+{
+    gridInterface->findInterfaceFC(index, this, &finerGrid);
+}
+
+void GridImp::findOverlapStopper(uint index, GridImp& finerGrid)
+{
+    gridInterface->findOverlapStopper(index, this, &finerGrid);
+}
+
+void GridImp::findInvalidBoundaryNodes(uint index)
+{
+    gridInterface->findInvalidBoundaryNodes(index, this);
+}
+
+// --------------------------------------------------------- //
+//                    Mesh Triangle                          //
+// --------------------------------------------------------- //
+void GridImp::mesh(Object* object)
+{
+    TriangularMesh* triangularMesh = dynamic_cast<TriangularMesh*>(object);
+    if (triangularMesh)
+        triangularMeshDiscretizationStrategy->discretize(triangularMesh, this, INVALID_SOLID, FLUID);
+    else
+		//new method for geometric primitives (not cell based) to be implemented
+        this->discretize(object, INVALID_SOLID, FLUID);
+
+    this->closeNeedleCells();
+
+	#pragma omp parallel for
+    for (int index = 0; index < (int)this->size; index++)
+        this->findSolidStopperNode(index);
+
+	//#pragma omp parallel for
+    for (int index = 0; index < (int)this->size; index++) {
+        this->findBoundarySolidNode(index);
+    }
+}
+
+
+void GridImp::mesh(TriangularMesh &triangularMesh)
+{
+    const clock_t begin = clock();
+
+#pragma omp parallel for
+    for (int i = 0; i < triangularMesh.size; i++)
+        this->mesh(triangularMesh.triangles[i]);
+
+    const clock_t end = clock();
+    const real time = (real)(real(end - begin) / CLOCKS_PER_SEC);
+
+    *logging::out << logging::Logger::INFO_INTERMEDIATE << "time grid generation: " << time << "s\n";
+}
+
+void GridImp::mesh(Triangle &triangle)
+{
+    auto box = this->getBoundingBoxOnNodes(triangle);
+    triangle.initalLayerThickness(getDelta());
+
+    for (real x = box.minX; x <= box.maxX; x += delta)
+    {
+        for (real y = box.minY; y <= box.maxY; y += delta)
+        {
+            for (real z = box.minZ; z <= box.maxZ; z += delta)
+            {
+                const uint index = this->transCoordToIndex(x, y, z);
+                if (!field.isFluid(index))
+                    continue;
+
+                const Vertex point(x, y, z);
+                const int value = triangle.isUnderFace(point);
+                //setDebugPoint(index, value);
+
+                if (value == Q_DEPRECATED)
+                    calculateQs(point, triangle);
+            }
+        }
+    }
+}
+
+void GridImp::closeNeedleCells()
+{
+    *logging::out << logging::Logger::INFO_INTERMEDIATE << "Start closeNeedleCells()\n";
+
+    uint numberOfClosedNeedleCells = 0;
+
+    do{
+#pragma omp parallel for reduction(+ : numberOfClosedNeedleCells)
+        for (int index = 0; index < (int)this->size; index++) {
+            if (this->closeCellIfNeedle(index))
+                numberOfClosedNeedleCells++;
+        }
+
+        *logging::out << logging::Logger::INFO_INTERMEDIATE << numberOfClosedNeedleCells << " cells closed!\n";
+    }
+    while( numberOfClosedNeedleCells > 0 );
+}
+
+bool GridImp::closeCellIfNeedle(uint index)
+{
+    if( !this->getField().is( index, FLUID ) ) return false;
+
+    real x, y, z;
+    this->transIndexToCoords(index, x, y, z);
+
+    bool noValidNeighborInX = this->getField().is( this->transCoordToIndex( x + this->delta, y,               z               ) , INVALID_SOLID ) &&
+                              this->getField().is( this->transCoordToIndex( x - this->delta, y,               z               ) , INVALID_SOLID );
+    bool noValidNeighborInY = this->getField().is( this->transCoordToIndex( x,               y + this->delta, z               ) , INVALID_SOLID ) &&
+                              this->getField().is( this->transCoordToIndex( x,               y - this->delta, z               ) , INVALID_SOLID );
+    bool noValidNeighborInZ = this->getField().is( this->transCoordToIndex( x,               y,               z + this->delta ) , INVALID_SOLID ) &&
+                              this->getField().is( this->transCoordToIndex( x,               y,               z - this->delta ) , INVALID_SOLID );
+
+    if( noValidNeighborInX || noValidNeighborInY || noValidNeighborInZ ){
+        this->setFieldEntry(index, INVALID_SOLID);
+        return true;
+    }
+
+    return false;
+}
+
+void GridImp::closeNeedleCellsThinWall()
+{
+    *logging::out << logging::Logger::INFO_INTERMEDIATE << "Start closeNeedleCellsThinWall()\n";
+
+    uint numberOfClosedNeedleCells = 0;
+
+    do{
+#pragma omp parallel for reduction(+ : numberOfClosedNeedleCells)
+        for (int index = 0; index < (int)this->size; index++) {
+            if (this->closeCellIfNeedleThinWall(index))
+                numberOfClosedNeedleCells++;
+        }
+
+        *logging::out << logging::Logger::INFO_INTERMEDIATE << numberOfClosedNeedleCells << " cells closed!\n";
+    }
+    while( numberOfClosedNeedleCells > 0 );
+}
+
+bool GridImp::closeCellIfNeedleThinWall(uint index)
+{
+    if( !this->getField().is( index, BC_SOLID ) ) return false;
+
+    real x, y, z;
+    this->transIndexToCoords(index, x, y, z);
+
+    if( !this->hasNeighborOfType(index, FLUID) ){
+        this->setFieldEntry(index, STOPPER_SOLID);
+        return true;
+    }
+
+    return false;
+}
+
+
+
+void GridImp::findQs(Object* object) //TODO: enable qs for primitive objects
+{
+    TriangularMesh* triangularMesh = dynamic_cast<TriangularMesh*>(object);
+    if (triangularMesh)
+        findQs(*triangularMesh);
+    else
+        findQsPrimitive(object);
+}
+
+void GridImp::allocateQs() 
+{
+    this->qPatches = new uint[this->getNumberOfSolidBoundaryNodes()];
+
+    for (uint i = 0; i < this->getNumberOfSolidBoundaryNodes(); i++)
+        this->qPatches[i] = INVALID_INDEX;
+
+    const uint numberOfQs = this->getNumberOfSolidBoundaryNodes() * (this->distribution.dir_end + 1);
+    this->qValues         = new real[numberOfQs];
+#pragma omp parallel for
+    for (int i = 0; i < (int)numberOfQs; i++)
+        this->qValues[i] = -1.0;
+}
+
+void GridImp::findQs(TriangularMesh &triangularMesh)
+{
+    const clock_t begin = clock();
+
+    if( this->qComputationStage == qComputationStageType::ComputeQs )
+        allocateQs();
+    
+    
+#pragma omp parallel for
+    for (int i = 0; i < triangularMesh.size; i++)
+        this->findQs(triangularMesh.triangles[i]);
+
+    const clock_t end = clock();
+    const real time = (real)(real(end - begin) / CLOCKS_PER_SEC);
+
+    *logging::out << logging::Logger::INFO_INTERMEDIATE << "time finding qs: " << time << "s\n";
+}
+
+void GridImp::findQs(Triangle &triangle)
+{
+    auto box = this->getBoundingBoxOnNodes(triangle);
+    triangle.initalLayerThickness(getDelta());
+
+    for (real x = box.minX; x <= box.maxX; x += delta)
+    {
+        for (real y = box.minY; y <= box.maxY; y += delta)
+        {
+            for (real z = box.minZ; z <= box.maxZ; z += delta)
+            {
+                const uint index = this->transCoordToIndex(x, y, z);
+                //if (!field.isFluid(index))
+                //    continue;
+
+				if( index == INVALID_INDEX ) continue;
+
+                const Vertex point(x, y, z);
+
+                if( this->qComputationStage == qComputationStageType::ComputeQs ){
+                    if(this->field.is(index, BC_SOLID))
+                    {
+					    calculateQs(index, point, triangle);
+				    }
+                }
+                else if( this->qComputationStage == qComputationStageType::FindSolidBoundaryNodes )
+                {
+                    //if( this->field.is(index, BC_SOLID) || this->field.is(index, STOPPER_SOLID ) ) continue;
+
+                    if( !this->field.is(index, FLUID) ) continue;
+
+                    if( checkIfAtLeastOneValidQ(index, point, triangle) )
+                    {
+                        // similar as in void GridImp::findBoundarySolidNode(uint index)
+                        this->field.setFieldEntry( index, BC_SOLID );
+                        this->qIndices[index] = this->numberOfSolidBoundaryNodes++;
+                    }
+                }
+            }
+        }
+    }
+}
+
+void GridImp::findQsPrimitive(Object * object)
+{
+
+    if( this->qComputationStage == qComputationStageType::ComputeQs )
+        allocateQs();
+
+
+    for( int index = 0; index < (int)this->size; index++ )
+    {
+
+        if( this->qIndices[index] == INVALID_INDEX ) continue;
+
+        real x,y,z;
+
+        this->transIndexToCoords(index,x,y,z);
+        
+        const Vertex point(x, y, z);
+
+        if( this->qComputationStage == qComputationStageType::ComputeQs ){
+            if(this->field.is(index, BC_SOLID))
+            {
+				calculateQs(index, point, object);
+			}
+        }
+        else if( this->qComputationStage == qComputationStageType::FindSolidBoundaryNodes )
+        {
+            if( !this->field.is(index, FLUID) ) continue;
+
+            if( checkIfAtLeastOneValidQ(index, point, object) )
+            {
+                // similar as in void GridImp::findBoundarySolidNode(uint index)
+                this->field.setFieldEntry( index, BC_SOLID );
+                this->qIndices[index] = this->numberOfSolidBoundaryNodes++;
+            }
+        }
+
+    }
+}
+
+void GridImp::calculateQs(const uint index, const Vertex &point, Object* object) const
+{
+    Vertex pointOnTriangle, direction;
+
+	real subdistance;
+	int error;
+	for (int i = distribution.dir_start; i <= distribution.dir_end; i++)
+	{
+		direction = Vertex( real(distribution.dirs[i * DIMENSION + 0]), 
+                            real(distribution.dirs[i * DIMENSION + 1]),
+			                real(distribution.dirs[i * DIMENSION + 2]) );
+
+		uint neighborIndex = this->transCoordToIndex(point.x + direction.x * this->delta,
+													    point.y + direction.y * this->delta,
+													    point.z + direction.z * this->delta);
+
+		if (neighborIndex == INVALID_INDEX) continue;
+
+		error = object->getIntersection(point, direction, pointOnTriangle, subdistance);
+
+		subdistance /= this->delta;
+
+		if (error == 0 && vf::Math::lessEqual(subdistance, 1.0) && vf::Math::greaterEqual(subdistance, 0.0))
+		{
+			if ( -0.5        > this->qValues[i*this->numberOfSolidBoundaryNodes + this->qIndices[index]] ||
+                    subdistance < this->qValues[i*this->numberOfSolidBoundaryNodes + this->qIndices[index]] )
+			{
+
+				this->qValues[i*this->numberOfSolidBoundaryNodes + this->qIndices[index]] = subdistance;
+                    
+                this->qPatches[ this->qIndices[index] ] = 0;
+
+				//printf("%d %f \n", this->qIndices[index], subdistance);
+			}
+		}
+	}
+}
+
+bool GridImp::checkIfAtLeastOneValidQ(const uint index, const Vertex &point, Object* object) const
+{
+    Vertex pointOnTriangle, direction;
+
+	real subdistance;
+	int error;
+	for (int i = distribution.dir_start; i <= distribution.dir_end; i++)
+	{
+		direction = Vertex( real(distribution.dirs[i * DIMENSION + 0]), 
+                            real(distribution.dirs[i * DIMENSION + 1]),
+			                real(distribution.dirs[i * DIMENSION + 2]) );
+
+		uint neighborIndex = this->transCoordToIndex(point.x + direction.x * this->delta,
+													 point.y + direction.y * this->delta,
+													 point.z + direction.z * this->delta);
+
+		if (neighborIndex == INVALID_INDEX) continue;
+
+		error = object->getIntersection(point, direction, pointOnTriangle, subdistance);
+
+		subdistance /= this->delta;
+
+		if (error == 0 && vf::Math::lessEqual(subdistance, 1.0) && vf::Math::greaterEqual(subdistance, 0.0))
+		{
+			return true;
+		}
+	}
+    return false;
+}
+
+void GridImp::setDebugPoint(uint index, int pointValue)
+{
+    if (field.isInvalidCoarseUnderFine(index) && pointValue == INVALID_SOLID)
+        field.setFieldEntry(index, pointValue);
+
+    if(!field.isInvalidSolid(index) && !field.isQ(index) && !field.isInvalidCoarseUnderFine(index) && pointValue != 3 && pointValue != 2)
+        field.setFieldEntry(index, pointValue);
+}
+
+void GridImp::calculateQs(const Vertex &point, const Triangle &triangle) const   // NOT USED !!!!
+{
+    Vertex pointOnTriangle, direction;
+    real subdistance;
+    int error;
+    for (int i = distribution.dir_start; i <= distribution.dir_end; i++)
+    {
+#if defined(__CUDA_ARCH__)
+        direction = Vertex(DIRECTIONS[i][0], DIRECTIONS[i][1], DIRECTIONS[i][2]);
+#else
+        direction = Vertex(real(distribution.dirs[i * DIMENSION + 0]), real(distribution.dirs[i * DIMENSION + 1]),
+            real(distribution.dirs[i * DIMENSION + 2]));
+#endif
+
+        error = triangle.getTriangleIntersection(point, direction, pointOnTriangle, subdistance);
+
+		subdistance /= this->delta;
+
+        if (error == 0 && subdistance < 1.0 && subdistance > 0.0)
+        {
+            distribution.f[i*size + transCoordToIndex(point.x, point.y, point.z)] = subdistance;
+        }
+    }
+}
+
+
+void GridImp::calculateQs(const uint index, const Vertex &point, const Triangle &triangle) const
+{
+	Vertex pointOnTriangle, direction;
+	real subdistance;
+	int error;
+	for (int i = distribution.dir_start; i <= distribution.dir_end; i++)
+	{
+#if defined(__CUDA_ARCH__)
+		direction = Vertex(DIRECTIONS[i][0], DIRECTIONS[i][1], DIRECTIONS[i][2]);
+#else
+		direction = Vertex( real(distribution.dirs[i * DIMENSION + 0]), 
+                            real(distribution.dirs[i * DIMENSION + 1]),
+			                real(distribution.dirs[i * DIMENSION + 2]) );
+#endif
+
+		uint neighborIndex = this->transCoordToIndex(point.x + direction.x * this->delta,
+													 point.y + direction.y * this->delta,
+													 point.z + direction.z * this->delta);
+
+		if (neighborIndex == INVALID_INDEX) continue;
+
+		error = triangle.getTriangleIntersection(point, direction, pointOnTriangle, subdistance);
+
+		subdistance /= this->delta;
+
+		if (error == 0 && vf::Math::lessEqual(subdistance, 1.0) && vf::Math::greaterEqual(subdistance, 0.0))
+		{
+			if ( -0.5        > this->qValues[i*this->numberOfSolidBoundaryNodes + this->qIndices[index]] ||
+                 subdistance < this->qValues[i*this->numberOfSolidBoundaryNodes + this->qIndices[index]] )
+			{
+				this->qValues[i*this->numberOfSolidBoundaryNodes + this->qIndices[index]] = subdistance;
+
+                this->qPatches[ this->qIndices[index] ] = triangle.patchIndex;
+			}
+		}
+	}
+}
+
+bool GridImp::checkIfAtLeastOneValidQ(const uint index, const Vertex & point, const Triangle & triangle) const
+{
+	Vertex pointOnTriangle, direction;
+	real subdistance;
+	int error;
+	for (int i = distribution.dir_start; i <= distribution.dir_end; i++)
+	{
+#if defined(__CUDA_ARCH__)
+		direction = Vertex(DIRECTIONS[i][0], DIRECTIONS[i][1], DIRECTIONS[i][2]);
+#else
+		direction = Vertex(real(distribution.dirs[i * DIMENSION + 0]), 
+                           real(distribution.dirs[i * DIMENSION + 1]),
+			               real(distribution.dirs[i * DIMENSION + 2]));
+#endif
+
+		uint neighborIndex = this->transCoordToIndex(point.x + direction.x * this->delta,
+													 point.y + direction.y * this->delta,
+													 point.z + direction.z * this->delta);
+		if (neighborIndex == INVALID_INDEX) continue;
+
+		error = triangle.getTriangleIntersection(point, direction, pointOnTriangle, subdistance);
+
+		subdistance /= this->delta;
+
+		if (error == 0 && vf::Math::lessEqual(subdistance, 1.0) && vf::Math::greaterEqual(subdistance, 0.0))
+		{
+			return true;
+		}
+	}
+    return false;
+}
+
+void GridImp::findCommunicationIndices(int direction, SPtr<BoundingBox> subDomainBox, LbmOrGks lbmOrGks)
+{
+    for( uint index = 0; index < this->size; index++ ){
+        
+        real x, y, z;
+        this->transIndexToCoords(index, x, y, z);
+    
+        if( this->getFieldEntry(index) == INVALID_OUT_OF_GRID ||
+            this->getFieldEntry(index) == INVALID_SOLID ||
+            this->getFieldEntry(index) == INVALID_COARSE_UNDER_FINE ||
+            this->getFieldEntry(index) == STOPPER_OUT_OF_GRID ||
+            this->getFieldEntry(index) == STOPPER_COARSE_UNDER_FINE ) continue;
+
+        if( lbmOrGks == LBM && this->getFieldEntry(index) == STOPPER_OUT_OF_GRID_BOUNDARY ) continue;
+        if( lbmOrGks == LBM && this->getFieldEntry(index) == STOPPER_SOLID ) continue;
+
+        if( direction == CommunicationDirections::MX ) findCommunicationIndex( index, x, subDomainBox->minX, direction);
+        if( direction == CommunicationDirections::PX ) findCommunicationIndex( index, x, subDomainBox->maxX, direction);
+        if( direction == CommunicationDirections::MY ) findCommunicationIndex( index, y, subDomainBox->minY, direction);
+        if( direction == CommunicationDirections::PY ) findCommunicationIndex( index, y, subDomainBox->maxY, direction);
+        if( direction == CommunicationDirections::MZ ) findCommunicationIndex( index, z, subDomainBox->minZ, direction);
+        if( direction == CommunicationDirections::PZ ) findCommunicationIndex( index, z, subDomainBox->maxZ, direction);
+    }
+}
+
+void GridImp::findCommunicationIndex( uint index, real coordinate, real limit, int direction ){
+    // negative direction get a negative sign
+    real s = ( direction % 2 == 0 ) ? ( -1.0 ) : ( 1.0 );  
+
+
+	if (std::abs(coordinate - (limit + s * 0.5 * this->delta)) < 0.1 * this->delta) {
+		this->communicationIndices[direction].receiveIndices.push_back(index);
+	}
+
+	if (std::abs(coordinate - (limit - s * 0.5 * this->delta)) < 0.1 * this->delta) {
+		this->communicationIndices[direction].sendIndices.push_back(index);
+	}
+}
+
+uint GridImp::getNumberOfSendNodes(int direction)
+{
+    return (uint)this->communicationIndices[direction].sendIndices.size();
+}
+
+uint GridImp::getNumberOfReceiveNodes(int direction)
+{
+    return (uint)this->communicationIndices[direction].receiveIndices.size();
+}
+
+uint GridImp::getSendIndex(int direction, uint index)
+{
+    return this->communicationIndices[direction].sendIndices[ index ];
+}
+
+uint GridImp::getReceiveIndex(int direction, uint index)
+{
+    return this->communicationIndices[direction].receiveIndices[ index ];
+}
+
+void GridImp::repairCommunicationInices(int direction )
+{
+    this->communicationIndices[direction].sendIndices.insert( this->communicationIndices[direction].sendIndices.end(), 
+                                                              this->communicationIndices[direction+1].sendIndices.begin(), 
+                                                              this->communicationIndices[direction+1].sendIndices.end() );
+
+
+
+    this->communicationIndices[direction+1].receiveIndices.insert( this->communicationIndices[direction+1].receiveIndices.end(), 
+                                                                 this->communicationIndices[direction].receiveIndices.begin(), 
+                                                                 this->communicationIndices[direction].receiveIndices.end() );
+
+    this->communicationIndices[direction].receiveIndices = this->communicationIndices[direction+1].receiveIndices;
+
+
+
+
+
+
+    *logging::out << logging::Logger::INFO_INTERMEDIATE << "size send " << (int)this->communicationIndices[direction].sendIndices.size() << "\n";
+    *logging::out << logging::Logger::INFO_INTERMEDIATE << "recv send " << (int)this->communicationIndices[direction].receiveIndices.size() << "\n";
+}
+
+
+// --------------------------------------------------------- //
+//                        Getter                             //
+// --------------------------------------------------------- //
+int GridImp::getSparseIndex(uint matrixIndex) const
+{
+    return this->sparseIndices[matrixIndex];
+}
+
+real* GridImp::getDistribution() const
+{
+    return this->distribution.f;
+}
+
+int* GridImp::getDirection() const
+{
+    return this->distribution.dirs;
+}
+
+int GridImp::getStartDirection() const
+{
+    return this->distribution.dir_start;
+}
+
+int GridImp::getEndDirection() const
+{
+    return this->distribution.dir_end;
+}
+
+BoundingBox GridImp::getBoundingBoxOnNodes(Triangle &triangle) const
+{
+    real minX, maxX, minY, maxY, minZ, maxZ;
+    triangle.setMinMax(minX, maxX, minY, maxY, minZ, maxZ);
+
+    int minXIndex = std::lround(floor((minX - this->startX) / this->delta)) - 1;
+    int minYIndex = std::lround(floor((minY - this->startY) / this->delta)) - 1;
+    int minZIndex = std::lround(floor((minZ - this->startZ) / this->delta)) - 1;
+
+    int maxXIndex = std::lround(ceil((maxX - this->startX) / this->delta)) + 1;
+    int maxYIndex = std::lround(ceil((maxY - this->startY) / this->delta)) + 1;
+    int maxZIndex = std::lround(ceil((maxZ - this->startZ) / this->delta)) + 1;
+
+    minX = this->startX + minXIndex * this->delta;
+    minY = this->startY + minYIndex * this->delta;
+    minZ = this->startZ + minZIndex * this->delta;
+
+    maxX = this->startX + maxXIndex * this->delta;
+    maxY = this->startY + maxYIndex * this->delta;
+    maxZ = this->startZ + maxZIndex * this->delta;
+
+    return BoundingBox(minX, maxX, minY, maxY, minZ, maxZ);
+}
+
+Vertex GridImp::getMinimumOnNode(Vertex exact) const // deprecated
+{
+    const real minX = getMinimumOnNodes(exact.x, vf::Math::getDecimalPart(startX), delta);
+    const real minY = getMinimumOnNodes(exact.y, vf::Math::getDecimalPart(startY), delta);
+    const real minZ = getMinimumOnNodes(exact.z, vf::Math::getDecimalPart(startZ), delta);
+    return Vertex(minX, minY, minZ);
+}
+
+real GridImp::getMinimumOnNodes(const real &minExact, const real &decimalStart, const real &delta) // deprecated
+{
+    real minNode = ceil(minExact - 1.0);
+    minNode += decimalStart;
+    while (minNode > minExact)
+        minNode -= delta;
+
+    while (minNode + delta < minExact)
+        minNode += delta;
+    return minNode;
+}
+
+Vertex GridImp::getMaximumOnNode(Vertex exact) const // deprecated
+{
+    const real maxX = getMaximumOnNodes(exact.x, vf::Math::getDecimalPart(startX), delta);
+    const real maxY = getMaximumOnNodes(exact.y, vf::Math::getDecimalPart(startY), delta);
+    const real maxZ = getMaximumOnNodes(exact.z, vf::Math::getDecimalPart(startZ), delta);
+    return Vertex(maxX, maxY, maxZ);
+}
+
+real GridImp::getMaximumOnNodes(const real &maxExact, const real &decimalStart, const real &delta) // deprecated
+{
+    real maxNode = ceil(maxExact - 1.0);
+    maxNode += decimalStart;
+
+    while (maxNode <= maxExact)
+        maxNode += delta;
+    return maxNode;
+}
+
+uint GridImp::getXIndex(real x) const 
+{
+    return std::lround((x - startX) / delta);
+}
+
+uint GridImp::getYIndex(real y) const
+{
+    return std::lround((y - startY) / delta);
+}
+
+uint GridImp::getZIndex(real z) const
+{
+	return std::lround((z - startZ) / delta);
+}
+
+real GridImp::getDelta() const
+{
+    return delta;
+}
+
+uint GridImp::getSize() const
+{
+    return this->size;
+}
+
+uint GridImp::getSparseSize() const
+{
+    return this->sparseSize;
+}
+
+Field GridImp::getField() const
+{
+    return this->field;
+}
+
+char GridImp::getFieldEntry(uint index) const
+{
+    return this->field.getFieldEntry(index);
+}
+
+void GridImp::setFieldEntry(uint matrixIndex, char type)
+{
+    this->field.setFieldEntry(matrixIndex, type);
+}
+
+
+real GridImp::getStartX() const
+{
+    return startX;
+}
+
+real GridImp::getStartY() const
+{
+    return startY;
+}
+
+real GridImp::getStartZ() const
+{
+    return startZ;
+}
+
+real GridImp::getEndX() const
+{
+    return endX;
+}
+
+real GridImp::getEndY() const
+{
+    return endY;
+}
+
+real GridImp::getEndZ() const
+{
+    return endZ;
+}
+
+uint GridImp::getNumberOfNodesX() const
+{
+    return nx;
+}
+
+uint GridImp::getNumberOfNodesY() const
+{
+    return ny;
+}
+
+uint GridImp::getNumberOfNodesZ() const
+{
+    return nz;
+}
+
+
+int* GridImp::getNeighborsX() const
+{
+    return this->neighborIndexX;
+}
+
+int* GridImp::getNeighborsY() const
+{
+    return this->neighborIndexY;
+}
+
+int* GridImp::getNeighborsZ() const
+{
+    return this->neighborIndexZ;
+}
+
+int* GridImp::getNeighborsNegative() const
+{
+    return this->neighborIndexNegative;
+}
+
+uint GridImp::getNumberOfNodesCF() const
+{
+    if(this->gridInterface)
+        return this->gridInterface->cf.numberOfEntries;
+    return 0;
+}
+
+uint GridImp::getNumberOfNodesFC() const
+{
+    if (this->gridInterface)
+        return this->gridInterface->fc.numberOfEntries;
+    return 0;
+}
+
+uint* GridImp::getCF_coarse() const
+{
+    return this->gridInterface->cf.coarse;
+}
+
+uint* GridImp::getCF_fine() const
+{
+    return this->gridInterface->cf.fine;
+}
+
+uint * GridImp::getCF_offset() const
+{
+    return this->gridInterface->cf.offset;
+}
+
+uint* GridImp::getFC_coarse() const
+{
+    return this->gridInterface->fc.coarse;
+}
+
+uint* GridImp::getFC_fine() const
+{
+    return this->gridInterface->fc.fine;
+}
+
+uint * GridImp::getFC_offset() const
+{
+    return this->gridInterface->fc.offset;
+}
+
+void GridImp::getGridInterfaceIndices(uint* iCellCfc, uint* iCellCff, uint* iCellFcc, uint* iCellFcf) const
+{
+    getGridInterface(iCellCfc, this->gridInterface->cf.coarse, this->gridInterface->cf.numberOfEntries);
+    getGridInterface(iCellCff, this->gridInterface->cf.fine, this->gridInterface->cf.numberOfEntries);
+    getGridInterface(iCellFcc, this->gridInterface->fc.coarse, this->gridInterface->fc.numberOfEntries);
+    getGridInterface(iCellFcf, this->gridInterface->fc.fine, this->gridInterface->fc.numberOfEntries);
+}
+
+void GridImp::getGridInterface(uint* gridInterfaceList, const uint* oldGridInterfaceList, uint size)
+{
+    for (uint i = 0; i < size; i++)
+        gridInterfaceList[i] = oldGridInterfaceList[i] + 1; // + 1 for numbering shift between GridGenerator and VF_GPU
+}
+
+#define GEOFLUID 19
+#define GEOSOLID 16
+
+void GridImp::getNodeValues(real *xCoords, real *yCoords, real *zCoords, uint *neighborX, uint *neighborY, uint *neighborZ, uint *neighborNegative, uint *geo) const
+{
+    xCoords[0] = 0;
+    yCoords[0] = 0;
+    zCoords[0] = 0;
+    neighborX[0] = 0;
+    neighborY[0] = 0;
+    neighborZ[0] = 0;
+    geo[0] = GEOSOLID;
+
+    int nodeNumber = 0;
+    for (uint i = 0; i < this->getSize(); i++)
+    {
+        if (this->sparseIndices[i] == -1)
+            continue;
+
+        real x, y, z;
+        this->transIndexToCoords(i, x, y, z);
+
+        // + 1 for numbering shift between GridGenerator and VF_GPU
+        const uint neighborXIndex        = uint(this->neighborIndexX[i] + 1);
+        const uint neighborYIndex        = uint(this->neighborIndexY[i] + 1);
+        const uint neighborZIndex        = uint(this->neighborIndexZ[i] + 1);
+        const uint neighborNegativeIndex = uint(this->neighborIndexNegative[i] + 1);
+
+        const uint type = uint(this->field.isFluid(i) ? GEOFLUID : GEOSOLID);
+
+        xCoords[nodeNumber + 1] = x;
+        yCoords[nodeNumber + 1] = y;
+        zCoords[nodeNumber + 1] = z;
+
+        neighborX       [nodeNumber + 1] = neighborXIndex;
+        neighborY       [nodeNumber + 1] = neighborYIndex;
+        neighborZ       [nodeNumber + 1] = neighborZIndex;
+        neighborNegative[nodeNumber + 1] = neighborNegativeIndex;
+
+        geo[nodeNumber + 1] = type;
+        nodeNumber++;
+    }
+}
+
+void GridImp::print() const
+{
+    printf("min: (%2.4f, %2.4f, %2.4f), max: (%2.4f, %2.4f, %2.4f), size: %d, delta: %2.4f\n", startX, startY, startZ,
+           endX, endY, endZ, size, delta);
+    if(this->gridInterface)
+        this->gridInterface->print();
+}
\ No newline at end of file
diff --git a/src/gpu/GridGenerator/grid/GridImp.cu b/src/gpu/GridGenerator/grid/GridImp.cu
deleted file mode 100644
index 2684893e37a7336ee00ff75d52a9821727c6be4a..0000000000000000000000000000000000000000
--- a/src/gpu/GridGenerator/grid/GridImp.cu
+++ /dev/null
@@ -1,866 +0,0 @@
-//=======================================================================================
-// ____          ____    __    ______     __________   __      __       __        __         
-// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |        
-//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |        
-//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |        
-//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____    
-//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|   
-//      \    \  |    |   ________________________________________________________________    
-//       \    \ |    |  |  ______________________________________________________________|   
-//        \    \|    |  |  |         __          __     __     __     ______      _______    
-//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)   
-//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______    
-//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
-//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/   
-//
-//  This file is part of VirtualFluids. VirtualFluids 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.
-//  
-//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
-//
-//! \file GridImp.cu
-//! \ingroup grid
-//! \author Soeren Peters, Stephan Lenz
-//=======================================================================================
-#include "GridImp.h"
-
-#include <stdio.h>
-#include <time.h>
-#include <iostream>
-#include <omp.h>
-#include <sstream>
-
-#include "global.h"
-
-#include "geometries/Object.h"
-#include "geometries/Vertex/Vertex.h"
-#include "geometries/BoundingBox/BoundingBox.h"
-
-#include "grid/GridStrategy/GridStrategy.h"
-#include "grid/distributions/Distribution.h"
-#include "grid/Field.h"
-#include "grid/NodeValues.h"
-
-#include "utilities/math/Math.h"
-
-int DIRECTIONS[DIR_END_MAX][DIMENSION];
-
-
-GridImp::GridImp(Object* object, real startX, real startY, real startZ, real endX, real endY, real endZ, real delta, SPtr<GridStrategy> gridStrategy, Distribution distribution, uint level) 
-            : object(object), 
-    startX(startX),
-    startY(startY),
-    startZ(startZ),
-    endX(endX),
-    endY(endY),
-    endZ(endZ),
-    delta(delta),
-    gridStrategy(gridStrategy),
-    distribution(distribution),
-    level(level),
-    periodicityX(false),
-    periodicityY(false),
-    periodicityZ(false),
-    neighborIndexX(nullptr),
-    neighborIndexY(nullptr),
-    neighborIndexZ(nullptr),
-    neighborIndexNegative(nullptr),
-    sparseIndices(nullptr)
-{
-    initalNumberOfNodesAndSize();
-}
-
-SPtr<GridImp> GridImp::makeShared(Object* object, real startX, real startY, real startZ, real endX, real endY, real endZ, real delta, SPtr<GridStrategy> gridStrategy, Distribution d, uint level)
-{
-    SPtr<GridImp> grid(new GridImp(object, startX, startY, startZ, endX, endY, endZ, delta, gridStrategy, d, level));
-    return grid;
-}
-
-
-void GridImp::initalNumberOfNodesAndSize()
-{
-    const real length = endX - startX;
-    const real width = endY - startY;
-    const real height = endZ - startZ;
-
-    nx = lround((length + delta) / delta);
-    ny = lround((width + delta) / delta);
-    nz = lround((height + delta) / delta);
-
-    this->size = nx * ny * nz;
-    this->sparseSize = size;
-    distribution.setSize(size);
-}
-
-void GridImp::inital(const SPtr<Grid> fineGrid, uint numberOfLayers)
-{
-    field = Field(gridStrategy, size);
-    field.allocateMemory();
-    gridStrategy->allocateGridMemory(shared_from_this());
-    
-    *logging::out << logging::Logger::INFO_INTERMEDIATE << "Start initalNodesToOutOfGrid()\n";
-    gridStrategy->initalNodesToOutOfGrid(shared_from_this());
-    
-    *logging::out << logging::Logger::INFO_INTERMEDIATE << "Start findInnerNodes()\n";
-    this->object->findInnerNodes( shared_from_this() );
-    
-    *logging::out << logging::Logger::INFO_INTERMEDIATE << "Start findEndOfGridStopperNodes()\n";
-	gridStrategy->findEndOfGridStopperNodes(shared_from_this());
-
-    *logging::out << logging::Logger::INFO_INTERMEDIATE
-        << "Grid created: " << "from (" << this->startX << ", " << this->startY << ", " << this->startZ << ") to (" << this->endX << ", " << this->endY << ", " << this->endZ << ")\n"
-        << "nodes: " << this->nx << " x " << this->ny << " x " << this->nz << " = " << this->size << "\n";
-}
-
-void GridImp::initalNodeToOutOfGrid(uint index)
-{
-    this->field.setFieldEntryToInvalidOutOfGrid(index);
-}
-
-void GridImp::freeMemory()
-{
-    gridStrategy->freeMemory(shared_from_this());
-}
-
-GridImp::GridImp()
-{
-}
-
-GridImp::~GridImp()
-{
-}
-
-void GridImp::findInnerNode(uint index)
-{
-    this->sparseIndices[index] = index;
-
-    real x, y, z;
-    this->transIndexToCoords(index, x, y, z);
-    const uint xIndex = getXIndex(x);
-    const uint yIndex = getYIndex(y);
-    const uint zIndex = getZIndex(z);
-
-    if( xIndex != 0 && xIndex != this->nx-1 &&
-        yIndex != 0 && yIndex != this->ny-1 &&
-        zIndex != 0 && zIndex != this->nz-1 )
-        this->field.setFieldEntryToFluid(index);
-}
-
-void GridImp::findEndOfGridStopperNode(uint index)
-{
-	if (isValidEndOfGridStopper(index)){
-        if( this->level != 0 )
-		    this->field.setFieldEntryToStopperOutOfGrid(index);
-        else
-            this->field.setFieldEntryToStopperOutOfGridBoundary(index);
-    }
-
-	if (isValidEndOfGridBoundaryStopper(index))
-		this->field.setFieldEntryToStopperOutOfGridBoundary(index);
-}
-
-bool GridImp::isOutSideOfGrid(Cell &cell) const
-{
-    for (const auto point : cell) {
-        if (point.x < startX || point.x > endX
-            || point.y < startY || point.y > endY
-            || point.z < startZ || point.z > endZ)
-            return true;
-    }
-    return false;
-}
-
-bool GridImp::contains(Cell &cell, char type) const
-{
-    for (const auto point : cell) {
-		uint index = transCoordToIndex(point.x, point.y, point.z);
-		if (index == INVALID_INDEX)
-			continue;
-        if (field.is(index, type))
-            return true;
-    }
-    return false;
-}
-
-bool GridImp::cellContainsOnly(Cell &cell, char type) const
-{
-    for (const auto point : cell) {
-		uint index = transCoordToIndex(point.x, point.y, point.z);
-		if (index == INVALID_INDEX)
-            return false;
-        if (!field.is(index, type))
-            return false;
-    }
-    return true;
-}
-
-bool GridImp::cellContainsOnly(Cell &cell, char typeA, char typeB) const
-{
-    for (const auto point : cell) {
-		uint index = transCoordToIndex(point.x, point.y, point.z);
-		if (index == INVALID_INDEX)
-            return false;
-        if (!field.is(index, typeA) && !field.is(index, typeB))
-            return false;
-    }
-    return true;
-}
-
-const Object * GridImp::getObject() const
-{
-    return this->object;
-}
-
-void GridImp::setNodeTo(Cell &cell, char type)
-{
-    for (const auto point : cell) {
-		uint index = transCoordToIndex(point.x, point.y, point.z);
-		if (index == INVALID_INDEX)
-			continue;
-		field.setFieldEntry(index, type);
-    }
-}
-
-void GridImp::setNodeTo(uint index, char type)
-{
-	if( index != INVALID_INDEX )
-		field.setFieldEntry(index, type);
-}
-
-bool GridImp::isNode(uint index, char type) const
-{
-    if( index != INVALID_INDEX )
-		return field.is(index, type);
-
-    throw std::runtime_error("GridImp::isNode() -> index == INVALID_INDEX not supported.");
-}
-
-bool GridImp::isValidEndOfGridStopper(uint index) const
-{
-	// Lenz: also includes corner stopper nodes
-	if (!this->field.is(index, INVALID_OUT_OF_GRID))
-		return false;
-
-	return hasNeighborOfType(index, FLUID);
-}
-
-bool GridImp::isValidEndOfGridBoundaryStopper(uint index) const
-{
-	// Lenz: also includes corner stopper nodes
-	if (!this->field.is(index, FLUID))
-		return false;
-
-	return ! hasAllNeighbors(index);
-}
-
-bool GridImp::isValidSolidStopper(uint index) const
-{
-	// Lenz: also includes corner stopper nodes
-	if (!this->field.is(index, INVALID_SOLID))
-		return false;
-
-	return hasNeighborOfType(index, FLUID);
-}
-
-bool GridImp::shouldBeBoundarySolidNode(uint index) const
-{
-	if (!this->field.is(index, FLUID))
-		return false;
-
-	return hasNeighborOfType(index, STOPPER_SOLID);
-}
-
-bool GridImp::hasAllNeighbors(uint index) const
-{
-	// new version by Lenz, utilizes the range based for loop for all directions
-	real x, y, z;
-	this->transIndexToCoords(index, x, y, z);
-	for (const auto dir : this->distribution) {
-		const uint neighborIndex = this->transCoordToIndex(x + dir[0] * this->getDelta(), y + dir[1] * this->getDelta(), z + dir[2] * this->getDelta());
-
-		if (neighborIndex == INVALID_INDEX) return false;
-	}
-
-	return true;
-}
-
-bool GridImp::hasNeighborOfType(uint index, char type) const
-{
-	// new version by Lenz, utilizes the range based for loop for all directions
-	real x, y, z;
-	this->transIndexToCoords(index, x, y, z);
-	for (const auto dir : this->distribution) {
-		const uint neighborIndex = this->transCoordToIndex(x + dir[0] * this->getDelta(), y + dir[1] * this->getDelta(), z + dir[2] * this->getDelta());
-
-		if (neighborIndex == INVALID_INDEX) continue;
-
-		if (this->field.is(neighborIndex, type))
-			return true;
-	}
-
-	return false;
-}
-
-bool GridImp::nodeInNextCellIs(int index, char type) const
-{
-    real x, y, z;
-    this->transIndexToCoords(index, x, y, z);
-
-    const real neighborX = x + this->delta > endX ? endX : x + this->delta;
-    const real neighborY = y + this->delta > endY ? endY : y + this->delta;
-    const real neighborZ = z + this->delta > endZ ? endZ : z + this->delta;
-
-    const uint indexX = transCoordToIndex(neighborX, y, z);
-    const uint indexY = transCoordToIndex(x, neighborY, z);
-    const uint indexZ = transCoordToIndex(x, y, neighborZ);
-
-    const uint indexXY = transCoordToIndex(neighborX, neighborY, z);
-    const uint indexYZ = transCoordToIndex(x, neighborY, neighborZ);
-    const uint indexXZ = transCoordToIndex(neighborX, y, neighborZ);
-
-    const uint indexXYZ = transCoordToIndex(neighborX, neighborY, neighborZ);
-
-	const bool typeX   = indexX   == INVALID_INDEX ? false : this->field.is(indexX, type);
-	const bool typeY   = indexY   == INVALID_INDEX ? false : this->field.is(indexY, type);
-	const bool typeXY  = indexXY  == INVALID_INDEX ? false : this->field.is(indexXY, type);
-	const bool typeZ   = indexZ   == INVALID_INDEX ? false : this->field.is(indexZ, type);
-	const bool typeYZ  = indexYZ  == INVALID_INDEX ? false : this->field.is(indexYZ, type);
-	const bool typeXZ  = indexXZ  == INVALID_INDEX ? false : this->field.is(indexXZ, type);
-	const bool typeXYZ = indexXYZ == INVALID_INDEX ? false : this->field.is(indexXYZ, type);
-
-    return typeX || typeY || typeXY || typeZ || typeYZ
-        || typeXZ || typeXYZ;
-}
-
-bool GridImp::nodeInPreviousCellIs(int index, char type) const
-{
-    real x, y, z;
-    this->transIndexToCoords(index, x, y, z);
-
-    const real neighborX = x - this->delta < startX ? startX : x - this->delta;
-    const real neighborY = y - this->delta < startY ? startY : y - this->delta;
-    const real neighborZ = z - this->delta < startZ ? startZ : z - this->delta;
-
-    const uint indexX = transCoordToIndex(neighborX, y, z);
-    const uint indexY = transCoordToIndex(x, neighborY, z);
-    const uint indexZ = transCoordToIndex(x, y, neighborZ);
-
-    const uint indexXY = transCoordToIndex(neighborX, neighborY, z);
-    const uint indexYZ = transCoordToIndex(x, neighborY, neighborZ);
-    const uint indexXZ = transCoordToIndex(neighborX, y, neighborZ);
-
-    const uint indexXYZ = transCoordToIndex(neighborX, neighborY, neighborZ);
-
-	const bool typeX   = indexX   == INVALID_INDEX ? false : this->field.is(indexX  , type);
-	const bool typeY   = indexY   == INVALID_INDEX ? false : this->field.is(indexY  , type);
-	const bool typeXY  = indexXY  == INVALID_INDEX ? false : this->field.is(indexXY , type);
-	const bool typeZ   = indexZ   == INVALID_INDEX ? false : this->field.is(indexZ  , type);
-	const bool typeYZ  = indexYZ  == INVALID_INDEX ? false : this->field.is(indexYZ , type);
-	const bool typeXZ  = indexXZ  == INVALID_INDEX ? false : this->field.is(indexXZ , type);
-	const bool typeXYZ = indexXYZ == INVALID_INDEX ? false : this->field.is(indexXYZ, type);
-
-    return typeX || typeY || typeXY || typeZ || typeYZ
-        || typeXZ || typeXYZ;
-}
-
-bool GridImp::nodeInCellIs(Cell& cell, char type) const
-{
-    for (const auto node : cell)
-    {
-        const uint index = transCoordToIndex(node.x, node.y, node.z);
-		if (index == INVALID_INDEX)
-			continue;
-        if (field.is(index, type))
-            return true;
-    }
-    return false;
-}
-
-
-void GridImp::setCellTo(uint index, char type)
-{
-    real x, y, z;
-    this->transIndexToCoords(index, x, y, z);
-
-    Cell cell(x, y, z, this->delta);
-    for (const auto node : cell)
-    {
-        const uint nodeIndex = transCoordToIndex(node.x, node.y, node.z);
-		if (nodeIndex == INVALID_INDEX)
-			continue;
-		this->field.setFieldEntry(nodeIndex, type);
-    }
-}
-
-
-void GridImp::setNonStopperOutOfGridCellTo(uint index, char type)
-{
-    real x, y, z;
-    this->transIndexToCoords(index, x, y, z);
-
-    Cell cell(x, y, z, this->delta);
-    for (const auto node : cell)
-    {
-        const uint nodeIndex = transCoordToIndex(node.x, node.y, node.z);
-		if (nodeIndex == INVALID_INDEX)
-			continue;
-
-        if( this->getFieldEntry( nodeIndex ) != STOPPER_OUT_OF_GRID && 
-            this->getFieldEntry( nodeIndex ) != STOPPER_OUT_OF_GRID_BOUNDARY )
-            this->field.setFieldEntry(nodeIndex, type);
-    }
-}
-
-
-void GridImp::setPeriodicity(bool periodicityX, bool periodicityY, bool periodicityZ)
-{
-    this->periodicityX = periodicityX;
-    this->periodicityY = periodicityY;
-    this->periodicityZ = periodicityZ;
-}
-
-void GridImp::setPeriodicityX(bool periodicity)
-{
-    this->periodicityX = periodicityX;
-}
-
-void GridImp::setPeriodicityY(bool periodicity)
-{
-    this->periodicityY = periodicityY;
-}
-
-void GridImp::setPeriodicityZ(bool periodicity)
-{
-    this->periodicityZ = periodicityZ;
-}
-
-bool GridImp::getPeriodicityX()
-{
-    return this->periodicityX;
-}
-
-bool GridImp::getPeriodicityY()
-{
-    return this->periodicityY;
-}
-
-bool GridImp::getPeriodicityZ()
-{
-    return this->periodicityZ;
-}
-
-uint GridImp::transCoordToIndex(const real &x, const real &y, const real &z) const
-{
-    const uint xIndex = getXIndex(x);
-    const uint yIndex = getYIndex(y);
-    const uint zIndex = getZIndex(z);
-
-	if (xIndex >= nx || yIndex >= ny || zIndex >= nz)
-        return INVALID_INDEX;
-
-    return xIndex + nx * (yIndex + ny * zIndex);
-}
-
-void GridImp::transIndexToCoords(uint index, real &x, real &y, real &z) const
-{
-    if (index == INVALID_INDEX)
-        printf("Function: transIndexToCoords. GridImp Index: %d, size: %d. Exit Program!\n", index, size);
-
-    x = (real)(index % nx);
-    y = (real)((index / nx) % ny);
-    z = (real)(((index / nx) / ny) % nz);
-
-    x = (x * delta) + startX;
-    y = (y * delta) + startY;
-    z = (z * delta) + startZ;
-}
-
-uint GridImp::getLevel(real startDelta) const
-{
-    uint level = 0;
-    real delta = this->delta;
-    while(!vf::Math::equal(delta, startDelta))
-    {
-        delta *= 2;
-        level++;
-    }
-    return level;
-}
-
-uint GridImp::getLevel() const
-{
-    return this->level;
-}
-
-// --------------------------------------------------------- //
-//                  Set Sparse Indices                       //
-// --------------------------------------------------------- //
-
-void GridImp::findSparseIndices(SPtr<Grid> fineGrid)
-{
-    this->gridStrategy->findSparseIndices(shared_from_this(), std::static_pointer_cast<GridImp>(fineGrid));
-}
-
-
-void GridImp::updateSparseIndices()
-{
-    int removedNodes = 0;
-    int newIndex = 0;
-    for (uint index = 0; index < size; index++)
-    {
-        if (this->field.isInvalidCoarseUnderFine(index) || this->field.isInvalidOutOfGrid(index) || this->field.isInvalidSolid(index))
-        {
-            sparseIndices[index] = -1;
-            removedNodes++;
-        }
-        else
-        {
-            sparseIndices[index] = newIndex;
-            newIndex++;
-        }
-    }
-    sparseSize = size - removedNodes;
-}
-
-void GridImp::setNeighborIndices(uint index)
-{
-    real x, y, z;
-    this->transIndexToCoords(index, x, y, z);
-
-    this->neighborIndexX[index]        = -1;
-    this->neighborIndexY[index]        = -1;
-    this->neighborIndexZ[index]        = -1;
-    this->neighborIndexNegative[index] = -1;
-
-    if (this->field.isStopper(index) || this->field.is(index, STOPPER_OUT_OF_GRID_BOUNDARY))
-    {
-        this->setStopperNeighborCoords(index);
-        return;
-    }
-     
-    if (this->sparseIndices[index] == -1)
-        return;
-
-
-    real neighborXCoord, neighborYCoord, neighborZCoord;
-    this->getNeighborCoords(neighborXCoord, neighborYCoord, neighborZCoord, x, y, z);
-    const int neighborX = getSparseIndex(neighborXCoord, y, z);
-    const int neighborY = getSparseIndex(x, neighborYCoord, z);
-    const int neighborZ = getSparseIndex(x, y, neighborZCoord);
-
-    this->getNegativeNeighborCoords(neighborXCoord, neighborYCoord, neighborZCoord, x, y, z);
-    const int neighborNegative = getSparseIndex(neighborXCoord, neighborYCoord, neighborZCoord);
-
-    this->neighborIndexX[index]        = neighborX;
-    this->neighborIndexY[index]        = neighborY;
-    this->neighborIndexZ[index]        = neighborZ;
-    this->neighborIndexNegative[index] = neighborNegative;
-}
-
-void GridImp::setStopperNeighborCoords(uint index)
-{
-    real x, y, z;
-    this->transIndexToCoords(index, x, y, z);
-
-    if (vf::Math::lessEqual(x + delta, endX) && !this->field.isInvalidOutOfGrid(this->transCoordToIndex(x + delta, y, z)))
-        neighborIndexX[index] = getSparseIndex(x + delta, y, z);
-
-    if (vf::Math::lessEqual(y + delta, endY) && !this->field.isInvalidOutOfGrid(this->transCoordToIndex(x, y + delta, z)))
-        neighborIndexY[index] = getSparseIndex(x, y + delta, z);
-
-    if (vf::Math::lessEqual(z + delta, endZ) && !this->field.isInvalidOutOfGrid(this->transCoordToIndex(x, y, z + delta)))
-        neighborIndexZ[index] = getSparseIndex(x, y, z + delta);
-
-    if (vf::Math::greaterEqual(x - delta, endX) && 
-        vf::Math::greaterEqual(y - delta, endY) && 
-        vf::Math::greaterEqual(z - delta, endZ) && 
-        !this->field.isInvalidOutOfGrid(this->transCoordToIndex(x - delta, y - delta, z - delta)))
-    {
-        neighborIndexNegative[index] = getSparseIndex(x - delta, y - delta, z - delta);
-    }
-}
-
-void GridImp::getNeighborCoords(real &neighborX, real &neighborY, real &neighborZ, real x, real y, real z) const
-{
-    real coords[3] = { x, y, z };
-    neighborX = getNeighborCoord(periodicityX, startX, coords, 0);
-    neighborY = getNeighborCoord(periodicityY, startY, coords, 1);
-    neighborZ = getNeighborCoord(periodicityZ, startZ, coords, 2);
-}
-
-real GridImp::getNeighborCoord(bool periodicity, real startCoord, real coords[3], int direction) const
-{
-    if (periodicity)
-    {
-        real neighborCoords[3] = {coords[0], coords[1] , coords[2] };
-        neighborCoords[direction] = neighborCoords[direction] + delta;
-        const int neighborIndex = this->transCoordToIndex(neighborCoords[0], neighborCoords[1], neighborCoords[2]);
-
-        //////////////////////////////////////////////////////////////////////////
-
-        if( field.is(neighborIndex, STOPPER_OUT_OF_GRID_BOUNDARY) )
-            return getFirstFluidNode(coords, direction, startCoord);
-        else
-            return coords[direction] + delta;
-
-    }
-    
-    return coords[direction] + delta;
-}
-
-void GridImp::getNegativeNeighborCoords(real &neighborX, real &neighborY, real &neighborZ, real x, real y, real z) const
-{
-    real coords[3] = { x, y, z };
-
-    neighborX = getNegativeNeighborCoord(periodicityX, endX, coords, 0);
-    neighborY = getNegativeNeighborCoord(periodicityY, endY, coords, 1);
-    neighborZ = getNegativeNeighborCoord(periodicityZ, endZ, coords, 2);
-}
-
-real GridImp::getNegativeNeighborCoord(bool periodicity, real startCoord, real coords[3], int direction) const
-{
-    if (periodicity)
-    {
-        real neighborCoords[3] = {coords[0], coords[1] , coords[2] };
-        neighborCoords[direction] = neighborCoords[direction] - delta;
-        const int neighborIndex = this->transCoordToIndex(neighborCoords[0], neighborCoords[1], neighborCoords[2]);
-
-        if(neighborIndex != INVALID_INDEX && !field.isStopperOutOfGrid(neighborIndex) && !field.is(neighborIndex, STOPPER_OUT_OF_GRID_BOUNDARY) )
-            return coords[direction] - delta;
-
-        return getLastFluidNode(coords, direction, startCoord);
-    }
-    
-    return coords[direction] - delta;
-}
-
-
-real GridImp::getLastFluidNode(real coords[3], int direction, real startCoord) const
-{
-    coords[direction] = startCoord;
-    int index = this->transCoordToIndex(coords[0], coords[1], coords[2]);
-    while (index != INVALID_INDEX && !field.isFluid(index))
-    {
-        coords[direction] -= delta;
-        index = this->transCoordToIndex(coords[0], coords[1], coords[2]);
-    }
-    return coords[direction];
-}
-
-real GridImp::getFirstFluidNode(real coords[3], int direction, real startCoord) const
-{
-    coords[direction] = startCoord;
-    uint index = this->transCoordToIndex(coords[0], coords[1], coords[2]);
-    while (!field.isFluid(index))
-    {
-        coords[direction] += delta;
-        index = this->transCoordToIndex(coords[0], coords[1], coords[2]);
-    }
-    return coords[direction];
-}
-
-
-int GridImp::getSparseIndex(const real &x, const real &y, const real &z) const
-{
-    const int matrixIndex = transCoordToIndex(x, y, z);
-    return sparseIndices[matrixIndex];
-}
-
-// --------------------------------------------------------- //
-//                        Getter                             //
-// --------------------------------------------------------- //
-int GridImp::getSparseIndex(uint matrixIndex) const
-{
-    return this->sparseIndices[matrixIndex];
-}
-
-real* GridImp::getDistribution() const
-{
-    return this->distribution.f;
-}
-
-int* GridImp::getDirection() const
-{
-    return this->distribution.dirs;
-}
-
-int GridImp::getStartDirection() const
-{
-    return this->distribution.dir_start;
-}
-
-int GridImp::getEndDirection() const
-{
-    return this->distribution.dir_end;
-}
-
-uint GridImp::getXIndex(real x) const
-{
-    return lround((x - startX) / delta);
-}
-
-uint GridImp::getYIndex(real y) const
-{
-    return lround((y - startY) / delta);
-}
-
-uint GridImp::getZIndex(real z) const
-{
-	return lround((z - startZ) / delta);
-}
-
-real GridImp::getDelta() const
-{
-    return delta;
-}
-
-uint GridImp::getSize() const
-{
-    return this->size;
-}
-
-uint GridImp::getSparseSize() const
-{
-    return this->sparseSize;
-}
-
-Field GridImp::getField() const
-{
-    return this->field;
-}
-
-char GridImp::getFieldEntry(uint index) const
-{
-    return this->field.getFieldEntry(index);
-}
-
-void GridImp::setFieldEntry(uint matrixIndex, char type)
-{
-    this->field.setFieldEntry(matrixIndex, type);
-}
-
-
-real GridImp::getStartX() const
-{
-    return startX;
-}
-
-real GridImp::getStartY() const
-{
-    return startY;
-}
-
-real GridImp::getStartZ() const
-{
-    return startZ;
-}
-
-real GridImp::getEndX() const
-{
-    return endX;
-}
-
-real GridImp::getEndY() const
-{
-    return endY;
-}
-
-real GridImp::getEndZ() const
-{
-    return endZ;
-}
-
-uint GridImp::getNumberOfNodesX() const
-{
-    return nx;
-}
-
-uint GridImp::getNumberOfNodesY() const
-{
-    return ny;
-}
-
-uint GridImp::getNumberOfNodesZ() const
-{
-    return nz;
-}
-
-SPtr<GridStrategy> GridImp::getGridStrategy() const
-{
-    return gridStrategy;
-}
-
-
-int* GridImp::getNeighborsX() const
-{
-    return this->neighborIndexX;
-}
-
-int* GridImp::getNeighborsY() const
-{
-    return this->neighborIndexY;
-}
-
-int* GridImp::getNeighborsZ() const
-{
-    return this->neighborIndexZ;
-}
-
-int* GridImp::getNeighborsNegative() const
-{
-    return this->neighborIndexNegative;
-}
-
-#define GEOFLUID 19
-#define GEOSOLID 16
-
-void GridImp::getNodeValues(real *xCoords, real *yCoords, real *zCoords, uint *neighborX, uint *neighborY, uint *neighborZ, uint *neighborNegative, uint *geo) const
-{
-    xCoords[0] = 0;
-    yCoords[0] = 0;
-    zCoords[0] = 0;
-    neighborX[0] = 0;
-    neighborY[0] = 0;
-    neighborZ[0] = 0;
-    geo[0] = GEOSOLID;
-
-    int nodeNumber = 0;
-    for (uint i = 0; i < this->getSize(); i++)
-    {
-        if (this->sparseIndices[i] == -1)
-            continue;
-
-        real x, y, z;
-        this->transIndexToCoords(i, x, y, z);
-
-        // + 1 for numbering shift between GridGenerator and VF_GPU
-        const uint neighborXIndex        = uint(this->neighborIndexX[i] + 1);
-        const uint neighborYIndex        = uint(this->neighborIndexY[i] + 1);
-        const uint neighborZIndex        = uint(this->neighborIndexZ[i] + 1);
-        const uint neighborNegativeIndex = uint(this->neighborIndexNegative[i] + 1);
-
-        const char type2 = this->field.getFieldEntry(i);
-
-        const uint type = uint(this->field.isFluid(i) ? GEOFLUID : GEOSOLID);
-
-        xCoords[nodeNumber + 1] = x;
-        yCoords[nodeNumber + 1] = y;
-        zCoords[nodeNumber + 1] = z;
-
-        neighborX       [nodeNumber + 1] = neighborXIndex;
-        neighborY       [nodeNumber + 1] = neighborYIndex;
-        neighborZ       [nodeNumber + 1] = neighborZIndex;
-        neighborNegative[nodeNumber + 1] = neighborNegativeIndex;
-
-        geo[nodeNumber + 1] = type;
-        nodeNumber++;
-    }
-}
diff --git a/src/gpu/GridGenerator/grid/GridImp.h b/src/gpu/GridGenerator/grid/GridImp.h
index c81aa67b42852cc2fc974513c01e9fbc0d87343c..7d44b0bb58168a6bf4da87ad94cf5a8f533002ed 100644
--- a/src/gpu/GridGenerator/grid/GridImp.h
+++ b/src/gpu/GridGenerator/grid/GridImp.h
@@ -28,7 +28,7 @@
 //
 //! \file GridImp.h
 //! \ingroup grid
-//! \author Soeren Peters, Stephan Lenz
+//! \author Soeren Peters, Stephan Lenz, Martin Schönherr
 //=======================================================================================
 #ifndef GRID_IMP_H
 #define GRID_IMP_H
@@ -44,25 +44,42 @@
 #include "grid/Cell.h"
 #include "grid/Field.h" 
 
+class TriangularMesh;
 struct Vertex;
-class GridStrategy;
+struct Triangle;
+class GridInterface;
 class Object;
 class BoundingBox;
+class TriangularMeshDiscretizationStrategy;
 
+#ifdef __GNUC__
+#ifndef __clang__
+#pragma push
+#pragma diag_suppress = 3156
+#endif
+#endif
+
+// GCC:  warning #3156-D: extern declaration of the entity DIRECTIONS is treated as a static definition
 extern int DIRECTIONS[DIR_END_MAX][DIMENSION];
 
+#ifdef __GNUC__
+#ifndef __clang__
+#pragma pop
+#endif
+#endif
+
 class GRIDGENERATOR_EXPORT GridImp : public enableSharedFromThis<GridImp>, public Grid
 {
 private:
-    GridImp();
-    GridImp(Object* object, real startX, real startY, real startZ, real endX, real endY, real endZ, real delta, SPtr<GridStrategy> gridStrategy, Distribution d, uint level);
+    GridImp() = default;
+    GridImp(Object* object, real startX, real startY, real startZ, real endX, real endY, real endZ, real delta, Distribution d, uint level);
 
 public:
-    virtual ~GridImp();
-    static SPtr<GridImp> makeShared(Object* object, real startX, real startY, real startZ, real endX, real endY, real endZ, real delta, SPtr<GridStrategy> gridStrategy, Distribution d, uint level);
+    static SPtr<GridImp> makeShared(Object* object, real startX, real startY, real startZ, real endX, real endY, real endZ, real delta, std::string d3Qxx, uint level);
 
 private:
     void initalNumberOfNodesAndSize();
+    Cell getOddCellFromIndex(uint index) const;
     bool isValidSolidStopper(uint index) const;
 	bool shouldBeBoundarySolidNode(uint index) const;
 	bool isValidEndOfGridStopper(uint index) const;
@@ -94,6 +111,7 @@ private:
 
     Field field;
     Object* object;
+    GridInterface *gridInterface;
 
     int *neighborIndexX, *neighborIndexY, *neighborIndexZ, *neighborIndexNegative;
     int *sparseIndices;
@@ -102,10 +120,20 @@ private:
 	real *qValues;
     uint *qPatches;
 
-    SPtr<GridStrategy> gridStrategy;
+    bool innerRegionFromFinerGrid;
+
+    uint numberOfLayers;
+
+    TriangularMeshDiscretizationStrategy *triangularMeshDiscretizationStrategy;
+
+    uint numberOfSolidBoundaryNodes;
+
+    bool enableFixRefinementIntoTheWall;
 
 public:
     void inital(const SPtr<Grid> fineGrid, uint numberOfLayers) override;
+    void setOddStart(bool xOddStart, bool yOddStart, bool zOddStart) override;
+    void fixOddCell(uint index);
 
     void setPeriodicity(bool periodicityX, bool periodicityY, bool periodicityZ) override;
     void setPeriodicityX(bool periodicity) override;
@@ -116,25 +144,66 @@ public:
     bool getPeriodicityY() override;
     bool getPeriodicityZ() override;
 
+    void setEnableFixRefinementIntoTheWall(bool enableFixRefinementIntoTheWall) override;
+
     void setCellTo(uint index, char type);
     void setNonStopperOutOfGridCellTo(uint index, char type);
 
     uint transCoordToIndex(const real &x, const real &y, const real &z) const override;
     void transIndexToCoords(uint index, real &x, real &y, real &z) const override;
 
+    virtual void findGridInterface(SPtr<Grid> grid, LbmOrGks lbmOrGks) override;
+
+    void repairGridInterfaceOnMultiGPU(SPtr<Grid> fineGrid) override;
+
+    virtual void limitToSubDomain(SPtr<BoundingBox> subDomainBox, LbmOrGks lbmOrGks) override;
+
     void freeMemory() override;
 
     uint getLevel(real levelNull) const;
     uint getLevel() const;
 
+    void setTriangularMeshDiscretizationStrategy(TriangularMeshDiscretizationStrategy *triangularMeshDiscretizationStrategy);
+    TriangularMeshDiscretizationStrategy *getTriangularMeshDiscretizationStrategy();
+
+    uint getNumberOfSolidBoundaryNodes() const override;
+    void setNumberOfSolidBoundaryNodes(uint numberOfSolidBoundaryNodes) override;
+
+    real getQValue(const uint index, const uint dir) const override;
+    uint getQPatch(const uint index) const override;
+
+    void setInnerRegionFromFinerGrid(bool innerRegionFromFinerGrid) override;
+
+    void setNumberOfLayers(uint numberOfLayers) override;
+
 public:
     Distribution distribution;
 
     void initalNodeToOutOfGrid(uint index);
 
+    void findInnerNodes();
     void findInnerNode(uint index);
 
-	void findEndOfGridStopperNode(uint index);
+    void discretize(Object *object, char innerType, char outerType);
+
+    bool isInside(const Cell &cell) const;
+
+    void setInnerBasedOnFinerGrid(const SPtr<Grid> fineGrid);
+
+    void addOverlap();
+    void setOverlapTmp(uint index);
+    void setOverlapFluid(uint index);
+
+    void fixRefinementIntoWall(uint xIndex, uint yIndex, uint zIndex, int dir);
+    void findStopperNode(uint index);
+    void findEndOfGridStopperNode(uint index);
+    void findSolidStopperNode(uint index);
+    void findBoundarySolidNode(uint index);
+
+    void findGridInterfaceCF(uint index, GridImp &finerGrid, LbmOrGks lbmOrGks);
+    void findGridInterfaceFC(uint index, GridImp &finerGrid);
+    void findOverlapStopper(uint index, GridImp &finerGrid);
+    void findInvalidBoundaryNodes(uint index);
 
     void setNodeTo(uint index, char type);
     bool isNode(uint index, char type) const;
@@ -160,6 +229,9 @@ public:
     int getStartDirection() const override;
     int getEndDirection() const override;
 
+    Vertex getMinimumOnNode(Vertex exact) const override;
+    Vertex getMaximumOnNode(Vertex exact) const override;
+
     real getStartX() const override;
     real getStartY() const override;
     real getStartZ() const override;
@@ -171,13 +243,25 @@ public:
     uint getNumberOfNodesZ() const override;
     void getNodeValues(real *xCoords, real *yCoords, real *zCoords, uint *neighborX, uint *neighborY, uint *neighborZ, uint *neighborNegative, uint *geo) const override;
 
-    int* getNeighborsX() const override;
+    uint getNumberOfNodesCF() const override;
+    uint getNumberOfNodesFC() const override;
+    void getGridInterfaceIndices(uint *iCellCfc, uint *iCellCff, uint *iCellFcc, uint *iCellFcf) const override;
+    static void getGridInterface(uint *gridInterfaceList, const uint *oldGridInterfaceList, uint size);
+
+    int *getNeighborsX() const override;
     int* getNeighborsY() const override;
     int* getNeighborsZ() const override;
     int* getNeighborsNegative() const override;
 
-    SPtr<GridStrategy> getGridStrategy() const override;
+    uint *getCF_coarse() const override;
+    uint *getCF_fine() const override;
+    uint *getCF_offset() const override;
 
+    uint *getFC_coarse() const override;
+    uint *getFC_fine() const override;
+    uint *getFC_offset() const override;
+
+    void print() const;
 
 public:
     virtual void findSparseIndices(SPtr<Grid> fineGrid) override;
@@ -196,9 +280,71 @@ private:
 
     int getSparseIndex(const real &expectedX, const real &expectedY, const real &expectedZ) const;
 
+    static real getMinimumOnNodes(const real &minExact, const real &decimalStart, const real &delta);
+    static real getMaximumOnNodes(const real &maxExact, const real &decimalStart, const real &delta);
+
+public:
+    BoundingBox getBoundingBoxOnNodes(Triangle &triangle) const;
+
+    void mesh(Object *object) override;
+
+    void mesh(TriangularMesh &geometry) override;
+    void mesh(Triangle &triangle);
+
+    void closeNeedleCells() override;
+    bool closeCellIfNeedle(uint index);
+
+    void closeNeedleCellsThinWall() override;
+    bool closeCellIfNeedleThinWall(uint index);
+
+    void findQs(Object *object) override;
+    void findQs(TriangularMesh &triangularMesh);
+    void findQs(Triangle &triangle);
+
+    void findQsPrimitive(Object *object);
+
+private:
+    enum class qComputationStageType { FindSolidBoundaryNodes, ComputeQs } qComputationStage;
+
+public:
+    void enableFindSolidBoundaryNodes() override
+    {
+        qComputationStage = qComputationStageType::FindSolidBoundaryNodes;
+    }
+    void enableComputeQs() override { qComputationStage = qComputationStageType::ComputeQs; }
+
 private:
-    friend class GridGpuStrategy;
-    friend class GridCpuStrategy;
+    void setDebugPoint(uint index, int pointValue);
+    void calculateQs(const Vertex &point, const Triangle &triangle) const;
+    void calculateQs(const uint index, const Vertex &point, const Triangle &triangle) const;
+    void calculateQs(const uint index, const Vertex &point, Object *object) const;
+
+    bool checkIfAtLeastOneValidQ(const uint index, const Vertex &point, const Triangle &triangle) const;
+
+    bool checkIfAtLeastOneValidQ(const uint index, const Vertex &point, Object *object) const;
+
+    void allocateQs();
+
+public:
+    void findCommunicationIndices(int direction, SPtr<BoundingBox> subDomainBox, LbmOrGks lbmOrGks) override;
+    void findCommunicationIndex(uint index, real coordinate, real limit, int direction);
+
+    uint getNumberOfSendNodes(int direction) override;
+    uint getNumberOfReceiveNodes(int direction) override;
+
+    uint getSendIndex(int direction, uint index) override;
+    uint getReceiveIndex(int direction, uint index) override;
+
+    void repairCommunicationInices(int direction) override;
+
+public:
+    struct CommunicationIndices {
+        std::vector<uint> sendIndices;
+        std::vector<uint> receiveIndices;
+    };
+
+    std::array<CommunicationIndices, 6> communicationIndices;
+
 };
 
 #endif
diff --git a/src/gpu/GridGenerator/grid/GridInterface.cpp b/src/gpu/GridGenerator/grid/GridInterface.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..47cb8ef9dd7c4704e420ca68888ce0d56c48a59e
--- /dev/null
+++ b/src/gpu/GridGenerator/grid/GridInterface.cpp
@@ -0,0 +1,441 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file GridInterface.cpp
+//! \ingroup grid
+//! \author Soeren Peters, Stephan Lenz
+//=======================================================================================
+#include "GridInterface.h"
+
+#include <iostream>
+#include <cstring>
+
+#include "grid/distributions/D3Q27.h"
+#include "grid/GridImp.h"
+#include "grid/Field.h"
+#include "grid/NodeValues.h"
+
+using namespace vf::gpu;
+
+GridInterface::GridInterface()
+{
+
+}
+
+GridInterface::~GridInterface()
+{
+
+}
+
+
+void GridInterface::findInterfaceCF(const uint& indexOnCoarseGrid, GridImp* coarseGrid, GridImp* fineGrid)
+{
+    const bool nodeOnCoarseGridIsFluid = coarseGrid->getField().isFluid(indexOnCoarseGrid);
+    if (!nodeOnCoarseGridIsFluid)
+        return;
+
+    const uint indexOnFineGridCF = getCoarseToFineIndexOnFineGrid(indexOnCoarseGrid, coarseGrid, fineGrid);
+    if (indexOnFineGridCF == INVALID_INDEX)
+        return;
+
+    const bool fineGridNodeIsFluid = fineGrid->getField().isFluid(indexOnFineGridCF);
+    if (!fineGridNodeIsFluid)
+        return;
+
+    real x, y, z;
+    coarseGrid->transIndexToCoords(indexOnCoarseGrid, x, y, z);
+
+    for(const auto dir : coarseGrid->distribution)
+    {
+        const bool isFineGridNeighborInvalid = isNeighborFineInvalid(x + dir[0] * coarseGrid->getDelta(), y + dir[1] * coarseGrid->getDelta(), z + dir[2] * coarseGrid->getDelta(), coarseGrid, fineGrid);
+        if(isFineGridNeighborInvalid)
+        {
+            cf.coarse[cf.numberOfEntries] = this->findOffsetCF(indexOnCoarseGrid, coarseGrid, cf.numberOfEntries);
+            cf.fine[cf.numberOfEntries]   = indexOnFineGridCF;
+
+            cf.numberOfEntries++;
+
+            coarseGrid->setNonStopperOutOfGridCellTo(indexOnCoarseGrid, FLUID_CFC);
+            fineGrid->setNonStopperOutOfGridCellTo(indexOnFineGridCF, FLUID_CFF);
+            break;
+        }
+    }
+}
+
+
+void GridInterface::findBoundaryGridInterfaceCF(const uint& indexOnCoarseGrid, GridImp* coarseGrid, GridImp* fineGrid)
+{
+    const bool nodeOnCoarseGridIsBoundaryStopper = coarseGrid->getField().is(indexOnCoarseGrid, STOPPER_OUT_OF_GRID_BOUNDARY);
+    if (!nodeOnCoarseGridIsBoundaryStopper)
+        return;
+
+    const uint indexOnFineGridCF = getCoarseToFineIndexOnFineGrid(indexOnCoarseGrid, coarseGrid, fineGrid);
+    if (indexOnFineGridCF == INVALID_INDEX)
+        return;
+
+    const bool fineGridNodeIsBoundaryStopper = fineGrid->getField().is(indexOnFineGridCF, STOPPER_OUT_OF_GRID_BOUNDARY);
+    if (!fineGridNodeIsBoundaryStopper)
+        return;
+
+    real x, y, z;
+    coarseGrid->transIndexToCoords(indexOnCoarseGrid, x, y, z);
+
+    for(const auto dir : coarseGrid->distribution)
+    {
+        const bool isFineGridNeighborInvalid = isNeighborFineInvalid(x + dir[0] * coarseGrid->getDelta(), y + dir[1] * coarseGrid->getDelta(), z + dir[2] * coarseGrid->getDelta(), coarseGrid, fineGrid);
+        if(isFineGridNeighborInvalid)
+        {
+			cf.coarse[cf.numberOfEntries] = this->findOffsetCF(indexOnCoarseGrid, coarseGrid, cf.numberOfEntries);
+			cf.fine[cf.numberOfEntries]   = indexOnFineGridCF;
+
+            cf.numberOfEntries++;
+
+            coarseGrid->setNonStopperOutOfGridCellTo(indexOnCoarseGrid, FLUID_CFC);
+            fineGrid->setNonStopperOutOfGridCellTo(indexOnFineGridCF, FLUID_CFF);
+            break;
+        }
+    }
+}
+
+void GridInterface::findInterfaceCF_GKS(const uint& indexOnCoarseGrid, GridImp* coarseGrid, GridImp* fineGrid)
+{
+	const bool nodeOnCoarseGridIsFluid = coarseGrid->getField().isFluid(indexOnCoarseGrid);
+	if (!nodeOnCoarseGridIsFluid)
+		return;
+
+	real x, y, z;
+	coarseGrid->transIndexToCoords(indexOnCoarseGrid, x, y, z);
+
+	for (const auto dir : coarseGrid->distribution)
+	{
+		const uint indexOnFineGrid = fineGrid->transCoordToIndex(x + 0.25 * dir[0] * coarseGrid->getDelta(),
+																 y + 0.25 * dir[1] * coarseGrid->getDelta(),
+																 z + 0.25 * dir[2] * coarseGrid->getDelta());
+
+		if (indexOnFineGrid != INVALID_INDEX && fineGrid->getField().is(indexOnFineGrid, STOPPER_OUT_OF_GRID)) 
+		{
+			coarseGrid->getField().setFieldEntry(indexOnCoarseGrid, FLUID_CFC);
+			break;
+		}
+	}
+}
+
+void GridInterface::findInterfaceFC(const uint& indexOnCoarseGrid, GridImp* coarseGrid, GridImp* fineGrid)
+{
+    const bool nodeOnCoarseGridIsFluid = coarseGrid->getField().isFluid(indexOnCoarseGrid);
+    const bool nodeOnCoarseGridIsCoarseToFine = coarseGrid->getField().isCoarseToFineNode(indexOnCoarseGrid);
+    if (!nodeOnCoarseGridIsFluid || nodeOnCoarseGridIsCoarseToFine)
+        return;
+
+    const uint indexOnFineGridFC = getFineToCoarseIndexOnFineGrid(indexOnCoarseGrid, coarseGrid, fineGrid);
+    if (indexOnFineGridFC == INVALID_INDEX)
+        return;
+
+    const bool fineGridNodeIsFluid = fineGrid->getField().isFluid(indexOnFineGridFC);
+    if (!fineGridNodeIsFluid)
+        return;
+
+    real x, y, z;
+    coarseGrid->transIndexToCoords(indexOnCoarseGrid, x, y, z);
+
+    for (const auto dir : coarseGrid->distribution)
+    {
+        const uint neighborIndex = coarseGrid->transCoordToIndex(x + dir[0] * coarseGrid->getDelta(), y + dir[1] * coarseGrid->getDelta(), z + dir[2] * coarseGrid->getDelta());
+		if (neighborIndex != INVALID_INDEX)
+		{
+			const bool neighborBelongsToCoarseToFineInterpolationCell = coarseGrid->getField().isCoarseToFineNode(neighborIndex);
+			if (neighborBelongsToCoarseToFineInterpolationCell)
+			{
+				fc.coarse[fc.numberOfEntries] = indexOnCoarseGrid;
+				fc.fine[fc.numberOfEntries] = this->findOffsetFC(indexOnFineGridFC, fineGrid, fc.numberOfEntries);
+
+				fc.numberOfEntries++;
+
+				fineGrid->setNonStopperOutOfGridCellTo(indexOnFineGridFC, FLUID_FCF);
+				coarseGrid->getField().setFieldEntry(indexOnCoarseGrid, FLUID_FCC);
+				break;
+			}
+		}
+    }
+}
+
+void GridInterface::findOverlapStopper(const uint& indexOnCoarseGrid, GridImp* coarseGrid, GridImp* fineGrid)
+{
+    const bool nodeOnCoarseGridIsFluid = coarseGrid->getField().isFluid(indexOnCoarseGrid);
+    const bool nodeOnCoarseGridIsCoarseToFine = coarseGrid->getField().isCoarseToFineNode(indexOnCoarseGrid);
+    const bool nodeOnCoarseGridIsFineToCoarse = coarseGrid->getField().isFineToCoarseNode(indexOnCoarseGrid);
+    if (!nodeOnCoarseGridIsFluid || nodeOnCoarseGridIsCoarseToFine || nodeOnCoarseGridIsFineToCoarse)
+        return;
+
+    const int indexOnFineGridFC = getFineToCoarseIndexOnFineGrid(indexOnCoarseGrid, coarseGrid, fineGrid);
+    if (indexOnFineGridFC == -1)
+        return;
+
+    real x, y, z;
+    coarseGrid->transIndexToCoords(indexOnCoarseGrid, x, y, z);
+
+    bool neighborBelongsToFineToCoarseInterpolationCell = false;
+    for (const auto dir : coarseGrid->distribution)
+    {
+        //if (dir[0] > 0 || dir[1] > 0 || dir[2] > 0)  //only Esoteric Twist stopper, not perfectly implemented
+        //    continue;								   //should not be here, should be made conditional
+
+        const uint neighborIndex = coarseGrid->transCoordToIndex(x + dir[0] * coarseGrid->getDelta(), y + dir[1] * coarseGrid->getDelta(), z + dir[2] * coarseGrid->getDelta());
+        neighborBelongsToFineToCoarseInterpolationCell = neighborIndex != INVALID_INDEX ? coarseGrid->getField().isFineToCoarseNode(neighborIndex) : false;
+        if (neighborBelongsToFineToCoarseInterpolationCell)
+        {
+            coarseGrid->getField().setFieldEntryToStopperCoarseUnderFine(indexOnCoarseGrid);
+            break;
+        }
+    }
+
+	//should be inside of fine grid and can be deleted
+    if(!neighborBelongsToFineToCoarseInterpolationCell && (fineGrid->getField().isInvalidSolid(indexOnFineGridFC) || 
+	                                                       fineGrid->getField().isFluid(indexOnFineGridFC) ||
+	                                                       fineGrid->getField().is(indexOnFineGridFC, STOPPER_SOLID) || 
+	                                                       fineGrid->getField().is(indexOnFineGridFC, BC_SOLID)))
+        coarseGrid->getField().setFieldEntryToInvalidCoarseUnderFine(indexOnCoarseGrid);
+}
+
+ void GridInterface::findInvalidBoundaryNodes(const uint& indexOnCoarseGrid, GridImp* coarseGrid)
+{
+     if( !coarseGrid->getField().is(indexOnCoarseGrid, STOPPER_OUT_OF_GRID_BOUNDARY ) ) return;
+
+     if( !coarseGrid->hasNeighborOfType(indexOnCoarseGrid, FLUID) &&
+         !coarseGrid->hasNeighborOfType(indexOnCoarseGrid, FLUID_CFC) &&
+         !coarseGrid->hasNeighborOfType(indexOnCoarseGrid, FLUID_CFF) )
+         coarseGrid->getField().setFieldEntryToInvalidCoarseUnderFine(indexOnCoarseGrid);
+}
+
+bool GridInterface::isNeighborFineInvalid(real x, real y, real z, const GridImp* coarseGrid, const GridImp* fineGrid)
+{
+    const uint neighbor = coarseGrid->transCoordToIndex(x, y, z);
+
+    if( neighbor == INVALID_INDEX )
+        return false;
+
+    if( (neighbor != INVALID_INDEX) && (coarseGrid->getField().isStopperOutOfGrid(neighbor) || coarseGrid->getField().is(neighbor, STOPPER_OUT_OF_GRID_BOUNDARY)) )
+        return false;
+
+    const uint indexOnFineGrid = getCoarseToFineIndexOnFineGrid(neighbor, coarseGrid, fineGrid);
+    if (indexOnFineGrid == INVALID_INDEX)
+        return true;
+
+    return fineGrid->getField().isInvalidOutOfGrid(indexOnFineGrid) || fineGrid->getField().isStopperOutOfGrid(indexOnFineGrid);
+}
+
+uint GridInterface::getCoarseToFineIndexOnFineGrid(const uint& indexOnCoarseGrid, const GridImp* coarseGrid, const GridImp* fineGrid)
+{
+    if( indexOnCoarseGrid == INVALID_INDEX )
+        return INVALID_INDEX;
+
+    real x, y, z;
+    coarseGrid->transIndexToCoords(indexOnCoarseGrid, x, y, z);
+    const real xFine = x + (fineGrid->getDelta() * 0.5);
+    const real yFine = y + (fineGrid->getDelta() * 0.5);
+    const real zFine = z + (fineGrid->getDelta() * 0.5);
+
+    return fineGrid->transCoordToIndex(xFine, yFine, zFine);
+}
+
+uint GridInterface::getFineToCoarseIndexOnFineGrid(const uint& indexOnCoarseGrid, const GridImp* coarseGrid, const GridImp* fineGrid)
+{
+    real x, y, z;
+    coarseGrid->transIndexToCoords(indexOnCoarseGrid, x, y, z);
+    const real xFine = x - (fineGrid->getDelta() * 0.5);
+    const real yFine = y - (fineGrid->getDelta() * 0.5);
+    const real zFine = z - (fineGrid->getDelta() * 0.5);
+
+    return fineGrid->transCoordToIndex(xFine, yFine, zFine);
+}
+
+void GridInterface::findForGridInterfaceSparseIndexCF(GridImp* coarseGrid, GridImp* fineGrid, uint index)
+{
+    findSparseIndex(cf.coarse, coarseGrid, index);
+    findSparseIndex(cf.fine, fineGrid, index);
+
+    if( cf.coarse[index] == 686916 )
+        printf("%d ===> %d \n", cf.coarse[index], cf.fine[index]);
+}
+
+void GridInterface::findForGridInterfaceSparseIndexFC(GridImp* coarseGrid, GridImp* fineGrid, uint index)
+{
+    findSparseIndex(fc.coarse, coarseGrid, index);
+    findSparseIndex(fc.fine, fineGrid, index);
+}
+
+void GRIDGENERATOR_EXPORT GridInterface::repairGridInterfaceOnMultiGPU(SPtr<GridImp> coarseGrid, SPtr<GridImp> fineGrid)
+{
+    {
+        std::vector<uint> tmpCFC;
+        std::vector<uint> tmpCFF;
+        std::vector<uint> tmpCFOffset;
+
+        for (uint index = 0; index < cf.numberOfEntries; index++) {
+
+            real x, y, z;
+            coarseGrid->transIndexToCoords(this->cf.coarse[index], x, y, z);
+            Cell cell(x, y, z, coarseGrid->getDelta());
+
+            if (coarseGrid->cellContainsOnly(cell, FLUID_CFC)) {
+                tmpCFC.push_back     (this->cf.coarse[index]);
+                tmpCFF.push_back     (this->cf.fine[index]);
+                tmpCFOffset.push_back(this->cf.offset[index]);
+            }
+        }
+
+        delete[] cf.coarse;
+        delete[] cf.fine;
+        delete[] cf.offset;
+
+        cf.numberOfEntries = (uint)tmpCFC.size();
+
+        cf.coarse = new uint[cf.numberOfEntries];
+        cf.fine   = new uint[cf.numberOfEntries];
+        cf.offset = new uint[cf.numberOfEntries];
+
+        memcpy(cf.coarse, tmpCFC.data()     , sizeof(uint)*cf.numberOfEntries);
+        memcpy(cf.fine  , tmpCFF.data()     , sizeof(uint)*cf.numberOfEntries);
+        memcpy(cf.offset, tmpCFOffset.data(), sizeof(uint)*cf.numberOfEntries);
+    }
+
+    {
+        std::vector<uint> tmpFCF;
+        std::vector<uint> tmpFCC;
+        std::vector<uint> tmpFCOffset;
+
+        for (uint index = 0; index < fc.numberOfEntries; index++) {
+
+            real x, y, z;
+            fineGrid->transIndexToCoords(this->fc.fine[index], x, y, z);
+            Cell cell(x, y, z, fineGrid->getDelta());
+
+            if (fineGrid->cellContainsOnly(cell, FLUID_FCF)) {
+                tmpFCF.push_back     (this->fc.fine[index]);
+                tmpFCC.push_back     (this->fc.coarse[index]);
+                tmpFCOffset.push_back(this->fc.offset[index]);
+            }
+        }
+        
+        delete[] fc.fine;
+        delete[] fc.coarse;
+        delete[] fc.offset;
+
+        fc.numberOfEntries = (uint)tmpFCC.size();
+        
+        fc.fine   = new uint[fc.numberOfEntries];
+        fc.coarse = new uint[fc.numberOfEntries];
+        fc.offset = new uint[fc.numberOfEntries];
+        
+        memcpy(fc.fine  , tmpFCF.data()     , sizeof(uint)*fc.numberOfEntries);
+        memcpy(fc.coarse, tmpFCC.data()     , sizeof(uint)*fc.numberOfEntries);
+        memcpy(fc.offset, tmpFCOffset.data(), sizeof(uint)*fc.numberOfEntries);
+    }
+}
+
+void GridInterface::findSparseIndex(uint* indices, GridImp* grid, uint index)
+{
+    const uint matrixIndex = indices[index];
+    const uint sparseIndex = grid->getSparseIndex(matrixIndex);
+    indices[index] = sparseIndex;
+}
+
+uint GridInterface::findOffsetCF(const uint& indexOnCoarseGrid, GridImp* coarseGrid, uint interfaceIndex)
+{
+    real x, y, z;
+    coarseGrid->transIndexToCoords(indexOnCoarseGrid, x, y, z);
+
+    Cell cell(x, y, z, coarseGrid->getDelta());
+
+    if( coarseGrid->cellContainsOnly( cell, FLUID, FLUID_CFC ) ){
+        this->cf.offset[ interfaceIndex ] = DIR_27_ZERO;
+        return indexOnCoarseGrid;
+    }
+
+    uint dirIndex = 0;
+    for(const auto dir : coarseGrid->distribution){
+    
+        Cell neighborCell( x + dir[0] * coarseGrid->getDelta(), 
+                           y + dir[1] * coarseGrid->getDelta(), 
+                           z + dir[2] * coarseGrid->getDelta(), 
+                           coarseGrid->getDelta() );
+
+        if( coarseGrid->cellContainsOnly( neighborCell, FLUID, FLUID_CFC ) ){
+            this->cf.offset[ interfaceIndex ] = dirIndex;
+
+			return coarseGrid->transCoordToIndex( x + dir[0] * coarseGrid->getDelta(),
+				                                  y + dir[1] * coarseGrid->getDelta(),
+				                                  z + dir[2] * coarseGrid->getDelta() );
+        }
+    
+        dirIndex++;
+    }
+
+	// this point should never be reached
+	return indexOnCoarseGrid;
+}
+
+uint GridInterface::findOffsetFC(const uint& indexOnFineGrid, GridImp* fineGrid, uint interfaceIndex)
+{
+    real x, y, z;
+    fineGrid->transIndexToCoords(indexOnFineGrid, x, y, z);
+
+    Cell cell(x, y, z, fineGrid->getDelta());
+
+    if( fineGrid->cellContainsOnly( cell, FLUID, FLUID_FCF ) ){
+        this->fc.offset[ interfaceIndex ] = DIR_27_ZERO;
+        return indexOnFineGrid;
+    }
+
+    uint dirIndex = 0;
+    for(const auto dir : fineGrid->distribution){
+    
+        Cell neighborCell( x + dir[0] * fineGrid->getDelta(), 
+                           y + dir[1] * fineGrid->getDelta(), 
+                           z + dir[2] * fineGrid->getDelta(), 
+                           fineGrid->getDelta() );
+
+        if( fineGrid->cellContainsOnly( neighborCell, FLUID, FLUID_CFC ) ){
+			this->fc.offset[interfaceIndex] = dirIndex;
+
+			return fineGrid->transCoordToIndex(x + dir[0] * fineGrid->getDelta(),
+				                               y + dir[1] * fineGrid->getDelta(),
+				                               z + dir[2] * fineGrid->getDelta());
+        }
+    
+        dirIndex++;
+    }
+
+	// this point should never be reached
+	return indexOnFineGrid;
+}
+
+void GridInterface::print() const
+{
+    printf("Grid Interface - CF nodes: %d, FC nodes: %d\n", cf.numberOfEntries, fc.numberOfEntries);
+}
diff --git a/src/gpu/GridGenerator/grid/GridInterface.h b/src/gpu/GridGenerator/grid/GridInterface.h
new file mode 100644
index 0000000000000000000000000000000000000000..303d79d4995ea04fe30b2a004c5738bf9c926cf2
--- /dev/null
+++ b/src/gpu/GridGenerator/grid/GridInterface.h
@@ -0,0 +1,86 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file GridInterface.h
+//! \ingroup grid
+//! \author Soeren Peters, Stephan Lenz
+//=======================================================================================
+#ifndef GRID_INTERFACE_H
+#define GRID_INTERFACE_H
+
+#include "global.h"
+
+class GridImp;
+
+class GridInterface
+{
+public:
+    GRIDGENERATOR_EXPORT GridInterface();
+    GRIDGENERATOR_EXPORT ~GridInterface();
+
+    void GRIDGENERATOR_EXPORT findInterfaceCF(const uint& indexOnCoarseGrid, GridImp* coarseGrid, GridImp* fineGrid);
+    void GRIDGENERATOR_EXPORT findBoundaryGridInterfaceCF(const uint& indexOnCoarseGrid, GridImp* coarseGrid, GridImp* fineGrid);
+
+
+	void GRIDGENERATOR_EXPORT findInterfaceCF_GKS(const uint& indexOnCoarseGrid, GridImp* coarseGrid, GridImp* fineGrid);
+
+	void GRIDGENERATOR_EXPORT findInterfaceFC(const uint& indexOnCoarseGrid, GridImp* coarseGrid, GridImp* fineGrid);
+    void GRIDGENERATOR_EXPORT findOverlapStopper(const uint& indexOnCoarseGrid, GridImp* coarseGrid, GridImp* fineGrid);
+    
+    void GRIDGENERATOR_EXPORT findInvalidBoundaryNodes(const uint& indexOnCoarseGrid, GridImp* coarseGrid);
+
+    void GRIDGENERATOR_EXPORT findForGridInterfaceSparseIndexCF(GridImp* coarseGrid, GridImp* fineGrid, uint index);
+    void GRIDGENERATOR_EXPORT findForGridInterfaceSparseIndexFC(GridImp* coarseGrid, GridImp* fineGrid, uint index);
+
+    void GRIDGENERATOR_EXPORT repairGridInterfaceOnMultiGPU(SPtr<GridImp> coarseGrid, SPtr<GridImp> fineGrid);
+
+    void GRIDGENERATOR_EXPORT print() const;
+
+    struct Interface
+    {
+        uint *fine, *coarse;
+        uint numberOfEntries = 0;
+        uint *offset;
+    } fc, cf;
+
+
+private:
+    uint getCoarseToFineIndexOnFineGrid(const uint& indexOnCoarseGrid, const GridImp* coarseGrid, const GridImp* fineGrid);
+    bool isNeighborFineInvalid(real x, real y, real z, const GridImp* coarseGrid, const GridImp* fineGrid);
+
+    uint getFineToCoarseIndexOnFineGrid(const uint& indexOnCoarseGrid, const GridImp* coarseGrid, const GridImp* fineGrid);
+
+    static void findSparseIndex(uint* indices, GridImp* grid, uint index);
+
+    uint findOffsetCF( const uint& indexOnCoarseGrid, GridImp* coarseGrid, uint interfaceIndex );
+
+    uint findOffsetFC( const uint& indexOnCoarseGrid, GridImp* coarseGrid, uint interfaceIndex );
+};
+
+
+#endif
\ No newline at end of file
diff --git a/src/gpu/GridGenerator/grid/GridStrategy/GridCpuStrategy/GridCpuStrategy.cpp b/src/gpu/GridGenerator/grid/GridStrategy/GridCpuStrategy/GridCpuStrategy.cpp
deleted file mode 100644
index ac63339582e3aed6c2d644807dbd44db9725b3c3..0000000000000000000000000000000000000000
--- a/src/gpu/GridGenerator/grid/GridStrategy/GridCpuStrategy/GridCpuStrategy.cpp
+++ /dev/null
@@ -1,125 +0,0 @@
-//=======================================================================================
-// ____          ____    __    ______     __________   __      __       __        __         
-// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |        
-//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |        
-//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |        
-//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____    
-//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|   
-//      \    \  |    |   ________________________________________________________________    
-//       \    \ |    |  |  ______________________________________________________________|   
-//        \    \|    |  |  |         __          __     __     __     ______      _______    
-//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)   
-//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______    
-//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
-//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/   
-//
-//  This file is part of VirtualFluids. VirtualFluids 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.
-//  
-//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
-//
-//! \file GridCpuStrategy.cpp
-//! \ingroup grid
-//! \author Soeren Peters, Stephan Lenz
-//=======================================================================================
-#include "GridCpuStrategy.h"
-
-#include <time.h>
-#include <stdio.h>
-#include <omp.h>
-#include <vector>
-#include <iostream>
-
-#include "grid/distributions/Distribution.h"
-#include "grid/GridImp.h"
-#include "grid/NodeValues.h"
-
-void GridCpuStrategy::allocateGridMemory(SPtr<GridImp> grid)
-{
-    grid->neighborIndexX        = new int[grid->size];
-    grid->neighborIndexY        = new int[grid->size];
-    grid->neighborIndexZ        = new int[grid->size];
-    grid->neighborIndexNegative = new int[grid->size];
-
-    grid->sparseIndices = new int[grid->size];
-
-	grid->qIndices = new uint[grid->size];
-	for (uint i = 0; i < grid->size; i++) 
-		grid->qIndices[i] = INVALID_INDEX;
-}
-
-void GridCpuStrategy::initalNodesToOutOfGrid(SPtr<GridImp> grid)
-{
-#pragma omp parallel for
-    for (int index = 0; index < (int)grid->size; index++)
-        grid->initalNodeToOutOfGrid(index);
-}
-
-void GridCpuStrategy::allocateFieldMemory(Field* field)
-{
-    field->field = new char[field->size];
-}
-
-
-void GridCpuStrategy::findInnerNodes(SPtr<GridImp> grid)
-{
-#pragma omp parallel for
-    for (int index = 0; index < (int)grid->size; index++)
-        grid->findInnerNode(index);
-}
-
-void GridCpuStrategy::findEndOfGridStopperNodes(SPtr<GridImp> grid)
-{
-#pragma omp parallel for
-	for (int index = 0; index < (int)grid->size; index++)
-		grid->findEndOfGridStopperNode(index);
-}
-
-void GridCpuStrategy::findSparseIndices(SPtr<GridImp> coarseGrid, SPtr<GridImp> fineGrid)
-{
-    *logging::out << logging::Logger::INFO_INTERMEDIATE << "Find sparse indices...";
-
-    coarseGrid->updateSparseIndices();
-    findForNeighborsNewIndices(coarseGrid);
-    if (fineGrid)
-    {
-        fineGrid->updateSparseIndices();
-    }
-
-    const uint newGridSize = coarseGrid->getSparseSize();
-    *logging::out << logging::Logger::INFO_INTERMEDIATE << "... done. new size: " << newGridSize << ", delete nodes:" << coarseGrid->getSize() - newGridSize << "\n";
-}
-
-
-void GridCpuStrategy::findForNeighborsNewIndices(SPtr<GridImp> grid)
-{
-#pragma omp parallel for
-    for (int index = 0; index < (int)grid->getSize(); index++)
-        grid->setNeighborIndices(index);
-}
-
-void GridCpuStrategy::freeFieldMemory(Field* field)
-{
-    delete[] field->field;
-}
-
-void GridCpuStrategy::freeMemory(SPtr<GridImp> grid)
-{
-    if( grid->neighborIndexX        != nullptr ) { delete[] grid->neighborIndexX;        grid->neighborIndexX        = nullptr; }
-    if( grid->neighborIndexY        != nullptr ) { delete[] grid->neighborIndexY;        grid->neighborIndexY        = nullptr; }
-    if( grid->neighborIndexZ        != nullptr ) { delete[] grid->neighborIndexZ;        grid->neighborIndexZ        = nullptr; }
-    if( grid->neighborIndexNegative != nullptr ) { delete[] grid->neighborIndexNegative; grid->neighborIndexNegative = nullptr; }
-    if( grid->sparseIndices         != nullptr ) { delete[] grid->sparseIndices;         grid->sparseIndices         = nullptr; }
-	if( grid->qIndices              != nullptr ) { delete[] grid->qIndices;              grid->qIndices              = nullptr; }
-	if( grid->qValues               != nullptr ) { delete[] grid->qValues;               grid->qValues               = nullptr; }
-	if( grid->qPatches              != nullptr ) { delete[] grid->qPatches;              grid->qPatches              = nullptr; }
-}
-
diff --git a/src/gpu/GridGenerator/grid/NodeValues.h b/src/gpu/GridGenerator/grid/NodeValues.h
index 36ed127de4cafa3a6a2b5dca88cfad3a79fea566..c726fdf85c8199633e118d8f8a5365ee658d4e6a 100644
--- a/src/gpu/GridGenerator/grid/NodeValues.h
+++ b/src/gpu/GridGenerator/grid/NodeValues.h
@@ -28,39 +28,51 @@
 //
 //! \file NodeValues.h
 //! \ingroup grid
-//! \author Soeren Peters, Stephan Lenz
+//! \author Soeren Peters, Stephan Lenz, Martin Schoenherr
 //=======================================================================================
 #ifndef NodeValues_H
 #define NodeValues_H
 
-#define FLUID 0
+namespace vf
+{
+namespace gpu
+{
 
-#define FLUID_CFC 1
-#define FLUID_CFF 2
+static constexpr char FLUID = 0;
 
-#define FLUID_FCC 3
-#define FLUID_FCF 4
+static constexpr char FLUID_CFC = 1;
+static constexpr char FLUID_CFF = 2;
 
-#define MULTI_GPU_SEND 10
-#define MULTI_GPU_RECIEVE 11
+static constexpr char FLUID_FCC = 3;
+static constexpr char FLUID_FCF = 4;
 
-#define BC_PRESSURE 20
-#define BC_VELOCITY 21
-#define BC_SOLID 22
+static constexpr char MULTI_GPU_SEND    = 10;
+static constexpr char MULTI_GPU_RECIEVE = 11;
 
-#define BC_SLIP 23
-#define BC_NOSLIP 24
-#define BC_OUTFLOW 25
+static constexpr char BC_PRESSURE = 20;
+static constexpr char BC_VELOCITY = 21;
+static constexpr char BC_SOLID    = 22;
 
-#define STOPPER_OUT_OF_GRID 30
-#define STOPPER_COARSE_UNDER_FINE 31
-#define STOPPER_SOLID 32
-#define STOPPER_OUT_OF_GRID_BOUNDARY 33
+static constexpr char BC_SLIP    = 23;
+static constexpr char BC_NOSLIP  = 24;
+static constexpr char BC_OUTFLOW = 25;
 
-#define INVALID_OUT_OF_GRID 40
-#define INVALID_COARSE_UNDER_FINE 41
-#define INVALID_SOLID 42
+static constexpr char STOPPER_OUT_OF_GRID          = 30;
+static constexpr char STOPPER_COARSE_UNDER_FINE    = 31;
+static constexpr char STOPPER_SOLID                = 32;
+static constexpr char STOPPER_OUT_OF_GRID_BOUNDARY = 33;
 
-#define OVERLAP_TMP 60
+static constexpr char INVALID_OUT_OF_GRID       = 40;
+static constexpr char INVALID_COARSE_UNDER_FINE = 41;
+static constexpr char INVALID_SOLID             = 42;
+
+static constexpr char INSIDE                    = 50;
+static constexpr char NEGATIVE_DIRECTION_BORDER = 51;
+static constexpr char Q_DEPRECATED              = 52;
+
+static constexpr char OVERLAP_TMP = 60;
+
+} // namespace gpu
+} // namespace vf
 
 #endif
diff --git a/src/gpu/GridGenerator/grid/distributions/D3Q7.h b/src/gpu/GridGenerator/grid/distributions/D3Q7.h
new file mode 100644
index 0000000000000000000000000000000000000000..f43aeb01c5ebf85f4b2f97e90f61585d4dd6da88
--- /dev/null
+++ b/src/gpu/GridGenerator/grid/distributions/D3Q7.h
@@ -0,0 +1,73 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file D3Q7.h
+//! \ingroup grid
+//! \author Soeren Peters, Stephan Lenz
+//=======================================================================================
+#ifndef D3Q7_H
+#define D3Q7_H
+
+#define DIR_7_E    0
+#define DIR_7_W    1
+#define DIR_7_N    2
+#define DIR_7_S    3
+#define DIR_7_T    4
+#define DIR_7_B    5
+#define DIR_7_ZERO 6
+
+#define DIR_7_START  0
+#define DIR_7_END   6
+
+
+#define DIR_7_E_X  1
+#define DIR_7_E_Y  0
+#define DIR_7_E_Z  0
+
+#define DIR_7_W_X  -1
+#define DIR_7_W_Y  0
+#define DIR_7_W_Z  0
+
+#define DIR_7_N_X  0
+#define DIR_7_N_Y  1
+#define DIR_7_N_Z  0
+
+#define DIR_7_S_X  0
+#define DIR_7_S_Y  -1
+#define DIR_7_S_Z  0
+
+#define DIR_7_T_X  0
+#define DIR_7_T_Y  0
+#define DIR_7_T_Z  1
+
+#define DIR_7_B_X  0
+#define DIR_7_B_Y  0
+#define DIR_7_B_Z  -1
+
+
+#endif
diff --git a/src/gpu/GridGenerator/io/GridVTKWriter/GridVTKWriter.cpp b/src/gpu/GridGenerator/io/GridVTKWriter/GridVTKWriter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2c8624732d70e52ac24d843888548bdaf5585686
--- /dev/null
+++ b/src/gpu/GridGenerator/io/GridVTKWriter/GridVTKWriter.cpp
@@ -0,0 +1,439 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file GridVTKWriter.cpp
+//! \ingroup io
+//! \author Soeren Peters, Stephan Lenz
+//=======================================================================================
+#define _CRT_SECURE_NO_DEPRECATE
+#include "GridVTKWriter.h"
+
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <memory>
+
+#include "basics/basics/writer/WbWriterVtkXmlBinary.h"
+#include "basics/basics/container/CbArray3D.h"
+
+#include "geometries/Vertex/Vertex.h"
+
+#include "grid/Grid.h"
+#include "grid/NodeValues.h"
+#include "grid/Cell.h"
+
+using namespace vf::gpu;
+
+FILE* GridVTKWriter::file = nullptr;
+WRITING_FORMAT GridVTKWriter::format = WRITING_FORMAT::ASCII;
+
+
+void GridVTKWriter::writeSparseGridToVTK(SPtr<Grid> grid, const std::string& name, WRITING_FORMAT format)
+{
+    initalVtkWriter(format, name);
+    writeVtkFile(grid);
+}
+
+void GridVTKWriter::writeGridToVTKXML(SPtr<Grid> grid, const std::string& name, WRITING_FORMAT format)
+{
+    
+    const uint chunkSize = 20000000; 
+
+    const uint chunkSizeZ = chunkSize / ( grid->getNumberOfNodesX() * grid->getNumberOfNodesY() );
+
+    for( uint startZ_Loop = 0, endZ_Loop = chunkSizeZ, part = 0; 
+         endZ_Loop < grid->getNumberOfNodesZ() + chunkSizeZ; 
+         startZ_Loop += chunkSizeZ, endZ_Loop += chunkSizeZ, part++ )
+
+    {
+        int endZ   = endZ_Loop;
+        int startZ = startZ_Loop - 1;
+
+        if(endZ >= (int)grid->getNumberOfNodesZ()) 
+            endZ = grid->getNumberOfNodesZ();
+
+        if( startZ < 0 )
+            startZ = 0;
+
+        std::vector<UbTupleFloat3> nodes;
+        std::vector<UbTupleUInt8> cells;
+        std::vector<std::string> nodedatanames;
+        std::vector< std::vector<double> > nodedata;
+
+        *logging::out << logging::Logger::INFO_INTERMEDIATE << "Write Grid to XML VTK (*.vtu) output file : " + name + "_Part_" + std::to_string(part) + "\n";
+
+        nodedatanames.push_back("types");
+        nodedatanames.push_back("sparse_id");
+        nodedatanames.push_back("matrix_id");
+
+        nodedata.resize(nodedatanames.size());
+
+        CbArray3D<int> nodeNumbers(grid->getNumberOfNodesX(), grid->getNumberOfNodesY(), grid->getNumberOfNodesZ(), -1);
+        int nr = 0;
+
+        for (uint xIndex = 0; xIndex < grid->getNumberOfNodesX(); xIndex++)
+        {
+            for (uint yIndex = 0; yIndex < grid->getNumberOfNodesY(); yIndex++)
+            {
+                for (int zIndex = startZ; zIndex < endZ; zIndex++)
+                {
+                    real x, y, z;
+                    uint index =
+                        grid->getNumberOfNodesX() * grid->getNumberOfNodesY() * zIndex
+                        + grid->getNumberOfNodesX() *                             yIndex
+                        + xIndex;
+
+                    grid->transIndexToCoords(index, x, y, z);
+
+                    nodeNumbers(xIndex, yIndex, zIndex) = nr++;
+                    nodes.push_back(UbTupleFloat3(float(x), float(y), float(z)));
+
+                    const char type = grid->getFieldEntry(grid->transCoordToIndex(x, y, z));
+                    nodedata[0].push_back(type);
+                    nodedata[1].push_back(grid->getSparseIndex(index));
+                    nodedata[2].push_back(index);
+                }
+            }
+        }
+
+        int SWB, SEB, NEB, NWB, SWT, SET, NET, NWT;
+        for (uint xIndex = 0; xIndex < grid->getNumberOfNodesX() - 1; xIndex++)
+        {
+            for (uint yIndex = 0; yIndex < grid->getNumberOfNodesY() - 1; yIndex++)
+            {
+                for (int zIndex = startZ; zIndex < endZ - 1; zIndex++)
+                {
+                    real x, y, z;
+                    uint index = grid->getNumberOfNodesX() * grid->getNumberOfNodesY() * zIndex
+                        + grid->getNumberOfNodesX() *                             yIndex
+                        + xIndex;
+
+                    grid->transIndexToCoords(index, x, y, z);
+
+                    if ((SWB = nodeNumbers(xIndex, yIndex, zIndex)) >= 0
+                        && (SEB = nodeNumbers(xIndex + 1, yIndex, zIndex)) >= 0
+                        && (NEB = nodeNumbers(xIndex + 1, yIndex + 1, zIndex)) >= 0
+                        && (NWB = nodeNumbers(xIndex, yIndex + 1, zIndex)) >= 0
+                        && (SWT = nodeNumbers(xIndex, yIndex, zIndex + 1)) >= 0
+                        && (SET = nodeNumbers(xIndex + 1, yIndex, zIndex + 1)) >= 0
+                        && (NET = nodeNumbers(xIndex + 1, yIndex + 1, zIndex + 1)) >= 0
+                        && (NWT = nodeNumbers(xIndex, yIndex + 1, zIndex + 1)) >= 0)
+                    {
+                        Cell cell(x, y, z, grid->getDelta());
+                        //if (grid->nodeInCellIs(cell, INVALID_OUT_OF_GRID) || grid->nodeInCellIs(cell, INVALID_COARSE_UNDER_FINE))
+                        //	continue;
+
+                        cells.push_back(makeUbTuple(uint(SWB), uint(SEB), uint(NEB), uint(NWB), uint(SWT), uint(SET), uint(NET), uint(NWT)));
+                    }
+                }
+            }
+        }
+        WbWriterVtkXmlBinary::getInstance()->writeOctsWithNodeData(name + "_Part_" + std::to_string(part), nodes, cells, nodedatanames, nodedata);
+        *logging::out << logging::Logger::INFO_INTERMEDIATE << "done. \n";
+    }
+
+}
+
+void GridVTKWriter::writeInterpolationCellsToVTKXML(SPtr<Grid> grid, SPtr<Grid> gridCoarse, const std::string& name, WRITING_FORMAT format)
+{
+    std::vector<char> nodeInterpolationCellType( grid->getSize() );
+    for( auto& type : nodeInterpolationCellType ) type = -1;
+
+    std::vector<char> nodeOffset( grid->getSize() );
+    for( auto& offset : nodeOffset ) offset = -1;
+
+    std::vector<uint> matrixIndices( grid->getSparseSize() );
+
+    for( uint matrixIndex = 0; matrixIndex < grid->getSize(); matrixIndex++ ){
+        uint sparseIndex = grid->getSparseIndex(matrixIndex);
+        if( sparseIndex != INVALID_INDEX )
+            matrixIndices[ sparseIndex ] = matrixIndex;
+    }
+
+    for( uint index = 0; index < grid->getNumberOfNodesCF(); index++ ){
+        nodeInterpolationCellType[ matrixIndices[ grid->getCF_coarse()[index] ] ] = grid->getFieldEntry( matrixIndices[ grid->getCF_coarse()[index] ] );
+
+        nodeOffset               [ matrixIndices[ grid->getCF_coarse()[index] ] ] = grid->getCF_offset()[index];
+    }
+
+    //for( int index = 0; index < grid->getNumberOfNodesFC(); index++ ){
+    //    nodeInterpolationCellType[ grid->getFC_coarse()[index] ] = grid->getFieldEntry( grid->getFC_coarse()[index] );
+    //}
+
+    if( gridCoarse ){
+
+        for( uint index = 0; index < gridCoarse->getNumberOfNodesCF(); index++ ){
+            nodeInterpolationCellType[ matrixIndices[ gridCoarse->getCF_fine()[index] ] ] = grid->getFieldEntry( matrixIndices[ gridCoarse->getCF_fine()[index] ] );
+        }
+
+        for( uint index = 0; index < gridCoarse->getNumberOfNodesFC(); index++ ){
+            nodeInterpolationCellType[ matrixIndices[ gridCoarse->getFC_fine()[index] ] ] = grid->getFieldEntry( matrixIndices[ gridCoarse->getFC_fine()[index] ] );
+
+            nodeOffset               [ matrixIndices[ gridCoarse->getFC_fine()[index] ] ] = gridCoarse->getFC_offset()[index];
+        }
+    }
+
+	std::vector<UbTupleFloat3> nodes;
+	std::vector<UbTupleInt8> cells;
+	std::vector<std::string> celldatanames;
+	std::vector< std::vector<double> > celldata;
+
+	celldatanames.push_back("InterpolationCells");
+    celldatanames.push_back("Offset");
+
+	celldata.resize(celldatanames.size());
+
+	CbArray3D<int> nodeNumbers(grid->getNumberOfNodesX(), grid->getNumberOfNodesY(), grid->getNumberOfNodesZ(), -1);
+	int nr = 0;
+
+	for (uint xIndex = 0; xIndex < grid->getNumberOfNodesX(); xIndex++)
+	{
+		for (uint yIndex = 0; yIndex < grid->getNumberOfNodesY(); yIndex++)
+		{
+			for (uint zIndex = 0; zIndex < grid->getNumberOfNodesZ(); zIndex++)
+			{
+				real x, y, z;
+				uint index = 
+					  grid->getNumberOfNodesX() * grid->getNumberOfNodesY() * zIndex
+					+ grid->getNumberOfNodesX() *                             yIndex
+					+ xIndex;
+
+				grid->transIndexToCoords(index, x, y, z);
+
+				nodeNumbers(xIndex, yIndex, zIndex) = nr++;
+				nodes.push_back(UbTupleFloat3(float(x), float(y), float(z)));
+			}
+		}
+	}
+
+	int SWB, SEB, NEB, NWB, SWT, SET, NET, NWT;
+	for (uint xIndex = 0; xIndex < grid->getNumberOfNodesX() - 1; xIndex++)
+	{
+		for (uint yIndex = 0; yIndex < grid->getNumberOfNodesY() - 1; yIndex++)
+		{
+			for (uint zIndex = 0; zIndex < grid->getNumberOfNodesZ() - 1; zIndex++)
+			{
+				real x, y, z;
+				uint index = grid->getNumberOfNodesX() * grid->getNumberOfNodesY() * zIndex
+					+ grid->getNumberOfNodesX() *                             yIndex
+					+ xIndex;
+
+				grid->transIndexToCoords(index, x, y, z);
+
+				if ((SWB = nodeNumbers(xIndex, yIndex, zIndex)) >= 0
+					&& (SEB = nodeNumbers(xIndex + 1, yIndex, zIndex)) >= 0
+					&& (NEB = nodeNumbers(xIndex + 1, yIndex + 1, zIndex)) >= 0
+					&& (NWB = nodeNumbers(xIndex, yIndex + 1, zIndex)) >= 0
+					&& (SWT = nodeNumbers(xIndex, yIndex, zIndex + 1)) >= 0
+					&& (SET = nodeNumbers(xIndex + 1, yIndex, zIndex + 1)) >= 0
+					&& (NET = nodeNumbers(xIndex + 1, yIndex + 1, zIndex + 1)) >= 0
+					&& (NWT = nodeNumbers(xIndex, yIndex + 1, zIndex + 1)) >= 0)
+				{
+					Cell cell(x, y, z, grid->getDelta());
+					//if (grid->nodeInCellIs(cell, INVALID_OUT_OF_GRID) || grid->nodeInCellIs(cell, INVALID_COARSE_UNDER_FINE))
+					//	continue;
+
+					cells.push_back(makeUbTuple(SWB, SEB, NEB, NWB, SWT, SET, NET, NWT));
+
+				    //const char type = grid->getFieldEntry(grid->transCoordToIndex(nodes[SWB].v1, nodes[SWB].v2.v1, nodes[SWB].v2.v2));
+				    //const char type = grid->getFieldEntry(grid->transCoordToIndex(val<1>(nodes[SWB]), val<2>(nodes[SWB]), val<3>(nodes[SWB])));
+				    const char type = nodeInterpolationCellType[ grid->transCoordToIndex(val<1>(nodes[SWB]), val<2>(nodes[SWB]), val<3>(nodes[SWB])) ];
+                    const char offset = nodeOffset               [ grid->transCoordToIndex(val<1>(nodes[SWB]), val<2>(nodes[SWB]), val<3>(nodes[SWB])) ];
+
+                    celldata[0].push_back( type );
+                    celldata[1].push_back( offset );
+				}
+			}
+		}
+	}
+    WbWriterVtkXmlBinary::getInstance()->writeOctsWithCellData(name, nodes, cells, celldatanames, celldata);
+}
+
+
+/*#################################################################################*/
+/*---------------------------------private methods---------------------------------*/
+/*---------------------------------------------------------------------------------*/
+void GridVTKWriter::initalVtkWriter(WRITING_FORMAT format, const std::string& name)
+{
+    GridVTKWriter::format = format;
+
+    *logging::out << logging::Logger::INFO_INTERMEDIATE << "Write Grid to vtk output file : " + name + "\n";
+
+    std::string mode = "w";
+    if (isBinaryWritingFormat())
+        mode = "wb";
+    GridVTKWriter::openFile(name, mode);
+
+    *logging::out << logging::Logger::INFO_INTERMEDIATE << "  Output file opened ...\n";
+}
+
+bool GridVTKWriter::isBinaryWritingFormat()
+{
+    return GridVTKWriter::format == WRITING_FORMAT::BINARY;
+}
+
+void GridVTKWriter::writeVtkFile(SPtr<Grid> grid)
+{
+    GridVTKWriter::writeHeader();
+    GridVTKWriter::writePoints(grid);
+    GridVTKWriter::writeCells(grid->getSize());
+    GridVTKWriter::writeTypeHeader(grid->getSize());
+    GridVTKWriter::writeTypes(grid);
+    GridVTKWriter::closeFile();
+
+    *logging::out << logging::Logger::INFO_INTERMEDIATE << "Output file closed\n";
+}
+
+void GridVTKWriter::openFile(const std::string& name, const std::string& mode)
+{
+    file = fopen(name.c_str(), mode.c_str());
+    if(file==NULL)
+        *logging::out << logging::Logger::INFO_HIGH << "  cannot open file ...\n";
+}
+
+void GridVTKWriter::closeFile()
+{
+    GridVTKWriter::end_line();
+	fclose(file);
+}
+
+void GridVTKWriter::writeHeader()
+{
+	fprintf(file, "# vtk DataFile Version 3.0\n");
+	fprintf(file, "by MeshGenerator\n");
+	if (isBinaryWritingFormat())
+		fprintf(file, "BINARY\n");
+	else
+		fprintf(file, "ASCII\n");
+	fprintf(file, "DATASET UNSTRUCTURED_GRID\n");
+}
+
+void GridVTKWriter::writePoints(SPtr<Grid> grid)
+{
+    fprintf(file, "POINTS %d float\n", grid->getSize());
+    real x, y, z;
+    for (unsigned int i = 0; i < grid->getSize(); i++) {
+
+        /*if (grid->getSparseIndex(i) == -1)
+            continue;*/
+
+        grid->transIndexToCoords(i, x, y, z);
+
+        if (isBinaryWritingFormat()) {
+            write_float(float(x));
+            write_float(float(y));
+            write_float(float(z));
+        }
+        else
+            fprintf(file, "%f %f %f\n", x, y, z);
+    }
+}
+
+void GridVTKWriter::writeCells(const unsigned int &size)
+{
+	fprintf(file, "\nCELLS %d %d\n", size, size * 2);
+	for (unsigned int i = 0; i < size; ++i)
+	{
+		if (isBinaryWritingFormat()){
+			write_int(1);
+			write_int(i);
+		}
+		else
+			fprintf(file, "1 %d\n", i);
+	}
+
+	fprintf(file, "\nCELL_TYPES %d\n", size);
+	for (unsigned int i = 0; i < size; ++i)
+	{
+		if (isBinaryWritingFormat())
+			write_int(1);
+		else
+			fprintf(file, "1 ");
+	}
+	if (!isBinaryWritingFormat())
+        GridVTKWriter::end_line();
+}
+
+void GridVTKWriter::writeTypeHeader(const unsigned int &size)
+{
+	fprintf(file, "\nPOINT_DATA %d\n", size);
+	fprintf(file, "SCALARS type int\n");
+	fprintf(file, "LOOKUP_TABLE default\n");
+}
+
+void GridVTKWriter::writeTypes(SPtr<Grid> grid)
+{
+    for (unsigned int i = 0; i < grid->getSize(); i++) 
+    {
+        /*if (grid->getSparseIndex(i) == -1)
+            continue;*/
+
+        if (isBinaryWritingFormat())
+            write_int(grid->getFieldEntry(i));
+        else
+            fprintf(file, "%d ", grid->getFieldEntry(i));
+    }
+}
+
+void GridVTKWriter::end_line()
+{
+	char str2[8] = "\n";
+	fprintf(file, "%s", str2);
+}
+
+void GridVTKWriter::write_int(int val)
+{
+	force_big_endian((unsigned char *)&val);
+	fwrite(&val, sizeof(int), 1, file);
+}
+
+void GridVTKWriter::write_float(float val)
+{
+	force_big_endian((unsigned char *)&val);
+	fwrite(&val, sizeof(float), 1, file);
+}
+
+
+void GridVTKWriter::force_big_endian(unsigned char *bytes)
+{
+	bool shouldSwap = false;
+	int tmp1 = 1;
+	unsigned char *tmp2 = (unsigned char *)&tmp1;
+	if (*tmp2 != 0)
+		shouldSwap = true;
+
+	if (shouldSwap)
+	{
+		unsigned char tmp = bytes[0];
+		bytes[0] = bytes[3];
+		bytes[3] = tmp;
+		tmp = bytes[1];
+		bytes[1] = bytes[2];
+		bytes[2] = tmp;
+	}
+}
diff --git a/src/gpu/GridGenerator/io/GridVTKWriter/GridVTKWriter.h b/src/gpu/GridGenerator/io/GridVTKWriter/GridVTKWriter.h
new file mode 100644
index 0000000000000000000000000000000000000000..cf33df096a6e670b65f79831d59927e3d7cea389
--- /dev/null
+++ b/src/gpu/GridGenerator/io/GridVTKWriter/GridVTKWriter.h
@@ -0,0 +1,81 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file GridVTKWriter.h
+//! \ingroup io
+//! \author Soeren Peters, Stephan Lenz
+//=======================================================================================
+#ifndef GridVTKWriter_h
+#define GridVTKWriter_h
+
+#include <string>
+
+#include "global.h"
+#include "GridGenerator_export.h"
+
+enum class WRITING_FORMAT { BINARY, ASCII };
+
+class Grid;
+
+class GRIDGENERATOR_EXPORT GridVTKWriter
+{
+public:
+    static void writeSparseGridToVTK(SPtr<Grid> grid, const std::string& name, WRITING_FORMAT format = WRITING_FORMAT::ASCII);
+    static void writeGridToVTKXML(SPtr<Grid> grid, const std::string& name, WRITING_FORMAT format = WRITING_FORMAT::ASCII);
+    static void writeInterpolationCellsToVTKXML(SPtr<Grid> grid, SPtr<Grid> gridCoarse, const std::string& name, WRITING_FORMAT format = WRITING_FORMAT::ASCII);
+
+private:
+    GridVTKWriter() {}
+    ~GridVTKWriter() {}
+
+    static FILE *file;
+    static WRITING_FORMAT format;
+
+    static void initalVtkWriter(WRITING_FORMAT format, const std::string& name);
+
+    static bool isBinaryWritingFormat();
+
+    static void writeVtkFile(SPtr<Grid> grid);
+
+    static void openFile(const std::string& name, const std::string& mode);
+    static void closeFile();
+
+    static void writeHeader();
+    static void writePoints(SPtr<Grid> grid);
+    static void writeCells(const unsigned int &size);
+    static void writeTypeHeader(const unsigned int &size);
+    static void writeTypes(SPtr<Grid> grid);
+
+    static void end_line();
+    static void force_big_endian(unsigned char *bytes);
+    static void write_int(int val);
+    static void write_float(float val);
+};
+
+
+#endif
diff --git a/src/gpu/GridGenerator/io/QLineWriter.cpp b/src/gpu/GridGenerator/io/QLineWriter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..29894e8d589fb59c1dbf57e08692dddfc03619a1
--- /dev/null
+++ b/src/gpu/GridGenerator/io/QLineWriter.cpp
@@ -0,0 +1,174 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file QLineWriter.cpp
+//! \ingroup io
+//! \author Soeren Peters, Stephan Lenz
+//=======================================================================================
+#include "QLineWriter.h"
+
+#include <vector>
+#include <string>
+#include <fstream>
+
+#include "basics/basics/utilities/UbTuple.h"
+
+#include "geometries/Vertex/Vertex.h"
+
+#include "grid/BoundaryConditions/BoundaryCondition.h"
+#include "grid/Grid.h"
+
+using namespace std;
+void writeLines(std::string filename, std::vector<UbTupleFloat3> nodes, std::vector<UbTupleInt2> lines);
+
+void QLineWriter::writeArrows(std::string fileName, SPtr<GeometryBoundaryCondition> geometryBoundaryCondition, SPtr<Grid> grid)
+{
+	if (geometryBoundaryCondition == nullptr)
+	{
+		*logging::out << logging::Logger::WARNING << "(QLineWriter::writeArrows) no geometry bc on this grid level.\n";
+		return;
+	}
+    std::vector<UbTupleFloat3> nodes;
+    std::vector<UbTupleInt2> cells;
+
+    int actualNodeNumber = 0;
+    for (std::size_t index = 0; index < geometryBoundaryCondition->indices.size(); index++)
+    {
+        Vertex startNode = getVertex(geometryBoundaryCondition->indices[index], grid);
+		for (int qi = 0; qi <= 26; qi++)
+        {
+            real qval = geometryBoundaryCondition->qs[index][qi];
+            if (qval > 0.0f)
+            {
+                Vertex dir((real)grid->getDirection()[qi * DIMENSION + 0], (real)grid->getDirection()[qi * DIMENSION + 1], (real)grid->getDirection()[qi * DIMENSION + 2]);
+                Vertex nodeOnGeometry(startNode + (dir * qval)*grid->getDelta());
+
+                nodes.push_back(makeUbTuple(float(startNode.x), float(startNode.y), float(startNode.z)));
+                nodes.push_back(makeUbTuple(float(nodeOnGeometry.x), float(nodeOnGeometry.y), float(nodeOnGeometry.z)));
+                actualNodeNumber += 2;
+                cells.push_back(makeUbTuple(actualNodeNumber - 2, actualNodeNumber - 1));
+            }
+        }
+    }
+
+    writeLines(fileName, nodes, cells);
+}
+
+Vertex QLineWriter::getVertex(int matrixIndex, SPtr<Grid> grid)
+{
+    real x, y, z;
+    grid->transIndexToCoords(matrixIndex, x, y, z);
+    return Vertex(x, y, z);
+}
+
+
+void writeLines(std::string filename, std::vector<UbTupleFloat3> nodes, std::vector<UbTupleInt2> lines)
+{
+    string vtkfilename = filename + ".bin.vtu";
+
+    ofstream out(vtkfilename.c_str(), ios::out | ios::binary);
+
+    int nofNodes = (int)nodes.size();
+    int nofCells = (int)lines.size();
+
+    int bytesPerByteVal = 4; //==sizeof(int)
+    int bytesPoints = 3 /*x1/x2/x3        */ * nofNodes * sizeof(float);
+    int bytesCellConnectivty = 2 /*nodes per line */ * nofCells * sizeof(int);
+    int bytesCellOffsets = 1 /*offset per line */ * nofCells * sizeof(int);
+    int bytesCellTypes = 1 /*type of line */ * nofCells * sizeof(unsigned char);
+
+    int offset = 0;
+    //VTK FILE
+    out << "<?xml version=\"1.0\"?>\n";
+    out << "<VTKFile type=\"UnstructuredGrid\" version=\"0.1\" byte_order=\"LittleEndian\" >" << "\n";
+    out << "   <UnstructuredGrid>" << "\n";
+    out << "      <Piece NumberOfPoints=\"" << nofNodes << "\" NumberOfCells=\"" << nofCells << "\">\n";
+
+    //POINTS SECTION
+    out << "         <Points>\n";
+    out << "            <DataArray type=\"Float32\" NumberOfComponents=\"3\" format=\"appended\" offset=\"" << offset << "\"  />\n";
+    out << "         </Points>\n";
+    offset += (bytesPerByteVal + bytesPoints);
+
+    //CELLS SECTION
+    out << "         <Cells>\n";
+    out << "            <DataArray type=\"Int32\" Name=\"connectivity\" format=\"appended\" offset=\"" << offset << "\" />\n";
+    offset += (bytesPerByteVal + bytesCellConnectivty);
+    out << "            <DataArray type=\"Int32\" Name=\"offsets\" format=\"appended\" offset=\"" << offset << "\" />\n";
+    offset += (bytesPerByteVal + bytesCellOffsets);
+    out << "            <DataArray type=\"UInt8\" Name=\"types\" format=\"appended\" offset=\"" << offset << "\" />\n ";
+    offset += (bytesPerByteVal + bytesCellTypes);
+    out << "         </Cells>\n";
+
+    out << "      </Piece>\n";
+    out << "   </UnstructuredGrid>\n";
+
+    // AppendedData SECTION
+    out << "   <AppendedData encoding=\"raw\">\n";
+    out << "_";
+
+    //POINTS SECTION
+    out.write((char*)&bytesPoints, bytesPerByteVal);
+    for (int n = 0; n < nofNodes; n++)
+    {
+        out.write((char*)&val<1>(nodes[n]), sizeof(float));
+        out.write((char*)&val<2>(nodes[n]), sizeof(float));
+        out.write((char*)&val<3>(nodes[n]), sizeof(float));
+    }
+
+    //CELLS SECTION
+    //cellConnectivity
+    out.write((char*)&bytesCellConnectivty, bytesPerByteVal);
+    for (int c = 0; c < nofCells; c++)
+    {
+        out.write((char*)&val<1>(lines[c]), sizeof(int));
+        out.write((char*)&val<2>(lines[c]), sizeof(int));
+
+    }
+
+    //cellOffsets
+    out.write((char*)&bytesCellOffsets, bytesPerByteVal);
+    int itmp;
+    for (int c = 1; c <= nofCells; c++)
+    {
+        itmp = 2 * c;
+        out.write((char*)&itmp, sizeof(int));
+    }
+
+    //cellTypes
+    out.write((char*)&bytesCellTypes, bytesPerByteVal);
+    unsigned char vtkCellType = 3;
+    for (int c = 0; c < nofCells; c++)
+    {
+        out.write((char*)&vtkCellType, sizeof(unsigned char));
+    }
+    out << "\n</AppendedData>\n";
+    out << "</VTKFile>";
+    out << endl;
+    out.close();
+}
diff --git a/src/gpu/GridGenerator/io/QLineWriter.h b/src/gpu/GridGenerator/io/QLineWriter.h
new file mode 100644
index 0000000000000000000000000000000000000000..c7fed1a8ff16e81398e18c7fdde347cd09a93452
--- /dev/null
+++ b/src/gpu/GridGenerator/io/QLineWriter.h
@@ -0,0 +1,57 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file QLineWriter.h
+//! \ingroup io
+//! \author Soeren Peters, Stephan Lenz
+//=======================================================================================
+#ifndef QLINEWRITER_H
+#define QLINEWRITER_H
+
+#include <vector>
+#include <string>
+#include <fstream>
+
+#include "global.h"
+
+class GeometryBoundaryCondition;
+class Grid;
+struct Vertex;
+
+
+class QLineWriter 
+{
+public:
+    static void writeArrows(std::string fileName, SPtr<GeometryBoundaryCondition> geometryBoundaryCondition, SPtr<Grid> grid);
+
+private:
+    static Vertex getVertex(int matrixIndex, SPtr<Grid> grid);
+};
+
+
+#endif
diff --git a/src/gpu/GridGenerator/io/STLReaderWriter/STLReader.cpp b/src/gpu/GridGenerator/io/STLReaderWriter/STLReader.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..173f79c184c0a455ffd5b27cae59e07fa6dd4fa6
--- /dev/null
+++ b/src/gpu/GridGenerator/io/STLReaderWriter/STLReader.cpp
@@ -0,0 +1,387 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file STLReader.cpp
+//! \ingroup io
+//! \author Soeren Peters, Stephan Lenz
+//=======================================================================================
+#define _CRT_SECURE_NO_DEPRECATE
+#include "STLReader.h"
+
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <string>
+#include <cstring>
+#include <stdexcept>
+#include <algorithm>
+
+#include "geometries/Vertex/Vertex.h"
+#include "geometries/Triangle/Triangle.h"
+#include "geometries/BoundingBox/BoundingBox.h"
+
+
+std::vector<Triangle> STLReader::readSTL(const std::string& name)
+{
+    std::ifstream file(name.c_str());
+    if (file.is_open()) {
+        std::string line;
+        std::getline(file, line);
+        line[strcspn(line.c_str(), "\r\n")] = 0;
+        if (strcmp(line.c_str(), "solid ascii") == 0) {
+            file.close();
+            *logging::out << logging::Logger::INFO_INTERMEDIATE << "start reading ascii STL file: " + name + "\n";
+            return readASCIISTL(name);
+        }
+        else {
+            file.close();
+            *logging::out << logging::Logger::INFO_INTERMEDIATE << "start reading binary STL file: " + name + "\n";
+            return readBinarySTL(name);
+        }
+    }
+
+     *logging::out << logging::Logger::INFO_INTERMEDIATE << "can't open STL-file" + name + " ... exit program! \n";
+     exit(1);
+}
+
+std::vector<Triangle> STLReader::readSTL(const std::string & name, FileType fileType, const std::vector<uint> ignorePatches)
+{
+    if ( fileType == ascii ) return readASCIISTLWithPatches(name, ignorePatches);
+    else                     return readBinarySTL(name);
+}
+
+
+std::vector<Triangle> STLReader::readASCIISTL(const std::string& name)
+{
+    const int lines = countLinesInFile(name);
+    const int nTriangles = (lines) / 7; // seven lines per triangle
+
+    *logging::out << logging::Logger::INFO_INTERMEDIATE << "Number of Triangles: " << nTriangles << "\n";
+    std::vector<Triangle> triangles;
+
+    std::string line;
+    std::ifstream file;
+    file.open(name.c_str(), std::ifstream::in);
+    std::getline(file, line); // solid ascii
+
+    for (int t = 0; t < nTriangles; t++) {
+        Vertex normal = parseLineToCoordinates(file, "%*s %*s %f %f %f");
+        getline(file, line); // outer loop
+        Vertex p1 = parseLineToCoordinates(file, "%*s %f %f %f");
+        Vertex p2 = parseLineToCoordinates(file, "%*s %f %f %f");
+        Vertex p3 = parseLineToCoordinates(file, "%*s %f %f %f");
+        getline(file, line); //endloop
+        getline(file, line); //endfacet
+
+        Triangle tri = Triangle(p1, p2, p3, normal);
+        tri.calcNormal();
+        triangles.push_back(tri);
+    }
+    file.close();
+    return triangles;
+}
+
+
+std::vector<Triangle> STLReader::readASCIISTLWithPatches(const std::string& name, const std::vector<uint> ignorePatches)
+{
+    *logging::out << logging::Logger::INFO_HIGH << "Start reading ascii STL file:\n";
+    *logging::out << logging::Logger::INFO_HIGH << "    " + name + "\n";
+
+    std::vector<Triangle> triangles;
+
+    std::string line;
+    std::ifstream file;
+    file.open(name.c_str(), std::ifstream::in);
+
+    if( !file.is_open() ) throw std::runtime_error(name + "cannot be opened!");
+
+    uint currentPatchIndex = 0;
+
+    uint currentFacetLine = 0;
+
+    bool ignoreCurrentPatch = false;
+
+    Vertex vertex1, vertex2, vertex3, normal;
+
+    while( std::getline(file, line) ){
+
+        // trim the string
+        line = line.substr( line.find_first_not_of(" "), line.find_last_not_of(" ") + 1 );
+
+        if( line.substr( 0, line.find(" ") ) == "color" ) continue;
+
+        // ========================================================================================
+        if     ( currentFacetLine == 0 && line.substr( 0, line.find(" ") ) == "solid" )
+        {
+            ignoreCurrentPatch = std::find( ignorePatches.begin(), ignorePatches.end(), currentPatchIndex ) != ignorePatches.end();
+
+            if( !ignoreCurrentPatch )
+                *logging::out << logging::Logger::INFO_INTERMEDIATE << "    Reading STL-Group " << line.substr( line.find(' ') + 1 ) << " as patch " << currentPatchIndex << "\n";
+            else
+                *logging::out << logging::Logger::WARNING           << "    Ignoring STL-Group " << line.substr( line.find(' ') + 1 ) << " as patch " << currentPatchIndex << "\n";
+
+            currentFacetLine++;
+        }
+        else if( currentFacetLine == 1 && line.substr( 0, line.find(" ") ) == "endsolid" )
+        {
+            currentFacetLine = 0;
+            currentPatchIndex++;
+        }
+        // ========================================================================================
+        else if( currentFacetLine == 1 && line.substr( 0, line.find(" ") ) == "facet" )
+        {
+            normal = parseLineToCoordinates(line, "%*s %*s %f %f %f");
+            currentFacetLine++;
+        }
+        else if( currentFacetLine == 2 && line.substr( 0, line.find(" ") ) == "outer" )
+        {
+            currentFacetLine++;
+        }
+        else if( currentFacetLine == 3 && line.substr( 0, line.find(" ") ) == "vertex" )
+        {
+            vertex1 = parseLineToCoordinates(line, "%*s %f %f %f");
+            currentFacetLine++;
+        }
+        else if( currentFacetLine == 4 && line.substr( 0, line.find(" ") ) == "vertex" )
+        {
+            vertex2 = parseLineToCoordinates(line, "%*s %f %f %f");
+            currentFacetLine++;
+        }
+        else if( currentFacetLine == 5 && line.substr( 0, line.find(" ") ) == "vertex" )
+        {
+            vertex3 = parseLineToCoordinates(line, "%*s %f %f %f");
+            currentFacetLine++;
+        }
+        else if( currentFacetLine == 6 && line.substr( 0, line.find(" ") ) == "endloop" )
+        {
+            currentFacetLine++;
+        }
+        else if( currentFacetLine == 7 && line.substr( 0, line.find(" ") ) == "endfacet" )
+        {
+            if( !ignoreCurrentPatch ){
+                Triangle tri = Triangle(vertex1, vertex2, vertex3, normal);
+                tri.calcNormal();
+
+                tri.patchIndex = currentPatchIndex;
+
+                triangles.push_back(tri);
+            }
+
+            currentFacetLine = 1;
+        }
+        else
+        {
+            throw std::runtime_error("STL-File does not comply with standard: " + line + "|\n");
+        }
+    }
+
+    file.close();
+
+    *logging::out << logging::Logger::INFO_HIGH << "Done reading ascii STL file\n";
+
+    return triangles;
+}
+
+std::vector<Triangle> STLReader::readBinarySTL(const std::string& name)
+{
+    const std::string mode = "rb";
+    FILE *file = fopen(name.c_str(), mode.c_str());
+
+    char header_info[80] = "";
+    size_t sizef         = fread(header_info, sizeof(char), 80, file);
+
+    char nTri[4];
+    sizef                  = fread(nTri, sizeof(char), 4, file);
+    unsigned long nTriLong = *((unsigned long*)nTri);
+    *logging::out << logging::Logger::INFO_INTERMEDIATE << "Number of Triangles: " << nTriLong << "\n";
+    std::vector<Triangle> triangles;
+
+    char facet[50];
+    for (unsigned int i = 0; i < nTriLong; i++){
+        sizef = fread(facet, sizeof(char), 50, file);
+
+        Vertex normal = getVertexFromChar(facet);
+
+        Vertex p1 = getVertexFromChar(facet + 12);
+        Vertex p2 = getVertexFromChar(facet + 24);
+        Vertex p3 = getVertexFromChar(facet + 36);
+
+        triangles.push_back(Triangle(p1, p2, p3, normal));
+    }
+    (void)sizef;
+	fclose(file);
+
+    return triangles;
+}
+
+std::vector<Triangle> STLReader::readSTL(const BoundingBox &box, const std::string& name)
+{
+	std::ifstream file(name.c_str());
+	if (file.is_open()) {
+		std::string line;
+		std::getline(file, line);
+		line[strcspn(line.c_str(), "\r\n")] = 0;
+		if (strcmp(line.c_str(), "solid ascii") == 0) {
+			file.close();
+			*logging::out << logging::Logger::INFO_INTERMEDIATE << "start reading ascii STL file: " + name + "\n";
+			return readASCIISTL(box, name);
+		}
+		else {
+			file.close();
+			*logging::out << logging::Logger::INFO_INTERMEDIATE << "start reading binary STL file: " + name + "\n";
+			std::vector<Triangle> triangles = readBinarySTL(box, name);
+			return triangles;
+		}
+	}
+	else {
+		*logging::out << logging::Logger::INFO_INTERMEDIATE << "can't open STL-file" + name + "\n";
+		exit(1);
+	}
+}
+
+std::vector<Triangle> STLReader::readASCIISTL(const BoundingBox &box, const std::string& name)
+{
+    int lines = countLinesInFile(name);
+    int nTriangles = (lines) / 7; // seven lines per triangle
+    std::cout << "Number of Triangles: " << nTriangles << std::endl;
+    std::vector<Triangle> triangles;
+
+    std::string line;
+    std::ifstream file;
+    file.open(name.c_str(), std::ifstream::in);
+    std::getline(file, line); // solid ascii
+
+    for (int i= 0; i < nTriangles; i++) {
+        Vertex normal = parseLineToCoordinates(file, "%*s %*s %f %f %f");
+        getline(file, line); // outer loop
+        Vertex p1 = parseLineToCoordinates(file, "%*s %f %f %f");
+        Vertex p2 = parseLineToCoordinates(file, "%*s %f %f %f");
+        Vertex p3 = parseLineToCoordinates(file, "%*s %f %f %f");
+        getline(file, line); //endloop
+        getline(file, line); //endfacet
+
+        Triangle t(p1, p2, p3, normal);
+        t.calcNormal();
+        if (box.isInside(t) || box.intersect(t))
+            triangles.push_back(t);
+    }
+    file.close();
+    return triangles;
+}
+
+
+std::vector<Triangle> STLReader::readBinarySTL(const BoundingBox &box, const std::string& name)
+{
+    FILE *file;
+    std::string mode = "rb";
+    file = fopen(name.c_str(), mode.c_str());
+
+    char header_info[80] = "";
+    char nTri[4];
+    unsigned long nTriLong;
+  
+    size_t sizef = fread(header_info, sizeof(char), 80, file);
+
+
+    sizef    = fread(nTri, sizeof(char), 4, file);
+    nTriLong = *((unsigned long*)nTri);
+
+    *logging::out << logging::Logger::INFO_INTERMEDIATE << "Number of Triangles complete geometry: " << nTriLong << "\n";
+    std::vector<Triangle> triangles;
+
+    char facet[50];
+    for (unsigned int i = 0; i < nTriLong; i++){
+        sizef = fread(facet, sizeof(char), 50, file);
+
+        Vertex normal = getVertexFromChar(facet);
+
+        Vertex p1 = getVertexFromChar(facet + 12);
+        Vertex p2 = getVertexFromChar(facet + 24);
+        Vertex p3 = getVertexFromChar(facet + 36);
+
+        Triangle t(p1, p2, p3, normal);
+        if (box.isInside(t) || box.intersect(t))
+            triangles.push_back(t);
+    }
+    int size = (int)triangles.size();
+    *logging::out << logging::Logger::INFO_INTERMEDIATE << "Number of Triangles in process: " << size << "\n";
+    *logging::out << logging::Logger::INFO_INTERMEDIATE << "Complete reading STL file. \n";
+    (void)sizef;
+	fclose(file);
+
+    return triangles;
+}
+
+
+/*#################################################################################*/
+/*---------------------------------private methods---------------------------------*/
+/*---------------------------------------------------------------------------------*/
+Vertex STLReader::parseLineToCoordinates(std::ifstream& file, std::string format)
+{
+    std::string line;
+    getline(file, line);
+    const char* buffer = line.c_str();
+    float x, y, z;
+    sscanf(buffer, format.c_str(), &x, &y, &z);
+    return Vertex(x, y, z);
+}
+
+Vertex STLReader::parseLineToCoordinates(const std::string& line, const std::string format)
+{
+    const char* buffer = line.c_str();
+    float x, y, z;
+    sscanf(buffer, format.c_str(), &x, &y, &z);
+    return Vertex(x, y, z);
+}
+
+int STLReader::countLinesInFile(std::string name)
+{
+    std::ifstream file;
+    file.open(name.c_str(), std::ifstream::in);
+    int nTriLong = (int)std::count(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>(), '\n');
+    file.close();
+    return nTriLong;
+}
+
+Vertex STLReader::getVertexFromChar(const char* facet)
+{
+    char f1[4] = { facet[0],
+        facet[1], facet[2], facet[3] };
+
+    char f2[4] = { facet[4],
+        facet[5], facet[6], facet[7] };
+
+    char f3[4] = { facet[8],
+        facet[9], facet[10], facet[11] };
+
+    float xx = *((float*)f1);
+    float yy = *((float*)f2);
+    float zz = *((float*)f3);
+
+    return Vertex((real)(xx), (real)(yy), (real)(zz));
+}
diff --git a/src/gpu/GridGenerator/io/STLReaderWriter/STLReader.h b/src/gpu/GridGenerator/io/STLReaderWriter/STLReader.h
new file mode 100644
index 0000000000000000000000000000000000000000..333313727530ae551c76a76984cd63f6cd0f11ce
--- /dev/null
+++ b/src/gpu/GridGenerator/io/STLReaderWriter/STLReader.h
@@ -0,0 +1,72 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file STLReader.h
+//! \ingroup io
+//! \author Soeren Peters, Stephan Lenz
+//=======================================================================================
+#ifndef STLReader_H
+#define STLReader_H
+
+
+#include <vector>
+#include <string>
+
+#include "global.h"
+
+struct Triangle;
+struct Vertex;
+class BoundingBox;
+
+class GRIDGENERATOR_EXPORT STLReader
+{
+public:
+
+    enum FileType { ascii, binary };
+
+    static std::vector<Triangle> readSTL(const std::string& name);
+    static std::vector<Triangle> readSTL(const std::string& name, FileType fileType, const std::vector<uint> ignorePatches = std::vector<uint>() );
+	static std::vector<Triangle> readSTL(const BoundingBox &box, const std::string& name);
+
+    static std::vector<Triangle> readBinarySTL(const std::string& name);
+    static std::vector<Triangle> readASCIISTL(const std::string& name);
+    static std::vector<Triangle> readASCIISTLWithPatches(const std::string& name, const std::vector<uint> ignorePatches);
+	static std::vector<Triangle> readBinarySTL(const BoundingBox &box, const std::string& name);
+	static std::vector<Triangle> readASCIISTL(const BoundingBox &box, const std::string& name);
+
+private:
+    STLReader(){};
+    ~STLReader(){};
+
+    static int countLinesInFile(std::string name);
+    static Vertex parseLineToCoordinates(std::ifstream& file, std::string format);
+    static Vertex parseLineToCoordinates(const std::string& file, const std::string format);
+    static Vertex getVertexFromChar(const char* facet);
+};
+
+#endif
diff --git a/src/gpu/GridGenerator/io/STLReaderWriter/STLWriter.cpp b/src/gpu/GridGenerator/io/STLReaderWriter/STLWriter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e29320cbd6867e1ae5a65cf41623780cd83aead7
--- /dev/null
+++ b/src/gpu/GridGenerator/io/STLReaderWriter/STLWriter.cpp
@@ -0,0 +1,116 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file STLWriter.cpp
+//! \ingroup io
+//! \author Soeren Peters, Stephan Lenz
+//=======================================================================================
+#define _CRT_SECURE_NO_DEPRECATE
+#include "STLWriter.h"
+
+#include <fstream>
+#include <sstream>
+
+#include "geometries/Vertex/Vertex.h"
+#include "geometries/Triangle/Triangle.h"
+
+void STLWriter::writeSTL(std::vector<Triangle> &vec, const std::string &name, bool writeBinary)
+{
+    const int size = (int)vec.size();
+    *logging::out << logging::Logger::INFO_INTERMEDIATE << "Write " << size << " Triangles to STL : " + name + "\n";
+
+    std::ios_base::openmode mode = std::ios::out;
+    if (writeBinary)
+        mode = std::ios::out | std::ios::binary;
+
+    std::ofstream ofstream(name, mode);
+
+    if (!ofstream.is_open()) {
+        *logging::out << logging::Logger::INFO_HIGH << " Output file not open - exit function\n";
+        return;
+    }
+
+    if (writeBinary)
+        writeBinarySTL(ofstream, vec);
+    else
+        writeAsciiSTL(ofstream, vec);
+
+    ofstream.close();
+    *logging::out << logging::Logger::INFO_INTERMEDIATE << "Output file closed\n";
+}
+
+
+void STLWriter::writeAsciiSTL(std::ofstream &ofstream, std::vector<Triangle> &vec)
+{
+    ofstream << "solid ascii\n";
+    for (size_t i = 0; i < vec.size(); i++) 
+    {
+        Triangle t = vec[i];
+
+        ofstream << "facet normal ";
+        t.normal.printFormatted(ofstream);
+        ofstream << "\n";
+
+        ofstream << "outer loop\n";
+
+        ofstream << "vertex ";
+        t.v1.printFormatted(ofstream);
+        ofstream << "\n";
+        ofstream << "vertex ";
+        t.v2.printFormatted(ofstream);
+        ofstream << "\n";
+        ofstream << "vertex ";
+        t.v3.printFormatted(ofstream);
+        ofstream << "\n";
+
+        ofstream << "endloop\n";
+        ofstream << "endfacet\n";
+    }
+    ofstream << "endsolid\n";
+}
+
+void STLWriter::writeBinarySTL(std::ofstream &ofstream, std::vector<Triangle> &vec)
+{
+    char header_info[80] = "GridGeneration-File iRMB";
+    unsigned long nTriLong = (unsigned long)vec.size();
+    ofstream.write(header_info, sizeof(header_info));
+    ofstream.write((char*)&nTriLong, 4);
+    char attribute[2] = "0";
+    for (size_t i = 0; i < vec.size(); i++)
+    {
+        Triangle t = vec[i];
+
+        t.normal.print(ofstream);
+
+        t.v1.print(ofstream);
+        t.v2.print(ofstream);
+        t.v3.print(ofstream);
+
+        ofstream.write(attribute, 2);
+    }
+}
diff --git a/src/gpu/GridGenerator/io/STLReaderWriter/STLWriter.h b/src/gpu/GridGenerator/io/STLReaderWriter/STLWriter.h
new file mode 100644
index 0000000000000000000000000000000000000000..4ba87fd82e147fd94507d5557a078f5c581c6d07
--- /dev/null
+++ b/src/gpu/GridGenerator/io/STLReaderWriter/STLWriter.h
@@ -0,0 +1,60 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file STLWriter.h
+//! \ingroup io
+//! \author Soeren Peters, Stephan Lenz
+//=======================================================================================
+#ifndef STLWriter_H
+#define STLWriter_H
+
+#include <vector>
+#include <string>
+#include <memory>
+#include <fstream>
+
+#include "global.h"
+
+class Transformator;
+struct Triangle;
+
+class GRIDGENERATOR_EXPORT STLWriter
+{
+public:
+    static void writeSTL(std::vector<Triangle> &vec, const std::string &name, bool writeBinary = false);
+
+private:
+    STLWriter() {}
+    STLWriter(const STLWriter &) {}
+    virtual ~STLWriter() {}
+
+    static void writeAsciiSTL(std::ofstream &ofstream, std::vector<Triangle> &vec);
+    static void writeBinarySTL(std::ofstream &ofstream, std::vector<Triangle> &vec);
+};
+
+#endif
diff --git a/src/gpu/GridGenerator/io/SimulationFileWriter/SimulationFileNames.cpp b/src/gpu/GridGenerator/io/SimulationFileWriter/SimulationFileNames.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..34b6b1d3c30b15333afb0afeb5d35d2894e07e52
--- /dev/null
+++ b/src/gpu/GridGenerator/io/SimulationFileWriter/SimulationFileNames.cpp
@@ -0,0 +1,77 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file SimulationFileNames.cpp
+//! \ingroup io
+//! \author Soeren Peters, Stephan Lenz
+//=======================================================================================
+#include "SimulationFileNames.h"
+
+const std::string fileEnding = ".dat";
+
+const std::string simulationFileNames::coordX = "coordX" + fileEnding;
+const std::string simulationFileNames::coordY = "coordY" + fileEnding;
+const std::string simulationFileNames::coordZ = "coordZ" + fileEnding;
+const std::string simulationFileNames::neighborX = "neighborX" + fileEnding;
+const std::string simulationFileNames::neighborY = "neighborY" + fileEnding;
+const std::string simulationFileNames::neighborZ = "neighborZ" + fileEnding;
+const std::string simulationFileNames::neighborWSB = "neighborWSB" + fileEnding;
+const std::string simulationFileNames::geoVec = "geoVec" + fileEnding;
+
+const std::string simulationFileNames::scaleCFC = "scaleCFC" + fileEnding;
+const std::string simulationFileNames::scaleCFF = "scaleCFF" + fileEnding;
+const std::string simulationFileNames::scaleFCC = "scaleFCC" + fileEnding;
+const std::string simulationFileNames::scaleFCF = "scaleFCF" + fileEnding;
+
+const std::string simulationFileNames::offsetVecCF = "offsetVecCF" + fileEnding;
+const std::string simulationFileNames::offsetVecFC = "offsetVecFC" + fileEnding;
+		
+const std::string simulationFileNames::geomBoundaryQ = "geomBoundaryQs" + fileEnding;
+const std::string simulationFileNames::geomBoundaryValues = "geomBoundaryValues" + fileEnding;
+			
+const std::string simulationFileNames::topBoundaryQ = "topBoundaryQs" + fileEnding;
+const std::string simulationFileNames::topBoundaryValues = "topBoundaryValues" + fileEnding;
+				
+const std::string simulationFileNames::bottomBoundaryQ = "bottomBoundaryQs" + fileEnding;
+const std::string simulationFileNames::bottomBoundaryValues = "bottomBoundaryValues" + fileEnding;
+			
+const std::string simulationFileNames::frontBoundaryQ = "frontBoundaryQs" + fileEnding;
+const std::string simulationFileNames::frontBoundaryValues = "frontBoundaryValues" + fileEnding;
+				 
+const std::string simulationFileNames::backBoundaryQ = "backBoundaryQs" + fileEnding;
+const std::string simulationFileNames::backBoundaryValues = "backBoundaryValues" + fileEnding;
+				  
+const std::string simulationFileNames::inletBoundaryQ = "inletBoundaryQs" + fileEnding;
+const std::string simulationFileNames::inletBoundaryValues = "inletBoundaryValues" + fileEnding;
+				
+const std::string simulationFileNames::outletBoundaryQ = "outletBoundaryQs" + fileEnding;
+const std::string simulationFileNames::outletBoundaryValues = "outletBoundaryValues" + fileEnding;
+
+const std::string simulationFileNames::numberNodes = "numberNodes" + fileEnding;
+const std::string simulationFileNames::LBMvsSI = "LBMvsSI" + fileEnding;
+
diff --git a/src/gpu/GridGenerator/io/SimulationFileWriter/SimulationFileNames.h b/src/gpu/GridGenerator/io/SimulationFileWriter/SimulationFileNames.h
new file mode 100644
index 0000000000000000000000000000000000000000..4be5b44bd4760764da672239052e17bd406316d3
--- /dev/null
+++ b/src/gpu/GridGenerator/io/SimulationFileWriter/SimulationFileNames.h
@@ -0,0 +1,85 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file SimulationFileNames.h
+//! \ingroup io
+//! \author Soeren Peters, Stephan Lenz
+//=======================================================================================
+#ifndef SimulationFileNames_H
+#define SimulationFileNames_H
+
+#include <string>
+
+#include "global.h"
+
+struct GRIDGENERATOR_EXPORT simulationFileNames
+{
+	static const std::string coordX;
+	static const std::string coordY;
+	static const std::string coordZ;
+	static const std::string neighborX;
+	static const std::string neighborY;
+	static const std::string neighborZ;
+	static const std::string neighborWSB;
+	static const std::string geoVec;
+
+    static const std::string scaleCFC;
+    static const std::string scaleCFF;
+    static const std::string scaleFCC;
+    static const std::string scaleFCF;
+
+    static const std::string offsetVecCF;
+    static const std::string offsetVecFC;
+	
+	static const std::string geomBoundaryQ;
+	static const std::string geomBoundaryValues;
+	
+	static const std::string topBoundaryQ;
+	static const std::string topBoundaryValues;
+	
+	static const std::string bottomBoundaryQ;
+	static const std::string bottomBoundaryValues;
+	
+	static const std::string frontBoundaryQ;
+	static const std::string frontBoundaryValues;
+	
+	static const std::string backBoundaryQ;
+	static const std::string backBoundaryValues;
+	
+	static const std::string inletBoundaryQ;
+	static const std::string inletBoundaryValues;
+	
+	static const std::string outletBoundaryQ;
+	static const std::string outletBoundaryValues;
+
+    static const std::string numberNodes;
+    static const std::string LBMvsSI;
+};
+
+
+#endif
diff --git a/src/gpu/GridGenerator/io/SimulationFileWriter/SimulationFileWriter.cpp b/src/gpu/GridGenerator/io/SimulationFileWriter/SimulationFileWriter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..320a6e5fb7bb8e52a335722bca71d7d6a2a0c6de
--- /dev/null
+++ b/src/gpu/GridGenerator/io/SimulationFileWriter/SimulationFileWriter.cpp
@@ -0,0 +1,784 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file SimulationFileWriter.cpp
+//! \ingroup io
+//! \author Soeren Peters, Stephan Lenz
+//=======================================================================================
+#define _CRT_SECURE_NO_DEPRECATE
+#include "SimulationFileWriter.h"
+
+#include <iostream>
+#include <iomanip>
+#include <omp.h>
+#include <cmath>
+#include <stdint.h>
+
+#include "Core/Timer/Timer.h"
+
+#include "grid/NodeValues.h"
+#include "grid/Grid.h"
+#include "grid/GridBuilder/GridBuilder.h"
+#include "grid/BoundaryConditions/Side.h"
+#include "grid/BoundaryConditions/BoundaryCondition.h"
+
+#include "io/SimulationFileWriter/SimulationFileNames.h"
+
+#include "utilities/communication.h"
+
+using namespace vf::gpu;
+
+/*#################################################################################*/
+/*---------------------------------public methods----------------------------------*/
+/*---------------------------------------------------------------------------------*/
+void SimulationFileWriter::write(std::string folder, SPtr<GridBuilder> builder, FILEFORMAT format)
+{
+    SimulationFileWriter::folder = folder;
+
+    *logging::out << logging::Logger::INFO_INTERMEDIATE << "Start writing simulation files to " << folder << ":\n";
+    auto timer = Timer::makeStart();
+
+    write(builder, format);
+
+    *logging::out << logging::Logger::INFO_INTERMEDIATE << "    Time writing files: " << timer->getCurrentRuntimeInSeconds() << " sec\n";
+    *logging::out << logging::Logger::INFO_INTERMEDIATE << "Done writing simulation Files!\n";
+}
+
+
+/*#################################################################################*/
+/*---------------------------------private methods---------------------------------*/
+/*---------------------------------------------------------------------------------*/
+void SimulationFileWriter::write(SPtr<GridBuilder> builder, FILEFORMAT format)
+{
+    const uint numberOfLevel = builder->getNumberOfGridLevels();
+    openFiles(builder);
+    writeLevel(numberOfLevel);
+    //auto qs = createBCVectors(builder->getGrid(0));
+
+    *logging::out << logging::Logger::INFO_INTERMEDIATE << "    Coordinate and neighbor files:\n";
+    for (uint level = 0; level < numberOfLevel; level++)
+    {
+        writeNumberNodes(builder, level);
+        writeLBMvsSI(builder, level);
+
+        writeLevelSize(builder->getNumberOfNodes(level), format);
+        writeCoordFiles(builder, level, format);
+
+        if (level < numberOfLevel - 1)
+        {
+            writeLevelSizeGridInterface(builder->getNumberOfNodesCF(level), builder->getNumberOfNodesFC(level));
+            writeGridInterfaceToFile(builder, level);
+        }
+    }
+    
+    *logging::out << logging::Logger::INFO_INTERMEDIATE << "    Boundary Condition files:\n";
+    writeBoundaryQsFile(builder);
+    
+    *logging::out << logging::Logger::INFO_INTERMEDIATE << "    Communication files:\n";
+    writeCommunicationFiles(builder);
+
+    closeFiles();
+}
+
+void SimulationFileWriter::openFiles(SPtr<GridBuilder> builder)
+{
+    std::string path = folder;
+    xCoordFile.open((      path + simulationFileNames::coordX).c_str(),      std::ios::out | std::ios::binary);
+    yCoordFile.open((      path + simulationFileNames::coordY).c_str(),      std::ios::out | std::ios::binary);
+    zCoordFile.open((      path + simulationFileNames::coordZ).c_str(),      std::ios::out | std::ios::binary);
+    xNeighborFile.open((   path + simulationFileNames::neighborX).c_str(),   std::ios::out | std::ios::binary);
+    yNeighborFile.open((   path + simulationFileNames::neighborY).c_str(),   std::ios::out | std::ios::binary);
+    zNeighborFile.open((   path + simulationFileNames::neighborZ).c_str(),   std::ios::out | std::ios::binary);
+    wsbNeighborFile.open(( path + simulationFileNames::neighborWSB).c_str(), std::ios::out | std::ios::binary);
+    geoVecFile.open((      path + simulationFileNames::geoVec).c_str(),      std::ios::out | std::ios::binary);
+
+    scaleCF_coarse_File.open((path + simulationFileNames::scaleCFC).c_str(), std::ios::out | std::ios::binary);
+    scaleCF_fine_File.open((path + simulationFileNames::scaleCFF).c_str(), std::ios::out | std::ios::binary);
+    scaleFC_coarse_File.open((path + simulationFileNames::scaleFCC).c_str(), std::ios::out | std::ios::binary);
+    scaleFC_fine_File.open((path + simulationFileNames::scaleFCF).c_str(), std::ios::out | std::ios::binary);
+
+    offsetVecCF_File.open((path + simulationFileNames::offsetVecCF).c_str(), std::ios::out | std::ios::binary);
+    offsetVecFC_File.open((path + simulationFileNames::offsetVecFC).c_str(), std::ios::out | std::ios::binary);
+
+
+    std::vector<std::string> qNames;
+    qNames.push_back(path + simulationFileNames::inletBoundaryQ);
+    qNames.push_back(path + simulationFileNames::outletBoundaryQ);
+    qNames.push_back(path + simulationFileNames::topBoundaryQ);
+    qNames.push_back(path + simulationFileNames::bottomBoundaryQ);
+    qNames.push_back(path + simulationFileNames::frontBoundaryQ);
+    qNames.push_back(path + simulationFileNames::backBoundaryQ);
+	qNames.push_back(path + simulationFileNames::geomBoundaryQ);
+
+    std::vector<std::string> valueNames;
+    valueNames.push_back(path + simulationFileNames::inletBoundaryValues);
+    valueNames.push_back(path + simulationFileNames::outletBoundaryValues);
+    valueNames.push_back(path + simulationFileNames::topBoundaryValues);
+    valueNames.push_back(path + simulationFileNames::bottomBoundaryValues);
+    valueNames.push_back(path + simulationFileNames::frontBoundaryValues);
+    valueNames.push_back(path + simulationFileNames::backBoundaryValues);
+	valueNames.push_back(path + simulationFileNames::geomBoundaryValues);
+
+    for (int i = 0; i < QFILES; i++){
+        SPtr<std::ofstream> outQ(new std::ofstream);
+        outQ->open(qNames[i].c_str(), std::ios::out | std::ios::binary);
+        qStreams.push_back(outQ);
+
+        SPtr<std::ofstream> outV(new std::ofstream);
+        outV->open(valueNames[i].c_str(), std::ios::out | std::ios::binary);
+        valueStreams.push_back(outV);
+    }
+
+    if(builder->getCommunicationProcess(CommunicationDirections::MX) != INVALID_INDEX) sendFiles   [CommunicationDirections::MX].open( (path + std::to_string(builder->getCommunicationProcess(CommunicationDirections::MX)) + "Xs.dat").c_str() );
+    if(builder->getCommunicationProcess(CommunicationDirections::PX) != INVALID_INDEX) sendFiles   [CommunicationDirections::PX].open( (path + std::to_string(builder->getCommunicationProcess(CommunicationDirections::PX)) + "Xs.dat").c_str() );
+    if(builder->getCommunicationProcess(CommunicationDirections::MY) != INVALID_INDEX) sendFiles   [CommunicationDirections::MY].open( (path + std::to_string(builder->getCommunicationProcess(CommunicationDirections::MY)) + "Ys.dat").c_str() );
+    if(builder->getCommunicationProcess(CommunicationDirections::PY) != INVALID_INDEX) sendFiles   [CommunicationDirections::PY].open( (path + std::to_string(builder->getCommunicationProcess(CommunicationDirections::PY)) + "Ys.dat").c_str() );
+    if(builder->getCommunicationProcess(CommunicationDirections::MZ) != INVALID_INDEX) sendFiles   [CommunicationDirections::MZ].open( (path + std::to_string(builder->getCommunicationProcess(CommunicationDirections::MZ)) + "Zs.dat").c_str() );
+    if(builder->getCommunicationProcess(CommunicationDirections::PZ) != INVALID_INDEX) sendFiles   [CommunicationDirections::PZ].open( (path + std::to_string(builder->getCommunicationProcess(CommunicationDirections::PZ)) + "Zs.dat").c_str() );
+
+    if(builder->getCommunicationProcess(CommunicationDirections::MX) != INVALID_INDEX) receiveFiles[CommunicationDirections::MX].open( (path + std::to_string(builder->getCommunicationProcess(CommunicationDirections::MX)) + "Xr.dat").c_str() );
+    if(builder->getCommunicationProcess(CommunicationDirections::PX) != INVALID_INDEX) receiveFiles[CommunicationDirections::PX].open( (path + std::to_string(builder->getCommunicationProcess(CommunicationDirections::PX)) + "Xr.dat").c_str() );
+    if(builder->getCommunicationProcess(CommunicationDirections::MY) != INVALID_INDEX) receiveFiles[CommunicationDirections::MY].open( (path + std::to_string(builder->getCommunicationProcess(CommunicationDirections::MY)) + "Yr.dat").c_str() );
+    if(builder->getCommunicationProcess(CommunicationDirections::PY) != INVALID_INDEX) receiveFiles[CommunicationDirections::PY].open( (path + std::to_string(builder->getCommunicationProcess(CommunicationDirections::PY)) + "Yr.dat").c_str() );
+    if(builder->getCommunicationProcess(CommunicationDirections::MZ) != INVALID_INDEX) receiveFiles[CommunicationDirections::MZ].open( (path + std::to_string(builder->getCommunicationProcess(CommunicationDirections::MZ)) + "Zr.dat").c_str() );
+    if(builder->getCommunicationProcess(CommunicationDirections::PZ) != INVALID_INDEX) receiveFiles[CommunicationDirections::PZ].open( (path + std::to_string(builder->getCommunicationProcess(CommunicationDirections::PZ)) + "Zr.dat").c_str() );
+
+    numberNodes_File.open((path + simulationFileNames::numberNodes).c_str(), std::ios::out | std::ios::binary);
+    LBMvsSI_File.open((path + simulationFileNames::LBMvsSI).c_str(), std::ios::out | std::ios::binary);
+}
+
+void SimulationFileWriter::writeNumberNodes(SPtr<GridBuilder> builder, uint level)
+{
+    SPtr<Grid> grid = builder->getGrid(level);
+    numberNodes_File << level << '\n';
+
+    numberNodes_File << grid->getNumberOfNodesX() << ' ';
+    numberNodes_File << grid->getNumberOfNodesY() << ' ';
+    numberNodes_File << grid->getNumberOfNodesZ() << ' ';
+    numberNodes_File << '\n';
+}
+
+void SimulationFileWriter::writeLBMvsSI(SPtr<GridBuilder> builder, uint level)
+{
+    SPtr<Grid> grid = builder->getGrid(level);
+
+    LBMvsSI_File << grid->getStartX() << ' ';
+    LBMvsSI_File << grid->getStartY() << ' ';
+    LBMvsSI_File << grid->getStartZ() << ' ';
+
+    LBMvsSI_File << grid->getEndX() << ' ';
+    LBMvsSI_File << grid->getEndY() << ' ';
+    LBMvsSI_File << grid->getEndZ() << ' ';
+    LBMvsSI_File << '\n';
+}
+
+void SimulationFileWriter::writeLevel(uint numberOfLevels)
+{
+    const std::string level = std::to_string(numberOfLevels - 1);
+    
+    xCoordFile << level << "\n";
+    yCoordFile << level << "\n";
+    zCoordFile << level << "\n";
+    xNeighborFile << level << "\n";
+    yNeighborFile << level << "\n";
+    zNeighborFile << level << "\n";
+    wsbNeighborFile << level << "\n";
+    geoVecFile << level << "\n";
+
+    scaleCF_coarse_File << level << "\n";
+    scaleCF_fine_File << level << "\n";
+    scaleFC_coarse_File << level << "\n";
+    scaleFC_fine_File << level << "\n";
+
+    offsetVecCF_File << level << "\n";
+    offsetVecFC_File << level << "\n";
+
+    //const std::string geoRB = "noSlip\n";
+
+    //for (int rb = 0; rb < QFILES; rb++) {
+    //    *qStreams[rb] << level << "\n";
+    //    *valueStreams[rb] << geoRB << level << "\n";
+    //}
+}
+
+void SimulationFileWriter::writeLevelSize(uint numberOfNodes, FILEFORMAT format)
+{
+    const std::string zeroIndex = "0 ";
+    const std::string zeroGeo = "16 ";
+
+    if (format == FILEFORMAT::BINARY)
+	{
+        //const uint zeroIndex = 0;
+        //const uint zeroGeo   = 16;
+
+        //xCoordFile.write((char*)&zeroIndex, sizeof(double));
+        //yCoordFile.write((char*)&zeroIndex, sizeof(double));
+        //zCoordFile.write((char*)&zeroIndex, sizeof(double));
+
+        //// + 1 for numbering shift between GridGenerator and VF_GPU
+        //xNeighborFile.write((char*)(&zeroIndex), sizeof(unsigned int));
+        //yNeighborFile.write((char*)(&zeroIndex), sizeof(unsigned int));
+        //zNeighborFile.write((char*)(&zeroIndex), sizeof(unsigned int));
+        //wsbNeighborFile.write((char*)(&zeroIndex), sizeof(unsigned int));
+
+        //geoVecFile.write((char*)&zeroGeo, sizeof(unsigned int));
+        
+        xCoordFile      << numberOfNodes << "\n" << zeroIndex;
+        yCoordFile      << numberOfNodes << "\n" << zeroIndex;
+        zCoordFile      << numberOfNodes << "\n" << zeroIndex;
+        xNeighborFile   << numberOfNodes << "\n" << zeroIndex;
+        yNeighborFile   << numberOfNodes << "\n" << zeroIndex;
+        zNeighborFile   << numberOfNodes << "\n" << zeroIndex;
+        wsbNeighborFile << numberOfNodes << "\n" << zeroIndex;
+        geoVecFile      << numberOfNodes << "\n" << zeroGeo  ;
+    }
+    else 
+	{
+        xCoordFile      << numberOfNodes << "\n" << zeroIndex << "\n";
+        yCoordFile      << numberOfNodes << "\n" << zeroIndex << "\n";
+        zCoordFile      << numberOfNodes << "\n" << zeroIndex << "\n";
+        xNeighborFile   << numberOfNodes << "\n" << zeroIndex << "\n";
+        yNeighborFile   << numberOfNodes << "\n" << zeroIndex << "\n";
+        zNeighborFile   << numberOfNodes << "\n" << zeroIndex << "\n";
+        wsbNeighborFile << numberOfNodes << "\n" << zeroIndex << "\n";
+        geoVecFile      << numberOfNodes << "\n" << zeroGeo   << "\n";
+    }
+}
+
+void SimulationFileWriter::writeLevelSizeGridInterface(uint sizeCF, uint sizeFC)
+{
+    scaleCF_coarse_File << sizeCF << "\n";
+    scaleCF_fine_File << sizeCF << "\n";
+    scaleFC_coarse_File << sizeFC << "\n";
+    scaleFC_fine_File << sizeFC << "\n";
+
+    offsetVecCF_File << sizeCF << "\n";
+    offsetVecFC_File << sizeFC << "\n";
+}
+
+void SimulationFileWriter::writeCoordFiles(SPtr<GridBuilder> builder, uint level, FILEFORMAT format)
+{
+    for (uint index = 0; index < builder->getGrid(level)->getSize(); index++){
+        writeCoordsNeighborsGeo(builder, index, level, format);
+    }
+
+    xCoordFile << "\n";
+    yCoordFile << "\n";
+    zCoordFile << "\n";
+
+    xNeighborFile << "\n";
+    yNeighborFile << "\n";
+    zNeighborFile << "\n";
+    wsbNeighborFile << "\n";
+
+    geoVecFile << "\n";
+}
+
+void SimulationFileWriter::writeCoordsNeighborsGeo(SPtr<GridBuilder> builder, int index, uint level, FILEFORMAT format)
+{
+    SPtr<Grid> grid = builder->getGrid(level);
+    if (grid->getSparseIndex(index) == -1)
+        return;
+
+    // Lenz: in the GPU code all nodes that perform collisions have to be fluid = 19
+    bool isStopper = grid->getFieldEntry(index) == STOPPER_SOLID                || 
+                     grid->getFieldEntry(index) == STOPPER_OUT_OF_GRID          || 
+                     grid->getFieldEntry(index) == STOPPER_OUT_OF_GRID_BOUNDARY || 
+                     grid->getFieldEntry(index) == STOPPER_COARSE_UNDER_FINE;
+    int type = !isStopper ? 19 : 16;
+
+    // old code from Soeren P.
+    //int type = grid->getFieldEntry(index) == FLUID ? 19 : 16;
+
+    real x, y, z;
+    grid->transIndexToCoords(index, x, y, z);
+
+    if (format == FILEFORMAT::BINARY)
+	{
+        double tmpX = (double)x;
+        double tmpY = (double)y;
+        double tmpZ = (double)z;
+
+        xCoordFile.write((char*)&tmpX, sizeof(double));
+        yCoordFile.write((char*)&tmpY, sizeof(double));
+        zCoordFile.write((char*)&tmpZ, sizeof(double));
+
+        // + 1 for numbering shift between GridGenerator and VF_GPU
+        int tmpNeighborX        = grid->getNeighborsX()[index]        + 1;
+        int tmpNeighborY        = grid->getNeighborsY()[index]        + 1;
+        int tmpNeighborZ        = grid->getNeighborsZ()[index]        + 1;
+        int tmpNeighborNegative = grid->getNeighborsNegative()[index] + 1;
+
+        xNeighborFile.write  ((char*)(&tmpNeighborX       ), sizeof(unsigned int));
+        yNeighborFile.write  ((char*)(&tmpNeighborY       ), sizeof(unsigned int));
+        zNeighborFile.write  ((char*)(&tmpNeighborZ       ), sizeof(unsigned int));
+        wsbNeighborFile.write((char*)(&tmpNeighborNegative), sizeof(unsigned int));
+
+        geoVecFile.write((char*)&type, sizeof(unsigned int));
+    }
+    else 
+	{
+        xCoordFile << x << "\n";
+        yCoordFile << y << "\n";
+        zCoordFile << z << "\n";
+
+        // + 1 for numbering shift between GridGenerator and VF_GPU
+        xNeighborFile << (grid->getNeighborsX()[index] + 1) << "\n";
+        yNeighborFile << (grid->getNeighborsY()[index] + 1) << "\n";
+        zNeighborFile << (grid->getNeighborsZ()[index] + 1) << "\n";
+        wsbNeighborFile << (grid->getNeighborsNegative()[index] + 1) << "\n";
+
+        geoVecFile << type << "\n";
+    }
+}
+
+void SimulationFileWriter::writeGridInterfaceToFile(SPtr<GridBuilder> builder, uint level)
+{
+    const uint numberOfNodesCF = builder->getNumberOfNodesCF(level);
+    const uint numberOfNodesFC = builder->getNumberOfNodesFC(level);
+
+    {
+        uint* cf_coarse = new uint[numberOfNodesCF];
+        uint* cf_fine = new uint[numberOfNodesCF];
+        uint* fc_coarse = new uint[numberOfNodesFC];
+        uint* fc_fine = new uint[numberOfNodesFC];
+
+        builder->getGridInterfaceIndices(cf_coarse, cf_fine, fc_coarse, fc_fine, level);
+
+        if (numberOfNodesCF > 0)
+        {
+            writeGridInterfaceToFile(numberOfNodesCF, scaleCF_coarse_File, cf_coarse, scaleCF_fine_File, cf_fine);
+        }
+
+        if (numberOfNodesFC > 0)
+        {
+            writeGridInterfaceToFile(numberOfNodesFC, scaleFC_coarse_File, fc_coarse, scaleFC_fine_File, fc_fine);
+        }
+
+        delete [] cf_coarse;
+        delete [] cf_fine;
+        delete [] fc_coarse;
+        delete [] fc_fine;
+    }
+
+    {
+        real* cf_offset_X = new real[numberOfNodesCF];
+        real* cf_offset_Y = new real[numberOfNodesCF];
+        real* cf_offset_Z = new real[numberOfNodesCF];
+
+        real* fc_offset_X = new real[numberOfNodesFC];
+        real* fc_offset_Y = new real[numberOfNodesFC];
+        real* fc_offset_Z = new real[numberOfNodesFC];
+
+        builder->getOffsetCF(cf_offset_X, cf_offset_Y, cf_offset_Z, level);
+        builder->getOffsetFC(fc_offset_X, fc_offset_Y, fc_offset_Z, level);
+
+        if (numberOfNodesCF > 0)
+        {
+            writeGridInterfaceOffsetToFile(numberOfNodesCF, offsetVecCF_File, cf_offset_X, cf_offset_Y, cf_offset_Z);
+        }
+
+        if (numberOfNodesFC > 0)
+        {
+            writeGridInterfaceOffsetToFile(numberOfNodesFC, offsetVecFC_File, fc_offset_X, fc_offset_Y, fc_offset_Z);
+        }
+
+        delete[] cf_offset_X;
+        delete[] cf_offset_Y;
+        delete[] cf_offset_Z;
+
+        delete[] fc_offset_X;
+        delete[] fc_offset_Y;
+        delete[] fc_offset_Z;
+    }
+}
+
+void SimulationFileWriter::writeGridInterfaceToFile(const uint numberOfNodes, std::ofstream& coarseFile, uint* coarse, std::ofstream& fineFile, uint* fine)
+{
+    for (uint index = 0; index < numberOfNodes; index++)
+    {
+        coarseFile << coarse[index] << " \n";
+        fineFile << fine[index] << " \n";
+    }
+    coarseFile << "\n";
+    fineFile << "\n";
+}
+
+void SimulationFileWriter::writeGridInterfaceOffsetToFile(uint numberOfNodes, std::ofstream & offsetFile, real* offset_X, real* offset_Y, real* offset_Z)
+{
+    for (uint index = 0; index < numberOfNodes; index++)
+    {
+        offsetFile << offset_X[index] << " " << offset_Y[index] << " " << offset_Z[index] << " \n";
+    }
+    offsetFile << "\n";
+}
+
+
+
+/*#################################################################################*/
+/*---------------------------------private methods---------------------------------*/
+/*---------------------------------------------------------------------------------*/
+std::vector<std::vector<std::vector<real> > > SimulationFileWriter::createBCVectors(SPtr<Grid> grid)
+{
+    std::vector<std::vector<std::vector<real> > > qs;
+	qs.resize(QFILES);
+    for (uint i = 0; i < grid->getSize(); i++)
+    {
+        real x, y, z;
+        grid->transIndexToCoords(i, x, y, z);
+
+        if (grid->getFieldEntry(i) == BC_SOLID) addShortQsToVector(i, qs, grid); //addQsToVector(i, qs, grid);
+        //if (x == 0 && y < grid->getNumberOfNodesY() - 1 && z < grid->getNumberOfNodesZ() - 1) fillRBForNode(i, 0, -1, INLETQS, qs, grid);
+        //if (x == grid->getNumberOfNodesX() - 2 && y < grid->getNumberOfNodesY() - 1 && z < grid->getNumberOfNodesZ() - 1) fillRBForNode(i, 0, 1, OUTLETQS, qs, grid);
+
+        //if (z == grid->getNumberOfNodesZ() - 2 && x < grid->getNumberOfNodesX() - 1 && y < grid->getNumberOfNodesY() - 1) fillRBForNode(i, 2, 1, TOPQS, qs, grid);
+        //if (z == 0 && x < grid->getNumberOfNodesX() - 1 && y < grid->getNumberOfNodesY() - 1) fillRBForNode(i, 2, -1, BOTTOMQS, qs, grid);
+
+        //if (y == 0 && x < grid->getNumberOfNodesX() - 1 && z < grid->getNumberOfNodesZ() - 1) fillRBForNode(i, 1, -1, FRONTQS, qs, grid);
+        //if (y == grid->getNumberOfNodesY() - 2 && x < grid->getNumberOfNodesX() - 1 && z < grid->getNumberOfNodesZ() - 1) fillRBForNode(i, 1, 1, BACKQS, qs, grid);
+    }
+    return qs;
+}
+
+void SimulationFileWriter::addShortQsToVector(int index, std::vector<std::vector<std::vector<real> > > &qs, SPtr<Grid> grid)
+{
+    uint32_t qKey = 0;
+    std::vector<real> qNode;
+
+    for (int i = grid->getEndDirection(); i >= 0; i--)
+    {
+		/*int qIndex = i * grid->getSize() + grid->getSparseIndex(index);
+		real q = grid->getDistribution()[qIndex];*/
+		real q = grid->getQValue(index, i);
+        if (q > 0) {
+            //printf("Q%d (old:%d, new:%d), : %2.8f \n", i, coordsVec[index].matrixIndex, index, grid.d.f[i * grid.size + coordsVec[index].matrixIndex]);
+            qKey += (uint32_t)pow(2, 26 - i);
+            qNode.push_back(q);
+        }
+    }
+    if (qKey > 0) {
+        real transportKey = *((real*)&qKey);
+        qNode.push_back(transportKey);
+        qNode.push_back((real)index);
+        qs[GEOMQS].push_back(qNode);
+    }
+    qNode.clear();
+}
+
+void SimulationFileWriter::addQsToVector(int index, std::vector<std::vector<std::vector<real> > > &qs, SPtr<Grid> grid)
+{
+    std::vector<real> qNode;
+    qNode.push_back((real)index);
+
+    for (int i = grid->getEndDirection(); i >= 0; i--)
+    {
+        //int qIndex = i * grid->getSize() + grid->getSparseIndex(index);
+        //real q = grid->getDistribution()[qIndex];
+		real q = grid->getQValue(index, i);
+        qNode.push_back(q);
+		if (q > 0)
+			printf("Q= %f; Index = %d \n", q, index);
+            //qNode.push_back(q);
+  //      else
+  //          qNode.push_back(-1);
+    }
+    qs[GEOMQS].push_back(qNode);
+    qNode.clear();
+}
+
+void SimulationFileWriter::fillRBForNode(int index, int direction, int directionSign, int rb, std::vector<std::vector<std::vector<real> > > &qs, SPtr<Grid> grid)
+{
+    uint32_t qKey = 0;
+    std::vector<real> qNode;
+
+    for (int i = grid->getEndDirection(); i >= 0; i--)
+    {
+        if (grid->getDirection()[i * DIMENSION + direction] != directionSign)
+            continue;
+
+        qKey += (uint32_t)pow(2, 26 - i);
+        qNode.push_back(0.5f);
+    }
+    if (qKey > 0) {
+        real transportKey = *((real*)&qKey);
+        qNode.push_back(transportKey);
+        qNode.push_back((real)index);
+        qs[rb].push_back(qNode);
+    }
+    qNode.clear();
+}
+
+
+void SimulationFileWriter::writeBoundaryQsFile(SPtr<GridBuilder> builder)
+{
+    // old code of Soeren P.
+  //  for (int rb = 0; rb < QFILES; rb++) {
+  //      for (int index = 0; index < qFiles[rb].size(); index++) {
+  //          //writeBoundary(qFiles[rb][index], rb);
+		//	writeBoundaryShort(qFiles[rb][index], rb);
+		//}
+  //  }
+
+    SideType sides[] = {SideType::MX, SideType::PX, SideType::PZ, SideType::MZ, SideType::MY, SideType::PY, SideType::GEOMETRY};
+
+    for (uint side = 0; side < QFILES; side++) {
+
+        for (uint level = 0; level < builder->getNumberOfGridLevels(); level++) {
+            
+            auto bc = builder->getBoundaryCondition( sides[side], level );
+
+            if( level == 0 ){
+            
+                if     ( !bc )                          *valueStreams[side] << "noSlip\n";
+                else if( bc->getType() == BC_PRESSURE ) *valueStreams[side] << "pressure\n";
+                else if( bc->getType() == BC_VELOCITY ) *valueStreams[side] << "velocity\n";
+                else if( bc->getType() == BC_SOLID    ) *valueStreams[side] << "noSlip\n";
+                else if( bc->getType() == BC_SLIP     ) *valueStreams[side] << "slip\n";
+                else if( bc->getType() == BC_OUTFLOW  ) *valueStreams[side] << "outflow\n";
+
+                *valueStreams[side] << builder->getNumberOfGridLevels() - 1 << "\n";
+                *qStreams[side]     << builder->getNumberOfGridLevels() - 1 << "\n";
+            }
+
+            if( !bc ){
+                *valueStreams[side] << "0\n";
+                *qStreams[side]     << "0\n";
+            }
+            else{
+                writeBoundaryShort( builder->getGrid(level), bc, side );
+            }
+        }
+    }
+}
+
+void SimulationFileWriter::writeBoundary(std::vector<real> boundary, int rb)
+{
+    int index = (int)boundary[0];
+
+    *qStreams[rb] << (index + 1);
+
+    for (std::size_t i = 1; i < boundary.size(); i++) {
+        *qStreams[rb] << " " << std::fixed << std::setprecision(16) << boundary[i];
+    }
+    *valueStreams[rb] << (index+1) << " 0 0 0";
+
+    *qStreams[rb] << "\n";
+    *valueStreams[rb] << "\n";
+}
+
+void SimulationFileWriter::writeBoundaryShort(std::vector<real> boundary, int rb)
+{
+	uint32_t key = *((uint32_t*)&boundary[boundary.size() - 2]);
+	int index = (int)boundary[boundary.size() - 1];
+
+	*qStreams[rb] << (index + 1) << " " << key;
+
+	for (std::size_t i = 0; i < boundary.size() - 2; i++) {
+		*qStreams[rb] << " " << std::fixed << std::setprecision(16) << boundary[i];
+	}
+	*valueStreams[rb] << (index + 1) << " 0 0 0";
+
+	*qStreams[rb] << "\n";
+	*valueStreams[rb] << "\n";
+}
+
+void SimulationFileWriter::writeBoundaryShort(SPtr<Grid> grid, SPtr<gg::BoundaryCondition> boundaryCondition, uint side)
+{
+    uint numberOfBoundaryNodes = (uint)boundaryCondition->indices.size();
+
+    *valueStreams[side] << numberOfBoundaryNodes << "\n";
+    *qStreams[side]     << numberOfBoundaryNodes << "\n";
+
+    for( uint index = 0; index < numberOfBoundaryNodes; index++ ){
+    
+        // + 1 for numbering shift between GridGenerator and VF_GPU
+        *valueStreams[side] << grid->getSparseIndex( boundaryCondition->indices[index] ) + 1 << " ";
+        *qStreams[side]     << grid->getSparseIndex( boundaryCondition->indices[index] ) + 1 << " ";
+
+        {
+            uint32_t key = 0;
+
+            for (int dir = 26; dir >= 0; dir--)
+            {
+                real q = boundaryCondition->getQ(index,dir);
+                if (q > 0) {
+                    key += (uint32_t)pow(2, 26 - dir);
+                }
+            }
+
+            *qStreams[side] << key << " ";
+
+            for (int dir = 26; dir >= 0; dir--)
+            {
+                real q = boundaryCondition->getQ(index,dir);
+                if (q > 0) {
+                    *qStreams[side] << std::fixed << std::setprecision(16) << q << " ";
+                }
+            }
+
+            *qStreams[side] << "\n";
+        }
+
+        if( boundaryCondition->getType() == BC_PRESSURE )
+        {
+            auto bcPressure = dynamic_cast< PressureBoundaryCondition* >( boundaryCondition.get() );
+
+            *valueStreams[side] << bcPressure->getRho() << " ";
+            // + 1 for numbering shift between GridGenerator and VF_GPU
+            *valueStreams[side] << grid->getSparseIndex( bcPressure->neighborIndices[index] ) + 1 << " ";
+        }
+
+        if( boundaryCondition->getType() == BC_VELOCITY )
+        {
+            auto bcVelocity = dynamic_cast< VelocityBoundaryCondition* >( boundaryCondition.get() );
+
+            *valueStreams[side] << bcVelocity->getVx(index) << " ";
+            *valueStreams[side] << bcVelocity->getVy(index) << " ";
+            *valueStreams[side] << bcVelocity->getVz(index) << " ";
+        }
+
+        if( boundaryCondition->getType() == BC_SOLID )
+        {
+            auto bcGeometry = dynamic_cast< GeometryBoundaryCondition* >( boundaryCondition.get() );
+
+            *valueStreams[side] << bcGeometry->getVx(index) << " ";
+            *valueStreams[side] << bcGeometry->getVy(index) << " ";
+            *valueStreams[side] << bcGeometry->getVz(index) << " ";
+        }
+
+        *valueStreams[side] << "\n";
+    }
+    
+}
+
+void SimulationFileWriter::writeCommunicationFiles(SPtr<GridBuilder> builder)
+{
+    const uint numberOfLevel = builder->getNumberOfGridLevels();
+    
+    for( uint direction = 0; direction < 6; direction++ ){
+        
+        if(builder->getCommunicationProcess(direction) == INVALID_INDEX) continue;
+
+        sendFiles[direction] << "processor\n";
+        sendFiles[direction] << builder->getNumberOfGridLevels() - 1 << "\n";
+
+        receiveFiles[direction] << "processor\n";
+        receiveFiles[direction] << builder->getNumberOfGridLevels() - 1 << "\n";
+
+        for (uint level = 0; level < numberOfLevel; level++){
+        
+            uint numberOfSendNodes    = builder->getGrid(level)->getNumberOfSendNodes(direction);
+            uint numberOfReceiveNodes = builder->getGrid(level)->getNumberOfReceiveNodes(direction);
+        
+            sendFiles[direction] <<    numberOfSendNodes    << "\n";
+            receiveFiles[direction] << numberOfReceiveNodes << "\n";
+
+            for( uint index = 0; index < numberOfSendNodes; index++ )
+                // + 1 for numbering shift between GridGenerator and VF_GPU
+                sendFiles[direction]    << builder->getGrid(level)->getSparseIndex( builder->getGrid(level)->getSendIndex   (direction, index) ) + 1 << "\n";
+
+            for( uint index = 0; index < numberOfReceiveNodes; index++ )
+                // + 1 for numbering shift between GridGenerator and VF_GPU
+                receiveFiles[direction] << builder->getGrid(level)->getSparseIndex( builder->getGrid(level)->getReceiveIndex(direction, index) ) + 1 << "\n";
+
+        }
+    }
+}
+
+void SimulationFileWriter::closeFiles()
+{
+    xCoordFile.close();
+    yCoordFile.close();
+    zCoordFile.close();
+    xNeighborFile.close();
+    yNeighborFile.close();
+    zNeighborFile.close();
+    wsbNeighborFile.close();
+    geoVecFile.close();
+
+    scaleCF_coarse_File.close();
+    scaleCF_fine_File.close();
+    scaleFC_coarse_File.close();
+    scaleFC_fine_File.close();
+
+    offsetVecCF_File.close();
+    offsetVecFC_File.close();
+
+    for (int rb = 0; rb < QFILES; rb++) {
+        qStreams[rb]->close();
+        valueStreams[rb]->close();
+    }
+
+    sendFiles[CommunicationDirections::MX].close();
+    sendFiles[CommunicationDirections::PX].close();
+    sendFiles[CommunicationDirections::MY].close();
+    sendFiles[CommunicationDirections::PY].close();
+    sendFiles[CommunicationDirections::MZ].close();
+    sendFiles[CommunicationDirections::PZ].close();
+    
+    receiveFiles[CommunicationDirections::MX].close();
+    receiveFiles[CommunicationDirections::PX].close();
+    receiveFiles[CommunicationDirections::MY].close();
+    receiveFiles[CommunicationDirections::PY].close();
+    receiveFiles[CommunicationDirections::MZ].close();
+    receiveFiles[CommunicationDirections::PZ].close();
+
+    numberNodes_File.close();
+    LBMvsSI_File.close();
+}
+
+
+/*#################################################################################*/
+/*-------------------------------static attributes---------------------------------*/
+/*---------------------------------------------------------------------------------*/
+std::vector<SPtr<std::ofstream> > SimulationFileWriter::qStreams;
+std::vector<SPtr<std::ofstream> > SimulationFileWriter::valueStreams;
+
+std::ofstream SimulationFileWriter::xCoordFile;
+std::ofstream SimulationFileWriter::yCoordFile;
+std::ofstream SimulationFileWriter::zCoordFile;
+std::ofstream SimulationFileWriter::xNeighborFile;
+std::ofstream SimulationFileWriter::yNeighborFile;
+std::ofstream SimulationFileWriter::zNeighborFile;
+std::ofstream SimulationFileWriter::wsbNeighborFile;
+std::ofstream SimulationFileWriter::geoVecFile;
+std::string SimulationFileWriter::folder;
+
+std::ofstream SimulationFileWriter::scaleCF_coarse_File;
+std::ofstream SimulationFileWriter::scaleCF_fine_File;
+std::ofstream SimulationFileWriter::scaleFC_coarse_File;
+std::ofstream SimulationFileWriter::scaleFC_fine_File;
+
+std::ofstream SimulationFileWriter::offsetVecCF_File;
+std::ofstream SimulationFileWriter::offsetVecFC_File;
+
+std::ofstream SimulationFileWriter::numberNodes_File;
+std::ofstream SimulationFileWriter::LBMvsSI_File;
+
+std::array<std::ofstream, 6> SimulationFileWriter::sendFiles;
+std::array<std::ofstream, 6> SimulationFileWriter::receiveFiles;
\ No newline at end of file
diff --git a/src/gpu/GridGenerator/io/SimulationFileWriter/SimulationFileWriter.h b/src/gpu/GridGenerator/io/SimulationFileWriter/SimulationFileWriter.h
new file mode 100644
index 0000000000000000000000000000000000000000..d5d2a377b33697704b86f8b78987fd0af75be415
--- /dev/null
+++ b/src/gpu/GridGenerator/io/SimulationFileWriter/SimulationFileWriter.h
@@ -0,0 +1,129 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file SimulationFileWriter.h
+//! \ingroup io
+//! \author Soeren Peters, Stephan Lenz
+//=======================================================================================
+#ifndef SimulationFileWriter_H
+#define SimulationFileWriter_H
+
+#include <string>
+#include <vector>
+#include <fstream>
+#include <memory>
+#include <vector>
+#include <array>
+
+#include "Core/NonCreatable.h"
+
+#include "global.h"
+
+class UnstructuredGridBuilder;
+class GridBuilder;
+class Grid;
+namespace gg
+{
+class BoundaryCondition;
+}
+
+enum class FILEFORMAT
+{
+    BINARY, ASCII
+};
+
+class SimulationFileWriter : private NonCreatable
+{
+public:
+    GRIDGENERATOR_EXPORT static void write(std::string folder, SPtr<GridBuilder> builder, FILEFORMAT format);
+
+private:
+    static void write(SPtr<GridBuilder> builder, FILEFORMAT format);
+    static void openFiles(SPtr<GridBuilder> builder);
+
+    static void writeNumberNodes(SPtr<GridBuilder> builder, uint level);
+    static void writeLBMvsSI(SPtr<GridBuilder> builder, uint level);
+
+    static void writeLevel(uint numberOfLevels);
+    static void writeLevelSize(uint numberOfNodes, FILEFORMAT format);
+    static void writeCoordFiles(SPtr<GridBuilder> builder, uint level, FILEFORMAT format);
+    static void writeCoordsNeighborsGeo(SPtr<GridBuilder> builder, int index, uint level, FILEFORMAT format);
+
+    static void writeLevelSizeGridInterface(uint sizeCF, uint sizeFC);
+    static void writeGridInterfaceToFile(SPtr<GridBuilder> builder, uint level);
+    static void writeGridInterfaceToFile(uint numberOfNodes, std::ofstream& coarseFile, uint* coarse, std::ofstream& fineFile, uint* fine);
+    static void writeGridInterfaceOffsetToFile(uint numberOfNodes, std::ofstream& offsetFile, real* cf_offset_X, real* cf_offset_Y, real* cf_offset_Z);
+
+    static void writeBoundaryQsFile(SPtr<GridBuilder> builder);
+    static std::vector<std::vector<std::vector<real> > > createBCVectors(SPtr<Grid> grid);
+    static void addShortQsToVector(int index, std::vector<std::vector<std::vector<real> > > &qs, SPtr<Grid> grid);
+    static void addQsToVector(int index, std::vector<std::vector<std::vector<real> > > &qs, SPtr<Grid> grid);
+    static void fillRBForNode(int index, int direction, int directionSign, int rb, std::vector<std::vector<std::vector<real> > > &qs, SPtr<Grid> grid);
+    static void writeBoundary(std::vector<real> boundary, int rb);
+	static void writeBoundaryShort(std::vector<real> boundary, int rb);
+	static void writeBoundaryShort(SPtr<Grid> grid, SPtr<gg::BoundaryCondition> boundaryCondition, uint side);
+
+    static void writeCommunicationFiles(SPtr<GridBuilder> builder);
+
+	static void closeFiles();
+
+
+    static std::ofstream xCoordFile;
+    static std::ofstream yCoordFile;
+    static std::ofstream zCoordFile;
+    static std::ofstream xNeighborFile;
+    static std::ofstream yNeighborFile;
+    static std::ofstream zNeighborFile;
+    static std::ofstream wsbNeighborFile;
+    static std::ofstream geoVecFile;
+
+    static std::ofstream scaleCF_coarse_File;
+    static std::ofstream scaleCF_fine_File;
+    static std::ofstream scaleFC_coarse_File;
+    static std::ofstream scaleFC_fine_File;
+
+    static std::ofstream offsetVecCF_File;
+    static std::ofstream offsetVecFC_File;
+
+    static std::vector<SPtr<std::ofstream> > qStreams;
+    static std::vector<SPtr<std::ofstream> > valueStreams;
+
+    static std::vector<std::ofstream> qFiles;
+    static std::vector<std::ofstream> valueFiles;
+
+    static std::array<std::ofstream, 6> sendFiles;
+    static std::array<std::ofstream, 6> receiveFiles;
+
+    static std::ofstream numberNodes_File;
+    static std::ofstream LBMvsSI_File;
+
+    static std::string folder;
+};
+
+
+#endif
diff --git a/src/gpu/GridGenerator/utilities/communication.h b/src/gpu/GridGenerator/utilities/communication.h
new file mode 100644
index 0000000000000000000000000000000000000000..11a1085f6a21db1dfb26025514d8b3a9501fba5e
--- /dev/null
+++ b/src/gpu/GridGenerator/utilities/communication.h
@@ -0,0 +1,47 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file Communication.h
+//! \ingroup utilities
+//! \author Soeren Peters, Stephan Lenz
+//=======================================================================================
+#ifndef Communication_H
+#define Communication_H
+
+namespace CommunicationDirections {
+    enum {
+        MX = 0,
+        PX = 1,
+        MY = 2,
+        PY = 3,
+        MZ = 4,
+        PZ = 5
+    };
+}
+
+#endif // Communication_H
\ No newline at end of file
diff --git a/src/gpu/GridGenerator/utilities/math/Math.cu b/src/gpu/GridGenerator/utilities/math/Math.cpp
similarity index 99%
rename from src/gpu/GridGenerator/utilities/math/Math.cu
rename to src/gpu/GridGenerator/utilities/math/Math.cpp
index 404ecaf33d5dd21e0b789468b6d0e9858c3bc640..0f5f5cc8e05c9ce08a2854c0354371e18964610e 100644
--- a/src/gpu/GridGenerator/utilities/math/Math.cu
+++ b/src/gpu/GridGenerator/utilities/math/Math.cpp
@@ -26,7 +26,7 @@
 //  You should have received a copy of the GNU General Public License along
 //  with VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
 //
-//! \file Math.cu
+//! \file Math.cpp
 //! \ingroup utilities
 //! \author Soeren Peters, Stephan Lenz
 //=======================================================================================
diff --git a/src/gpu/GridGenerator/utilities/transformator/ArrowTransformator.cpp b/src/gpu/GridGenerator/utilities/transformator/ArrowTransformator.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..74a33c31b4b87edd736e9beea783075906772829
--- /dev/null
+++ b/src/gpu/GridGenerator/utilities/transformator/ArrowTransformator.cpp
@@ -0,0 +1,40 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file ArrowTransformator.h
+//! \ingroup utilities
+//! \author Soeren Peters, Stephan Lenz
+//=======================================================================================
+#include "ArrowTransformator.h"
+
+#include "utilities/transformator/TransformatorImp.h"
+
+std::shared_ptr<ArrowTransformator> ArrowTransformator::makeTransformator(real delta, real dx, real dy, real dz)
+{
+    return std::shared_ptr<ArrowTransformator>(new TransformatorImp(delta, dx, dy, dz));
+}
diff --git a/src/gpu/GridGenerator/utilities/transformator/ArrowTransformator.h b/src/gpu/GridGenerator/utilities/transformator/ArrowTransformator.h
new file mode 100644
index 0000000000000000000000000000000000000000..ad80114945c9e9be4cc38afa46c493edc1c55b66
--- /dev/null
+++ b/src/gpu/GridGenerator/utilities/transformator/ArrowTransformator.h
@@ -0,0 +1,56 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file ArrowTransformator.h
+//! \ingroup utilities
+//! \author Soeren Peters, Stephan Lenz
+//=======================================================================================
+#ifndef ArrowTransformator_h
+#define ArrowTransformator_h
+
+#include <memory>
+
+#include "global.h"
+
+class Arrow;
+
+class ArrowTransformator
+{
+public:
+    static GRIDGENERATOR_EXPORT std::shared_ptr<ArrowTransformator> makeTransformator(real delta, real dx, real dy, real dz);
+	virtual ~ArrowTransformator() {}
+
+protected:
+	ArrowTransformator() {}
+	
+public:
+	virtual void transformGridToWorld(std::shared_ptr<Arrow> arrow) const = 0;
+};
+
+
+#endif
diff --git a/src/gpu/GridGenerator/utilities/transformator/Transformator.cpp b/src/gpu/GridGenerator/utilities/transformator/Transformator.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7e854c4baa21bb6d59834b2e099c5857389fd50c
--- /dev/null
+++ b/src/gpu/GridGenerator/utilities/transformator/Transformator.cpp
@@ -0,0 +1,40 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file Transformator.cpp
+//! \ingroup utilities
+//! \author Soeren Peters, Stephan Lenz
+//=======================================================================================
+#include "Transformator.h"
+
+#include "utilities/transformator/TransformatorImp.h"
+
+std::shared_ptr<Transformator> Transformator::makeTransformator(real delta, real dx, real dy, real dz)
+{
+    return std::shared_ptr<Transformator>(new TransformatorImp(delta, dx, dy, dz));
+}
\ No newline at end of file
diff --git a/src/gpu/GridGenerator/grid/GridStrategy/GridCpuStrategy/GridCpuStrategy.h b/src/gpu/GridGenerator/utilities/transformator/Transformator.h
similarity index 58%
rename from src/gpu/GridGenerator/grid/GridStrategy/GridCpuStrategy/GridCpuStrategy.h
rename to src/gpu/GridGenerator/utilities/transformator/Transformator.h
index 2b3d5a8d939924c198c53b8625622b1bd6e96dff..9510e818f3467bc4346fc9e8ece58a83c139e11d 100644
--- a/src/gpu/GridGenerator/grid/GridStrategy/GridCpuStrategy/GridCpuStrategy.h
+++ b/src/gpu/GridGenerator/utilities/transformator/Transformator.h
@@ -1,69 +1,69 @@
 //=======================================================================================
-// ____          ____    __    ______     __________   __      __       __        __         
-// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |        
-//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |        
-//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |        
-//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____    
-//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|   
-//      \    \  |    |   ________________________________________________________________    
-//       \    \ |    |  |  ______________________________________________________________|   
-//        \    \|    |  |  |         __          __     __     __     ______      _______    
-//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)   
-//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______    
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
 //           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
-//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/   
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
 //
-//  This file is part of VirtualFluids. VirtualFluids is free software: you can 
+//  This file is part of VirtualFluids. VirtualFluids 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 
+//  License as published by the Free Software Foundation, either version 3 of
 //  the License, or (at your option) any later version.
-//  
-//  VirtualFluids 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 
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
 //
-//! \file GridCpuStrategy.h
-//! \ingroup grid
+//! \file Transformator.h
+//! \ingroup utilities
 //! \author Soeren Peters, Stephan Lenz
 //=======================================================================================
-#ifndef GRID_CPU_STRATEGY_H
-#define GRID_CPU_STRATEGY_H
+#ifndef Transformator_h
+#define Transformator_h
 
-#include "global.h"
+#include <memory>
 
-#include "grid/GridStrategy/GridStrategy.h"
+#include "global.h"
 
-class GridImp;
+class BoundingBox;
+struct Triangle;
 class TriangularMesh;
+struct Vertex;
 
-class GRIDGENERATOR_EXPORT GridCpuStrategy : public GridStrategy
+
+class Transformator
 {
 public:
-    virtual ~GridCpuStrategy() {};
-
-    void allocateGridMemory(SPtr<GridImp> grid) override;
-
-    void initalNodesToOutOfGrid(SPtr<GridImp> grid) override;
-    void findInnerNodes(SPtr<GridImp> grid) override;
-	void findEndOfGridStopperNodes(SPtr<GridImp> grid) override;
-
-    void freeMemory(SPtr<GridImp> grid) override;
-
-
-
-    virtual void copyDataFromGPU() {};
+    static GRIDGENERATOR_EXPORT std::shared_ptr<Transformator> makeTransformator(real delta, real dx, real dy, real dz);
+	virtual ~Transformator() {}
 
 protected:
-    static void findForNeighborsNewIndices(SPtr<GridImp> grid);
+	Transformator(){}
+
 public:
-    void allocateFieldMemory(Field* field) override;
-    void freeFieldMemory(Field* field) override;
-    void findSparseIndices(SPtr<GridImp> coarseGrid, SPtr<GridImp> fineGrid) override;
+	virtual void transformWorldToGrid(Triangle &value) const = 0;
+	virtual void transformWorldToGrid(TriangularMesh &geom) const = 0;
+	virtual void transformWorldToGrid(Vertex &value) const = 0;
+
+    virtual void transformGridToWorld(Triangle &t) const = 0;
+	virtual void transformGridToWorld(Vertex &value) const = 0;
+	
+	virtual void transformGridToWorld(BoundingBox &box) const = 0;
+	virtual void transformWorldToGrid(BoundingBox &box) const = 0;
 
 };
 
-#endif
\ No newline at end of file
+
+#endif
diff --git a/src/gpu/GridGenerator/utilities/transformator/TransformatorImp.cpp b/src/gpu/GridGenerator/utilities/transformator/TransformatorImp.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3c7a3b675104eabab89c59d481797ff41b2033c8
--- /dev/null
+++ b/src/gpu/GridGenerator/utilities/transformator/TransformatorImp.cpp
@@ -0,0 +1,190 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file TransformatorImp.cpp
+//! \ingroup utilities
+//! \author Soeren Peters, Stephan Lenz
+//=======================================================================================
+#include "TransformatorImp.h"
+
+#include <memory>
+
+#include "geometries/BoundingBox/BoundingBox.h"
+#include "geometries/Triangle/Triangle.h"
+#include "geometries/TriangularMesh/TriangularMesh.h"
+#include "geometries/Vertex/Vertex.h"
+#include "geometries/Arrow/Arrow.h"
+
+TransformatorImp::TransformatorImp() 
+{
+	this->translater = std::shared_ptr<Vertex>(new Vertex());
+	this->delta = 1.0;
+	this->translater->x = 0;
+	this->translater->y = 0;
+	this->translater->z = 0;
+}
+
+TransformatorImp::TransformatorImp(real delta, const Vertex& translater) : delta(delta), translater(std::make_shared<Vertex>(translater))
+{
+	this->verifyDelta(delta);
+}
+
+TransformatorImp::TransformatorImp(real delta, real dx, real dy, real dz) : TransformatorImp(delta, Vertex(dx,dy,dz))
+{
+
+}
+
+TransformatorImp::TransformatorImp(const TransformatorImp& trafo)
+{
+	this->delta = trafo.delta;
+	this->translater = std::shared_ptr<Vertex>(new Vertex(*trafo.translater.get()));
+}
+
+TransformatorImp::~TransformatorImp()
+{
+
+}
+
+void TransformatorImp::transformWorldToGrid(TriangularMesh &geom) const
+{
+	for (int i = 0; i < geom.size; i++)
+		transformWorldToGrid(geom.triangleVec[i]);
+}
+
+void TransformatorImp::transformWorldToGrid(Triangle &value) const
+{
+	transformWorldToGrid(value.v1);
+	transformWorldToGrid(value.v2);
+	transformWorldToGrid(value.v3);
+}
+
+void TransformatorImp::transformGridToWorld(std::shared_ptr<Arrow> arrow) const
+{
+	transformGridToWorld(*arrow->getStart());
+	transformGridToWorld(*arrow->getEnd());
+}
+
+void TransformatorImp::transformWorldToGrid(Vertex &v) const
+{
+	translateWorldToView(v);
+	scaleWorldToView(v);
+}
+
+
+void TransformatorImp::translateWorldToView(Vertex& v) const
+{
+	v = *translater.get() + v;
+}
+
+void TransformatorImp::scaleWorldToView(Vertex& v) const
+{
+	v = v * (1.0f / this->delta);
+}
+
+
+void TransformatorImp::transformGridToWorld(Triangle & t) const
+{
+    transformGridToWorld(t.v1);
+    transformGridToWorld(t.v2);
+    transformGridToWorld(t.v3);
+}
+
+void TransformatorImp::transformGridToWorld(Vertex &value) const
+{
+	scaleGridToWorld(value);
+	translateGridToWorld(value);
+}
+
+void TransformatorImp::scaleGridToWorld(Vertex & value) const
+{
+	value = value * this->delta;
+}
+
+
+void TransformatorImp::translateGridToWorld(Vertex & value) const
+{
+	value = value - *translater.get();
+}
+
+
+void TransformatorImp::transformGridToWorld(BoundingBox &box) const
+{
+	//scale
+	box.minX = (box.minX * this->delta);
+	box.minY = (box.minY * this->delta);
+	box.minZ = (box.minZ * this->delta);
+
+	box.maxX = (box.maxX * this->delta);
+	box.maxY = (box.maxY * this->delta);
+	box.maxZ = (box.maxZ * this->delta);
+
+	//translate
+	box.minX = (box.minX - this->translater->x);
+	box.minY = (box.minY - this->translater->y);
+	box.minZ = (box.minZ - this->translater->z);
+
+	box.maxX = (box.maxX - this->translater->x);
+	box.maxY = (box.maxY - this->translater->y);
+	box.maxZ = (box.maxZ - this->translater->z);
+}
+
+void TransformatorImp::transformWorldToGrid(BoundingBox &box) const
+{
+	//translate
+	box.minX += this->translater->x;
+	box.minY += this->translater->y;
+	box.minZ += this->translater->z;
+
+	box.maxX += this->translater->x;
+	box.maxY += this->translater->y;
+	box.maxZ += this->translater->z;
+
+	//scale
+	box.minX *= (1.0f / this->delta);
+	box.minY *= (1.0f / this->delta);
+	box.minZ *= (1.0f / this->delta);
+
+	box.maxX *= (1.0f / this->delta);
+	box.maxY *= (1.0f / this->delta);
+	box.maxZ *= (1.0f / this->delta);
+}
+
+
+void TransformatorImp::verifyDelta(real delta) const
+{
+	if (delta <= 0.0)
+		throw invalidDelta();
+}
+
+bool TransformatorImp::operator==(const TransformatorImp& trafo) const
+{
+	return (this->delta == trafo.delta
+		&& this->translater->x == trafo.translater->x
+		&& this->translater->y == trafo.translater->y
+		&& this->translater->z == trafo.translater->z);
+}
diff --git a/src/gpu/GridGenerator/utilities/transformator/TransformatorImp.h b/src/gpu/GridGenerator/utilities/transformator/TransformatorImp.h
new file mode 100644
index 0000000000000000000000000000000000000000..81ba5a25badc879aa501256ed67eed0a4b39961c
--- /dev/null
+++ b/src/gpu/GridGenerator/utilities/transformator/TransformatorImp.h
@@ -0,0 +1,103 @@
+//=======================================================================================
+// ____          ____    __    ______     __________   __      __       __        __
+// \    \       |    |  |  |  |   _   \  |___    ___| |  |    |  |     /  \      |  |
+//  \    \      |    |  |  |  |  |_)   |     |  |     |  |    |  |    /    \     |  |
+//   \    \     |    |  |  |  |   _   /      |  |     |  |    |  |   /  /\  \    |  |
+//    \    \    |    |  |  |  |  | \  \      |  |     |   \__/   |  /  ____  \   |  |____
+//     \    \   |    |  |__|  |__|  \__\     |__|      \________/  /__/    \__\  |_______|
+//      \    \  |    |   ________________________________________________________________
+//       \    \ |    |  |  ______________________________________________________________|
+//        \    \|    |  |  |         __          __     __     __     ______      _______
+//         \         |  |  |_____   |  |        |  |   |  |   |  |   |   _  \    /  _____)
+//          \        |  |   _____|  |  |        |  |   |  |   |  |   |  | \  \   \_______
+//           \       |  |  |        |  |_____   |   \_/   |   |  |   |  |_/  /    _____  |
+//            \ _____|  |__|        |________|   \_______/    |__|   |______/    (_______/
+//
+//  This file is part of VirtualFluids. VirtualFluids 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.
+//
+//  VirtualFluids 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 VirtualFluids (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file TransformatorImp.h
+//! \ingroup utilities
+//! \author Soeren Peters, Stephan Lenz
+//=======================================================================================
+#ifndef TransformatorImp_h
+#define TransformatorImp_h
+
+#include <exception>
+#include <sstream>
+
+#include "global.h"
+#include "GridGenerator_export.h"
+
+#include "utilities/transformator/Transformator.h"
+#include "utilities/transformator/ArrowTransformator.h"
+
+class BoundingBox;
+struct Triangle;
+class TriangularMesh;
+struct Vertex;
+
+class invalidDelta : public std::exception
+{
+    public:
+    invalidDelta() : error_message ("Delta cant be < Null. To enable no changes change delta to 1.0.")
+    {}
+
+	const char* what() const noexcept
+    {
+	    return error_message.c_str();
+	}
+
+    private:
+    std::string error_message;
+};
+
+class TransformatorImp
+	: public Transformator, public ArrowTransformator
+{
+public:
+	GRIDGENERATOR_EXPORT TransformatorImp();
+	GRIDGENERATOR_EXPORT TransformatorImp(const TransformatorImp& trafo);
+	GRIDGENERATOR_EXPORT TransformatorImp(real delta, const Vertex& translater);
+	GRIDGENERATOR_EXPORT TransformatorImp(real delta, real dx, real dy, real dz);
+	GRIDGENERATOR_EXPORT virtual ~TransformatorImp();
+	
+	GRIDGENERATOR_EXPORT void transformWorldToGrid(Triangle &value) const override;
+	GRIDGENERATOR_EXPORT void transformWorldToGrid(TriangularMesh &geom) const override;
+	GRIDGENERATOR_EXPORT void transformWorldToGrid(Vertex &value) const override;
+
+    GRIDGENERATOR_EXPORT void transformGridToWorld(Triangle &t) const override;
+	GRIDGENERATOR_EXPORT void transformGridToWorld(Vertex &value) const override;
+
+	GRIDGENERATOR_EXPORT void transformGridToWorld(BoundingBox &box) const override;
+	GRIDGENERATOR_EXPORT void transformWorldToGrid(BoundingBox &box) const override;
+
+	GRIDGENERATOR_EXPORT bool operator==(const TransformatorImp& trafo) const;
+
+	GRIDGENERATOR_EXPORT virtual void transformGridToWorld(std::shared_ptr<Arrow> arrow) const override;
+
+private:
+	real delta;
+	std::shared_ptr<Vertex> translater;
+
+	void scaleWorldToView(Vertex & v) const;
+	void translateWorldToView(Vertex & v) const;
+
+	void translateGridToWorld(Vertex & value) const;
+	void scaleGridToWorld(Vertex & value) const;
+
+	void verifyDelta(real delta) const;
+};
+
+
+#endif