From ee2d8c9ef8b2991af06b0b051ed66e47ee2d6eb2 Mon Sep 17 00:00:00 2001
From: Martin Schoenherr <m.schoenherr@tu-braunschweig.de>
Date: Mon, 26 Jul 2021 13:59:32 +0200
Subject: [PATCH] the complete grid generator is now included

---
 .../LidDrivenCavityGPU/LidDrivenCavity.cpp    |    2 +-
 src/basics/basics/container/CbVectorPool.h    |  474 ++++++
 src/basics/basics/memory/MbSmartPtr.h         |  108 ++
 src/basics/basics/memory/MbSmartPtrBase.cpp   |   43 +
 src/basics/basics/memory/MbSmartPtrBase.h     |   56 +
 src/basics/basics/parallel/PbMpi.h            |  477 ++++++
 src/basics/basics/transmitter/TbTransmitter.h |   68 +
 .../basics/transmitter/TbTransmitterLocal.h   |  122 ++
 .../basics/transmitter/TbTransmitterMpiPool.h |  548 ++++++
 src/basics/basics/utilities/UbFileInput.h     |   96 ++
 .../basics/utilities/UbFileInputASCII.cpp     |  248 +++
 .../basics/utilities/UbFileInputASCII.h       |   75 +
 .../basics/utilities/UbFileInputBinary.cpp    |  150 ++
 .../basics/utilities/UbFileInputBinary.h      |   78 +
 src/basics/basics/utilities/UbFileOutput.h    |   95 ++
 .../basics/utilities/UbFileOutputASCII.cpp    |  171 ++
 .../basics/utilities/UbFileOutputASCII.h      |   73 +
 .../basics/utilities/UbFileOutputBinary.cpp   |  176 ++
 .../basics/utilities/UbFileOutputBinary.h     |   76 +
 src/basics/basics/utilities/UbNupsTimer.h     |   93 +
 src/basics/basics/utilities/UbRandom.h        |   60 +
 .../basics/utilities/UbStringInputASCII.cpp   |  212 +++
 .../basics/utilities/UbStringInputASCII.h     |   55 +
 src/basics/basics/utilities/Vector3DTest.cpp  |  157 ++
 src/basics/basics/writer/WbWriterAvsASCII.cpp | 1126 +++++++++++++
 src/basics/basics/writer/WbWriterAvsASCII.h   |   92 +
 .../basics/writer/WbWriterAvsBinary.cpp       | 1222 ++++++++++++++
 src/basics/basics/writer/WbWriterAvsBinary.h  |   90 +
 src/basics/basics/writer/WbWriterBOBJ.cpp     |   81 +
 src/basics/basics/writer/WbWriterBOBJ.h       |   47 +
 src/basics/basics/writer/WbWriterSunflow.cpp  |  115 ++
 src/basics/basics/writer/WbWriterSunflow.h    |   40 +
 .../basics/writer/WbWriterTecPlotASCII.cpp    |   64 +
 .../basics/writer/WbWriterTecPlotASCII.h      |  107 ++
 src/basics/basics/writer/WbWriterVtkASCII.cpp |  667 ++++++++
 src/basics/basics/writer/WbWriterVtkASCII.h   |   91 +
 .../basics/writer/WbWriterVtkBinary.cpp       |  818 +++++++++
 src/basics/basics/writer/WbWriterVtkBinary.h  |   90 +
 src/basics/basics/writer/WbWriterX3D.cpp      |  159 ++
 src/basics/basics/writer/WbWriterX3D.h        |   40 +
 src/basics/geometry3d/GbCylinder3D.cpp        | 1312 +++++++++++++++
 src/basics/geometry3d/GbCylinder3D.h          |  130 ++
 src/basics/geometry3d/GbHalfSpace3D.cpp       |   99 ++
 src/basics/geometry3d/GbHalfSpace3D.h         |   82 +
 .../geometry3d/GbHalfSpaceKrischan3D.cpp      |  271 +++
 src/basics/geometry3d/GbHalfSpaceKrischan3D.h |  200 +++
 src/basics/geometry3d/GbMeshTools3D.h         |  464 +++++
 src/basics/geometry3d/GbObjectGroup3D.cpp     |  116 ++
 src/basics/geometry3d/GbObjectGroup3D.h       |  137 ++
 src/basics/geometry3d/GbQuadFaceMesh3D.cpp    |  310 ++++
 src/basics/geometry3d/GbQuadFaceMesh3D.h      |  124 ++
 src/basics/geometry3d/GbSphere3D.cpp          |  925 ++++++++++
 src/basics/geometry3d/GbSphere3D.h            |  146 ++
 src/basics/geometry3d/GbTriFaceMesh3D.cpp     | 1138 +++++++++++++
 src/basics/geometry3d/GbTriFaceMesh3D.h       |  410 +++++
 src/basics/geometry3d/GbTriangularMesh3D.cpp  | 1499 +++++++++++++++++
 src/basics/geometry3d/GbTriangularMesh3D.h    |  173 ++
 src/basics/geometry3d/GbVoxelMatrix3D.cpp     |  964 +++++++++++
 src/basics/geometry3d/GbVoxelMatrix3D.h       |  324 ++++
 src/basics/geometry3d/KdTree/KdNode.h         |  283 ++++
 src/basics/geometry3d/KdTree/KdRay.h          |   73 +
 .../geometry3d/KdTree/KdSplitCandidate.h      |   43 +
 .../KdTree/KdSplitCandidateManager.h          |   68 +
 src/basics/geometry3d/KdTree/KdTree.h         |  103 ++
 src/basics/geometry3d/KdTree/KdUtilities.cpp  |   13 +
 src/basics/geometry3d/KdTree/KdUtilities.h    |  164 ++
 .../KdCountLineIntersectionHandler.h          |   53 +
 .../KdCountRayIntersectionHandler.h           |  159 ++
 .../KdLineIntersectionHandler.h               |   31 +
 .../KdRayIntersectionHandler.h                |   21 +
 .../KdTree/splitalgorithms/KdSAHSplit.cpp     |    7 +
 .../KdTree/splitalgorithms/KdSAHSplit.h       |  255 +++
 .../splitalgorithms/KdSpatiallMedianSplit.h   |   83 +
 .../KdTree/splitalgorithms/KdSplitAlgorithm.h |   27 +
 .../BoundaryConditions/BoundaryCondition.cpp  |    2 +
 src/gpu/GksMeshAdapter/GksMeshAdapter.cpp     |    2 +
 src/gpu/GksMeshAdapter/MeshCell.cpp           |    2 +
 .../StreetPointFinder/JunctionReader.cpp      |  113 ++
 .../StreetPointFinder/JunctionReader.h        |   46 +
 .../StreetPointFinder/SinkReader.cpp          |   43 +
 .../StreetPointFinder/SinkReader.h            |   33 +
 .../StreetPointFinder/SourceReader.cpp        |   46 +
 .../StreetPointFinder/SourceReader.h          |   31 +
 .../StreetPointFinder/StreetPointFinder.cpp   |  758 +++++++++
 .../StreetPointFinder/StreetPointFinder.h     |   88 +
 .../GridGenerator/geometries/Arrow/Arrow.h    |   23 +
 .../geometries/Arrow/ArrowImp.cpp             |   37 +
 .../GridGenerator/geometries/Arrow/ArrowImp.h |   32 +
 .../geometries/BoundingBox/BoundingBox.cu     |   34 +
 .../geometries/BoundingBox/BoundingBox.h      |    7 +-
 .../geometries/Conglomerate/Conglomerate.cu   |  165 ++
 .../geometries/Conglomerate/Conglomerate.h    |   59 +
 src/gpu/GridGenerator/geometries/Object.cu    |    5 +
 src/gpu/GridGenerator/geometries/Object.h     |    3 +
 .../GridGenerator/geometries/Point/Point.cpp  |    0
 .../GridGenerator/geometries/Point/Point.h    |    0
 .../GridGenerator/geometries/Sphere/Sphere.cu |  140 ++
 .../GridGenerator/geometries/Sphere/Sphere.h  |   52 +
 .../geometries/Triangle/Triangle.cu           |  321 ++++
 .../geometries/Triangle/Triangle.h            |   63 +
 .../geometries/Triangle/TriangleException.h   |   69 +
 .../TriangularMesh/TriangularMesh.cu          |  258 +++
 .../TriangularMesh/TriangularMesh.h           |   83 +
 .../TriangularMesh/TriangularMeshStrategy.cpp |  278 +++
 .../TriangularMesh/TriangularMeshStrategy.h   |   69 +
 .../TriangleNeighborFinder.cpp                |  324 ++++
 .../TriangleNeighborFinder.h                  |   56 +
 .../triangleRefinement/TriangleRefinement.cpp |  217 +++
 .../triangleRefinement/TriangleRefinement.h   |   47 +
 .../VerticalCylinder/VerticalCylinder.cu      |   90 +
 .../VerticalCylinder/VerticalCylinder.h       |   50 +
 .../BoundaryConditions/BoundaryCondition.h    |    8 +-
 .../grid/BoundaryConditions/Side.cpp          |   16 +-
 src/gpu/GridGenerator/grid/Field.cu           |    7 +
 src/gpu/GridGenerator/grid/Field.h            |    1 +
 src/gpu/GridGenerator/grid/Grid.h             |   65 +-
 .../grid/GridBuilder/GridBuilder.h            |   24 +-
 .../grid/GridBuilder/LevelGridBuilder.cpp     |  249 ++-
 .../grid/GridBuilder/LevelGridBuilder.h       |   46 +
 .../grid/GridBuilder/MultipleGridBuilder.cpp  |  500 +++++-
 .../grid/GridBuilder/MultipleGridBuilder.h    |   30 +-
 src/gpu/GridGenerator/grid/GridFactory.cpp    |    4 +
 src/gpu/GridGenerator/grid/GridImp.cu         | 1015 ++++++++++-
 src/gpu/GridGenerator/grid/GridImp.h          |  157 +-
 src/gpu/GridGenerator/grid/GridInterface.cu   |  408 +++++
 src/gpu/GridGenerator/grid/GridInterface.h    |   54 +
 .../GridCpuStrategy/GridCpuStrategy.cpp       |  175 +-
 .../GridCpuStrategy/GridCpuStrategy.h         |   30 +-
 .../GridGpuStrategy/GridGpuStrategy.cpp       |  430 +++++
 .../GridGpuStrategy/GridGpuStrategy.h         |   76 +
 .../grid/GridStrategy/GridStrategy.h          |   30 +-
 src/gpu/GridGenerator/grid/NodeValues.h       |   86 +-
 .../GridGenerator/grid/distributions/D3Q13.h  |   70 +
 .../GridGenerator/grid/distributions/D3Q19.h  |  100 ++
 .../GridGenerator/grid/distributions/D3Q7.h   |   41 +
 .../grid/kernel/runGridKernelGPU.cu           |  220 +++
 .../grid/kernel/runGridKernelGPU.cuh          |   23 +
 .../grid/partition/Partition.cpp              |  653 +++++++
 .../GridGenerator/grid/partition/Partition.h  |   45 +
 .../io/GridVTKWriter/GridVTKWriter.cpp        |  475 ++++++
 .../io/GridVTKWriter/GridVTKWriter.h          |   49 +
 src/gpu/GridGenerator/io/QLineWriter.cpp      |  142 ++
 src/gpu/GridGenerator/io/QLineWriter.h        |   25 +
 .../io/STLReaderWriter/STLReader.cpp          |  354 ++++
 .../io/STLReaderWriter/STLReader.h            |   40 +
 .../io/STLReaderWriter/STLWriter.cpp          |   84 +
 .../io/STLReaderWriter/STLWriter.h            |   28 +
 .../SimulationFileNames.cpp                   |   45 +
 .../SimulationFileNames.h                     |   53 +
 .../SimulationFileWriter.cpp                  |  752 +++++++++
 .../SimulationFileWriter.h                    |   97 ++
 .../PolyDataWriterWrapper.cpp                 |   29 +
 .../VTKWriterWrapper/PolyDataWriterWrapper.h  |   26 +
 .../UnstructuredGridWrapper.cpp               |  137 ++
 .../UnstructuredGridWrapper.h                 |   53 +
 .../GridGenerator/utilities/communication.h   |   15 +
 .../utilities/cuda/CudaErrorCheck.cu          |   55 +
 .../utilities/cuda/LaunchParameter.cu         |   49 +
 .../utilities/cuda/LaunchParameter.cuh        |   29 +
 .../utilities/cuda/cudaDefines.h              |   66 +
 .../utilities/cuda/cudaKernelCall.h           |   33 +
 .../transformator/ArrowTransformator.cpp      |    8 +
 .../transformator/ArrowTransformator.h        |   24 +
 .../utilities/transformator/Transformator.cpp |    8 +
 .../utilities/transformator/Transformator.h   |   37 +
 .../transformator/TransformatorImp.cpp        |  158 ++
 .../transformator/TransformatorImp.h          |   71 +
 167 files changed, 29837 insertions(+), 83 deletions(-)
 create mode 100644 src/basics/basics/container/CbVectorPool.h
 create mode 100644 src/basics/basics/memory/MbSmartPtr.h
 create mode 100644 src/basics/basics/memory/MbSmartPtrBase.cpp
 create mode 100644 src/basics/basics/memory/MbSmartPtrBase.h
 create mode 100644 src/basics/basics/parallel/PbMpi.h
 create mode 100644 src/basics/basics/transmitter/TbTransmitter.h
 create mode 100644 src/basics/basics/transmitter/TbTransmitterLocal.h
 create mode 100644 src/basics/basics/transmitter/TbTransmitterMpiPool.h
 create mode 100644 src/basics/basics/utilities/UbFileInput.h
 create mode 100644 src/basics/basics/utilities/UbFileInputASCII.cpp
 create mode 100644 src/basics/basics/utilities/UbFileInputASCII.h
 create mode 100644 src/basics/basics/utilities/UbFileInputBinary.cpp
 create mode 100644 src/basics/basics/utilities/UbFileInputBinary.h
 create mode 100644 src/basics/basics/utilities/UbFileOutput.h
 create mode 100644 src/basics/basics/utilities/UbFileOutputASCII.cpp
 create mode 100644 src/basics/basics/utilities/UbFileOutputASCII.h
 create mode 100644 src/basics/basics/utilities/UbFileOutputBinary.cpp
 create mode 100644 src/basics/basics/utilities/UbFileOutputBinary.h
 create mode 100644 src/basics/basics/utilities/UbNupsTimer.h
 create mode 100644 src/basics/basics/utilities/UbRandom.h
 create mode 100644 src/basics/basics/utilities/UbStringInputASCII.cpp
 create mode 100644 src/basics/basics/utilities/UbStringInputASCII.h
 create mode 100644 src/basics/basics/utilities/Vector3DTest.cpp
 create mode 100644 src/basics/basics/writer/WbWriterAvsASCII.cpp
 create mode 100644 src/basics/basics/writer/WbWriterAvsASCII.h
 create mode 100644 src/basics/basics/writer/WbWriterAvsBinary.cpp
 create mode 100644 src/basics/basics/writer/WbWriterAvsBinary.h
 create mode 100644 src/basics/basics/writer/WbWriterBOBJ.cpp
 create mode 100644 src/basics/basics/writer/WbWriterBOBJ.h
 create mode 100644 src/basics/basics/writer/WbWriterSunflow.cpp
 create mode 100644 src/basics/basics/writer/WbWriterSunflow.h
 create mode 100644 src/basics/basics/writer/WbWriterTecPlotASCII.cpp
 create mode 100644 src/basics/basics/writer/WbWriterTecPlotASCII.h
 create mode 100644 src/basics/basics/writer/WbWriterVtkASCII.cpp
 create mode 100644 src/basics/basics/writer/WbWriterVtkASCII.h
 create mode 100644 src/basics/basics/writer/WbWriterVtkBinary.cpp
 create mode 100644 src/basics/basics/writer/WbWriterVtkBinary.h
 create mode 100644 src/basics/basics/writer/WbWriterX3D.cpp
 create mode 100644 src/basics/basics/writer/WbWriterX3D.h
 create mode 100644 src/basics/geometry3d/GbCylinder3D.cpp
 create mode 100644 src/basics/geometry3d/GbCylinder3D.h
 create mode 100644 src/basics/geometry3d/GbHalfSpace3D.cpp
 create mode 100644 src/basics/geometry3d/GbHalfSpace3D.h
 create mode 100644 src/basics/geometry3d/GbHalfSpaceKrischan3D.cpp
 create mode 100644 src/basics/geometry3d/GbHalfSpaceKrischan3D.h
 create mode 100644 src/basics/geometry3d/GbMeshTools3D.h
 create mode 100644 src/basics/geometry3d/GbObjectGroup3D.cpp
 create mode 100644 src/basics/geometry3d/GbObjectGroup3D.h
 create mode 100644 src/basics/geometry3d/GbQuadFaceMesh3D.cpp
 create mode 100644 src/basics/geometry3d/GbQuadFaceMesh3D.h
 create mode 100644 src/basics/geometry3d/GbSphere3D.cpp
 create mode 100644 src/basics/geometry3d/GbSphere3D.h
 create mode 100644 src/basics/geometry3d/GbTriFaceMesh3D.cpp
 create mode 100644 src/basics/geometry3d/GbTriFaceMesh3D.h
 create mode 100644 src/basics/geometry3d/GbTriangularMesh3D.cpp
 create mode 100644 src/basics/geometry3d/GbTriangularMesh3D.h
 create mode 100644 src/basics/geometry3d/GbVoxelMatrix3D.cpp
 create mode 100644 src/basics/geometry3d/GbVoxelMatrix3D.h
 create mode 100644 src/basics/geometry3d/KdTree/KdNode.h
 create mode 100644 src/basics/geometry3d/KdTree/KdRay.h
 create mode 100644 src/basics/geometry3d/KdTree/KdSplitCandidate.h
 create mode 100644 src/basics/geometry3d/KdTree/KdSplitCandidateManager.h
 create mode 100644 src/basics/geometry3d/KdTree/KdTree.h
 create mode 100644 src/basics/geometry3d/KdTree/KdUtilities.cpp
 create mode 100644 src/basics/geometry3d/KdTree/KdUtilities.h
 create mode 100644 src/basics/geometry3d/KdTree/intersectionhandler/KdCountLineIntersectionHandler.h
 create mode 100644 src/basics/geometry3d/KdTree/intersectionhandler/KdCountRayIntersectionHandler.h
 create mode 100644 src/basics/geometry3d/KdTree/intersectionhandler/KdLineIntersectionHandler.h
 create mode 100644 src/basics/geometry3d/KdTree/intersectionhandler/KdRayIntersectionHandler.h
 create mode 100644 src/basics/geometry3d/KdTree/splitalgorithms/KdSAHSplit.cpp
 create mode 100644 src/basics/geometry3d/KdTree/splitalgorithms/KdSAHSplit.h
 create mode 100644 src/basics/geometry3d/KdTree/splitalgorithms/KdSpatiallMedianSplit.h
 create mode 100644 src/basics/geometry3d/KdTree/splitalgorithms/KdSplitAlgorithm.h
 create mode 100644 src/gpu/GridGenerator/StreetPointFinder/JunctionReader.cpp
 create mode 100644 src/gpu/GridGenerator/StreetPointFinder/JunctionReader.h
 create mode 100644 src/gpu/GridGenerator/StreetPointFinder/SinkReader.cpp
 create mode 100644 src/gpu/GridGenerator/StreetPointFinder/SinkReader.h
 create mode 100644 src/gpu/GridGenerator/StreetPointFinder/SourceReader.cpp
 create mode 100644 src/gpu/GridGenerator/StreetPointFinder/SourceReader.h
 create mode 100644 src/gpu/GridGenerator/StreetPointFinder/StreetPointFinder.cpp
 create mode 100644 src/gpu/GridGenerator/StreetPointFinder/StreetPointFinder.h
 create mode 100644 src/gpu/GridGenerator/geometries/Arrow/Arrow.h
 create mode 100644 src/gpu/GridGenerator/geometries/Arrow/ArrowImp.cpp
 create mode 100644 src/gpu/GridGenerator/geometries/Arrow/ArrowImp.h
 create mode 100644 src/gpu/GridGenerator/geometries/Conglomerate/Conglomerate.cu
 create mode 100644 src/gpu/GridGenerator/geometries/Conglomerate/Conglomerate.h
 create mode 100644 src/gpu/GridGenerator/geometries/Point/Point.cpp
 create mode 100644 src/gpu/GridGenerator/geometries/Point/Point.h
 create mode 100644 src/gpu/GridGenerator/geometries/Sphere/Sphere.cu
 create mode 100644 src/gpu/GridGenerator/geometries/Sphere/Sphere.h
 create mode 100644 src/gpu/GridGenerator/geometries/Triangle/Triangle.cu
 create mode 100644 src/gpu/GridGenerator/geometries/Triangle/Triangle.h
 create mode 100644 src/gpu/GridGenerator/geometries/Triangle/TriangleException.h
 create mode 100644 src/gpu/GridGenerator/geometries/TriangularMesh/TriangularMesh.cu
 create mode 100644 src/gpu/GridGenerator/geometries/TriangularMesh/TriangularMesh.h
 create mode 100644 src/gpu/GridGenerator/geometries/TriangularMesh/TriangularMeshStrategy.cpp
 create mode 100644 src/gpu/GridGenerator/geometries/TriangularMesh/TriangularMeshStrategy.h
 create mode 100644 src/gpu/GridGenerator/geometries/TriangularMesh/triangleNeighborFinder/TriangleNeighborFinder.cpp
 create mode 100644 src/gpu/GridGenerator/geometries/TriangularMesh/triangleNeighborFinder/TriangleNeighborFinder.h
 create mode 100644 src/gpu/GridGenerator/geometries/TriangularMesh/triangleRefinement/TriangleRefinement.cpp
 create mode 100644 src/gpu/GridGenerator/geometries/TriangularMesh/triangleRefinement/TriangleRefinement.h
 create mode 100644 src/gpu/GridGenerator/geometries/VerticalCylinder/VerticalCylinder.cu
 create mode 100644 src/gpu/GridGenerator/geometries/VerticalCylinder/VerticalCylinder.h
 create mode 100644 src/gpu/GridGenerator/grid/GridFactory.cpp
 create mode 100644 src/gpu/GridGenerator/grid/GridInterface.cu
 create mode 100644 src/gpu/GridGenerator/grid/GridInterface.h
 create mode 100644 src/gpu/GridGenerator/grid/GridStrategy/GridGpuStrategy/GridGpuStrategy.cpp
 create mode 100644 src/gpu/GridGenerator/grid/GridStrategy/GridGpuStrategy/GridGpuStrategy.h
 create mode 100644 src/gpu/GridGenerator/grid/distributions/D3Q13.h
 create mode 100644 src/gpu/GridGenerator/grid/distributions/D3Q19.h
 create mode 100644 src/gpu/GridGenerator/grid/distributions/D3Q7.h
 create mode 100644 src/gpu/GridGenerator/grid/kernel/runGridKernelGPU.cu
 create mode 100644 src/gpu/GridGenerator/grid/kernel/runGridKernelGPU.cuh
 create mode 100644 src/gpu/GridGenerator/grid/partition/Partition.cpp
 create mode 100644 src/gpu/GridGenerator/grid/partition/Partition.h
 create mode 100644 src/gpu/GridGenerator/io/GridVTKWriter/GridVTKWriter.cpp
 create mode 100644 src/gpu/GridGenerator/io/GridVTKWriter/GridVTKWriter.h
 create mode 100644 src/gpu/GridGenerator/io/QLineWriter.cpp
 create mode 100644 src/gpu/GridGenerator/io/QLineWriter.h
 create mode 100644 src/gpu/GridGenerator/io/STLReaderWriter/STLReader.cpp
 create mode 100644 src/gpu/GridGenerator/io/STLReaderWriter/STLReader.h
 create mode 100644 src/gpu/GridGenerator/io/STLReaderWriter/STLWriter.cpp
 create mode 100644 src/gpu/GridGenerator/io/STLReaderWriter/STLWriter.h
 create mode 100644 src/gpu/GridGenerator/io/SimulationFileWriter/SimulationFileNames.cpp
 create mode 100644 src/gpu/GridGenerator/io/SimulationFileWriter/SimulationFileNames.h
 create mode 100644 src/gpu/GridGenerator/io/SimulationFileWriter/SimulationFileWriter.cpp
 create mode 100644 src/gpu/GridGenerator/io/SimulationFileWriter/SimulationFileWriter.h
 create mode 100644 src/gpu/GridGenerator/io/VTKWriterWrapper/PolyDataWriterWrapper.cpp
 create mode 100644 src/gpu/GridGenerator/io/VTKWriterWrapper/PolyDataWriterWrapper.h
 create mode 100644 src/gpu/GridGenerator/io/VTKWriterWrapper/UnstructuredGridWrapper.cpp
 create mode 100644 src/gpu/GridGenerator/io/VTKWriterWrapper/UnstructuredGridWrapper.h
 create mode 100644 src/gpu/GridGenerator/utilities/communication.h
 create mode 100644 src/gpu/GridGenerator/utilities/cuda/CudaErrorCheck.cu
 create mode 100644 src/gpu/GridGenerator/utilities/cuda/LaunchParameter.cu
 create mode 100644 src/gpu/GridGenerator/utilities/cuda/LaunchParameter.cuh
 create mode 100644 src/gpu/GridGenerator/utilities/cuda/cudaDefines.h
 create mode 100644 src/gpu/GridGenerator/utilities/cuda/cudaKernelCall.h
 create mode 100644 src/gpu/GridGenerator/utilities/transformator/ArrowTransformator.cpp
 create mode 100644 src/gpu/GridGenerator/utilities/transformator/ArrowTransformator.h
 create mode 100644 src/gpu/GridGenerator/utilities/transformator/Transformator.cpp
 create mode 100644 src/gpu/GridGenerator/utilities/transformator/Transformator.h
 create mode 100644 src/gpu/GridGenerator/utilities/transformator/TransformatorImp.cpp
 create mode 100644 src/gpu/GridGenerator/utilities/transformator/TransformatorImp.h

diff --git a/apps/gpu/LidDrivenCavityGPU/LidDrivenCavity.cpp b/apps/gpu/LidDrivenCavityGPU/LidDrivenCavity.cpp
index 86b6f5f4a..29da31990 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;
diff --git a/src/basics/basics/container/CbVectorPool.h b/src/basics/basics/container/CbVectorPool.h
new file mode 100644
index 000000000..0272056b5
--- /dev/null
+++ b/src/basics/basics/container/CbVectorPool.h
@@ -0,0 +1,474 @@
+//  _    ___      __              __________      _     __
+// | |  / (_)____/ /___  ______ _/ / ____/ /_  __(_)___/ /____
+// | | / / / ___/ __/ / / / __ `/ / /_  / / / / / / __  / ___/
+// | |/ / / /  / /_/ /_/ / /_/ / / __/ / / /_/ / / /_/ (__  )
+// |___/_/_/   \__/\__,_/\__,_/_/_/   /_/\__,_/_/\__,_/____/
+//
+#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 000000000..1ddced8c0
--- /dev/null
+++ b/src/basics/basics/memory/MbSmartPtr.h
@@ -0,0 +1,108 @@
+//  _    ___      __              __________      _     __
+// | |  / (_)____/ /___  ______ _/ / ____/ /_  __(_)___/ /____
+// | | / / / ___/ __/ / / / __ `/ / /_  / / / / / / __  / ___/
+// | |/ / / /  / /_/ /_/ / /_/ / / __/ / / /_/ / / /_/ (__  )
+// |___/_/_/   \__/\__,_/\__,_/_/_/   /_/\__,_/_/\__,_/____/
+//
+#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 000000000..a0651b029
--- /dev/null
+++ b/src/basics/basics/memory/MbSmartPtrBase.cpp
@@ -0,0 +1,43 @@
+#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 000000000..1abdcac81
--- /dev/null
+++ b/src/basics/basics/memory/MbSmartPtrBase.h
@@ -0,0 +1,56 @@
+//  _    ___      __              __________      _     __
+// | |  / (_)____/ /___  ______ _/ / ____/ /_  __(_)___/ /____
+// | | / / / ___/ __/ / / / __ `/ / /_  / / / / / / __  / ___/
+// | |/ / / /  / /_/ /_/ / /_/ / / __/ / / /_/ / / /_/ (__  )
+// |___/_/_/   \__/\__,_/\__,_/_/_/   /_/\__,_/_/\__,_/____/
+//
+#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 000000000..857ff7b10
--- /dev/null
+++ b/src/basics/basics/parallel/PbMpi.h
@@ -0,0 +1,477 @@
+//  _    ___      __              __________      _     __
+// | |  / (_)____/ /___  ______ _/ / ____/ /_  __(_)___/ /____
+// | | / / / ___/ __/ / / / __ `/ / /_  / / / / / / __  / ___/
+// | |/ / / /  / /_/ /_/ / /_/ / / __/ / / /_/ / / /_/ (__  )
+// |___/_/_/   \__/\__,_/\__,_/_/_/   /_/\__,_/_/\__,_/____/
+//
+#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 000000000..4d5e5195d
--- /dev/null
+++ b/src/basics/basics/transmitter/TbTransmitter.h
@@ -0,0 +1,68 @@
+//  _    ___      __              __________      _     __
+// | |  / (_)____/ /___  ______ _/ / ____/ /_  __(_)___/ /____
+// | | / / / ___/ __/ / / / __ `/ / /_  / / / / / / __  / ___/
+// | |/ / / /  / /_/ /_/ / /_/ / / __/ / / /_/ / / /_/ (__  )
+// |___/_/_/   \__/\__,_/\__,_/_/_/   /_/\__,_/_/\__,_/____/
+//
+#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 000000000..f0a6c30df
--- /dev/null
+++ b/src/basics/basics/transmitter/TbTransmitterLocal.h
@@ -0,0 +1,122 @@
+//  _    ___      __              __________      _     __
+// | |  / (_)____/ /___  ______ _/ / ____/ /_  __(_)___/ /____
+// | | / / / ___/ __/ / / / __ `/ / /_  / / / / / / __  / ___/
+// | |/ / / /  / /_/ /_/ / /_/ / / __/ / / /_/ / / /_/ (__  )
+// |___/_/_/   \__/\__,_/\__,_/_/_/   /_/\__,_/_/\__,_/____/
+//
+#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 000000000..ff170e18e
--- /dev/null
+++ b/src/basics/basics/transmitter/TbTransmitterMpiPool.h
@@ -0,0 +1,548 @@
+//  _    ___      __              __________      _     __
+// | |  / (_)____/ /___  ______ _/ / ____/ /_  __(_)___/ /____
+// | | / / / ___/ __/ / / / __ `/ / /_  / / / / / / __  / ___/
+// | |/ / / /  / /_/ /_/ / /_/ / / __/ / / /_/ / / /_/ (__  )
+// |___/_/_/   \__/\__,_/\__,_/_/_/   /_/\__,_/_/\__,_/____/
+//
+#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 000000000..d3128830b
--- /dev/null
+++ b/src/basics/basics/utilities/UbFileInput.h
@@ -0,0 +1,96 @@
+//  _    ___      __              __________      _     __
+// | |  / (_)____/ /___  ______ _/ / ____/ /_  __(_)___/ /____
+// | | / / / ___/ __/ / / / __ `/ / /_  / / / / / / __  / ___/
+// | |/ / / /  / /_/ /_/ / /_/ / / __/ / / /_/ / / /_/ (__  )
+// |___/_/_/   \__/\__,_/\__,_/_/_/   /_/\__,_/_/\__,_/____/
+//
+#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 000000000..12ce32ab0
--- /dev/null
+++ b/src/basics/basics/utilities/UbFileInputASCII.cpp
@@ -0,0 +1,248 @@
+#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 [10.3.2004] at [9:46]
+// 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
+
+    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 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
+
+    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 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
+
+    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 static_cast<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 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 000000000..65cd28921
--- /dev/null
+++ b/src/basics/basics/utilities/UbFileInputASCII.h
@@ -0,0 +1,75 @@
+//  _    ___      __              __________      _     __
+// | |  / (_)____/ /___  ______ _/ / ____/ /_  __(_)___/ /____
+// | | / / / ___/ __/ / / / __ `/ / /_  / / / / / / __  / ___/
+// | |/ / / /  / /_/ /_/ / /_/ / / __/ / / /_/ / / /_/ (__  )
+// |___/_/_/   \__/\__,_/\__,_/_/_/   /_/\__,_/_/\__,_/____/
+//
+#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/UbFileInputBinary.cpp b/src/basics/basics/utilities/UbFileInputBinary.cpp
new file mode 100644
index 000000000..120b4ab86
--- /dev/null
+++ b/src/basics/basics/utilities/UbFileInputBinary.cpp
@@ -0,0 +1,150 @@
+#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 000000000..b1e40d396
--- /dev/null
+++ b/src/basics/basics/utilities/UbFileInputBinary.h
@@ -0,0 +1,78 @@
+//  _    ___      __              __________      _     __
+// | |  / (_)____/ /___  ______ _/ / ____/ /_  __(_)___/ /____
+// | | / / / ___/ __/ / / / __ `/ / /_  / / / / / / __  / ___/
+// | |/ / / /  / /_/ /_/ / /_/ / / __/ / / /_/ / / /_/ (__  )
+// |___/_/_/   \__/\__,_/\__,_/_/_/   /_/\__,_/_/\__,_/____/
+//
+#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 000000000..7e3e12d4c
--- /dev/null
+++ b/src/basics/basics/utilities/UbFileOutput.h
@@ -0,0 +1,95 @@
+//  _    ___      __              __________      _     __
+// | |  / (_)____/ /___  ______ _/ / ____/ /_  __(_)___/ /____
+// | | / / / ___/ __/ / / / __ `/ / /_  / / / / / / __  / ___/
+// | |/ / / /  / /_/ /_/ / /_/ / / __/ / / /_/ / / /_/ (__  )
+// |___/_/_/   \__/\__,_/\__,_/_/_/   /_/\__,_/_/\__,_/____/
+//
+#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 000000000..68bfc8b64
--- /dev/null
+++ b/src/basics/basics/utilities/UbFileOutputASCII.cpp
@@ -0,0 +1,171 @@
+#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 000000000..e6d763561
--- /dev/null
+++ b/src/basics/basics/utilities/UbFileOutputASCII.h
@@ -0,0 +1,73 @@
+//  _    ___      __              __________      _     __
+// | |  / (_)____/ /___  ______ _/ / ____/ /_  __(_)___/ /____
+// | | / / / ___/ __/ / / / __ `/ / /_  / / / / / / __  / ___/
+// | |/ / / /  / /_/ /_/ / /_/ / / __/ / / /_/ / / /_/ (__  )
+// |___/_/_/   \__/\__,_/\__,_/_/_/   /_/\__,_/_/\__,_/____/
+//
+#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 000000000..fa9ab7480
--- /dev/null
+++ b/src/basics/basics/utilities/UbFileOutputBinary.cpp
@@ -0,0 +1,176 @@
+#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 000000000..fb4799d17
--- /dev/null
+++ b/src/basics/basics/utilities/UbFileOutputBinary.h
@@ -0,0 +1,76 @@
+//  _    ___      __              __________      _     __
+// | |  / (_)____/ /___  ______ _/ / ____/ /_  __(_)___/ /____
+// | | / / / ___/ __/ / / / __ `/ / /_  / / / / / / __  / ___/
+// | |/ / / /  / /_/ /_/ / /_/ / / __/ / / /_/ / / /_/ (__  )
+// |___/_/_/   \__/\__,_/\__,_/_/_/   /_/\__,_/_/\__,_/____/
+//
+#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 000000000..ca576fa6c
--- /dev/null
+++ b/src/basics/basics/utilities/UbNupsTimer.h
@@ -0,0 +1,93 @@
+#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 000000000..aed28014b
--- /dev/null
+++ b/src/basics/basics/utilities/UbRandom.h
@@ -0,0 +1,60 @@
+//  _    ___      __              __________      _     __
+// | |  / (_)____/ /___  ______ _/ / ____/ /_  __(_)___/ /____
+// | | / / / ___/ __/ / / / __ `/ / /_  / / / / / / __  / ___/
+// | |/ / / /  / /_/ /_/ / /_/ / / __/ / / /_/ / / /_/ (__  )
+// |___/_/_/   \__/\__,_/\__,_/_/_/   /_/\__,_/_/\__,_/____/
+//
+#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 000000000..6a04f86ae
--- /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 000000000..d83adde4d
--- /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/Vector3DTest.cpp b/src/basics/basics/utilities/Vector3DTest.cpp
new file mode 100644
index 000000000..0aaf47456
--- /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 000000000..31b922c92
--- /dev/null
+++ b/src/basics/basics/writer/WbWriterAvsASCII.cpp
@@ -0,0 +1,1126 @@
+#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 000000000..493d8b1e0
--- /dev/null
+++ b/src/basics/basics/writer/WbWriterAvsASCII.h
@@ -0,0 +1,92 @@
+//  _    ___      __              __________      _     __
+// | |  / (_)____/ /___  ______ _/ / ____/ /_  __(_)___/ /____
+// | | / / / ___/ __/ / / / __ `/ / /_  / / / / / / __  / ___/
+// | |/ / / /  / /_/ /_/ / /_/ / / __/ / / /_/ / / /_/ (__  )
+// |___/_/_/   \__/\__,_/\__,_/_/_/   /_/\__,_/_/\__,_/____/
+//
+#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 000000000..e52b2232a
--- /dev/null
+++ b/src/basics/basics/writer/WbWriterAvsBinary.cpp
@@ -0,0 +1,1222 @@
+#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 000000000..42e50debd
--- /dev/null
+++ b/src/basics/basics/writer/WbWriterAvsBinary.h
@@ -0,0 +1,90 @@
+//  _    ___      __              __________      _     __
+// | |  / (_)____/ /___  ______ _/ / ____/ /_  __(_)___/ /____
+// | | / / / ___/ __/ / / / __ `/ / /_  / / / / / / __  / ___/
+// | |/ / / /  / /_/ /_/ / /_/ / / __/ / / /_/ / / /_/ (__  )
+// |___/_/_/   \__/\__,_/\__,_/_/_/   /_/\__,_/_/\__,_/____/
+//
+#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 000000000..4401f25b0
--- /dev/null
+++ b/src/basics/basics/writer/WbWriterBOBJ.cpp
@@ -0,0 +1,81 @@
+#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 000000000..f5872cc3a
--- /dev/null
+++ b/src/basics/basics/writer/WbWriterBOBJ.h
@@ -0,0 +1,47 @@
+#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 000000000..6c60fe9d0
--- /dev/null
+++ b/src/basics/basics/writer/WbWriterSunflow.cpp
@@ -0,0 +1,115 @@
+#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 000000000..328f9c310
--- /dev/null
+++ b/src/basics/basics/writer/WbWriterSunflow.h
@@ -0,0 +1,40 @@
+#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 000000000..895853eb2
--- /dev/null
+++ b/src/basics/basics/writer/WbWriterTecPlotASCII.cpp
@@ -0,0 +1,64 @@
+#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 000000000..8869b59de
--- /dev/null
+++ b/src/basics/basics/writer/WbWriterTecPlotASCII.h
@@ -0,0 +1,107 @@
+#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 000000000..754d6d006
--- /dev/null
+++ b/src/basics/basics/writer/WbWriterVtkASCII.cpp
@@ -0,0 +1,667 @@
+#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 000000000..cce49c5fd
--- /dev/null
+++ b/src/basics/basics/writer/WbWriterVtkASCII.h
@@ -0,0 +1,91 @@
+//  _    ___      __              __________      _     __
+// | |  / (_)____/ /___  ______ _/ / ____/ /_  __(_)___/ /____
+// | | / / / ___/ __/ / / / __ `/ / /_  / / / / / / __  / ___/
+// | |/ / / /  / /_/ /_/ / /_/ / / __/ / / /_/ / / /_/ (__  )
+// |___/_/_/   \__/\__,_/\__,_/_/_/   /_/\__,_/_/\__,_/____/
+//
+#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 000000000..2f0a203da
--- /dev/null
+++ b/src/basics/basics/writer/WbWriterVtkBinary.cpp
@@ -0,0 +1,818 @@
+#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 000000000..aa39a3daa
--- /dev/null
+++ b/src/basics/basics/writer/WbWriterVtkBinary.h
@@ -0,0 +1,90 @@
+//  _    ___      __              __________      _     __
+// | |  / (_)____/ /___  ______ _/ / ____/ /_  __(_)___/ /____
+// | | / / / ___/ __/ / / / __ `/ / /_  / / / / / / __  / ___/
+// | |/ / / /  / /_/ /_/ / /_/ / / __/ / / /_/ / / /_/ (__  )
+// |___/_/_/   \__/\__,_/\__,_/_/_/   /_/\__,_/_/\__,_/____/
+//
+#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 000000000..3a0432523
--- /dev/null
+++ b/src/basics/basics/writer/WbWriterX3D.cpp
@@ -0,0 +1,159 @@
+#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 000000000..86f0abfb5
--- /dev/null
+++ b/src/basics/basics/writer/WbWriterX3D.h
@@ -0,0 +1,40 @@
+#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/geometry3d/GbCylinder3D.cpp b/src/basics/geometry3d/GbCylinder3D.cpp
new file mode 100644
index 000000000..2b90ca0fa
--- /dev/null
+++ b/src/basics/geometry3d/GbCylinder3D.cpp
@@ -0,0 +1,1312 @@
+#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 000000000..3740f18b1
--- /dev/null
+++ b/src/basics/geometry3d/GbCylinder3D.h
@@ -0,0 +1,130 @@
+//  _    ___      __              __________      _     __
+// | |  / (_)____/ /___  ______ _/ / ____/ /_  __(_)___/ /____
+// | | / / / ___/ __/ / / / __ `/ / /_  / / / / / / __  / ___/
+// | |/ / / /  / /_/ /_/ / /_/ / / __/ / / /_/ / / /_/ (__  )
+// |___/_/_/   \__/\__,_/\__,_/_/_/   /_/\__,_/_/\__,_/____/
+//
+#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 000000000..8566d337d
--- /dev/null
+++ b/src/basics/geometry3d/GbHalfSpace3D.cpp
@@ -0,0 +1,99 @@
+#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 000000000..768a01c96
--- /dev/null
+++ b/src/basics/geometry3d/GbHalfSpace3D.h
@@ -0,0 +1,82 @@
+//  _    ___      __              __________      _     __
+// | |  / (_)____/ /___  ______ _/ / ____/ /_  __(_)___/ /____
+// | | / / / ___/ __/ / / / __ `/ / /_  / / / / / / __  / ___/
+// | |/ / / /  / /_/ /_/ / /_/ / / __/ / / /_/ / / /_/ (__  )
+// |___/_/_/   \__/\__,_/\__,_/_/_/   /_/\__,_/_/\__,_/____/
+//
+#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 000000000..903cffa95
--- /dev/null
+++ b/src/basics/geometry3d/GbHalfSpaceKrischan3D.cpp
@@ -0,0 +1,271 @@
+#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 000000000..df01e6c7b
--- /dev/null
+++ b/src/basics/geometry3d/GbHalfSpaceKrischan3D.h
@@ -0,0 +1,200 @@
+//  _    ___      __              __________      _     __
+// | |  / (_)____/ /___  ______ _/ / ____/ /_  __(_)___/ /____
+// | | / / / ___/ __/ / / / __ `/ / /_  / / / / / / __  / ___/
+// | |/ / / /  / /_/ /_/ / /_/ / / __/ / / /_/ / / /_/ (__  )
+// |___/_/_/   \__/\__,_/\__,_/_/_/   /_/\__,_/_/\__,_/____/
+//
+#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 000000000..5c260e9c6
--- /dev/null
+++ b/src/basics/geometry3d/GbMeshTools3D.h
@@ -0,0 +1,464 @@
+#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 000000000..4d7656918
--- /dev/null
+++ b/src/basics/geometry3d/GbObjectGroup3D.cpp
@@ -0,0 +1,116 @@
+#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 000000000..51413cbe9
--- /dev/null
+++ b/src/basics/geometry3d/GbObjectGroup3D.h
@@ -0,0 +1,137 @@
+//  _    ___      __              __________      _     __
+// | |  / (_)____/ /___  ______ _/ / ____/ /_  __(_)___/ /____
+// | | / / / ___/ __/ / / / __ `/ / /_  / / / / / / __  / ___/
+// | |/ / / /  / /_/ /_/ / /_/ / / __/ / / /_/ / / /_/ (__  )
+// |___/_/_/   \__/\__,_/\__,_/_/_/   /_/\__,_/_/\__,_/____/
+//
+#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 000000000..e525d710e
--- /dev/null
+++ b/src/basics/geometry3d/GbQuadFaceMesh3D.cpp
@@ -0,0 +1,310 @@
+#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 000000000..d4f1c1310
--- /dev/null
+++ b/src/basics/geometry3d/GbQuadFaceMesh3D.h
@@ -0,0 +1,124 @@
+//  _    ___      __              __________      _     __
+// | |  / (_)____/ /___  ______ _/ / ____/ /_  __(_)___/ /____
+// | | / / / ___/ __/ / / / __ `/ / /_  / / / / / / __  / ___/
+// | |/ / / /  / /_/ /_/ / /_/ / / __/ / / /_/ / / /_/ (__  )
+// |___/_/_/   \__/\__,_/\__,_/_/_/   /_/\__,_/_/\__,_/____/
+//
+#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 000000000..da8aba0cb
--- /dev/null
+++ b/src/basics/geometry3d/GbSphere3D.cpp
@@ -0,0 +1,925 @@
+#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 000000000..738a122a1
--- /dev/null
+++ b/src/basics/geometry3d/GbSphere3D.h
@@ -0,0 +1,146 @@
+//  _    ___      __              __________      _     __
+// | |  / (_)____/ /___  ______ _/ / ____/ /_  __(_)___/ /____
+// | | / / / ___/ __/ / / / __ `/ / /_  / / / / / / __  / ___/
+// | |/ / / /  / /_/ /_/ / /_/ / / __/ / / /_/ / / /_/ (__  )
+// |___/_/_/   \__/\__,_/\__,_/_/_/   /_/\__,_/_/\__,_/____/
+//
+#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 000000000..92442dd54
--- /dev/null
+++ b/src/basics/geometry3d/GbTriFaceMesh3D.cpp
@@ -0,0 +1,1138 @@
+
+#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;
+    fread(title, 80, 1, f);
+    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) {
+            fread((void *)&v[j], sizeof(float), 1, f);
+        }
+        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;
+    }
+    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 000000000..7a3654cb1
--- /dev/null
+++ b/src/basics/geometry3d/GbTriFaceMesh3D.h
@@ -0,0 +1,410 @@
+//  _    ___      __              __________      _     __
+// | |  / (_)____/ /___  ______ _/ / ____/ /_  __(_)___/ /____
+// | | / / / ___/ __/ / / / __ `/ / /_  / / / / / / __  / ___/
+// | |/ / / /  / /_/ /_/ / /_/ / / __/ / / /_/ / / /_/ (__  )
+// |___/_/_/   \__/\__,_/\__,_/_/_/   /_/\__,_/_/\__,_/____/
+//
+#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 000000000..94138be75
--- /dev/null
+++ b/src/basics/geometry3d/GbTriangularMesh3D.cpp
@@ -0,0 +1,1499 @@
+#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 000000000..46be833a2
--- /dev/null
+++ b/src/basics/geometry3d/GbTriangularMesh3D.h
@@ -0,0 +1,173 @@
+//  _    ___      __              __________      _     __
+// | |  / (_)____/ /___  ______ _/ / ____/ /_  __(_)___/ /____
+// | | / / / ___/ __/ / / / __ `/ / /_  / / / / / / __  / ___/
+// | |/ / / /  / /_/ /_/ / /_/ / / __/ / / /_/ / / /_/ (__  )
+// |___/_/_/   \__/\__,_/\__,_/_/_/   /_/\__,_/_/\__,_/____/
+//
+#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 000000000..d4a047323
--- /dev/null
+++ b/src/basics/geometry3d/GbVoxelMatrix3D.cpp
@@ -0,0 +1,964 @@
+#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 000000000..ba4b3b420
--- /dev/null
+++ b/src/basics/geometry3d/GbVoxelMatrix3D.h
@@ -0,0 +1,324 @@
+//  _    ___      __              __________      _     __
+// | |  / (_)____/ /___  ______ _/ / ____/ /_  __(_)___/ /____
+// | | / / / ___/ __/ / / / __ `/ / /_  / / / / / / __  / ___/
+// | |/ / / /  / /_/ /_/ / /_/ / / __/ / / /_/ / / /_/ (__  )
+// |___/_/_/   \__/\__,_/\__,_/_/_/   /_/\__,_/_/\__,_/____/
+//
+#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 000000000..eef1eb696
--- /dev/null
+++ b/src/basics/geometry3d/KdTree/KdNode.h
@@ -0,0 +1,283 @@
+#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 000000000..b37e30ce6
--- /dev/null
+++ b/src/basics/geometry3d/KdTree/KdRay.h
@@ -0,0 +1,73 @@
+#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 000000000..b937a1235
--- /dev/null
+++ b/src/basics/geometry3d/KdTree/KdSplitCandidate.h
@@ -0,0 +1,43 @@
+#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 000000000..cf32711b1
--- /dev/null
+++ b/src/basics/geometry3d/KdTree/KdSplitCandidateManager.h
@@ -0,0 +1,68 @@
+#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 000000000..42c337f66
--- /dev/null
+++ b/src/basics/geometry3d/KdTree/KdTree.h
@@ -0,0 +1,103 @@
+#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>(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 000000000..b2b56b091
--- /dev/null
+++ b/src/basics/geometry3d/KdTree/KdUtilities.cpp
@@ -0,0 +1,13 @@
+#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 000000000..bf02ee444
--- /dev/null
+++ b/src/basics/geometry3d/KdTree/KdUtilities.h
@@ -0,0 +1,164 @@
+#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 000000000..0e5a9eb02
--- /dev/null
+++ b/src/basics/geometry3d/KdTree/intersectionhandler/KdCountLineIntersectionHandler.h
@@ -0,0 +1,53 @@
+#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 000000000..2fab632ff
--- /dev/null
+++ b/src/basics/geometry3d/KdTree/intersectionhandler/KdCountRayIntersectionHandler.h
@@ -0,0 +1,159 @@
+#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 000000000..61d4800d2
--- /dev/null
+++ b/src/basics/geometry3d/KdTree/intersectionhandler/KdLineIntersectionHandler.h
@@ -0,0 +1,31 @@
+#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 000000000..2965b0b39
--- /dev/null
+++ b/src/basics/geometry3d/KdTree/intersectionhandler/KdRayIntersectionHandler.h
@@ -0,0 +1,21 @@
+#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 000000000..31cfa74d8
--- /dev/null
+++ b/src/basics/geometry3d/KdTree/splitalgorithms/KdSAHSplit.cpp
@@ -0,0 +1,7 @@
+//#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 000000000..c828f5f7f
--- /dev/null
+++ b/src/basics/geometry3d/KdTree/splitalgorithms/KdSAHSplit.h
@@ -0,0 +1,255 @@
+#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 000000000..518ac967a
--- /dev/null
+++ b/src/basics/geometry3d/KdTree/splitalgorithms/KdSpatiallMedianSplit.h
@@ -0,0 +1,83 @@
+#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 000000000..c767a0c0d
--- /dev/null
+++ b/src/basics/geometry3d/KdTree/splitalgorithms/KdSplitAlgorithm.h
@@ -0,0 +1,27 @@
+#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 781ba46d2..b9abb5013 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 fcff658b3..28a0b87d1 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 65a931c84..349d308ee 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/StreetPointFinder/JunctionReader.cpp b/src/gpu/GridGenerator/StreetPointFinder/JunctionReader.cpp
new file mode 100644
index 000000000..065d4ae64
--- /dev/null
+++ b/src/gpu/GridGenerator/StreetPointFinder/JunctionReader.cpp
@@ -0,0 +1,113 @@
+#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 000000000..dea2a6a91
--- /dev/null
+++ b/src/gpu/GridGenerator/StreetPointFinder/JunctionReader.h
@@ -0,0 +1,46 @@
+#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 000000000..3c3e76689
--- /dev/null
+++ b/src/gpu/GridGenerator/StreetPointFinder/SinkReader.cpp
@@ -0,0 +1,43 @@
+#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 000000000..115aea552
--- /dev/null
+++ b/src/gpu/GridGenerator/StreetPointFinder/SinkReader.h
@@ -0,0 +1,33 @@
+#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 000000000..e9cab0847
--- /dev/null
+++ b/src/gpu/GridGenerator/StreetPointFinder/SourceReader.cpp
@@ -0,0 +1,46 @@
+#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 000000000..db95259ea
--- /dev/null
+++ b/src/gpu/GridGenerator/StreetPointFinder/SourceReader.h
@@ -0,0 +1,31 @@
+#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 000000000..3a764dd35
--- /dev/null
+++ b/src/gpu/GridGenerator/StreetPointFinder/StreetPointFinder.cpp
@@ -0,0 +1,758 @@
+#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 000000000..73d1e0de0
--- /dev/null
+++ b/src/gpu/GridGenerator/StreetPointFinder/StreetPointFinder.h
@@ -0,0 +1,88 @@
+#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 000000000..dfd006042
--- /dev/null
+++ b/src/gpu/GridGenerator/geometries/Arrow/Arrow.h
@@ -0,0 +1,23 @@
+#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 000000000..28176b4f5
--- /dev/null
+++ b/src/gpu/GridGenerator/geometries/Arrow/ArrowImp.cpp
@@ -0,0 +1,37 @@
+#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/geometries/Arrow/ArrowImp.h b/src/gpu/GridGenerator/geometries/Arrow/ArrowImp.h
new file mode 100644
index 000000000..195223d91
--- /dev/null
+++ b/src/gpu/GridGenerator/geometries/Arrow/ArrowImp.h
@@ -0,0 +1,32 @@
+#ifndef ArrowImp_H
+#define ArrowImp_H
+
+#include <memory>
+
+#include "global.h"
+#include "GridGenerator_export.h"
+
+#include "Arrow.h"
+
+struct Vertex;
+
+class ArrowImp : public Arrow 
+{
+public:
+	GRIDGENERATOR_EXPORT virtual ~ArrowImp();
+	GRIDGENERATOR_EXPORT static std::shared_ptr<Arrow> make(const Vertex &start, const Vertex &end);
+
+	GRIDGENERATOR_EXPORT std::shared_ptr<Vertex> getStart() const;
+	GRIDGENERATOR_EXPORT std::shared_ptr<Vertex> getEnd() const;
+
+	GRIDGENERATOR_EXPORT void print() const;
+private:
+	ArrowImp(const Vertex &start, const Vertex &end);
+
+	std::shared_ptr<Vertex> start;
+	std::shared_ptr<Vertex> end;
+};
+
+
+
+#endif
diff --git a/src/gpu/GridGenerator/geometries/BoundingBox/BoundingBox.cu b/src/gpu/GridGenerator/geometries/BoundingBox/BoundingBox.cu
index 52295a150..a0e348ef8 100644
--- a/src/gpu/GridGenerator/geometries/BoundingBox/BoundingBox.cu
+++ b/src/gpu/GridGenerator/geometries/BoundingBox/BoundingBox.cu
@@ -32,6 +32,7 @@
 //=======================================================================================
 #include "BoundingBox.h"
 
+#include "../Triangle/Triangle.h"
 #include "../Vertex/Vertex.h"
 #include <GridGenerator/utilities/math/Math.h>
 
@@ -63,6 +64,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 161db459b..b4f2ab441 100644
--- a/src/gpu/GridGenerator/geometries/BoundingBox/BoundingBox.h
+++ b/src/gpu/GridGenerator/geometries/BoundingBox/BoundingBox.h
@@ -59,9 +59,12 @@ public:
 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.cu b/src/gpu/GridGenerator/geometries/Conglomerate/Conglomerate.cu
new file mode 100644
index 000000000..b87eba98c
--- /dev/null
+++ b/src/gpu/GridGenerator/geometries/Conglomerate/Conglomerate.cu
@@ -0,0 +1,165 @@
+#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 000000000..ab7369390
--- /dev/null
+++ b/src/gpu/GridGenerator/geometries/Conglomerate/Conglomerate.h
@@ -0,0 +1,59 @@
+//  _    ___      __              __________      _     __
+// | |  / (_)____/ /___  ______ _/ / ____/ /_  __(_)___/ /____
+// | | / / / ___/ __/ / / / __ `/ / /_  / / / / / / __  / ___/
+// | |/ / / /  / /_/ /_/ / /_/ / / __/ / / /_/ / / /_/ (__  )
+// |___/_/_/   \__/\__,_/\__,_/_/_/   /_/\__,_/_/\__,_/____/
+//
+#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/Object.cu b/src/gpu/GridGenerator/geometries/Object.cu
index 1b369d708..f34aa19aa 100644
--- a/src/gpu/GridGenerator/geometries/Object.cu
+++ b/src/gpu/GridGenerator/geometries/Object.cu
@@ -38,3 +38,8 @@ void Object::findInnerNodes(SPtr<GridImp> grid)
 {
     grid->getGridStrategy()->findInnerNodes( grid );
 }
+
+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 88f092536..b92cca799 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/Point/Point.cpp b/src/gpu/GridGenerator/geometries/Point/Point.cpp
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/gpu/GridGenerator/geometries/Point/Point.h b/src/gpu/GridGenerator/geometries/Point/Point.h
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/gpu/GridGenerator/geometries/Sphere/Sphere.cu b/src/gpu/GridGenerator/geometries/Sphere/Sphere.cu
new file mode 100644
index 000000000..18a15e380
--- /dev/null
+++ b/src/gpu/GridGenerator/geometries/Sphere/Sphere.cu
@@ -0,0 +1,140 @@
+#include "Sphere.h"
+
+#include <algorithm>    // std::min
+#include <float.h>
+
+#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 000000000..2e701efb3
--- /dev/null
+++ b/src/gpu/GridGenerator/geometries/Sphere/Sphere.h
@@ -0,0 +1,52 @@
+//  _    ___      __              __________      _     __
+// | |  / (_)____/ /___  ______ _/ / ____/ /_  __(_)___/ /____
+// | | / / / ___/ __/ / / / __ `/ / /_  / / / / / / __  / ___/
+// | |/ / / /  / /_/ /_/ / /_/ / / __/ / / /_/ / / /_/ (__  )
+// |___/_/_/   \__/\__,_/\__,_/_/_/   /_/\__,_/_/\__,_/____/
+//
+#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.cu b/src/gpu/GridGenerator/geometries/Triangle/Triangle.cu
new file mode 100644
index 000000000..ffbe326fa
--- /dev/null
+++ b/src/gpu/GridGenerator/geometries/Triangle/Triangle.cu
@@ -0,0 +1,321 @@
+#include "Triangle.h"
+#include "TriangleException.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*(abs(this->normal.x) + abs(this->normal.y) + 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 000000000..fe72956a5
--- /dev/null
+++ b/src/gpu/GridGenerator/geometries/Triangle/Triangle.h
@@ -0,0 +1,63 @@
+#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/Triangle/TriangleException.h b/src/gpu/GridGenerator/geometries/Triangle/TriangleException.h
new file mode 100644
index 000000000..962a471b3
--- /dev/null
+++ b/src/gpu/GridGenerator/geometries/Triangle/TriangleException.h
@@ -0,0 +1,69 @@
+#ifndef meshGenExcpetion_h
+#define meshGenExcpetion_h
+
+#include <exception>
+#include <iostream>
+#include <string>
+#include <sstream>
+
+class meshGenExcpetion : public std::exception {
+public:
+    virtual const char* what() const throw() = 0;
+};
+
+class nullVectorImpossibleToCalculateAngle : public meshGenExcpetion
+{
+    const char* what() const throw() {
+        std::ostringstream getNr;
+        getNr << "nullVectorImpossibleToCalculateAngle.";
+        return getNr.str().c_str();
+    }
+};
+
+class calculateAngleWhenTrianglesHaveNoCommonEdge : public meshGenExcpetion
+{
+    const char* what() const throw() {
+        std::ostringstream getNr;
+        getNr << "Triangles have no common Edge.";
+        return getNr.str().c_str();
+    }
+};
+
+class invalidTriangles : public meshGenExcpetion
+{
+    const char* what() const throw() {
+        std::ostringstream getNr;
+        getNr << "Triangles not valid.";
+        return getNr.str().c_str();
+    }
+};
+
+class invalidDelta : public meshGenExcpetion
+{
+	const char* what() const throw() {
+		std::ostringstream getNr;
+		getNr << "Delta cant be < Null. To enable no changes change delta to 1.0.";
+		return getNr.str().c_str();
+	}
+};
+
+class compareSameTriangleToFindNeighbor : public meshGenExcpetion
+{
+	const char* what() const throw() {
+		std::ostringstream getNr;
+		getNr << "Triangle Container function problem.";
+		return getNr.str().c_str();
+	}
+};
+
+class normalFromTwoAdjacentTrianglesShowInOppositeDirection : public meshGenExcpetion
+{
+	const char* what() const throw() {
+		std::ostringstream getNr;
+		getNr << "STL broken, it is not allowed that two adjacent Triangles have a normal that shows in the opposite direction.";
+		return getNr.str().c_str();
+	}
+};
+
+
+#endif
diff --git a/src/gpu/GridGenerator/geometries/TriangularMesh/TriangularMesh.cu b/src/gpu/GridGenerator/geometries/TriangularMesh/TriangularMesh.cu
new file mode 100644
index 000000000..b03691611
--- /dev/null
+++ b/src/gpu/GridGenerator/geometries/TriangularMesh/TriangularMesh.cu
@@ -0,0 +1,258 @@
+#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 < 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 < 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 (int i = 0; i < triangles.size() - 1; i++) {
+        for (int 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 000000000..59c99d32e
--- /dev/null
+++ b/src/gpu/GridGenerator/geometries/TriangularMesh/TriangularMesh.h
@@ -0,0 +1,83 @@
+#ifndef Geometry_h
+#define Geometry_h
+
+#include <stdio.h>
+#include <cuda_runtime.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 000000000..d4a42b918
--- /dev/null
+++ b/src/gpu/GridGenerator/geometries/TriangularMesh/TriangularMeshStrategy.cpp
@@ -0,0 +1,278 @@
+#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 000000000..1822229ec
--- /dev/null
+++ b/src/gpu/GridGenerator/geometries/TriangularMesh/TriangularMeshStrategy.h
@@ -0,0 +1,69 @@
+#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 000000000..4fc0e6ded
--- /dev/null
+++ b/src/gpu/GridGenerator/geometries/TriangularMesh/triangleNeighborFinder/TriangleNeighborFinder.cpp
@@ -0,0 +1,324 @@
+#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 000000000..be0ebc5d0
--- /dev/null
+++ b/src/gpu/GridGenerator/geometries/TriangularMesh/triangleNeighborFinder/TriangleNeighborFinder.h
@@ -0,0 +1,56 @@
+#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 000000000..d97983925
--- /dev/null
+++ b/src/gpu/GridGenerator/geometries/TriangularMesh/triangleRefinement/TriangleRefinement.cpp
@@ -0,0 +1,217 @@
+#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 000000000..2cd5045a1
--- /dev/null
+++ b/src/gpu/GridGenerator/geometries/TriangularMesh/triangleRefinement/TriangleRefinement.h
@@ -0,0 +1,47 @@
+#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/VerticalCylinder/VerticalCylinder.cu b/src/gpu/GridGenerator/geometries/VerticalCylinder/VerticalCylinder.cu
new file mode 100644
index 000000000..16a2640c1
--- /dev/null
+++ b/src/gpu/GridGenerator/geometries/VerticalCylinder/VerticalCylinder.cu
@@ -0,0 +1,90 @@
+#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 000000000..a0c97aa80
--- /dev/null
+++ b/src/gpu/GridGenerator/geometries/VerticalCylinder/VerticalCylinder.h
@@ -0,0 +1,50 @@
+//  _    ___      __              __________      _     __
+// | |  / (_)____/ /___  ______ _/ / ____/ /_  __(_)___/ /____
+// | | / / / ___/ __/ / / / __ `/ / /_  / / / / / / __  / ___/
+// | |/ / / /  / /_/ /_/ / /_/ / / __/ / / /_/ / / /_/ (__  )
+// |___/_/_/   \__/\__,_/\__,_/_/_/   /_/\__,_/_/\__,_/____/
+//
+#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.h b/src/gpu/GridGenerator/grid/BoundaryConditions/BoundaryCondition.h
index 28570b46e..c1d8524ec 100644
--- a/src/gpu/GridGenerator/grid/BoundaryConditions/BoundaryCondition.h
+++ b/src/gpu/GridGenerator/grid/BoundaryConditions/BoundaryCondition.h
@@ -86,7 +86,7 @@ protected:
 public:
     char getType() const override
     {
-        return BC_PRESSURE;
+        return vf::gpu::BC_PRESSURE;
     }
 
     real getRho()
@@ -113,7 +113,7 @@ protected:
 public:
     virtual char getType() const override
     {
-        return BC_SLIP;
+        return vf::gpu::BC_SLIP;
     }
 
     void fillSlipNormalLists()
@@ -153,7 +153,7 @@ protected:
 public:
     virtual char getType() const override
     {
-        return BC_VELOCITY;
+        return vf::gpu::BC_VELOCITY;
     }
 
     void fillVelocityLists()
@@ -192,7 +192,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 99097a393..02d61a834 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.cu
index 6067cb66e..6e663751b 100644
--- a/src/gpu/GridGenerator/grid/Field.cu
+++ b/src/gpu/GridGenerator/grid/Field.cu
@@ -35,6 +35,8 @@
 #include "grid/NodeValues.h"
 #include "grid/GridStrategy/GridStrategy.h"
 
+using namespace vf::gpu;
+
 Field::Field(SPtr<GridStrategy> gridStrategy, uint size) : gridStrategy(gridStrategy), size(size)
 {
     
@@ -132,6 +134,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 8b66c56d8..9dc8e6857 100644
--- a/src/gpu/GridGenerator/grid/Field.h
+++ b/src/gpu/GridGenerator/grid/Field.h
@@ -55,6 +55,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;
diff --git a/src/gpu/GridGenerator/grid/Grid.h b/src/gpu/GridGenerator/grid/Grid.h
index 1582c0bb6..1f8a33380 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,6 +41,7 @@
 
 #include "grid/Cell.h"
 
+class TriangularMesh;
 struct Vertex;
 struct Triangle;
 class GridStrategy;
@@ -67,20 +68,36 @@ 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;
@@ -93,6 +110,25 @@ public:
 
     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 +138,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 +148,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 63ea9b188..faee46ca6 100644
--- a/src/gpu/GridGenerator/grid/GridBuilder/GridBuilder.h
+++ b/src/gpu/GridGenerator/grid/GridBuilder/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 73bcbdf2b..2a5f017ad 100644
--- a/src/gpu/GridGenerator/grid/GridBuilder/LevelGridBuilder.cpp
+++ b/src/gpu/GridGenerator/grid/GridBuilder/LevelGridBuilder.cpp
@@ -35,21 +35,43 @@
 #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/Grid.h"
+#include "grid/GridFactory.h"
+#include "grid/GridInterface.h"
 #include "grid/GridStrategy/GridCpuStrategy/GridCpuStrategy.h"
+#include "grid/GridStrategy/GridGpuStrategy/GridGpuStrategy.h"
 #include "grid/NodeValues.h"
-#include "grid/GridFactory.h"
-#include "grid/Grid.h"
+#include "grid/partition/Partition.h"
+
+#include "io/GridVTKWriter/GridVTKWriter.h"
+#include "io/QLineWriter.h"
+#include "io/SimulationFileWriter/SimulationFileWriter.h"
+#include "io/VTKWriterWrapper/PolyDataWriterWrapper.h"
+#include "io/VTKWriterWrapper/UnstructuredGridWrapper.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(Device device, const std::string &d3qxx) : device(device), d3qxx(d3qxx)
 {
-    (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)
@@ -89,6 +111,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 +168,31 @@ 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];
+}
+
+void LevelGridBuilder::copyDataFromGpu()
+{
+    for (const auto &grid : grids) {
+        auto gridGpuStrategy = std::dynamic_pointer_cast<GridGpuStrategy>(grid->getGridStrategy());
+        if (gridGpuStrategy)
+            gridGpuStrategy->copyDataFromGPU(std::static_pointer_cast<GridImp>(grid));
+    }
+}
+
 LevelGridBuilder::~LevelGridBuilder()
 {
     for (const auto& grid : grids)
@@ -146,24 +229,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 +415,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 8e0f79a7a..c2f6b9da6 100644
--- a/src/gpu/GridGenerator/grid/GridBuilder/LevelGridBuilder.h
+++ b/src/gpu/GridGenerator/grid/GridBuilder/LevelGridBuilder.h
@@ -46,6 +46,8 @@
 
 struct Vertex;
 class  Grid;
+class Transformator;
+class ArrowTransformator;
 class PolyDataWriterWrapper;
 class BoundingBox;
 enum class Device;
@@ -53,6 +55,8 @@ enum class Device;
 class Side;
 class VelocityBoundaryCondition;
 class SlipBoundaryCondition;
+class PressureBoundaryCondition;
+class GeometryBoundaryCondition;
 enum class SideType;
 
 
@@ -67,13 +71,21 @@ public:
 
     GRIDGENERATOR_EXPORT SPtr<Grid> getGrid(uint level) override;
 
+    GRIDGENERATOR_EXPORT void copyDataFromGpu();
     GRIDGENERATOR_EXPORT virtual ~LevelGridBuilder();
 
     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 +105,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,16 +131,33 @@ 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);
 
+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;
+
 private:
+    Device device;
     std::string d3qxx;
 
 public:
@@ -132,6 +174,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 f3fdaa25d..da01099cf 100644
--- a/src/gpu/GridGenerator/grid/GridBuilder/MultipleGridBuilder.cpp
+++ b/src/gpu/GridGenerator/grid/GridBuilder/MultipleGridBuilder.cpp
@@ -46,6 +46,9 @@
 #include "grid/Grid.h"
 #include "grid/GridFactory.h"
 
+#include "io/GridVTKWriter/GridVTKWriter.h"
+#include "io/STLReaderWriter/STLWriter.h"
+
 MultipleGridBuilder::MultipleGridBuilder(SPtr<GridFactory> gridFactory, Device device, const std::string &d3qxx) :
     LevelGridBuilder(device, d3qxx), gridFactory(gridFactory), numberOfLayersFine(12), numberOfLayersBetweenLevels(8), subDomainBox(nullptr)
 {
@@ -72,6 +75,125 @@ 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);
@@ -82,6 +204,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 +446,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 +605,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 df13fa31f..5f2f54353 100644
--- a/src/gpu/GridGenerator/grid/GridBuilder/MultipleGridBuilder.h
+++ b/src/gpu/GridGenerator/grid/GridBuilder/MultipleGridBuilder.h
@@ -35,7 +35,7 @@
 
 #include <vector>
 #include <array>
-
+#include "GridGenerator_export.h"
 #include "Core/LbmOrGks.h"
 
 #include "global.h"
@@ -55,6 +55,11 @@ public:
     GRIDGENERATOR_EXPORT static SPtr<MultipleGridBuilder> makeShared(SPtr<GridFactory> gridFactory);
 
     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,42 @@ 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<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();
 
     SPtr<GridFactory> gridFactory;
+    Object *solidObject;
 
     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.cpp b/src/gpu/GridGenerator/grid/GridFactory.cpp
new file mode 100644
index 000000000..3e2297c21
--- /dev/null
+++ b/src/gpu/GridGenerator/grid/GridFactory.cpp
@@ -0,0 +1,4 @@
+#include "GridFactory.h"
+
+
+
diff --git a/src/gpu/GridGenerator/grid/GridImp.cu b/src/gpu/GridGenerator/grid/GridImp.cu
index 2684893e3..27ab17b79 100644
--- a/src/gpu/GridGenerator/grid/GridImp.cu
+++ b/src/gpu/GridGenerator/grid/GridImp.cu
@@ -42,17 +42,25 @@
 
 #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/GridStrategy/GridStrategy.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, SPtr<GridStrategy> gridStrategy, Distribution distribution, uint level) 
             : object(object), 
@@ -69,11 +77,19 @@ GridImp::GridImp(Object* object, real startX, real startY, real startZ, real end
     periodicityX(false),
     periodicityY(false),
     periodicityZ(false),
+    enableFixRefinementIntoTheWall(false),
+    gridInterface(nullptr),
     neighborIndexX(nullptr),
     neighborIndexY(nullptr),
     neighborIndexZ(nullptr),
     neighborIndexNegative(nullptr),
-    sparseIndices(nullptr)
+    sparseIndices(nullptr),
+    qIndices(nullptr),
+    qValues(nullptr),
+    qPatches(nullptr),
+    innerRegionFromFinerGrid(false),
+    numberOfLayers(0),
+    qComputationStage(qComputationStageType::ComputeQs)
 {
     initalNumberOfNodesAndSize();
 }
@@ -109,8 +125,26 @@ void GridImp::inital(const SPtr<Grid> fineGrid, uint numberOfLayers)
     *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() );
+    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";
+    gridStrategy->fixOddCells( shared_from_this() );
+    
+    if( enableFixRefinementIntoTheWall )
+    {
+        *logging::out << logging::Logger::INFO_INTERMEDIATE << "Start fixRefinementIntoWall()\n";
+        gridStrategy->fixRefinementIntoWall(shared_from_this());
+    }
     
     *logging::out << logging::Logger::INFO_INTERMEDIATE << "Start findEndOfGridStopperNodes()\n";
 	gridStrategy->findEndOfGridStopperNodes(shared_from_this());
@@ -120,14 +154,22 @@ void GridImp::inital(const SPtr<Grid> fineGrid, uint numberOfLayers)
         << "nodes: " << this->nx << " x " << this->ny << " x " << this->nz << " = " << this->size << "\n";
 }
 
-void GridImp::initalNodeToOutOfGrid(uint index)
+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()
 {
     gridStrategy->freeMemory(shared_from_this());
+
+    gridStrategy->freeFieldMemory(&field);
 }
 
 GridImp::GridImp()
@@ -142,16 +184,202 @@ 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);
 
-    if( xIndex != 0 && xIndex != this->nx-1 &&
-        yIndex != 0 && yIndex != this->ny-1 &&
-        zIndex != 0 && zIndex != this->nz-1 )
-        this->field.setFieldEntryToFluid(index);
+    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++ ){
+        this->gridStrategy->addOverlap( shared_from_this() );
+    }
+}
+
+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, dy, dz;
+
+    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)
@@ -167,6 +395,31 @@ void GridImp::findEndOfGridStopperNode(uint 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) {
@@ -457,6 +710,11 @@ 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);
@@ -500,6 +758,49 @@ 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                       //
 // --------------------------------------------------------- //
@@ -674,6 +975,575 @@ int GridImp::getSparseIndex(const real &x, const real &y, const real &z) const
     return sparseIndices[matrixIndex];
 }
 
+// --------------------------------------------------------- //
+//                    Find Interface                         //
+// --------------------------------------------------------- //
+void GridImp::findGridInterface(SPtr<Grid> finerGrid, LbmOrGks lbmOrGks)
+{
+    gridStrategy->findGridInterface(shared_from_this(), std::static_pointer_cast<GridImp>(finerGrid), lbmOrGks);
+}
+
+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);
+        }
+    }
+
+    //this->gridStrategy->findEndOfGridStopperNodes(shared_from_this());
+}
+
+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
+        //gridStrategy->findInnerNodes(shared_from_this()); //TODO: adds INNERTYPE AND OUTERTYPE to findInnerNodes 
+		//new method for geometric primitives (not cell based) to be implemented
+        this->discretize(object, INVALID_SOLID, FLUID);
+
+    this->closeNeedleCells();
+
+	gridStrategy->findSolidStopperNodes(shared_from_this());
+	gridStrategy->findBoundarySolidNodes(shared_from_this());
+}
+
+
+void GridImp::mesh(TriangularMesh &triangularMesh)
+{
+    const clock_t begin = clock();
+
+    gridStrategy->mesh(shared_from_this(), triangularMesh);
+
+    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{
+        numberOfClosedNeedleCells = this->gridStrategy->closeNeedleCells( shared_from_this() );
+        *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{
+        numberOfClosedNeedleCells = this->gridStrategy->closeNeedleCellsThinWall( shared_from_this() );
+        *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::findQs(TriangularMesh &triangularMesh)
+{
+    const clock_t begin = clock();
+
+    if( this->qComputationStage == qComputationStageType::ComputeQs ){
+	    gridStrategy->allocateQs(shared_from_this());
+    }
+
+    gridStrategy->findQs(shared_from_this(), triangularMesh);
+
+    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 ){
+	    gridStrategy->allocateQs(shared_from_this());
+    }
+
+
+    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                             //
 // --------------------------------------------------------- //
@@ -702,8 +1572,69 @@ int GridImp::getEndDirection() const
     return this->distribution.dir_end;
 }
 
-uint GridImp::getXIndex(real x) const
+BoundingBox GridImp::getBoundingBoxOnNodes(Triangle &triangle) const
+{
+    real minX, maxX, minY, maxY, minZ, maxZ;
+    triangle.setMinMax(minX, maxX, minY, maxY, minZ, maxZ);
+
+    int minXIndex = lround(floor((minX - this->startX) / this->delta)) - 1;
+    int minYIndex = lround(floor((minY - this->startY) / this->delta)) - 1;
+    int minZIndex = lround(floor((minZ - this->startZ) / this->delta)) - 1;
+
+    int maxXIndex = lround(ceil((maxX - this->startX) / this->delta)) + 1;
+    int maxYIndex = lround(ceil((maxY - this->startY) / this->delta)) + 1;
+    int maxZIndex = 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 lround((x - startX) / delta);
 }
 
@@ -819,6 +1750,64 @@ 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
 
@@ -864,3 +1853,11 @@ void GridImp::getNodeValues(real *xCoords, real *yCoords, real *zCoords, uint *n
         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.h b/src/gpu/GridGenerator/grid/GridImp.h
index c81aa67b4..938fa1d80 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,13 +44,31 @@
 #include "grid/Cell.h"
 #include "grid/Field.h" 
 
+class TriangularMesh;
 struct Vertex;
+struct Triangle;
 class GridStrategy;
+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:
@@ -63,6 +81,7 @@ public:
 
 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 +113,7 @@ private:
 
     Field field;
     Object* object;
+    GridInterface *gridInterface;
 
     int *neighborIndexX, *neighborIndexY, *neighborIndexZ, *neighborIndexNegative;
     int *sparseIndices;
@@ -102,10 +122,21 @@ private:
 	real *qValues;
     uint *qPatches;
 
+    bool innerRegionFromFinerGrid;
+
+    uint numberOfLayers;
+
     SPtr<GridStrategy> gridStrategy;
+    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,17 +147,38 @@ 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;
 
@@ -134,7 +186,26 @@ public:
 
     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 +231,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 +245,27 @@ 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;
 
+    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;
+
     SPtr<GridStrategy> getGridStrategy() const override;
 
+    void print() const;
 
 public:
     virtual void findSparseIndices(SPtr<Grid> fineGrid) override;
@@ -196,6 +284,69 @@ 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:
+    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;
+
+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;
+
 private:
     friend class GridGpuStrategy;
     friend class GridCpuStrategy;
diff --git a/src/gpu/GridGenerator/grid/GridInterface.cu b/src/gpu/GridGenerator/grid/GridInterface.cu
new file mode 100644
index 000000000..5b4dc9310
--- /dev/null
+++ b/src/gpu/GridGenerator/grid/GridInterface.cu
@@ -0,0 +1,408 @@
+#include "GridInterface.h"
+
+#include <iostream>
+
+#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 int 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 int 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 000000000..d3ade4706
--- /dev/null
+++ b/src/gpu/GridGenerator/grid/GridInterface.h
@@ -0,0 +1,54 @@
+#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
index ac6333958..79f89b5a1 100644
--- a/src/gpu/GridGenerator/grid/GridStrategy/GridCpuStrategy/GridCpuStrategy.cpp
+++ b/src/gpu/GridGenerator/grid/GridStrategy/GridCpuStrategy/GridCpuStrategy.cpp
@@ -38,9 +38,14 @@
 #include <vector>
 #include <iostream>
 
-#include "grid/distributions/Distribution.h"
+#include "geometries/TriangularMesh/TriangularMesh.h"
+
 #include "grid/GridImp.h"
+#include "grid/GridInterface.h"
 #include "grid/NodeValues.h"
+#include "grid/distributions/Distribution.h"
+
+using namespace vf::gpu;
 
 void GridCpuStrategy::allocateGridMemory(SPtr<GridImp> grid)
 {
@@ -56,6 +61,20 @@ void GridCpuStrategy::allocateGridMemory(SPtr<GridImp> grid)
 		grid->qIndices[i] = INVALID_INDEX;
 }
 
+void GridCpuStrategy::allocateQs(SPtr<GridImp> grid)
+{
+    grid->qPatches = new uint[grid->getNumberOfSolidBoundaryNodes()];
+
+    for (uint i = 0; i < grid->getNumberOfSolidBoundaryNodes(); i++)
+        grid->qPatches[i] = INVALID_INDEX;
+
+    const uint numberOfQs = grid->getNumberOfSolidBoundaryNodes() * (grid->distribution.dir_end + 1);
+    grid->qValues         = new real[numberOfQs];
+#pragma omp parallel for
+    for (int i = 0; i < (int)numberOfQs; i++)
+        grid->qValues[i] = -1.0;
+}
+
 void GridCpuStrategy::initalNodesToOutOfGrid(SPtr<GridImp> grid)
 {
 #pragma omp parallel for
@@ -76,6 +95,59 @@ void GridCpuStrategy::findInnerNodes(SPtr<GridImp> grid)
         grid->findInnerNode(index);
 }
 
+void GridCpuStrategy::addOverlap(SPtr<GridImp> grid)
+{
+
+#pragma omp parallel for
+    for (int index = 0; index < (int)grid->size; index++)
+        grid->setOverlapTmp(index);
+
+#pragma omp parallel for
+    for (int index = 0; index < (int)grid->size; index++)
+        grid->setOverlapFluid(index);
+}
+
+void GridCpuStrategy::fixOddCells(SPtr<GridImp> grid)
+{
+#pragma omp parallel for
+    for (int index = 0; index < (int)grid->size; index++)
+        grid->fixOddCell(index);
+}
+
+void GridCpuStrategy::fixRefinementIntoWall(SPtr<GridImp> grid)
+{
+#pragma omp parallel for
+    for (int xIdx = 0; xIdx < (int)grid->nx; xIdx++) {
+        for (uint yIdx = 0; yIdx < grid->ny; yIdx++) {
+            grid->fixRefinementIntoWall(xIdx, yIdx, 0, 3);
+            grid->fixRefinementIntoWall(xIdx, yIdx, grid->nz - 1, -3);
+        }
+    }
+
+#pragma omp parallel for
+    for (int xIdx = 0; xIdx < (int)grid->nx; xIdx++) {
+        for (uint zIdx = 0; zIdx < grid->nz; zIdx++) {
+            grid->fixRefinementIntoWall(xIdx, 0, zIdx, 2);
+            grid->fixRefinementIntoWall(xIdx, grid->ny - 1, zIdx, -2);
+        }
+    }
+
+#pragma omp parallel for
+    for (int yIdx = 0; yIdx < (int)grid->ny; yIdx++) {
+        for (uint zIdx = 0; zIdx < grid->nz; zIdx++) {
+            grid->fixRefinementIntoWall(0, yIdx, zIdx, 1);
+            grid->fixRefinementIntoWall(grid->nx - 1, yIdx, zIdx, -1);
+        }
+    }
+}
+
+void GridCpuStrategy::findStopperNodes(SPtr<GridImp> grid)
+{
+#pragma omp parallel for
+    for (int index = 0; index < (int)grid->size; index++)
+        grid->findStopperNode(index);
+}
+
 void GridCpuStrategy::findEndOfGridStopperNodes(SPtr<GridImp> grid)
 {
 #pragma omp parallel for
@@ -83,6 +155,96 @@ void GridCpuStrategy::findEndOfGridStopperNodes(SPtr<GridImp> grid)
 		grid->findEndOfGridStopperNode(index);
 }
 
+void GridCpuStrategy::findSolidStopperNodes(SPtr<GridImp> grid)
+{
+#pragma omp parallel for
+    for (int index = 0; index < (int)grid->size; index++)
+        grid->findSolidStopperNode(index);
+}
+
+void GridCpuStrategy::findBoundarySolidNodes(SPtr<GridImp> grid)
+{
+    //#pragma omp parallel for
+    for (int index = 0; index < (int)grid->size; index++) {
+        grid->findBoundarySolidNode(index);
+    }
+}
+
+void GridCpuStrategy::mesh(SPtr<GridImp> grid, TriangularMesh &geom)
+{
+#pragma omp parallel for
+    for (int i = 0; i < geom.size; i++)
+        grid->mesh(geom.triangles[i]);
+}
+
+uint GridCpuStrategy::closeNeedleCells(SPtr<GridImp> grid)
+{
+    uint numberOfClosedNeedleCells = 0;
+
+#pragma omp parallel for reduction(+ : numberOfClosedNeedleCells)
+    for (int index = 0; index < (int)grid->size; index++) {
+        if (grid->closeCellIfNeedle(index))
+            numberOfClosedNeedleCells++;
+    }
+
+    return numberOfClosedNeedleCells;
+}
+
+uint GridCpuStrategy::closeNeedleCellsThinWall(SPtr<GridImp> grid)
+{
+    uint numberOfClosedNeedleCells = 0;
+
+#pragma omp parallel for reduction(+ : numberOfClosedNeedleCells)
+    for (int index = 0; index < (int)grid->size; index++) {
+        if (grid->closeCellIfNeedleThinWall(index))
+            numberOfClosedNeedleCells++;
+    }
+
+    return numberOfClosedNeedleCells;
+}
+
+void GridCpuStrategy::findQs(SPtr<GridImp> grid, TriangularMesh &geom)
+{
+#pragma omp parallel for
+    for (int i = 0; i < geom.size; i++)
+        grid->findQs(geom.triangles[i]);
+}
+
+void GridCpuStrategy::findGridInterface(SPtr<GridImp> grid, SPtr<GridImp> fineGrid, LbmOrGks lbmOrGks)
+{
+    const auto coarseLevel = grid->getLevel();
+    const auto fineLevel   = fineGrid->getLevel();
+
+    *logging::out << logging::Logger::INFO_INTERMEDIATE << "find interface level " << coarseLevel << " -> "
+                  << fineLevel;
+
+    grid->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);
+    grid->gridInterface->cf.coarse = new uint[sizeCF];
+    grid->gridInterface->cf.fine   = new uint[sizeCF];
+    grid->gridInterface->cf.offset = new uint[sizeCF];
+    grid->gridInterface->fc.coarse = new uint[sizeCF];
+    grid->gridInterface->fc.fine   = new uint[sizeCF];
+    grid->gridInterface->fc.offset = new uint[sizeCF];
+
+    for (uint index = 0; index < grid->getSize(); index++)
+        grid->findGridInterfaceCF(index, *fineGrid, lbmOrGks);
+
+    for (uint index = 0; index < grid->getSize(); index++)
+        grid->findGridInterfaceFC(index, *fineGrid);
+
+    for (uint index = 0; index < grid->getSize(); index++)
+        grid->findOverlapStopper(index, *fineGrid);
+
+    if (lbmOrGks == GKS) {
+        for (uint index = 0; index < grid->getSize(); index++)
+            grid->findInvalidBoundaryNodes(index);
+    }
+
+    *logging::out << logging::Logger::INFO_INTERMEDIATE << "  ... done. \n";
+}
+
 void GridCpuStrategy::findSparseIndices(SPtr<GridImp> coarseGrid, SPtr<GridImp> fineGrid)
 {
     *logging::out << logging::Logger::INFO_INTERMEDIATE << "Find sparse indices...";
@@ -106,6 +268,17 @@ void GridCpuStrategy::findForNeighborsNewIndices(SPtr<GridImp> grid)
         grid->setNeighborIndices(index);
 }
 
+void GridCpuStrategy::findForGridInterfaceNewIndices(SPtr<GridImp> grid, SPtr<GridImp> fineGrid)
+{
+#pragma omp parallel for
+    for (int index = 0; index < (int)grid->getNumberOfNodesCF(); index++)
+        grid->gridInterface->findForGridInterfaceSparseIndexCF(grid.get(), fineGrid.get(), index);
+
+#pragma omp parallel for
+    for (int index = 0; index < (int)grid->getNumberOfNodesFC(); index++)
+        grid->gridInterface->findForGridInterfaceSparseIndexFC(grid.get(), fineGrid.get(), index);
+}
+
 void GridCpuStrategy::freeFieldMemory(Field* field)
 {
     delete[] field->field;
diff --git a/src/gpu/GridGenerator/grid/GridStrategy/GridCpuStrategy/GridCpuStrategy.h b/src/gpu/GridGenerator/grid/GridStrategy/GridCpuStrategy/GridCpuStrategy.h
index 2b3d5a8d9..c5c52d68a 100644
--- a/src/gpu/GridGenerator/grid/GridStrategy/GridCpuStrategy/GridCpuStrategy.h
+++ b/src/gpu/GridGenerator/grid/GridStrategy/GridCpuStrategy/GridCpuStrategy.h
@@ -43,27 +43,43 @@ class TriangularMesh;
 class GRIDGENERATOR_EXPORT GridCpuStrategy : public GridStrategy
 {
 public:
-    virtual ~GridCpuStrategy() {};
+    virtual ~GridCpuStrategy(){};
 
     void allocateGridMemory(SPtr<GridImp> grid) override;
 
+    void allocateQs(SPtr<GridImp> grid) override;
+
     void initalNodesToOutOfGrid(SPtr<GridImp> grid) override;
+    void fixOddCells(SPtr<GridImp> grid) override;
     void findInnerNodes(SPtr<GridImp> grid) override;
-	void findEndOfGridStopperNodes(SPtr<GridImp> grid) override;
+    void addOverlap(SPtr<GridImp> grid) override;
+    void fixRefinementIntoWall(SPtr<GridImp> grid) override;
+    void findStopperNodes(SPtr<GridImp> grid) override;
+    void findBoundarySolidNodes(SPtr<GridImp> grid) override;
+    void findEndOfGridStopperNodes(SPtr<GridImp> grid) override;
+    void findSolidStopperNodes(SPtr<GridImp> grid) override;
 
-    void freeMemory(SPtr<GridImp> grid) override;
+    void mesh(SPtr<GridImp> grid, TriangularMesh &geom) override;
 
+    uint closeNeedleCells(SPtr<GridImp> grid) override;
+    uint closeNeedleCellsThinWall(SPtr<GridImp> grid) override;
 
+    void findQs(SPtr<GridImp> grid, TriangularMesh &geom) override;
 
-    virtual void copyDataFromGPU() {};
+    void findGridInterface(SPtr<GridImp> grid, SPtr<GridImp> fineGrid, LbmOrGks lbmOrGks) override;
+
+    void freeMemory(SPtr<GridImp> grid) override;
+
+    virtual void copyDataFromGPU(){};
 
 protected:
     static void findForNeighborsNewIndices(SPtr<GridImp> grid);
+    static void findForGridInterfaceNewIndices(SPtr<GridImp> grid, SPtr<GridImp> fineGrid);
+
 public:
-    void allocateFieldMemory(Field* field) override;
-    void freeFieldMemory(Field* field) override;
+    void allocateFieldMemory(Field *field) override;
+    void freeFieldMemory(Field *field) override;
     void findSparseIndices(SPtr<GridImp> coarseGrid, SPtr<GridImp> fineGrid) override;
-
 };
 
 #endif
\ No newline at end of file
diff --git a/src/gpu/GridGenerator/grid/GridStrategy/GridGpuStrategy/GridGpuStrategy.cpp b/src/gpu/GridGenerator/grid/GridStrategy/GridGpuStrategy/GridGpuStrategy.cpp
new file mode 100644
index 000000000..a19daf22a
--- /dev/null
+++ b/src/gpu/GridGenerator/grid/GridStrategy/GridGpuStrategy/GridGpuStrategy.cpp
@@ -0,0 +1,430 @@
+#include "GridGpuStrategy.h"
+
+#include "Core/Timer/Timer.h"
+
+#include "geometries/BoundingBox/BoundingBox.h"
+#include "geometries/TriangularMesh/TriangularMesh.h"
+
+#include "grid/kernel/runGridKernelGPU.cuh"
+#include "grid/distributions/Distribution.h"
+#include "grid/GridImp.h"
+#include "grid/GridInterface.h"
+
+#include "utilities/cuda/CudaErrorCheck.cu"
+#include "utilities/cuda/LaunchParameter.cuh"
+
+void GridGpuStrategy::allocateGridMemory(SPtr<GridImp> grid)
+{
+    //printCudaInformation(0);
+    cudaSetDevice(0);
+
+    this->allocDistribution(grid);
+    this->allocField(grid);
+    this->allocMatrixIndicesOnGPU(grid);
+    this->allocNeighborsIndices(grid);
+}
+
+void GridGpuStrategy::allocateQs(SPtr<GridImp> grid)
+{
+}
+
+void GridGpuStrategy::initalNodesToOutOfGrid(SPtr<GridImp> grid)
+{
+
+}
+
+void GridGpuStrategy::fixOddCells(SPtr<GridImp> grid)
+{
+}
+
+
+
+void GridGpuStrategy::findInnerNodes(SPtr<GridImp> grid)
+{
+    //float time = runKernelInitalUniformGrid3d(LaunchParameter::make_2D1D_launchParameter(grid->size, 256), *grid.get());
+}
+
+void GridGpuStrategy::addOverlap(SPtr<GridImp> grid)
+{
+}
+
+void GridGpuStrategy::fixRefinementIntoWall(SPtr<GridImp> grid)
+{
+}
+
+void GridGpuStrategy::findStopperNodes(SPtr<GridImp> grid)
+{
+
+}
+
+void GridGpuStrategy::findBoundarySolidNodes(SPtr<GridImp> grid)
+{
+}
+
+void GridGpuStrategy::findEndOfGridStopperNodes(SPtr<GridImp> grid)
+{
+
+}
+
+void GridGpuStrategy::findSolidStopperNodes(SPtr<GridImp> grid)
+{
+
+}
+
+void GridGpuStrategy::mesh(SPtr<GridImp> grid, TriangularMesh &geom)
+{
+    *logging::out << logging::Logger::INFO_INTERMEDIATE << "start meshing on GPU...\n";
+    allocAndCopyTrianglesToGPU(geom);
+
+    /*---------------------------------------------------------------------------------*/
+    float time = runKernelToMesh(LaunchParameter::make_1D1D_launchParameter(geom.size, 256), *grid.get(), geom);
+    /*---------------------------------------------------------------------------------*/
+    *logging::out << logging::Logger::INFO_INTERMEDIATE << "Time GPU build grid: "  << time / 1000 << "sec\n";
+    *logging::out << logging::Logger::INFO_INTERMEDIATE << "-------------------------------------------\n";
+
+    freeTrianglesFromGPU(geom);
+
+}
+
+uint GridGpuStrategy::closeNeedleCells(SPtr<GridImp> grid)
+{
+    return uint();
+}
+
+uint GridGpuStrategy::closeNeedleCellsThinWall(SPtr<GridImp> grid)
+{
+    return uint();
+}
+
+
+void GridGpuStrategy::findQs(SPtr<GridImp> grid, TriangularMesh &geom)
+{
+    
+}
+
+
+void GridGpuStrategy::findGridInterface(SPtr<GridImp> grid, SPtr<GridImp> fineGrid, LbmOrGks lbmOrGks)
+{
+    //copyAndFreeFieldFromGPU(grid->getField());
+    //copyAndFreeFieldFromGPU(fineGrid->getField());
+    //copyAndFreeMatrixIndicesFromGPU(grid, grid->size);
+    //copyAndFreeMatrixIndicesFromGPU(fineGrid, fineGrid->getSize());
+
+    //grid->gridInterface = new GridInterface();
+    //const uint sizeCF = fineGrid->nx * fineGrid->ny + fineGrid->ny * fineGrid->nz + fineGrid->nx * fineGrid->nz;
+    //grid->gridInterface->cf.coarse = new uint[sizeCF];
+    //grid->gridInterface->cf.fine = new uint[sizeCF];
+    //grid->gridInterface->fc.coarse = new uint[sizeCF];
+    //grid->gridInterface->fc.fine = new uint[sizeCF];
+
+    ////for (uint index = 0; index < grid->getSize(); index++)
+    ////    grid->findGridInterface(index, *fineGrid.get());
+
+    //uint *cfc;
+    //uint *cff;
+    //uint *fcc;
+    //uint *fcf;
+
+    //CudaSafeCall(cudaMalloc(&cfc, sizeCF * sizeof(uint)));
+    //CudaSafeCall(cudaMalloc(&cff, sizeCF * sizeof(uint)));
+    //CudaSafeCall(cudaMalloc(&fcc, sizeCF * sizeof(uint)));
+    //CudaSafeCall(cudaMalloc(&fcf, sizeCF * sizeof(uint)));
+
+    //CudaSafeCall(cudaMemcpy(cfc, grid->gridInterface->cf.coarse, grid->gridInterface->cf.numberOfEntries * sizeof(uint), cudaMemcpyHostToDevice));
+    //CudaSafeCall(cudaMemcpy(cff, grid->gridInterface->cf.fine, grid->gridInterface->cf.numberOfEntries * sizeof(uint), cudaMemcpyHostToDevice));
+    //CudaSafeCall(cudaMemcpy(fcc, grid->gridInterface->fc.coarse, grid->gridInterface->fc.numberOfEntries * sizeof(uint), cudaMemcpyHostToDevice));
+    //CudaSafeCall(cudaMemcpy(fcf, grid->gridInterface->fc.fine, grid->gridInterface->fc.numberOfEntries * sizeof(uint), cudaMemcpyHostToDevice));
+
+    //grid->gridInterface->cf.coarse = cfc;
+    //grid->gridInterface->cf.fine = cff;
+    //grid->gridInterface->fc.coarse = fcc;
+    //grid->gridInterface->fc.fine = fcf;
+
+    //GridInterface *gridInterface_d;
+    //CudaSafeCall(cudaMalloc(&gridInterface_d, sizeof(GridInterface)));
+    //CudaSafeCall(cudaMemcpy(gridInterface_d, grid->gridInterface, sizeof(GridInterface), cudaMemcpyHostToDevice));
+    //grid->gridInterface = gridInterface_d;
+    //CudaCheckError();
+
+
+    //grid->updateSparseIndices();
+
+    //allocAndCopyFieldToGPU(grid->getField());
+    //allocAndCopyFieldToGPU(fineGrid->getField());
+    //allocAndCopyMatrixIndicesToGPU(grid, grid->size);
+    //allocAndCopyMatrixIndicesToGPU(fineGrid, fineGrid->size);
+
+    //float time = runKernelToFindNeighborsNewIndices(LaunchParameter::make_2D1D_launchParameter(grid->size, 256), *grid.get());
+    //float time2 = runKernelToFindGridInterfaceNewIndices(LaunchParameter::make_2D1D_launchParameter(grid->size, 256), *grid.get());
+
+    //copyAndFreeGridInterfaceFromGPU(grid);
+
+
+    ////*logging::out << logging::Logger::INTERMEDIATE << "time find indices: " << time / 1000 <<  "sec\n";
+}
+
+//void GridGpuStrategy::deleteSolidNodes(SPtr<GridImp> grid)
+//{
+//    float time1 = runKernelSetToInvalid(LaunchParameter::make_2D1D_launchParameter(grid->size, 512), *grid.get());
+//
+//    copyAndFreeFieldFromGPU(grid->getField());
+//    copyAndFreeMatrixIndicesFromGPU(grid, grid->size);
+//
+//    grid->updateSparseIndices();
+//
+//    allocAndCopyFieldToGPU(grid->getField());
+//    allocAndCopyMatrixIndicesToGPU(grid, grid->size);
+//
+//    float time2 = runKernelFindIndices(LaunchParameter::make_2D1D_launchParameter(grid->size, 256), *grid.get());
+//    *logging::out << logging::Logger::INFO_INTERMEDIATE << "time delete solid nodes: " << (time1 + time2) / 1000 << "sec\n";
+//}
+
+
+
+void GridGpuStrategy::freeMemory(SPtr<GridImp> grid)
+{
+    //delete[] grid->gridInterface->cf.coarse;
+    //delete[] grid->gridInterface->cf.fine;
+
+    //delete[] grid->gridInterface->fc.coarse;
+    //delete[] grid->gridInterface->fc.fine;
+
+    //delete grid->gridInterface;
+
+    delete[] grid->neighborIndexX;
+    delete[] grid->neighborIndexY;
+    delete[] grid->neighborIndexZ;
+    delete[] grid->neighborIndexNegative;
+    delete[] grid->sparseIndices;
+
+    delete[] grid->distribution.f;
+}
+
+
+
+void GridGpuStrategy::copyDataFromGPU(SPtr<GridImp> grid)
+{
+    //copyAndFreeFieldFromGPU(grid->getField());
+    //copyAndFreeNeighborsToCPU(grid);
+    //copyAndFreeMatrixIndicesFromGPU(grid, grid->size);
+    //copyAndFreeDistributiondFromGPU(grid);
+}
+
+void GridGpuStrategy::allocField(SPtr<GridImp> grid)
+{
+    //int size_in_bytes = grid->size * sizeof(char);
+    //CudaSafeCall(cudaMalloc(grid->getField().field, size_in_bytes));
+}
+
+
+void GridGpuStrategy::allocateFieldMemory(Field* field)
+{
+    long size = field->size * sizeof(char) / 1000 / 1000;
+    *logging::out << logging::Logger::INFO_INTERMEDIATE << "alloc on device for grid field: " << int(size) << " MB\n";
+
+    char *field_d;
+    CudaSafeCall(cudaMalloc(&field_d, field->size * sizeof(char)));
+    field->field = field_d;
+}
+
+void GridGpuStrategy::freeFieldMemory(Field* field)
+{
+}
+
+void GridGpuStrategy::findSparseIndices(SPtr<GridImp> coarseGrid, SPtr<GridImp> fineGrid)
+{
+}
+
+//
+//void GridWrapperGPU::markNodesToDeleteOutsideOfGeometry()
+//{
+//    int numberOfEdgeNodes = grid.ny * grid.nz;
+//
+//    /*---------------------------------------------------------------------------------*/
+//    float time = runKernelToMarkNodesToDeleteOutsideOfGeometry(LaunchParameter::make_1D1D_launchParameter(numberOfEdgeNodes, 256), grid);
+//    /*---------------------------------------------------------------------------------*/
+//
+//    *logging::out << logging::Logger::INTERMEDIATE << "mark nodes to delete: " << time / 1000 << "sec\n";
+//    *logging::out << logging::Logger::INTERMEDIATE << "-------------------------------------------\n";
+//}
+
+/*#################################################################################*/
+/*--------------------------------private methods----------------------------------*/
+/*---------------------------------------------------------------------------------*/
+
+void GridGpuStrategy::allocDistribution(SPtr<GridImp> grid)
+{
+    CudaSafeCall(cudaMemcpyToSymbol(DIRECTIONS, grid->distribution.dirs, grid->distribution.dir_end * DIMENSION * sizeof(int)));
+    CudaCheckError();
+
+    unsigned long long distributionSize = grid->size * (grid->distribution.dir_end + 1);
+    unsigned long long size_in_bytes = distributionSize * sizeof(real);
+    real sizeInMB = size_in_bytes / (1024.f*1024.f);
+    *logging::out << logging::Logger::INFO_INTERMEDIATE << "Allocating " << sizeInMB << " [MB] device memory for distributions.\n\n";
+
+    CudaSafeCall(cudaMalloc(&grid->distribution.f, size_in_bytes));
+    CudaCheckError();
+}
+
+void GridGpuStrategy::allocNeighborsIndices(SPtr<GridImp> grid)
+{
+    int size_in_bytes_neighbors = grid->size * sizeof(int);
+    int *neighborIndexX, *neighborIndexY, *neighborIndexZ, *neighborIndexNegative;;
+
+    CudaSafeCall(cudaMalloc(&neighborIndexX,        size_in_bytes_neighbors));
+    CudaSafeCall(cudaMalloc(&neighborIndexY,        size_in_bytes_neighbors));
+    CudaSafeCall(cudaMalloc(&neighborIndexZ,        size_in_bytes_neighbors));
+    CudaSafeCall(cudaMalloc(&neighborIndexNegative, size_in_bytes_neighbors));
+
+    grid->neighborIndexX        = neighborIndexX;
+    grid->neighborIndexY        = neighborIndexY;
+    grid->neighborIndexZ        = neighborIndexZ;
+    grid->neighborIndexNegative = neighborIndexNegative;
+
+    CudaCheckError();
+}
+
+void GridGpuStrategy::allocMatrixIndicesOnGPU(SPtr<GridImp> grid)
+{
+    int size_in_bytes_nodes_reduced = grid->size * sizeof(int);
+    int* indices_reduced_d;
+    CudaSafeCall(cudaMalloc(&indices_reduced_d, size_in_bytes_nodes_reduced));
+    grid->sparseIndices = indices_reduced_d;
+    CudaCheckError();
+}
+
+
+void GridGpuStrategy::allocAndCopyTrianglesToGPU(TriangularMesh &geom)
+{
+    *logging::out << logging::Logger::INFO_INTERMEDIATE << "start copying triangles ...\n";
+    //clock_t begin = clock();
+    int size_in_bytes_triangles = sizeof(Triangle)*geom.size;
+    real sizeInMB = size_in_bytes_triangles / (1024.f*1024.f);
+
+    *logging::out << logging::Logger::INFO_INTERMEDIATE << "Allocating " << sizeInMB << " [MB] device memory for triangles.\n\n";
+
+    Triangle *triangles_d;
+    CudaSafeCall(cudaMalloc(&triangles_d, size_in_bytes_triangles));
+    CudaSafeCall(cudaMemcpy(triangles_d, geom.triangles, size_in_bytes_triangles, cudaMemcpyHostToDevice));
+    geom.triangles = triangles_d;
+    CudaCheckError();
+    //clock_t end = clock();
+    //real time = real(end - begin) / CLOCKS_PER_SEC;
+    //*logging::out << logging::Logger::INFO_INTERMEDIATE << "time copying triangles: " << time << "s\n";
+    *logging::out << logging::Logger::INFO_INTERMEDIATE << "...copying triangles finish!\n\n";
+}
+
+void GridGpuStrategy::freeTrianglesFromGPU(const TriangularMesh &geom)
+{
+    CudaSafeCall(cudaFree(geom.triangles));
+    CudaCheckError();
+}
+
+void GridGpuStrategy::allocAndCopyMatrixIndicesToGPU(SPtr<GridImp> grid, const uint& size)
+{
+    int size_in_bytes_nodes_reduced = size * sizeof(int);
+    int* indices_reduced_d;
+    CudaSafeCall(cudaMalloc(&indices_reduced_d, size_in_bytes_nodes_reduced));
+    CudaSafeCall(cudaMemcpy(indices_reduced_d, grid->sparseIndices, size_in_bytes_nodes_reduced, cudaMemcpyHostToDevice));
+    delete[] grid->sparseIndices;
+    grid->sparseIndices = indices_reduced_d;
+    CudaCheckError();
+}
+
+void GridGpuStrategy::allocAndCopyFieldToGPU(Field& field)
+{
+    int size_in_bytes_grid = field.getSize() * sizeof(char);
+    char* field_d;
+    CudaSafeCall(cudaMalloc(&field_d, size_in_bytes_grid));
+    CudaSafeCall(cudaMemcpy(field_d, field.field, size_in_bytes_grid, cudaMemcpyHostToDevice));
+    delete[] field.field;
+    field.field = field_d;
+    CudaCheckError();
+}
+
+void GridGpuStrategy::copyAndFreeFieldFromGPU(Field& field)
+{
+    char *field_h = new char[field.size];
+    CudaSafeCall(cudaMemcpy(field_h, field.field, field.size * sizeof(char), cudaMemcpyDeviceToHost));
+    CudaSafeCall(cudaFree(field.field));
+    CudaCheckError();
+    field.field = field_h;
+}
+
+void GridGpuStrategy::copyAndFreeDistributiondFromGPU(SPtr<GridImp> grid)
+{
+    unsigned long long distributionSize = grid->size * (grid->distribution.dir_end + 1);
+    real *f_host = new real[distributionSize];
+    CudaSafeCall(cudaMemcpy(f_host, grid->distribution.f, distributionSize * sizeof(real), cudaMemcpyDeviceToHost));
+    CudaSafeCall(cudaFree(grid->distribution.f));
+    CudaCheckError();
+    grid->distribution.f = f_host;
+}
+
+
+
+void GridGpuStrategy::copyAndFreeNeighborsToCPU(SPtr<GridImp> grid)
+{
+    int size_in_bytes_neighbors = grid->size * sizeof(int);
+    int *neighborIndexX_h, *neighborIndexY_h, *neighborIndexZ_h, *neighborIndexNegative_h;
+    neighborIndexX_h        = new int[grid->size];
+    neighborIndexY_h        = new int[grid->size];
+    neighborIndexZ_h        = new int[grid->size];
+    neighborIndexNegative_h = new int[grid->size];
+
+    CudaSafeCall(cudaMemcpy(neighborIndexX_h,        grid->neighborIndexX,        size_in_bytes_neighbors, cudaMemcpyDeviceToHost));
+    CudaSafeCall(cudaMemcpy(neighborIndexY_h,        grid->neighborIndexY,        size_in_bytes_neighbors, cudaMemcpyDeviceToHost));
+    CudaSafeCall(cudaMemcpy(neighborIndexZ_h,        grid->neighborIndexZ,        size_in_bytes_neighbors, cudaMemcpyDeviceToHost));
+    CudaSafeCall(cudaMemcpy(neighborIndexNegative_h, grid->neighborIndexNegative, size_in_bytes_neighbors, cudaMemcpyDeviceToHost));
+
+    CudaSafeCall(cudaFree(grid->neighborIndexX));
+    CudaSafeCall(cudaFree(grid->neighborIndexY));
+    CudaSafeCall(cudaFree(grid->neighborIndexZ));
+    CudaSafeCall(cudaFree(grid->neighborIndexNegative));
+
+    grid->neighborIndexX        = neighborIndexX_h;
+    grid->neighborIndexY        = neighborIndexY_h;
+    grid->neighborIndexZ        = neighborIndexZ_h;
+    grid->neighborIndexNegative = neighborIndexNegative_h;
+    CudaCheckError();
+}
+
+void GridGpuStrategy::copyAndFreeMatrixIndicesFromGPU(SPtr<GridImp> grid, int size)
+{
+    int size_in_bytes_nodes_reduced = size * sizeof(int);
+    int *indices_reduced_h = new int[size];
+    CudaSafeCall(cudaMemcpy(indices_reduced_h, grid->sparseIndices, size_in_bytes_nodes_reduced, cudaMemcpyDeviceToHost));
+    CudaSafeCall(cudaFree(grid->sparseIndices));
+    grid->sparseIndices = indices_reduced_h;
+    CudaCheckError();
+}
+
+
+void GridGpuStrategy::copyAndFreeGridInterfaceFromGPU(SPtr<GridImp> grid)
+{
+    GridInterface *gridInterface = new GridInterface();
+    CudaSafeCall(cudaMemcpy(gridInterface, grid->gridInterface, sizeof(GridInterface), cudaMemcpyDeviceToHost));
+
+    uint *cfc = new uint[gridInterface->cf.numberOfEntries];
+    uint *cff = new uint[gridInterface->cf.numberOfEntries];
+    uint *fcc = new uint[gridInterface->fc.numberOfEntries];
+    uint *fcf = new uint[gridInterface->fc.numberOfEntries];
+
+
+    CudaSafeCall(cudaMemcpy(cfc, gridInterface->cf.coarse, gridInterface->cf.numberOfEntries * sizeof(uint), cudaMemcpyDeviceToHost));
+    CudaSafeCall(cudaMemcpy(cff, gridInterface->cf.fine, gridInterface->cf.numberOfEntries * sizeof(uint), cudaMemcpyDeviceToHost));
+    CudaSafeCall(cudaMemcpy(fcc, gridInterface->fc.coarse, gridInterface->fc.numberOfEntries * sizeof(uint), cudaMemcpyDeviceToHost));
+    CudaSafeCall(cudaMemcpy(fcf, gridInterface->fc.fine, gridInterface->fc.numberOfEntries * sizeof(uint), cudaMemcpyDeviceToHost));
+    CudaSafeCall(cudaFree(gridInterface->cf.coarse));
+    CudaSafeCall(cudaFree(gridInterface->cf.fine));
+    CudaSafeCall(cudaFree(gridInterface->fc.coarse));
+    CudaSafeCall(cudaFree(gridInterface->fc.fine));
+    CudaSafeCall(cudaFree(grid->gridInterface));
+
+    grid->gridInterface = gridInterface;
+    grid->gridInterface->cf.coarse = cfc;
+    grid->gridInterface->cf.fine = cff;
+    grid->gridInterface->fc.coarse = fcc;
+    grid->gridInterface->fc.fine = fcf;
+    CudaCheckError();
+}
diff --git a/src/gpu/GridGenerator/grid/GridStrategy/GridGpuStrategy/GridGpuStrategy.h b/src/gpu/GridGenerator/grid/GridStrategy/GridGpuStrategy/GridGpuStrategy.h
new file mode 100644
index 000000000..fb886824a
--- /dev/null
+++ b/src/gpu/GridGenerator/grid/GridStrategy/GridGpuStrategy/GridGpuStrategy.h
@@ -0,0 +1,76 @@
+#ifndef GRID_GPU_STRATEGY_H
+#define GRID_GPU_STRATEGY_H
+
+#include "global.h"
+
+#include "grid/GridStrategy/GridStrategy.h"
+
+class BoundingBox;
+class TriangularMesh;
+
+class GRIDGENERATOR_EXPORT GridGpuStrategy : public GridStrategy
+{
+public:
+    virtual ~GridGpuStrategy() {};
+
+    void allocateGridMemory(SPtr<GridImp> grid) override;
+
+	void allocateQs(SPtr<GridImp> grid) override;
+	
+	void initalNodesToOutOfGrid(SPtr<GridImp> grid) override;
+    void fixOddCells(SPtr<GridImp> grid) override;
+    void findInnerNodes(SPtr<GridImp> grid) override;
+    void addOverlap(SPtr<GridImp> grid) override;
+    void fixRefinementIntoWall(SPtr<GridImp> grid) override;
+    void findStopperNodes(SPtr<GridImp> grid) override;
+	void findBoundarySolidNodes(SPtr<GridImp> grid)  override;
+	void findEndOfGridStopperNodes(SPtr<GridImp> grid) override;
+	void findSolidStopperNodes(SPtr<GridImp> grid) override;
+
+    void mesh(SPtr<GridImp> grid, TriangularMesh &geom) override;
+
+    uint closeNeedleCells(SPtr<GridImp> grid) override;
+    uint closeNeedleCellsThinWall(SPtr<GridImp> grid) override;
+
+    void findQs(SPtr<GridImp> grid, TriangularMesh &geom) override;
+
+
+    void findGridInterface(SPtr<GridImp> grid, SPtr<GridImp> fineGrid, LbmOrGks lbmOrGks) override;
+
+    void freeMemory(SPtr<GridImp> grid) override;
+
+
+
+    void copyAndFreeGridInterfaceFromGPU(SPtr<GridImp> grid);
+    virtual void copyDataFromGPU(SPtr<GridImp> grid);
+
+	//void markNodesToDeleteOutsideOfGeometry();
+
+private:
+    void allocField(SPtr<GridImp> grid);
+    void allocDistribution(SPtr<GridImp> grid);
+    void allocNeighborsIndices(SPtr<GridImp> grid);
+    void allocMatrixIndicesOnGPU(SPtr<GridImp> grid);
+
+    void allocAndCopyTrianglesToGPU(TriangularMesh &geom);
+    void freeTrianglesFromGPU(const TriangularMesh &geom);
+
+
+    void allocAndCopyMatrixIndicesToGPU(SPtr<GridImp> grid, const uint& size);
+
+    void allocAndCopyFieldToGPU(Field& field);
+    void copyAndFreeFieldFromGPU(Field& field);
+
+    void copyAndFreeDistributiondFromGPU(SPtr<GridImp> grid);
+
+    void copyAndFreeNeighborsToCPU(SPtr<GridImp> grid);
+    void copyAndFreeMatrixIndicesFromGPU(SPtr<GridImp> grid, int size);
+
+public:
+    void allocateFieldMemory(Field* field) override;
+    void freeFieldMemory(Field* field) override;
+    void findSparseIndices(SPtr<GridImp> coarseGrid, SPtr<GridImp> fineGrid) override;
+    
+};
+
+#endif
diff --git a/src/gpu/GridGenerator/grid/GridStrategy/GridStrategy.h b/src/gpu/GridGenerator/grid/GridStrategy/GridStrategy.h
index 6d7f0f2c0..f1cf20f25 100644
--- a/src/gpu/GridGenerator/grid/GridStrategy/GridStrategy.h
+++ b/src/gpu/GridGenerator/grid/GridStrategy/GridStrategy.h
@@ -40,28 +40,42 @@
 #include "grid/Field.h"
 
 struct Vertex;
+class TriangularMesh;
 class GridImp;
 
 class GRIDGENERATOR_EXPORT GridStrategy
 {
 public:
-    virtual ~GridStrategy() {}
-
-    virtual void allocateFieldMemory(Field* field) = 0;
-    virtual void freeFieldMemory(Field* field) = 0;
+    virtual void allocateFieldMemory(Field *field) = 0;
+    virtual void freeFieldMemory(Field *field)     = 0;
 
     virtual void allocateGridMemory(SPtr<GridImp> grid) = 0;
 
+    virtual void allocateQs(SPtr<GridImp> grid) = 0;
+
     virtual void initalNodesToOutOfGrid(SPtr<GridImp> grid) = 0;
-    virtual void findInnerNodes(SPtr<GridImp> grid) = 0;
+    virtual void fixOddCells(SPtr<GridImp> grid)            = 0;
+    virtual void findInnerNodes(SPtr<GridImp> grid)         = 0;
+    virtual void addOverlap(SPtr<GridImp> grid)             = 0;
 
-	virtual void findEndOfGridStopperNodes(SPtr<GridImp> grid) = 0;
+    virtual void fixRefinementIntoWall(SPtr<GridImp> grid)     = 0;
+    virtual void findStopperNodes(SPtr<GridImp> grid)          = 0;
+    virtual void findBoundarySolidNodes(SPtr<GridImp> grid)    = 0;
+    virtual void findEndOfGridStopperNodes(SPtr<GridImp> grid) = 0;
+    virtual void findSolidStopperNodes(SPtr<GridImp> grid)     = 0;
 
-    virtual void findSparseIndices(SPtr<GridImp> coarseGrid, SPtr<GridImp> fineGrid) = 0;
+    virtual void mesh(SPtr<GridImp> grid, TriangularMesh &geom) = 0;
 
+    virtual uint closeNeedleCells(SPtr<GridImp> grid)         = 0;
+    virtual uint closeNeedleCellsThinWall(SPtr<GridImp> grid) = 0;
 
-    virtual void freeMemory(SPtr<GridImp> grid) = 0;
+    virtual void findQs(SPtr<GridImp> grid, TriangularMesh &geom) = 0;
 
+    virtual void findGridInterface(SPtr<GridImp> grid, SPtr<GridImp> fineGrid, LbmOrGks lbmOrGks) = 0;
+
+    virtual void findSparseIndices(SPtr<GridImp> coarseGrid, SPtr<GridImp> fineGrid) = 0;
+
+    virtual void freeMemory(SPtr<GridImp> grid) = 0;
 };
 
 #endif
diff --git a/src/gpu/GridGenerator/grid/NodeValues.h b/src/gpu/GridGenerator/grid/NodeValues.h
index 36ed127de..5ecd9bce6 100644
--- a/src/gpu/GridGenerator/grid/NodeValues.h
+++ b/src/gpu/GridGenerator/grid/NodeValues.h
@@ -33,34 +33,78 @@
 #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
+
+//#define FLUID 0
+//
+//#define FLUID_CFC 1
+//#define FLUID_CFF 2
+//
+//#define FLUID_FCC 3
+//#define FLUID_FCF 4
+//
+//#define MULTI_GPU_SEND 10
+//#define MULTI_GPU_RECIEVE 11
+//
+//#define BC_PRESSURE 20
+//#define BC_VELOCITY 21
+//#define BC_SOLID 22
+//
+//#define BC_SLIP 23
+//#define BC_NOSLIP 24
+//#define BC_OUTFLOW 25
+//
+//#define STOPPER_OUT_OF_GRID 30
+//#define STOPPER_COARSE_UNDER_FINE 31
+//#define STOPPER_SOLID 32
+//#define STOPPER_OUT_OF_GRID_BOUNDARY 33
+//
+//#define INVALID_OUT_OF_GRID 40
+//#define INVALID_COARSE_UNDER_FINE 41
+//#define INVALID_SOLID 42
+//
+//#define NEGATIVE_DIRECTION_BORDER = 51;
+//
+//#define OVERLAP_TMP 60
 
 #endif
diff --git a/src/gpu/GridGenerator/grid/distributions/D3Q13.h b/src/gpu/GridGenerator/grid/distributions/D3Q13.h
new file mode 100644
index 000000000..f314b970c
--- /dev/null
+++ b/src/gpu/GridGenerator/grid/distributions/D3Q13.h
@@ -0,0 +1,70 @@
+#ifndef D3Q13_H
+#define D3Q13_H
+
+#define DIR_13_R 0
+#define DIR_13_NE 1
+#define DIR_13_SW 2
+#define DIR_13_SE 3
+#define DIR_13_NW 4
+#define DIR_13_TE 5
+#define DIR_13_BW 6
+#define DIR_13_BE 7
+#define DIR_13_TW 8
+#define DIR_13_TN 9
+#define DIR_13_BS 10
+#define DIR_13_BN 11
+#define DIR_13_TS 12
+
+#define DIR_13_START  0
+#define DIR_13_END   12
+
+
+#define DIR_13_NE_X  1
+#define DIR_13_NE_Y  1
+#define DIR_13_NE_Z  0
+
+#define DIR_13_SW_X  -1
+#define DIR_13_SW_Y  -1
+#define DIR_13_SW_Z  0
+
+#define DIR_13_SE_X  1
+#define DIR_13_SE_Y  -1
+#define DIR_13_SE_Z  0
+
+#define DIR_13_NW_X  -1
+#define DIR_13_NW_Y  1
+#define DIR_13_NW_Z  0
+
+#define DIR_13_TE_X  1
+#define DIR_13_TE_Y  0
+#define DIR_13_TE_Z  1
+
+#define DIR_13_BW_X  -1
+#define DIR_13_BW_Y  0
+#define DIR_13_BW_Z  -1
+
+#define DIR_13_BE_X  1
+#define DIR_13_BE_Y  0
+#define DIR_13_BE_Z  -1
+
+#define DIR_13_TW_X  -1
+#define DIR_13_TW_Y  0
+#define DIR_13_TW_Z  1
+
+#define DIR_13_TN_X  0
+#define DIR_13_TN_Y  1
+#define DIR_13_TN_Z  1
+
+#define DIR_13_BS_X  0
+#define DIR_13_BS_Y  -1
+#define DIR_13_BS_Z  -1
+
+#define DIR_13_BN_X  0
+#define DIR_13_BN_Y  1
+#define DIR_13_BN_Z  -1
+
+#define DIR_13_TS_X  0
+#define DIR_13_TS_Y  -1
+#define DIR_13_TS_Z  1
+
+#endif
diff --git a/src/gpu/GridGenerator/grid/distributions/D3Q19.h b/src/gpu/GridGenerator/grid/distributions/D3Q19.h
new file mode 100644
index 000000000..3f48a3bb1
--- /dev/null
+++ b/src/gpu/GridGenerator/grid/distributions/D3Q19.h
@@ -0,0 +1,100 @@
+#ifndef D3Q19_H_
+#define D3Q19_H_
+
+#define DIR_19_E    0
+#define DIR_19_W    1
+#define DIR_19_N    2
+#define DIR_19_S    3
+#define DIR_19_T    4
+#define DIR_19_B    5
+#define DIR_19_NE   6
+#define DIR_19_SW   7
+#define DIR_19_SE   8
+#define DIR_19_NW   9
+#define DIR_19_TE   10
+#define DIR_19_BW   11
+#define DIR_19_BE   12
+#define DIR_19_TW   13
+#define DIR_19_TN   14
+#define DIR_19_BS   15
+#define DIR_19_BN   16
+#define DIR_19_TS   17
+#define DIR_19_ZERO 18
+
+#define DIR_19_START  0
+#define DIR_19_END   18
+
+
+#define DIR_19_E_X  1
+#define DIR_19_E_Y  0
+#define DIR_19_E_Z  0
+            
+#define DIR_19_W_X  -1
+#define DIR_19_W_Y  0
+#define DIR_19_W_Z  0
+            
+#define DIR_19_N_X  0
+#define DIR_19_N_Y  1
+#define DIR_19_N_Z  0
+            
+#define DIR_19_S_X  0
+#define DIR_19_S_Y  -1
+#define DIR_19_S_Z  0
+            
+#define DIR_19_T_X  0
+#define DIR_19_T_Y  0
+#define DIR_19_T_Z  1
+            
+#define DIR_19_B_X  0
+#define DIR_19_B_Y  0
+#define DIR_19_B_Z  -1
+
+#define DIR_19_NE_X  1
+#define DIR_19_NE_Y  1
+#define DIR_19_NE_Z  0
+             
+#define DIR_19_SW_X  -1
+#define DIR_19_SW_Y  -1
+#define DIR_19_SW_Z  0
+             
+#define DIR_19_SE_X  1
+#define DIR_19_SE_Y  -1
+#define DIR_19_SE_Z  0
+             
+#define DIR_19_NW_X  -1
+#define DIR_19_NW_Y  1
+#define DIR_19_NW_Z  0
+             
+#define DIR_19_TE_X  1
+#define DIR_19_TE_Y  0
+#define DIR_19_TE_Z  1
+             
+#define DIR_19_BW_X  -1
+#define DIR_19_BW_Y  0
+#define DIR_19_BW_Z  -1
+             
+#define DIR_19_BE_X  1
+#define DIR_19_BE_Y  0
+#define DIR_19_BE_Z  -1
+             
+#define DIR_19_TW_X  -1
+#define DIR_19_TW_Y  0
+#define DIR_19_TW_Z  1
+             
+#define DIR_19_TN_X  0
+#define DIR_19_TN_Y  1
+#define DIR_19_TN_Z  1
+             
+#define DIR_19_BS_X  0
+#define DIR_19_BS_Y  -1
+#define DIR_19_BS_Z  -1
+             
+#define DIR_19_BN_X  0
+#define DIR_19_BN_Y  1
+#define DIR_19_BN_Z  -1
+             
+#define DIR_19_TS_X  0
+#define DIR_19_TS_Y  -1
+#define DIR_19_TS_Z  1
+
+#endif
diff --git a/src/gpu/GridGenerator/grid/distributions/D3Q7.h b/src/gpu/GridGenerator/grid/distributions/D3Q7.h
new file mode 100644
index 000000000..6654cc147
--- /dev/null
+++ b/src/gpu/GridGenerator/grid/distributions/D3Q7.h
@@ -0,0 +1,41 @@
+#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/grid/kernel/runGridKernelGPU.cu b/src/gpu/GridGenerator/grid/kernel/runGridKernelGPU.cu
new file mode 100644
index 000000000..ff9a60d78
--- /dev/null
+++ b/src/gpu/GridGenerator/grid/kernel/runGridKernelGPU.cu
@@ -0,0 +1,220 @@
+#include "runGridKernelGPU.cuh"
+
+#include "utilities/cuda/cudaDefines.h"
+#include "utilities/cuda/cudaKernelCall.h"
+#include "utilities/cuda/LaunchParameter.cuh"
+#include "grid/GridImp.h"
+#include "geometries/TriangularMesh/TriangularMesh.h"
+
+GLOBAL void initalField(GridImp grid);
+GLOBAL void runMeshing(GridImp grid, const TriangularMesh geom);
+
+GLOBAL void findGridInterface(GridImp grid, GridImp finerGrid);
+GLOBAL void runKernelTomarkNodesToDeleteOutsideOfGeometry(GridImp grid);
+GLOBAL void markNodesToDeleteOutsideOfGeometry(GridImp grid);
+GLOBAL void findNeighborIndicesKernel(GridImp grid);
+GLOBAL void setOverlapNodesToInvalid(GridImp grid, GridImp finderGrid);
+
+//////////////////////////////////////////////////////////////////////////
+
+float runKernelInitalUniformGrid3d(const LaunchParameter& para, GridImp &grid)
+{
+    return runKernel(initalField, para, grid);
+}
+
+GLOBAL void initalField(GridImp grid)
+{
+    //TODO: outcomment because of nvlink warning caused by the new allocation in Cell().
+    //uint index = LaunchParameter::getGlobalIdx_2D_1D();
+    //if (index < grid.getSize())
+    //    grid.findInnerNode(index);
+}
+
+//////////////////////////////////////////////////////////////////////////
+
+float runKernelToMesh(const LaunchParameter& para, GridImp &grid, const TriangularMesh &geom)
+{
+    return runKernel(runMeshing, para, grid, geom);
+}
+
+GLOBAL void runMeshing(GridImp grid, const TriangularMesh geom)
+{
+    // TODO: outcomment because of nvlink warning caused by the new allocation in Cell().
+    //unsigned int i = LaunchParameter::getGlobalIdx_1D_1D();
+    //if (i < geom.size)
+    //    grid.mesh(geom.triangles[i]);
+}
+
+//////////////////////////////////////////////////////////////////////////
+
+float runKernelToMarkNodesToDeleteOutsideOfGeometry(const LaunchParameter& para, GridImp &grid)
+{
+    return runKernel(markNodesToDeleteOutsideOfGeometry, para, grid);
+}
+
+GLOBAL void markNodesToDeleteOutsideOfGeometry(GridImp grid)
+{
+    //int numberOfEdgeNodes = grid.ny * grid.nz;
+    //unsigned int i = LaunchParameter::getGlobalIdx_1D_1D();
+
+    //if (i < numberOfEdgeNodes)
+    //{
+    //    int x = 0;
+    //    int y = i % grid.ny;
+    //    int z = i / grid.ny;
+
+    //    grid.setFieldEntryToSolid(grid.transCoordToIndex(x, y, z));
+
+    //    while (grid.isFluid(i) && x < grid.nx - 1)
+    //    {
+    //        x += 1;
+    //        grid.setFieldEntryToSolid(grid.transCoordToIndex(x, y, z));
+    //    }
+    //}
+
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+
+float runKernelSetOverlapNodesToInvalid(const LaunchParameter& para, GridImp &grid, GridImp &finerGrid)
+{
+    return runKernel(setOverlapNodesToInvalid, para, grid, finerGrid);
+}
+
+GLOBAL void setOverlapNodesToInvalid(GridImp grid, GridImp finerGrid)
+{
+	// not up to date
+    //const uint index = LaunchParameter::getGlobalIdx_2D_1D();
+    //if (index < grid.getSize())
+        //grid.findGridInterfaceCF(index, finerGrid);
+}
+
+
+
+/*#################################################################################*/
+/*---------------------------------find invalid nodes------------------------------*/
+/*---------------------------------------------------------------------------------*/
+GLOBAL void setInvalidNodes(GridImp grid, bool *foundInvalidNode);
+/*---------------------------------------------------------------------------------*/
+
+float runKernelSetToInvalid(const LaunchParameter& para, GridImp &grid)
+{
+    bool* foundInvalidNode_d;
+    bool* foundInvalidNode_h = new bool();
+    *foundInvalidNode_h = true;
+    CudaSafeCall( cudaMalloc(&foundInvalidNode_d, sizeof(bool)));
+    CudaCheckError();
+    cudaEvent_t start, stop;
+    cudaEventCreate(&start);
+    cudaEventCreate(&stop);
+    cudaEventRecord(start, 0);
+
+    while (*foundInvalidNode_h)
+    {
+        *foundInvalidNode_h = false;
+        CudaSafeCall(cudaMemcpy(foundInvalidNode_d, foundInvalidNode_h, sizeof(bool), cudaMemcpyHostToDevice));
+        setInvalidNodes << <para.blocks, para.threads >> >(grid, foundInvalidNode_d);
+        cudaDeviceSynchronize();
+        CudaCheckError();
+
+        CudaSafeCall(cudaMemcpy(foundInvalidNode_h, foundInvalidNode_d, sizeof(bool), cudaMemcpyDeviceToHost));
+    }
+
+    cudaDeviceSynchronize();
+    cudaEventRecord(stop, 0);
+    cudaEventSynchronize(stop);
+    float elapsedTime;
+    cudaEventElapsedTime(&elapsedTime, start, stop);
+
+    cudaEventDestroy(start);
+    cudaEventDestroy(stop);
+
+    CudaCheckError();
+    cudaFree(foundInvalidNode_d);
+    delete foundInvalidNode_h;
+
+    return elapsedTime;
+}
+
+
+GLOBAL void setInvalidNodes(GridImp grid, bool *foundInvalidNode)
+{
+    // not up to date
+    //uint index = LaunchParameter::getGlobalIdx_2D_1D();
+    ////if (index < grid.getSize())
+    //    //grid.setInsideNode(index, *foundInvalidNode);
+}
+
+
+/*#################################################################################*/
+
+float runKernelFindIndices(const LaunchParameter& para, GridImp &grid)
+{
+    return runKernel(findNeighborIndicesKernel, para, grid);
+}
+
+GLOBAL void findNeighborIndicesKernel(GridImp grid)
+{
+    // not up to date
+    //uint index = LaunchParameter::getGlobalIdx_2D_1D();
+    //if (index < grid.getSize())
+    //    grid.setNeighborIndices(index);
+}
+
+
+/*#################################################################################*/
+
+float runKernelToFindGridInterface(const LaunchParameter& para, GridImp &grid, GridImp &finerGrid)
+{
+    return runKernel(findGridInterface, para, grid, finerGrid);
+}
+
+GLOBAL void findGridInterface(GridImp grid, GridImp finerGrid)
+{
+	// not up to date
+    //uint index = LaunchParameter::getGlobalIdx_2D_1D();
+    //if (index < grid.getSize())
+    //    grid.findGridInterfaceCF(index, finerGrid);
+}
+/*#################################################################################*/
+
+GLOBAL void findNeighborsNewIndices(GridImp grid);
+float runKernelToFindNeighborsNewIndices(const LaunchParameter& para, GridImp &grid)
+{
+    return runKernel(findNeighborsNewIndices, para, grid);
+}
+
+GLOBAL void findNeighborsNewIndices(GridImp grid)
+{
+    // not up to date
+    //unsigned int index = LaunchParameter::getGlobalIdx_2D_1D();
+    //if (index < grid.getSize())
+    //    grid.setNeighborIndices(index);
+}
+/*#################################################################################*/
+
+GLOBAL void findGridInterfaceNewIndicesFC(GridImp grid);
+GLOBAL void findGridInterfaceNewIndicesCF(GridImp grid);
+float runKernelToFindGridInterfaceNewIndices(const LaunchParameter& para, GridImp &grid)
+{
+    runKernel(findGridInterfaceNewIndicesCF, para, grid);
+    return runKernel(findGridInterfaceNewIndicesFC, para, grid);
+}
+
+
+GLOBAL void findGridInterfaceNewIndicesCF(GridImp grid)
+{
+    // not up to date
+    //unsigned int index = LaunchParameter::getGlobalIdx_2D_1D();
+    //if (index < grid.getNumberOfNodesCF())
+        //grid.findForGridInterfaceSparseIndexCF(index);
+}
+
+GLOBAL void findGridInterfaceNewIndicesFC(GridImp grid)
+{
+    // not up to date
+    // unsigned int index = LaunchParameter::getGlobalIdx_2D_1D();
+    //if (index < grid.getNumberOfNodesFC())
+    //    grid.findForGridInterfaceSparseIndexFCcoarse(index);
+}
diff --git a/src/gpu/GridGenerator/grid/kernel/runGridKernelGPU.cuh b/src/gpu/GridGenerator/grid/kernel/runGridKernelGPU.cuh
new file mode 100644
index 000000000..e63e42881
--- /dev/null
+++ b/src/gpu/GridGenerator/grid/kernel/runGridKernelGPU.cuh
@@ -0,0 +1,23 @@
+#ifndef runGridKernelGPU_H
+#define runGridKernelGPU_H
+
+
+class Grid;
+class GridImp;
+class TriangularMesh;
+class LaunchParameter;
+
+float runKernelInitalUniformGrid3d(const LaunchParameter& para, GridImp &grid);
+float runKernelToMesh(const LaunchParameter& para, GridImp &grid, const TriangularMesh &geom);
+float runKernelToMarkNodesToDeleteOutsideOfGeometry(const LaunchParameter& para, GridImp &grid);
+
+float runKernelToFindGridInterface(const LaunchParameter& para, GridImp &grid, GridImp &finerGrid);
+float runKernelToFindNeighborsNewIndices(const LaunchParameter& para, GridImp &grid);
+float runKernelToFindGridInterfaceNewIndices(const LaunchParameter& para, GridImp &grid);
+
+
+float runKernelSetOverlapNodesToInvalid(const LaunchParameter& para, GridImp &grid, GridImp &finerGrid);
+float runKernelSetToInvalid(const LaunchParameter& para, GridImp &grid);
+float runKernelFindIndices(const LaunchParameter& para, GridImp &grid);
+
+#endif
diff --git a/src/gpu/GridGenerator/grid/partition/Partition.cpp b/src/gpu/GridGenerator/grid/partition/Partition.cpp
new file mode 100644
index 000000000..970599105
--- /dev/null
+++ b/src/gpu/GridGenerator/grid/partition/Partition.cpp
@@ -0,0 +1,653 @@
+//#include "Partition.h"
+//
+//#include "metis.h"
+//#include <stdio.h>
+//#include <iostream>
+//
+//#include <global.h>
+//#include <GridGenerator/grid/Grid.h>
+//#include <GridGenerator/geometries/Triangle/Triangle.h>
+//#include <GridGenerator/geometries/Vertex/Vertex.h>
+//#include <GridGenerator/geometries/BoundingBox/BoundingBox.h>
+//#include <GridGenerator/io/GridVTKWriter/GridVTKWriter.h>
+//#include <GridGenerator/io/VTKWriterWrapper/UnstructuredGridWrapper.h>
+//#include <GridGenerator/utilities/Transformator/TransformatorImp.h>
+//
+//#include <utilities/logger/Logger.h>
+//
+//int Partition::calcEdgesFromGraph(SPtr<Grid> grid) 
+//{
+//    int insideNeighbors = 6;
+//    int cornerNeighbors = 3;
+//    int outsideEdgesNeighbors = 4;
+//    int ousiteAreaNeighbors = 5;
+//
+//    int corner = 8;
+//    int outsiteEdges = grid->getNumberOfNodesX() * 4 + grid->getNumberOfNodesY() * 4 + grid->getNumberOfNodesZ() * 4 - 24;
+//    int outsideArea = 2 * grid->getNumberOfNodesX()*grid->getNumberOfNodesY() + 2 * grid->getNumberOfNodesX()*grid->getNumberOfNodesZ() + 2 * grid->getNumberOfNodesY()*grid->getNumberOfNodesZ() - 8 * grid->getNumberOfNodesX() - 8 * grid->getNumberOfNodesY() - 8 * grid->getNumberOfNodesZ() + 24;
+//    int inside = grid->getSize() - corner - outsiteEdges - outsideArea;
+//    return inside * insideNeighbors + outsideArea * ousiteAreaNeighbors + outsiteEdges * outsideEdgesNeighbors + corner * cornerNeighbors;
+//}
+//
+//void Partition::partitionGridMesh(SPtr<Grid> grid) 
+//{
+//    printf("MESH\n");
+//
+//    idx_t nelements = (grid->getNumberOfNodesX() - 1) * (grid->getNumberOfNodesY() - 1) * (grid->getNumberOfNodesZ() - 1);
+//    idx_t nNodes = nelements * 8;
+//    idx_t nWeightsMesh = 1;
+//    idx_t nPartsMesh = 2;
+//
+//    idx_t *partMeshNodes = new idx_t[nNodes];
+//    idx_t *partMeshElements = new idx_t[nelements];
+//    idx_t objval;
+//
+//    // Indexes of starting points in adjacent array
+//    idx_t *eptr = new idx_t[nelements + 1];
+//
+//    for (int i = 0; i < nelements + 1; i++) {
+//        eptr[i] = i * 8;
+//    }
+//
+//    // Adjacent vertices in consecutive index order
+//    idx_t *eind = new idx_t[nNodes];
+//
+//    real x, y, z, newX, newY, newZ;
+//    int nIndex;
+//    int numberNode = 0;
+//    for (unsigned int index = 0; index < grid->getSize(); index++) {
+//        grid->transIndexToCoords(index, x, y, z);
+//
+//        newX = x + 1;
+//        newY = y + 1;
+//        newZ = z + 1;
+//        if (newX >= grid->getNumberOfNodesX() || newY >= grid->getNumberOfNodesY() || newZ >= grid->getNumberOfNodesZ())
+//            continue;
+//
+//        // self
+//        eind[numberNode] = index;
+//        numberNode++;
+//
+//        //+x
+//        nIndex = grid->transCoordToIndex(newX, y, z);
+//        eind[numberNode] = nIndex;
+//        numberNode++;
+//
+//        //x//+y
+//        nIndex = grid->transCoordToIndex(newX, newY, z);
+//        eind[numberNode] = nIndex;
+//        numberNode++;
+//
+//        //+y
+//        nIndex = grid->transCoordToIndex(x, newY, z);
+//        eind[numberNode] = nIndex;
+//        numberNode++;
+//
+//        //+z
+//        nIndex = grid->transCoordToIndex(x, y, newZ);
+//        eind[numberNode] = nIndex;
+//        numberNode++;
+//
+//        //+z//+x
+//        nIndex = grid->transCoordToIndex(newX, y, newZ);
+//        eind[numberNode] = nIndex;
+//        numberNode++;
+//
+//        //+z//+x//+y
+//        nIndex = grid->transCoordToIndex(newX, newY, newZ);
+//        eind[numberNode] = nIndex;
+//        numberNode++;
+//
+//        //+z//+y
+//        nIndex = grid->transCoordToIndex(x, newY, newZ);
+//        eind[numberNode] = nIndex;
+//        numberNode++;
+//
+//    }
+//
+//
+//    //for (int i = 0; i < nelements; i++) {
+//    //    printf("element %d: ", i);
+//    //    for (int v = eptr[i]; v < eptr[i + 1]; v++) {
+//    //        printf("%d ", eind[v]);
+//    //    }
+//    //    printf("\n");
+//    //}
+//
+//    // Weights of vertices
+//    // if all weights are equal then can be set to NULL
+//    //idx_t vwgtMesh[nNodes * nWeightsMesh] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 };
+//
+//    idx_t ncommon = 4;
+//
+//    rstatus_et ret = (rstatus_et)METIS_PartMeshDual(&nelements, &nNodes, eptr, eind,
+//        NULL, NULL, &ncommon, &nPartsMesh,
+//        NULL, NULL, &objval, partMeshElements, partMeshNodes);
+//
+//    std::cout << ret << std::endl;
+//
+//    for (int part_i = 0; part_i < nelements; part_i++){
+//        std::cout << part_i << " " << partMeshElements[part_i] << std::endl;
+//    }
+//
+//
+//    for (unsigned int part_i = 0; part_i < grid->getSize(); part_i++){
+//        //grid->setFieldEntry(part_i, partMeshNodes[part_i]);
+//    }
+//
+//    GridVTKWriter::writeSparseGridToVTK(grid, "../../../../metisGridMesh.vtk");
+//
+//    delete[] partMeshNodes;
+//    delete[] partMeshElements;
+//    delete[] eptr;
+//    delete[] eind;
+//}
+//
+//void Partition::partitionGrid(SPtr<Grid> grid) {
+//    idx_t nVertices = grid->getSize();
+//    idx_t nEdges = calcEdgesFromGraph(grid);
+//    idx_t nWeights = 1;
+//    idx_t nParts = 4;
+//
+//    idx_t objval;
+//    idx_t* part = new idx_t[nVertices];
+//    idx_t* xadj = new idx_t[nVertices + 1];
+//    idx_t* adjncy = new idx_t[nEdges];
+//
+//    xadj[0] = 0;
+//	real x, y, z, newX, newY, newZ;
+//    int nIndex;
+//    int numberOfNeighbors = 0;
+//    int counter = 0;
+//    for (int index = 0; index < nVertices; index++) {
+//        grid->transIndexToCoords(index, x, y, z);
+//        //+x 
+//        newX = x + 1;
+//        if (newX >= 0 && newX < grid->getNumberOfNodesX()) {
+//            nIndex = grid->transCoordToIndex(newX, y, z);
+//            adjncy[numberOfNeighbors] = nIndex;
+//            numberOfNeighbors++;
+//        }
+//        //-x
+//        newX = x - 1;
+//        if (newX >= 0 && newX < grid->getNumberOfNodesX()) {
+//            nIndex = grid->transCoordToIndex(newX, y, z);
+//            adjncy[numberOfNeighbors] = nIndex;
+//            numberOfNeighbors++;
+//        }
+//
+//        //+y
+//        newY = y + 1;
+//        if (newY >= 0 && newY < grid->getNumberOfNodesY()) {
+//            nIndex = grid->transCoordToIndex(x, newY, z);
+//            adjncy[numberOfNeighbors] = nIndex;
+//            numberOfNeighbors++;
+//        }
+//
+//        //-y
+//        newY = y - 1;
+//        if (newY >= 0 && newY < grid->getNumberOfNodesY()) {
+//            nIndex = grid->transCoordToIndex(x, newY, z);
+//            adjncy[numberOfNeighbors] = nIndex;
+//            numberOfNeighbors++;
+//        }
+//
+//        //+z
+//        newZ = z + 1;
+//        if (newZ >= 0 && newZ < grid->getNumberOfNodesZ()) {
+//            nIndex = grid->transCoordToIndex(x, y, newZ);
+//            adjncy[numberOfNeighbors] = nIndex;
+//            numberOfNeighbors++;
+//        }
+//
+//        //-z
+//        newZ = z - 1;
+//        if (newZ >= 0 && newZ < grid->getNumberOfNodesZ()) {
+//            nIndex = grid->transCoordToIndex(x, y, newZ);
+//            adjncy[numberOfNeighbors] = nIndex;
+//            numberOfNeighbors++;
+//        }
+//        xadj[index + 1] = numberOfNeighbors;
+//    }
+//
+//
+//    // Indexes of starting points in adjacent array
+//    //idx_t xadj[nVertices + 1] = { 0, 2, 5, 7, 9, 12, 14 };
+//
+//    // Adjacent vertices in consecutive index order
+//    //idx_t adjncy[2 * nEdges] = { 1, 3, 0, 4, 2, 1, 5, 0, 4, 3, 1, 5, 4, 2 };
+//
+//
+//    //for (int index = 0; index < nVertices; index++) {
+//    //    printf("vertexNachbarn von %d: ", index);
+//    //    printf("Grenzen: %d - %d, ", xadj[index], xadj[index + 1]);
+//    //    for (int v = xadj[index]; v < xadj[index + 1]; v++) {
+//    //        printf("%d ", adjncy[v]);
+//    //    }
+//    //    printf("\n");
+//    //}
+//
+//    // Weights of vertices
+//    // if all weights are equal then can be set to NULL
+//    //idx_t* vwgt = new idx_t[nVertices * nWeights];
+//
+//    idx_t options[METIS_NOPTIONS];
+//    METIS_SetDefaultOptions(options);
+//
+//    options[METIS_OPTION_OBJTYPE] = METIS_OBJTYPE_CUT; //minimizing the edge-cut communication
+//
+//    options[METIS_OPTION_NCUTS] = 1; // number of different partitioning //default 1
+//    options[METIS_OPTION_CONTIG] = 1; // force contiguous partitions
+//    options[METIS_OPTION_DBGLVL] = 0; //print debugging information
+//
+//    rstatus_et ret = (rstatus_et)METIS_PartGraphKway(&nVertices, &nWeights, xadj, adjncy,
+//        NULL, NULL, NULL, &nParts, NULL,
+//        NULL, options, &objval, part);
+//
+//    std::cout << ret << std::endl;
+//
+//    //for (unsigned part_i = 0; part_i < nVertices; part_i++){
+//    //    std::cout << part_i << " " << part[part_i] << std::endl;
+//    //}
+//
+//    for (int part_i = 0; part_i < nVertices; part_i++){
+//        //grid->setFieldEntry(part_i, part[part_i]);
+//    }
+//
+//    GridVTKWriter::writeSparseGridToVTK(grid, "../../../../metisGridFineFourParts.vtk");
+//}
+//
+//std::vector<std::vector<int> > Partition::partitionBoxes(std::vector<std::vector<BoundingBox> > boxes, int processes, std::vector< std::shared_ptr<Transformator> > transformators)
+//{
+//    if (processes == 1){
+//        std::vector<std::vector<int> > tasks;
+//        tasks.resize(processes);
+//        tasks[0].push_back(0);
+//        tasks[0].push_back(0);
+//        return tasks;
+//    }
+//
+//    std::vector<idx_t> xadj;
+//    std::vector<idx_t> adjncy;
+//
+//    int numberOfNeighbors = 0;
+//    xadj.push_back(0);
+//    for (int level = 0; level < boxes.size(); level++) {
+//        for (int i = 0; i < boxes[level].size(); i++) {
+//        	
+//			BoundingBox box = boxes[level][i];
+//            transformators[level]->transformGridToWorld(box);
+//
+//            int index = i + (int)boxes[level].size() * level;
+//            for (int levelCompare = 0; levelCompare < boxes.size(); levelCompare++) {
+//                for (int iCompare = 0; iCompare < boxes[levelCompare].size(); iCompare++) {
+//                    int indexCompare = iCompare + (int)boxes[levelCompare].size() * levelCompare;
+//                    if (index == indexCompare)
+//                        continue;
+//
+//					BoundingBox boxCompare = boxes[levelCompare][iCompare];
+//                    transformators[level]->transformGridToWorld(boxCompare);
+//                    if (box.intersect(boxCompare)) {
+//                        adjncy.push_back(indexCompare);
+//                        numberOfNeighbors++;
+//                    }
+//                }
+//            }
+//            xadj.push_back(numberOfNeighbors);
+//        }
+//    }
+//
+//    //logging::Logger::getInstance()->logTerminal("Metis Graph Structure:");
+//    //for (int index = 0; index < xadj.size() - 1; index++) {
+//    //    logging::Logger::getInstance()->logTerminal("vertex neighbor [" + SSTR(index) + "]");
+//    //    logging::Logger::getInstance()->logTerminal(" boundary: " + SSTR(xadj[index]) + " - " + SSTR(xadj[index + 1]) + ",");
+//    //    for (int v = xadj[index]; v < xadj[index + 1]; v++) {
+//    //        logging::Logger::getInstance()->logTerminal(SSTR(adjncy[v]) + " ");
+//    //    }
+//    //    logging::Logger::getInstance()->logTerminal("\n");
+//    //}
+//
+//    // Weights of vertices
+//    // if all weights are equal then can be set to NULL
+//    //idx_t* vwgt = new idx_t[nVertices * nWeights];
+//
+//    idx_t options[METIS_NOPTIONS];
+//    METIS_SetDefaultOptions(options);
+//
+//    options[METIS_OPTION_OBJTYPE] = METIS_OBJTYPE_CUT; //minimizing the edge-cut communication
+//
+//    options[METIS_OPTION_NCUTS] = 1; // number of different partitioning //default 1
+//    options[METIS_OPTION_CONTIG] = 1; // force contiguous partitions
+//    options[METIS_OPTION_DBGLVL] = 0; //print debugging information
+//
+//    idx_t nVertices = (idx_t)xadj.size() - 1;
+//    idx_t nWeights = 1;
+//    idx_t nParts = processes;
+//
+//    idx_t objval;
+//    idx_t* part = new idx_t[nVertices];
+//
+//    //rstatus_et ret = (rstatus_et)METIS_PartGraphKway(&nVertices, &nWeights, xadj.data(), adjncy.data(),
+//    //    NULL, NULL, NULL, &nParts, NULL,
+//    //    NULL, options, &objval, part);
+//
+//    rstatus_et ret = (rstatus_et)METIS_PartGraphRecursive(&nVertices, &nWeights, xadj.data(), adjncy.data(),
+//        NULL, NULL, NULL, &nParts, NULL,
+//        NULL, options, &objval, part);
+//
+//	if (ret == METIS_OK)
+//		*logging::out << logging::Logger::INFO_INTERMEDIATE << "Metis Status: OK\n";
+//
+//    
+//
+//    for (int part_i = 0; part_i < nVertices; part_i++)
+//		*logging::out << logging::Logger::INFO_INTERMEDIATE << "Block: " << part_i << " - Partition: " << part[part_i] << "\n";
+//    
+//
+//    std::vector<std::vector<int> > tasks;
+//    tasks.resize(processes);
+//    
+//    for (int i = 0; i < nVertices; i++) {
+//        int x = i % boxes[0].size();
+//        int level = (i - x) / (int)boxes[0].size();
+//        tasks[part[i]].push_back(level);
+//        tasks[part[i]].push_back(x);
+//    }
+//
+//    return tasks;
+//}
+//
+//std::vector<BoundingBox> Partition::getProcessBoxes(const int numberOfProcesses, const int globalNx, const int globalNy, const int globalNz)
+//{
+//    std::vector<BoundingBox> boxes;
+//	BoundingBox b(0, globalNx, 0, globalNy, 0, globalNz);
+//    boxes.push_back(b);
+//    if (numberOfProcesses == 1)
+//        return boxes;
+//
+//    bool splitX, splitY, splitZ;
+//    while (boxes.size() < numberOfProcesses)
+//	{
+//        findMaxBoxSize(boxes, splitX, splitY, splitZ);
+//        if (numberOfProcesses % 3 == 0)
+//            splitAllBoxesInThreePieces(boxes, splitX, splitY, splitZ);
+//        else 
+//            splitAllBoxesInTwoPieces(boxes, splitX, splitY, splitZ);
+//    }
+//    return boxes;
+//}
+//
+//std::vector<std::vector<Triangle> > Partition::getTrianglesPerProcess(std::vector<BoundingBox> &boxes, Triangle *triangles, int nTriangles)
+//{
+//    std::vector<Triangle> triangleVec;
+//    triangleVec.resize(nTriangles);
+//    for (int i = 0; i < nTriangles; i++)
+//        triangleVec[i] = triangles[i];
+//
+//    std::vector<std::vector<Triangle> > trianglesPerProcess;
+//    trianglesPerProcess.resize(boxes.size());
+//
+//    for (int j = 0; j < triangleVec.size(); j++) {
+//        for (int i = 0; i < boxes.size(); i++) {
+//            if (boxes[i].isInside(triangleVec[j])) {
+//                trianglesPerProcess[i].push_back(triangleVec[j]);
+//                triangleVec.erase(triangleVec.begin() + j);
+//                j--;
+//                break;
+//            }
+//            else if (boxes[i].intersect(triangleVec[j])) {
+//                //splitAndPushTriangle(boxes[i], trianglesPerProcess[i], triangleVec, j);
+//                trianglesPerProcess[i].push_back(triangleVec[j]);
+//            }
+//        }
+//    }
+//    return trianglesPerProcess;
+//}
+//
+//void Partition::findMaxBoxSize(std::vector<BoundingBox> &boxes, bool &splitX, bool &splitY, bool &splitZ)
+//{
+//    int lengthX, lengthY, lengthZ;
+//    lengthX = boxes[0].maxX - boxes[0].minX;
+//    lengthY = boxes[0].maxY - boxes[0].minY;
+//    lengthZ = boxes[0].maxZ - boxes[0].minZ;
+//
+//    splitX = true, splitY = false, splitZ = false;
+//    if (lengthX < lengthY){
+//        splitX = splitZ = false;
+//        splitY = true;
+//    }
+//    else if (lengthY < lengthZ){
+//        splitX = splitY = false;
+//        splitZ = true;
+//    }
+//}
+//
+//void Partition::splitAllBoxesInThreePieces(std::vector<BoundingBox> &boxes, bool splitX, bool splitY, bool splitZ)
+//{
+//    std::vector<BoundingBox> boxesTemp;
+//    for (int i = 0; i < boxes.size(); i++) {
+//        if (splitX) {
+//            int newLengthX = (boxes[i].maxX - boxes[i].minX) / 3;
+//			BoundingBox splitBox1(boxes[i].minX, boxes[i].minX + newLengthX, boxes[i].minY, boxes[i].maxY, boxes[i].minZ, boxes[i].maxZ);
+//			BoundingBox splitBox2(boxes[i].minX, boxes[i].minX + newLengthX + newLengthX, boxes[i].minY, boxes[i].maxY, boxes[i].minZ, boxes[i].maxZ);
+//			BoundingBox splitBox3(boxes[i].minX + newLengthX + newLengthX, boxes[i].maxX, boxes[i].minY, boxes[i].maxY, boxes[i].minZ, boxes[i].maxZ);
+//            boxesTemp.push_back(splitBox1);
+//            boxesTemp.push_back(splitBox2);
+//            boxesTemp.push_back(splitBox3);
+//        }
+//        if (splitY) {
+//            int newLengthY = (boxes[i].maxY - boxes[i].minY) / 3;
+//			BoundingBox splitBox1(boxes[i].minX, boxes[i].maxX, boxes[i].minY, boxes[i].minY + newLengthY, boxes[i].minZ, boxes[i].maxZ);
+//			BoundingBox splitBox2(boxes[i].minX, boxes[i].maxX, boxes[i].minY + newLengthY, boxes[i].minY + newLengthY + newLengthY, boxes[i].minZ, boxes[i].maxZ);
+//			BoundingBox splitBox3(boxes[i].minX, boxes[i].maxX, boxes[i].minY + newLengthY + newLengthY, boxes[i].maxY, boxes[i].minZ, boxes[i].maxZ);
+//            boxesTemp.push_back(splitBox1);
+//            boxesTemp.push_back(splitBox2);
+//            boxesTemp.push_back(splitBox3);
+//        }
+//        if (splitZ) {
+//            int newLengthZ = (boxes[i].maxZ - boxes[i].minZ) / 3;
+//			BoundingBox splitBox1(boxes[i].minX, boxes[i].maxX, boxes[i].minY, boxes[i].maxY, boxes[i].minZ, boxes[i].minZ + newLengthZ);
+//			BoundingBox splitBox2(boxes[i].minX, boxes[i].maxX, boxes[i].minY, boxes[i].maxY, boxes[i].minZ + newLengthZ, boxes[i].minZ + newLengthZ + newLengthZ);
+//			BoundingBox splitBox3(boxes[i].minX, boxes[i].maxX, boxes[i].minY, boxes[i].maxY, boxes[i].minZ + newLengthZ + newLengthZ, boxes[i].maxZ);
+//            boxesTemp.push_back(splitBox1);
+//            boxesTemp.push_back(splitBox2);
+//            boxesTemp.push_back(splitBox3);
+//        }
+//    }
+//    boxes.clear();
+//    boxes = boxesTemp;
+//}
+//
+//void Partition::splitAllBoxesInTwoPieces(std::vector<BoundingBox> &boxes, bool splitX, bool splitY, bool splitZ)
+//{
+//    std::vector<BoundingBox> boxesTemp;
+//    for (int i = 0; i < boxes.size(); i++) {
+//        if (splitX) {
+//            int newLengthX = (boxes[i].maxX - boxes[i].minX) / 2;
+//			BoundingBox splitBox1(boxes[i].minX, boxes[i].minX + newLengthX, boxes[i].minY, boxes[i].maxY, boxes[i].minZ, boxes[i].maxZ);
+//			BoundingBox splitBox2(boxes[i].minX + newLengthX, boxes[i].maxX, boxes[i].minY, boxes[i].maxY, boxes[i].minZ, boxes[i].maxZ);
+//            boxesTemp.push_back(splitBox1);
+//            boxesTemp.push_back(splitBox2);
+//        }
+//        if (splitY) {
+//            int newLengthY = (boxes[i].maxY - boxes[i].minY) / 2;
+//			BoundingBox splitBox1(boxes[i].minX, boxes[i].maxX, boxes[i].minY, boxes[i].minY + newLengthY, boxes[i].minZ, boxes[i].maxZ);
+//			BoundingBox splitBox2(boxes[i].minX, boxes[i].maxX, boxes[i].minY + newLengthY, boxes[i].maxY, boxes[i].minZ, boxes[i].maxZ);
+//            boxesTemp.push_back(splitBox1);
+//            boxesTemp.push_back(splitBox2);
+//        }
+//        if (splitZ) {
+//            int newLengthZ = (boxes[i].maxZ - boxes[i].minZ) / 2;
+//			BoundingBox splitBox1(boxes[i].minX, boxes[i].maxX, boxes[i].minY, boxes[i].maxY, boxes[i].minZ, boxes[i].minZ + newLengthZ);
+//			BoundingBox splitBox2(boxes[i].minX, boxes[i].maxX, boxes[i].minY, boxes[i].maxY, boxes[i].minZ + newLengthZ, boxes[i].maxZ);
+//            boxesTemp.push_back(splitBox1);
+//            boxesTemp.push_back(splitBox2);
+//        }
+//    }
+//    boxes.clear();
+//    boxes = boxesTemp;
+//}
+//
+//std::vector<std::vector<Triangle> >  Partition::splitTriangles(std::vector<Triangle> &triangleVec, std::vector<BoundingBox> boxes)
+//{
+//    std::vector<std::vector<Triangle> > trianglesPerProcess;
+//    trianglesPerProcess.resize(boxes.size());
+//
+//    for (int j = 0; j < triangleVec.size(); j++) {
+//        for (int i = 0; i < boxes.size(); i++) {
+//            if (boxes[i].isInside(triangleVec[j])) {
+//                trianglesPerProcess[i].push_back(triangleVec[j]);
+//                triangleVec.erase(triangleVec.begin() + j);
+//                j--;
+//                break;
+//            }
+//            else if (boxes[i].intersect(triangleVec[j])) {
+//                splitAndPushTriangle(boxes[i], trianglesPerProcess[i], triangleVec, j);
+//                //trianglesPerProcess[i].push_back(triangleVec[j]);
+//            }
+//        }
+//    }
+//
+//    return trianglesPerProcess;
+//
+//}
+//
+//
+//
+//void Partition::splitAndPushTriangle(BoundingBox &box, std::vector<Triangle> &trianglesPerProcess, std::vector<Triangle> &triangleVec, int indexTriangle)
+//{
+//    Triangle triangleToSplit = triangleVec[indexTriangle];
+//	//BoundingBox triangleBox = BoundingBox::makeExactBox(triangleToSplit);
+//    //std::vector<std::vector<Vertex> > intersectionsBox = box.getIntersectionPoints(triangleBox);
+//
+//    //UnstructuredGridWriter writer;
+//    //double v1[3] = { triangleToSplit.v1.x, triangleToSplit.v1.y, triangleToSplit.v1.z };
+//    //double v2[3] = { triangleToSplit.v2.x, triangleToSplit.v2.y, triangleToSplit.v2.z };
+//    //double v3[3] = { triangleToSplit.v3.x, triangleToSplit.v3.y, triangleToSplit.v3.z };
+//    //writer.addTriangle(v1, v2, v3);
+//    //double b[6] = { box.minX, box.maxX, box.minY, box.maxY, box.minZ, box.maxZ };
+//    //writer.addBoundingBox(b);
+//    //double b2[6] = { triangleBox.minX, triangleBox.maxX, triangleBox.minY, triangleBox.maxY, triangleBox.minZ, triangleBox.maxZ };
+//    //writer.addBoundingBox(b2);
+//    //writer.writeUnstructuredGridToFile("testIntersectionTriangle");
+//
+//
+//    //for (int i = 0; i < intersectionsBox.size(); i++) {
+//    //    if (intersectionsBox[i].size() == 0)
+//    //        continue;
+//
+//    //    Vertex edge1 = intersectionsBox[i][0] - intersectionsBox[i][1];
+//    //    Vertex edge2 = intersectionsBox[i][1] - intersectionsBox[i][2];
+//    //    Vertex normal = edge1.crossProduct(edge2);
+//    //    normal.normalize();
+//
+//    //    Vertex point(intersectionsBox[i][0].x, intersectionsBox[i][0].y, intersectionsBox[i][0].z);
+//    //    Vertex v4 = (triangleToSplit.v1 - point);
+//    //    Vertex v5 = (triangleToSplit.v2 - point);
+//    //    Vertex v6 = (triangleToSplit.v3 - point);
+//
+//    //    real d1 = v4 * normal;
+//    //    real d2 = v5 * normal;
+//    //    real d3 = v6 * normal;
+//
+//    //    // a to b crosses the clipping plane
+//    //    if (d1 * d2 < 0.0f)
+//    //        sliceTriangle(trianglesPerProcess, triangleVec, indexTriangle, triangleToSplit.v1, triangleToSplit.v2, triangleToSplit.v3, d1, d2, d3);
+//
+//    //    // a to c crosses the clipping plane
+//    //    else if (d1 * d3 < 0.0f)
+//    //        sliceTriangle(trianglesPerProcess, triangleVec, indexTriangle, triangleToSplit.v3, triangleToSplit.v1, triangleToSplit.v2, d3, d1, d2);
+//
+//    //    // b to c crosses the clipping plane
+//    //    else if (d2 * d3 < 0.0f)
+//    //        sliceTriangle(trianglesPerProcess, triangleVec, indexTriangle, triangleToSplit.v2, triangleToSplit.v3, triangleToSplit.v1, d2, d3, d1);
+//    //}
+//}
+//
+//
+//void Partition::sliceTriangle(
+//    std::vector<Triangle>& out,
+//    std::vector<Triangle>& triangleVec,
+//    int index,
+//    const Vertex& a, // First point on triangle, CCW order
+//    const Vertex& b, // Second point on triangle, CCW order
+//    const Vertex& c, // Third point on triangle, CCW order
+//    real d1,        // Distance of point a to the splitting plane
+//    real d2,        // Distance of point b to the splitting plane
+//    real d3         // Distance of point c to the splitting plane
+//    )
+//{
+//    // Calculate the intersection point from a to b
+//    Vertex ab = a + ((b - a) * (d1 / (d1 - d2)) );
+//    Triangle tri;
+//
+//    if (d1 < 0.0f)
+//    {
+//        // b to c crosses the clipping plane
+//        if (d3 < 0.0f)
+//        {
+//            // Calculate intersection point from b to c
+//            Vertex bc = b + ((c - b) *  (d2 / (d2 - d3)));
+//
+//            tri.set(b, bc, ab);
+//            triangleVec.push_back(tri);
+//
+//            tri.set(bc, c, a);
+//            triangleVec.push_back(tri);
+//
+//            tri.set(ab, bc, a);
+//            triangleVec.push_back(tri);
+//        }
+//
+//        // c to a crosses the clipping plane
+//        else
+//        {
+//            // Calculate intersection point from a to c
+//            Vertex ac = a + ((c - a) * (d1 / (d1 - d3)));
+//
+//            tri.set(a, ab, ac);
+//            triangleVec.push_back(tri);
+//
+//            tri.set(ab, b, c);
+//            triangleVec.push_back(tri);
+//
+//            tri.set(ac, ab, c);
+//            triangleVec.push_back(tri);
+//        }
+//    }
+//    else
+//    {
+//        // c to a crosses the clipping plane
+//        if (d3 < 0.0f)
+//        {
+//            // Calculate intersection point from a to c
+//            Vertex ac = a +  ((c - a) * (d1 / (d1 - d3)));
+//
+//            tri.set(a, ab, ac);
+//            triangleVec.push_back(tri);
+//
+//            tri.set(ac, ab, b);
+//            triangleVec.push_back(tri);
+//
+//            tri.set(b, c, ac);
+//            triangleVec.push_back(tri);
+//        }
+//
+//        // b to c crosses the clipping plane
+//        else
+//        {
+//            // Calculate intersection point from b to c
+//            Vertex bc = b + ((c - b) * (d2 / (d2 - d3)));
+//
+//            tri.set(b, bc, ab);
+//            triangleVec.push_back(tri);
+//
+//            tri.set(a, ab, bc);
+//            triangleVec.push_back(tri);
+//
+//            tri.set(c, a, bc);
+//            triangleVec.push_back(tri);
+//        }
+//    }
+//}
+//
diff --git a/src/gpu/GridGenerator/grid/partition/Partition.h b/src/gpu/GridGenerator/grid/partition/Partition.h
new file mode 100644
index 000000000..a45f7668b
--- /dev/null
+++ b/src/gpu/GridGenerator/grid/partition/Partition.h
@@ -0,0 +1,45 @@
+//#ifndef Partition_H
+//#define Partition_H
+//
+//#include "global.h"
+//
+//
+//#include <vector>
+//#include <string>
+//#include <memory>
+//
+//class BoundingBox;
+//struct Triangle;
+//struct Vertex;
+//class Grid;
+//class Transformator;
+//
+//class GRIDGENERATOR_EXPORT Partition
+//{
+//public:
+//    static void partitionGridMesh(SPtr<Grid> grid);
+//    static void partitionGrid(SPtr<Grid> grid);
+//
+//	static std::vector<BoundingBox > getProcessBoxes(const int numberOfProcesses, const int globalNx, const int globalNy, const int globalNz);
+//    static std::vector<std::vector<int> > partitionBoxes(std::vector<std::vector<BoundingBox> >, int processes, std::vector< std::shared_ptr<Transformator> > transformators);
+//
+//    static std::vector<std::vector<Triangle> > getTrianglesPerProcess(std::vector<BoundingBox> &boxes, Triangle *triangles, int nTriangles);
+//
+//    static std::vector<std::vector<Triangle> >  splitTriangles(std::vector<Triangle> &triangleVec, std::vector<BoundingBox> boxes);
+//    
+//private:
+//    Partition(){};
+//    ~Partition(){};
+//
+//    static int calcEdgesFromGraph(SPtr<Grid> grid);
+//
+//    static void splitAllBoxesInThreePieces(std::vector<BoundingBox> &boxes, bool splitX, bool splitY, bool splitZ);
+//    static void splitAllBoxesInTwoPieces(std::vector<BoundingBox> &boxes, bool splitX, bool splitY, bool splitZ);
+//    static void findMaxBoxSize(std::vector<BoundingBox> &boxes, bool &splitX, bool &splitY, bool &splitZ);
+//
+//    static void splitAndPushTriangle(BoundingBox &box, std::vector<Triangle> &trianglesPerProcess, std::vector<Triangle> &triangleVec, int indexTriangle);
+//    static void sliceTriangle(std::vector<Triangle> &out, std::vector<Triangle>& triangleVec, int index, const Vertex& a, const Vertex& b, const Vertex& c, real d1, real d2, real d3);
+//
+//};
+//
+//#endif
diff --git a/src/gpu/GridGenerator/io/GridVTKWriter/GridVTKWriter.cpp b/src/gpu/GridGenerator/io/GridVTKWriter/GridVTKWriter.cpp
new file mode 100644
index 000000000..835cdf8d6
--- /dev/null
+++ b/src/gpu/GridGenerator/io/GridVTKWriter/GridVTKWriter.cpp
@@ -0,0 +1,475 @@
+#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);
+}
+//deprecated
+//void GridVTKWriter::writeGridToVTKXML(SPtr<Grid> grid, const std::string& name, WRITING_FORMAT format)
+//{
+//    std::vector<UbTupleFloat3> nodes;
+//    std::vector<UbTupleUInt8> cells;
+//    std::vector<std::string> nodedatanames;
+//    std::vector< std::vector<double> > nodedata;
+//
+//    nodedatanames.push_back("types");
+//
+//
+//    nodedata.resize(nodedatanames.size());
+//
+//    CbArray3D<int> nodeNumbers(grid->getNumberOfNodesX(), grid->getNumberOfNodesY(), grid->getNumberOfNodesZ(), -1);
+//    int nr = 0;
+//
+//    for (real x = grid->getStartX(); x <= grid->getEndX(); x += grid->getDelta())
+//    {
+//        for (real y = grid->getStartY(); y <= grid->getEndY(); y += grid->getDelta())
+//        {
+//            for (real z = grid->getStartZ(); z <= grid->getEndZ(); z += grid->getDelta())
+//            {
+//                const auto xTranslate = int((x - grid->getStartX()) / grid->getDelta());
+//                const auto yTranslate = int((y - grid->getStartY()) / grid->getDelta());
+//                const auto zTranslate = int((z - grid->getStartZ()) / grid->getDelta());
+//                nodeNumbers(xTranslate, yTranslate, zTranslate) = 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);
+//            }
+//        }
+//    }
+//
+//    int SWB, SEB, NEB, NWB, SWT, SET, NET, NWT;
+//    for (real x = grid->getStartX(); x < grid->getEndX(); x += grid->getDelta())
+//    {
+//        for (real y = grid->getStartY(); y < grid->getEndY(); y += grid->getDelta())
+//        {
+//            for (real z = grid->getStartZ(); z < grid->getEndZ(); z += grid->getDelta())
+//            {
+//                const auto xTranslate = int((x - grid->getStartX()) / grid->getDelta());
+//                const auto yTranslate = int((y - grid->getStartY()) / grid->getDelta());
+//                const auto zTranslate = int((z - grid->getStartZ()) / grid->getDelta());
+//
+//				if (!nodeNumbers.indicesInRange(xTranslate + 1, yTranslate +1, zTranslate +1)) // blame Lenz
+//					continue;
+//
+//                if ((SWB = nodeNumbers(xTranslate, yTranslate, zTranslate)) >= 0
+//                    && (SEB = nodeNumbers(xTranslate + 1, yTranslate, zTranslate)) >= 0
+//                    && (NEB = nodeNumbers(xTranslate + 1, yTranslate + 1, zTranslate)) >= 0
+//                    && (NWB = nodeNumbers(xTranslate, yTranslate + 1, zTranslate)) >= 0
+//                    && (SWT = nodeNumbers(xTranslate, yTranslate, zTranslate + 1)) >= 0
+//                    && (SET = nodeNumbers(xTranslate + 1, yTranslate, zTranslate + 1)) >= 0
+//                    && (NET = nodeNumbers(xTranslate + 1, yTranslate + 1, zTranslate + 1)) >= 0
+//                    && (NWT = nodeNumbers(xTranslate, yTranslate + 1, zTranslate + 1)) >= 0)
+//                {
+//                    Cell cell(x, y, z, grid->getDelta());
+//                    if(grid->nodeInCellIs(cell, OUT_OF_GRID) || grid->nodeInCellIs(cell, INVALID_NODE))
+//                        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, nodes, cells, nodedatanames, nodedata);
+//}
+
+
+/*#################################################################################*/
+/*---------------------------------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 000000000..43fe61145
--- /dev/null
+++ b/src/gpu/GridGenerator/io/GridVTKWriter/GridVTKWriter.h
@@ -0,0 +1,49 @@
+#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 000000000..6df995b2d
--- /dev/null
+++ b/src/gpu/GridGenerator/io/QLineWriter.cpp
@@ -0,0 +1,142 @@
+#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 000000000..01596adbd
--- /dev/null
+++ b/src/gpu/GridGenerator/io/QLineWriter.h
@@ -0,0 +1,25 @@
+#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 000000000..3f41f66ae
--- /dev/null
+++ b/src/gpu/GridGenerator/io/STLReaderWriter/STLReader.cpp
@@ -0,0 +1,354 @@
+#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] = "";
+    fread(header_info, sizeof(char), 80, file);
+
+    char nTri[4];
+    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++){
+        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));
+    }
+	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;
+  
+    fread(header_info, sizeof(char), 80, file);
+
+
+    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++){
+        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";
+
+	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 000000000..3e7beef8c
--- /dev/null
+++ b/src/gpu/GridGenerator/io/STLReaderWriter/STLReader.h
@@ -0,0 +1,40 @@
+#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 000000000..36e099c61
--- /dev/null
+++ b/src/gpu/GridGenerator/io/STLReaderWriter/STLWriter.cpp
@@ -0,0 +1,84 @@
+#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 000000000..c61854802
--- /dev/null
+++ b/src/gpu/GridGenerator/io/STLReaderWriter/STLWriter.h
@@ -0,0 +1,28 @@
+#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 000000000..7cf2412a3
--- /dev/null
+++ b/src/gpu/GridGenerator/io/SimulationFileWriter/SimulationFileNames.cpp
@@ -0,0 +1,45 @@
+#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 000000000..fdc09047f
--- /dev/null
+++ b/src/gpu/GridGenerator/io/SimulationFileWriter/SimulationFileNames.h
@@ -0,0 +1,53 @@
+#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 000000000..5921f5be0
--- /dev/null
+++ b/src/gpu/GridGenerator/io/SimulationFileWriter/SimulationFileWriter.cpp
@@ -0,0 +1,752 @@
+#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 000000000..ef9110880
--- /dev/null
+++ b/src/gpu/GridGenerator/io/SimulationFileWriter/SimulationFileWriter.h
@@ -0,0 +1,97 @@
+#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/io/VTKWriterWrapper/PolyDataWriterWrapper.cpp b/src/gpu/GridGenerator/io/VTKWriterWrapper/PolyDataWriterWrapper.cpp
new file mode 100644
index 000000000..3ce6742b1
--- /dev/null
+++ b/src/gpu/GridGenerator/io/VTKWriterWrapper/PolyDataWriterWrapper.cpp
@@ -0,0 +1,29 @@
+//#include "PolyDataWriterWrapper.h"
+//
+//#include <VTKWriter/PolyDataWriter/PolyDataWriterImp.h>
+//
+//#include <GridGenerator/geometries/Arrow/Arrow.h>
+//#include <GridGenerator/geometries/Vertex/Vertex.h>
+//
+//
+//PolyDataWriterWrapper::PolyDataWriterWrapper()
+//{
+//	writer = std::shared_ptr<PolyDataWriter>(new PolyDataWriterImp());
+//}
+//
+//PolyDataWriterWrapper::~PolyDataWriterWrapper()
+//{
+//
+//}
+//
+//void PolyDataWriterWrapper::addVectorArrow(std::shared_ptr<const Arrow> arrow)
+//{
+//	double startPoint[] = { arrow->getStart()->x, arrow->getStart()->y, arrow->getStart()->z };
+//	double endPoint[] = { arrow->getEnd()->x, arrow->getEnd()->y, arrow->getEnd()->z };
+//	writer->addVectorArrow(startPoint, endPoint);
+//}
+//
+//void PolyDataWriterWrapper::writePolyDataToFile(const std::string& filename) const
+//{
+//	writer->writePolyDataToFile(filename);
+//}
diff --git a/src/gpu/GridGenerator/io/VTKWriterWrapper/PolyDataWriterWrapper.h b/src/gpu/GridGenerator/io/VTKWriterWrapper/PolyDataWriterWrapper.h
new file mode 100644
index 000000000..c7b3829d6
--- /dev/null
+++ b/src/gpu/GridGenerator/io/VTKWriterWrapper/PolyDataWriterWrapper.h
@@ -0,0 +1,26 @@
+//#ifndef PolyDataWriterWrapper_H
+//#define PolyDataWriterWrapper_H
+//
+//
+//#include <string>
+//#include <memory>
+//
+//class PolyDataWriter;
+//class Arrow;
+//
+//class PolyDataWriterWrapper
+//{
+//public:
+//	GRIDGENERATOR_EXPORT PolyDataWriterWrapper();
+//	GRIDGENERATOR_EXPORT ~PolyDataWriterWrapper();
+//
+//	GRIDGENERATOR_EXPORT virtual void addVectorArrow(std::shared_ptr<const Arrow> arrow);
+//	GRIDGENERATOR_EXPORT virtual void writePolyDataToFile(const std::string &filename) const;
+//
+//private:
+//    std::shared_ptr<PolyDataWriter> writer;
+//
+//};
+//
+//
+//#endif
diff --git a/src/gpu/GridGenerator/io/VTKWriterWrapper/UnstructuredGridWrapper.cpp b/src/gpu/GridGenerator/io/VTKWriterWrapper/UnstructuredGridWrapper.cpp
new file mode 100644
index 000000000..b2de0057c
--- /dev/null
+++ b/src/gpu/GridGenerator/io/VTKWriterWrapper/UnstructuredGridWrapper.cpp
@@ -0,0 +1,137 @@
+//#define _CRT_SECURE_NO_DEPRECATE
+//#include "UnstructuredGridWrapper.h"
+//#include <iostream>
+//
+//#include <VTKWriter/UnstructuredGridWriter/UnstructuredGridWriter.h>
+//
+//#include <GridGenerator/geometries/Triangle/Triangle.h>
+//#include <GridGenerator/geometries/Vertex/Vertex.h>
+//#include <GridGenerator/geometries/BoundingBox/BoundingBox.h>
+//#include <GridGenerator/grid/Grid.cuh>
+//
+//UnstructuredGridWrapper::UnstructuredGridWrapper()
+//{
+//#ifndef __unix__
+//    this->writer = new UnstructuredGridWriter();
+//#endif
+//}
+//
+//UnstructuredGridWrapper::~UnstructuredGridWrapper()
+//{
+//#ifndef __unix__
+//    delete this->writer;
+//#endif
+//}
+//
+//void UnstructuredGridWrapper::addBoundingBox(double boundingBox[6], int type)
+//{
+//#ifndef __unix__
+//    this->writer->addBoundingBox(boundingBox, type);
+//#endif
+//}
+//
+//template <typename T>
+//void UnstructuredGridWrapper::addBoundingBox(BoundingBox<T> box, int type)
+//{
+//#ifndef __unix__
+//    double b[6] = {box.minX,box.maxX,box.minY,box.maxY,box.minZ,box.maxZ };
+//    this->writer->addBoundingBox(b, type);
+//#endif
+//}
+//
+//void UnstructuredGridWrapper::addVoxel(double node[3], double nodeNX[3], double nodeNY[3], double nodeNZ[3], double nodeNYNX[3], double nodeNZNY[3], double nodeNZNX[3], double nodeNZNYNX[3], int nodeTypes[8])
+//{
+//#ifndef __unix__
+//    this->writer->addVoxel(node, nodeNX, nodeNY, nodeNZ, nodeNYNX, nodeNZNY, nodeNZNX, nodeNZNYNX, nodeTypes);
+//#endif
+//}
+//
+//void UnstructuredGridWrapper::addTriangle(double v1[3], double v2[3], double v3[3], int type[3])
+//{
+//#ifndef __unix__
+//    this->writer->addTriangle(v1, v2, v3, type);
+//#endif
+//}
+//
+//void UnstructuredGridWrapper::addTriangle(Triangle t, int type[3])
+//{
+//#ifndef __unix__
+//    double v1[3] = { t.v1.x, t.v1.y, t.v1.z };
+//    double v2[3] = { t.v2.x, t.v2.y, t.v2.z };
+//    double v3[3] = { t.v3.x, t.v3.y, t.v3.z };
+//
+//    this->writer->addTriangle(v1, v2, v3, type);
+//#endif
+//}
+//
+//void UnstructuredGridWrapper::addTriangles(std::vector<Triangle> triangles)
+//{
+//#ifndef __unix__
+//    for (int i = 0; i < triangles.size(); i++) {
+//        double v1[3] = { triangles[i].v1.x, triangles[i].v1.y, triangles[i].v1.z };
+//        double v2[3] = { triangles[i].v2.x, triangles[i].v2.y, triangles[i].v2.z };
+//        double v3[3] = { triangles[i].v3.x, triangles[i].v3.y, triangles[i].v3.z };
+//
+//        this->writer->addTriangle(v1, v2, v3, 0);
+//    }
+//#endif
+//}
+//
+//void UnstructuredGridWrapper::addGridPoints(double grid[], int nx, int ny, int nz)
+//{
+//#ifndef __unix__
+//    this->writer->addGridPoints(grid, nx, ny, nz);
+//#endif
+//}
+//
+//void UnstructuredGridWrapper::addGridPoint(int x, int y, int z, int type)
+//{
+//#ifndef __unix__
+//    this->writer->addGridPoint(x, y, z, type);
+//#endif
+//}
+//
+//void UnstructuredGridWrapper::addGridPoint(Vertex v, int type)
+//{
+//#ifndef __unix__
+//    this->writer->addGridPoint((int)v.x, (int)v.y, (int)v.z, type);
+//#endif
+//}
+//
+//void UnstructuredGridWrapper::writeUnstructuredGridToFile(std::string filename)
+//{
+//#ifndef __unix__
+//    std::string path = PATH_TO_DATA;
+//    filename = path + filename;
+//    this->writer->writeUnstructuredGridToFile(filename);
+//#endif
+//}
+//
+//void UnstructuredGridWrapper::displayUnstructuredGrid()
+//{
+//#ifndef __unix__
+//    this->writer->displayUnstructuredGrid();
+//#endif
+//}
+//
+//void UnstructuredGridWrapper::displayUnstructuredGrid(std::string filename)
+//{
+//#ifndef __unix__
+//    std::string path = PATH_TO_DATA;
+//    filename = path + filename;
+//    this->writer->displayUnstructuredGrid(filename);
+//#endif
+//}
+//template <typename T>
+//void UnstructuredGridWrapper::writeBoxesToFile(std::vector<BoundingBox<T>> boxes, std::string name)
+//{
+//#ifndef __unix__
+//	UnstructuredGridWrapper writer;
+//	for (int i = 0; i < boxes.size(); i++) {
+//		writer.addBoundingBox(boxes[i], 0);
+//	}
+//	writer.writeUnstructuredGridToFile(name);
+//#endif
+//}
+//
+//template void UnstructuredGridWrapper::addBoundingBox(BoundingBox b, int type);
diff --git a/src/gpu/GridGenerator/io/VTKWriterWrapper/UnstructuredGridWrapper.h b/src/gpu/GridGenerator/io/VTKWriterWrapper/UnstructuredGridWrapper.h
new file mode 100644
index 000000000..6e13ba9dd
--- /dev/null
+++ b/src/gpu/GridGenerator/io/VTKWriterWrapper/UnstructuredGridWrapper.h
@@ -0,0 +1,53 @@
+//#ifndef UnstructuredGridWrapper_H
+//#define UnstructuredGridWrapper_H
+//
+//
+//#include <string>
+//#include <vector>
+//
+//class UnstructuredGridWriter;
+//struct Triangle;
+//
+//template <class T>
+//class BoundingBox;
+//struct Vertex;
+//class Grid;
+//
+//class GRIDGENERATOR_EXPORT UnstructuredGridWrapper
+//{
+//public:
+//    UnstructuredGridWrapper();
+//    ~UnstructuredGridWrapper();
+//
+//    void addBoundingBox(double boundingBox[6], int type);
+//	template <typename T>
+//    void addBoundingBox(BoundingBox<T> b, int type);
+//    void addVoxel(double node[3], double nodeNX[3], double nodeNY[3], double nodeNZ[3],
+//        double nodeNYNX[3], double nodeNZNY[3], double nodeNZNX[3], double nodeNZNYNX[3], int nodeTypes[8]);
+//
+//    void addTriangle(double v1[3], double v2[3], double v3[3], int type[3]);
+//    void addTriangle(Triangle t, int type[3]);
+//    void addTriangles(std::vector<Triangle> triangles);
+//
+//    void addGridPoints(double grid[], int nx, int ny, int nz);
+//
+//    void addGridPoint(int x, int y, int z, int type);
+//    void addGridPoint(Vertex v, int type);
+//
+//    void writeUnstructuredGridToFile(std::string filename);
+//	
+//    void displayUnstructuredGrid();
+//    void displayUnstructuredGrid(std::string filename);
+//
+//	template <typename T>
+//	static void writeBoxesToFile(std::vector<BoundingBox<T>>, std::string name);
+//
+//private:
+//#ifndef __unix__
+//    UnstructuredGridWriter *writer;
+//#endif
+//
+//};
+//
+//
+//#endif
diff --git a/src/gpu/GridGenerator/utilities/communication.h b/src/gpu/GridGenerator/utilities/communication.h
new file mode 100644
index 000000000..23dbd0832
--- /dev/null
+++ b/src/gpu/GridGenerator/utilities/communication.h
@@ -0,0 +1,15 @@
+#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/cuda/CudaErrorCheck.cu b/src/gpu/GridGenerator/utilities/cuda/CudaErrorCheck.cu
new file mode 100644
index 000000000..1d06e1783
--- /dev/null
+++ b/src/gpu/GridGenerator/utilities/cuda/CudaErrorCheck.cu
@@ -0,0 +1,55 @@
+#ifndef CudaErrorCheck_cu
+#define CudaErrorCheck_cu
+
+
+#include "cuda.h"
+#include "cuda_runtime.h"
+#include "device_launch_parameters.h"
+#include <stdio.h>
+
+#define CUDA_ERROR_CHECK
+
+#define CudaSafeCall( err ) __cudaSafeCall( err, __FILE__, __LINE__ )
+#define CudaCheckError()    __cudaCheckError( __FILE__, __LINE__ )
+
+inline void __cudaSafeCall(cudaError err, const char *file, const int line)
+{
+#ifdef CUDA_ERROR_CHECK
+	if (cudaSuccess != err)
+	{
+		fprintf(stderr, "cudaSafeCall() failed at %s:%i : %s\n",
+			file, line, cudaGetErrorString(err));
+		exit(-1);
+	}
+#endif
+
+	return;
+}
+
+inline void __cudaCheckError(const char *file, const int line)
+{
+#ifdef CUDA_ERROR_CHECK
+	cudaError err = cudaGetLastError();
+	if (cudaSuccess != err)
+	{
+		fprintf(stderr, "cudaCheckError() failed at %s\nline:%i : %s\n",
+			file, line, cudaGetErrorString(err));
+		fprintf(stderr, "CudaError: %d\n", err);
+		exit(-1);
+	}
+
+	// More careful checking. However, this will affect performance.
+	// Comment away if needed.
+	err = cudaDeviceSynchronize();
+	if (cudaSuccess != err)
+	{
+		fprintf(stderr, "cudaCheckError() with sync failed at %s:%i : %s\n",
+			file, line, cudaGetErrorString(err));
+		exit(-1);
+	}
+#endif
+
+	return;
+}
+
+#endif
diff --git a/src/gpu/GridGenerator/utilities/cuda/LaunchParameter.cu b/src/gpu/GridGenerator/utilities/cuda/LaunchParameter.cu
new file mode 100644
index 000000000..ce1371592
--- /dev/null
+++ b/src/gpu/GridGenerator/utilities/cuda/LaunchParameter.cu
@@ -0,0 +1,49 @@
+#include "LaunchParameter.cuh"
+
+#define MAXBLOCKSIZE 65535
+
+LaunchParameter::LaunchParameter()
+{
+
+}
+
+LaunchParameter LaunchParameter::make_2D1D_launchParameter(int size, int threadDim)
+{
+	LaunchParameter para;
+	para.threads = dim3(threadDim, 1, 1);
+
+	int blocks_ = (int)(ceil((size / ((real)threadDim))));
+	para.blocks = dim3(blocks_, 1, 1);
+
+	if (blocks_ > MAXBLOCKSIZE) {
+		blocks_ = (int)sqrt((double)blocks_);
+		para.blocks = dim3(blocks_, blocks_, 1);
+	}
+	return para;
+}
+
+LaunchParameter LaunchParameter::make_1D1D_launchParameter(int size, int threadDim)
+{
+	LaunchParameter para;
+	para.threads = dim3(threadDim, 1, 1);
+	int blocks_ = (int)(ceil((real)size / (real)threadDim));
+	para.blocks = dim3(blocks_, 1);
+	return para;
+}
+
+__device__ int LaunchParameter::getGlobalIdx_2D_1D()
+{
+	int blockId = blockIdx.y * gridDim.x + blockIdx.x;
+	int threadId = blockId * blockDim.x + threadIdx.x;
+	return threadId;
+}
+
+__device__ int LaunchParameter::getGlobalIdx_1D_1D() {
+	return blockIdx.x *blockDim.x + threadIdx.x;
+}
+
+void LaunchParameter::print() const
+{
+	*logging::out << logging::Logger::INFO_INTERMEDIATE << "blocks: (" << blocks.x << ", " << blocks.y << ", " << blocks.z << ")"
+		<< ", threads: (" << threads.x << ", " << threads.y << ", " << threads.z << ")\n";
+}
diff --git a/src/gpu/GridGenerator/utilities/cuda/LaunchParameter.cuh b/src/gpu/GridGenerator/utilities/cuda/LaunchParameter.cuh
new file mode 100644
index 000000000..5029b0c52
--- /dev/null
+++ b/src/gpu/GridGenerator/utilities/cuda/LaunchParameter.cuh
@@ -0,0 +1,29 @@
+#ifndef kernelHelper_CUH
+#define kernelHelper_CUH
+
+#include <cuda.h>
+#include <cuda_runtime.h>
+#include <device_launch_parameters.h>
+#include <stdio.h>
+
+#include "global.h"
+
+class LaunchParameter
+{
+public:
+	GRIDGENERATOR_EXPORT LaunchParameter();
+
+	GRIDGENERATOR_EXPORT static LaunchParameter make_2D1D_launchParameter(int size, int threadDim);
+	GRIDGENERATOR_EXPORT static LaunchParameter make_1D1D_launchParameter(int size, int threadDim);
+
+	static int getGlobalIdx_2D_1D();
+	static int getGlobalIdx_1D_1D();
+
+	void print() const;
+
+	dim3 threads;
+	dim3 blocks;
+};
+
+
+#endif
diff --git a/src/gpu/GridGenerator/utilities/cuda/cudaDefines.h b/src/gpu/GridGenerator/utilities/cuda/cudaDefines.h
new file mode 100644
index 000000000..b20401ef4
--- /dev/null
+++ b/src/gpu/GridGenerator/utilities/cuda/cudaDefines.h
@@ -0,0 +1,66 @@
+#ifndef CUDA_DEFINES_H
+#define CUDA_DEFINES_H
+
+#include <cuda_runtime.h>
+#include <stdio.h>
+
+#define CUDA_HOST __host__
+#define DEVICE __device__
+#define GLOBAL __global__
+#define CONSTANT __constant__
+
+
+#define HOSTDEVICE CUDA_HOST DEVICE
+
+static void printCudaInformation(int i) {
+    cudaDeviceProp prop;
+    cudaGetDeviceProperties(&prop, i);
+    printf(" --- General Information for device %d ---\n", i);
+    printf("Name: %s\n", prop.name);
+    printf("Compute capability: %d.%d\n", prop.major, prop.minor);
+    printf("Clock rate: %d\n", prop.clockRate);
+    printf("Device copy overlap: ");
+    if (prop.deviceOverlap)
+        printf("Enabled\n");
+    else
+        printf("Disabled\n");
+    printf("Kernel execition timeout : ");
+    if (prop.kernelExecTimeoutEnabled)
+        printf("Enabled\n");
+    else
+        printf("Disabled\n");
+    printf(" --- Memory Information for device %d ---\n", i);
+    printf("Total global mem: %zu\n", prop.totalGlobalMem);
+    printf("Total constant Mem: %zu\n", prop.totalConstMem);
+    printf("Max mem pitch: %zu\n", prop.memPitch);
+    printf("Texture Alignment: %zu\n", prop.textureAlignment);
+    printf("max Texture 1D: %d\n", prop.maxTexture1D);
+    printf("max Texture 2D: %d, %d\n", prop.maxTexture2D[0], prop.maxTexture2D[1]);
+    printf("max Texture 3D: %d, %d, %d\n", prop.maxTexture3D[0], prop.maxTexture3D[1], prop.maxTexture3D[2]);
+    printf(" --- MP Information for device %d ---\n", i);
+    printf("Multiprocessor count: %d\n",
+        prop.multiProcessorCount);
+    printf("Shared mem per mp: %zd\n", prop.sharedMemPerBlock);
+    printf("Registers per mp: %d\n", prop.regsPerBlock);
+    printf("Threads in warp: %d\n", prop.warpSize);
+    printf("Max threads per block: %d\n",
+        prop.maxThreadsPerBlock);
+    printf("Max thread dimensions: (%d, %d, %d)\n",
+        prop.maxThreadsDim[0], prop.maxThreadsDim[1],
+        prop.maxThreadsDim[2]);
+    printf("Max grid dimensions: (%d, %d, %d)\n",
+        prop.maxGridSize[0], prop.maxGridSize[1],
+        prop.maxGridSize[2]);
+    printf(" --- -------------------------------- ---\n");
+    printf("\n");
+
+    cudaSetDevice(i);
+    size_t free;
+    size_t total;
+    cudaMemGetInfo(&free, &total);
+    printf("Free: %zu Bytes, Total: %zu Bytes\n", free, total);
+    printf("Free: %zu MB, Total: %zu MB\n", free / 1000 / 1000, total / 1000 / 1000);
+    //cudaDeviceSetLimit(cudaLimitMallocHeapSize, free);
+}
+
+#endif 
diff --git a/src/gpu/GridGenerator/utilities/cuda/cudaKernelCall.h b/src/gpu/GridGenerator/utilities/cuda/cudaKernelCall.h
new file mode 100644
index 000000000..591197742
--- /dev/null
+++ b/src/gpu/GridGenerator/utilities/cuda/cudaKernelCall.h
@@ -0,0 +1,33 @@
+#ifndef cudaKernelCall_H
+#define cudaKernelCall_H
+
+#include "utilities/cuda/cudaDefines.h"
+#include "utilities/cuda/CudaErrorCheck.cu"
+#include "utilities/cuda/LaunchParameter.cuh"
+
+template<typename Functor, typename... TArgs>
+CUDA_HOST float runKernel(Functor kernel, const LaunchParameter& para, TArgs... args)
+{
+	para.print();
+
+	cudaEvent_t start, stop;
+	cudaEventCreate(&start);
+	cudaEventCreate(&stop);
+
+	cudaEventRecord(start, 0);
+	kernel << < para.blocks, para.threads >> >(args...);
+	CudaCheckError();
+	cudaDeviceSynchronize();
+	cudaEventRecord(stop, 0);
+
+	cudaEventSynchronize(stop);
+	float elapsedTime;
+	cudaEventElapsedTime(&elapsedTime, start, stop);
+	cudaEventDestroy(start);
+	cudaEventDestroy(stop);
+
+	return elapsedTime;
+}
+
+
+#endif 
diff --git a/src/gpu/GridGenerator/utilities/transformator/ArrowTransformator.cpp b/src/gpu/GridGenerator/utilities/transformator/ArrowTransformator.cpp
new file mode 100644
index 000000000..7ec055c59
--- /dev/null
+++ b/src/gpu/GridGenerator/utilities/transformator/ArrowTransformator.cpp
@@ -0,0 +1,8 @@
+#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 000000000..186b66838
--- /dev/null
+++ b/src/gpu/GridGenerator/utilities/transformator/ArrowTransformator.h
@@ -0,0 +1,24 @@
+#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 000000000..4f59dc648
--- /dev/null
+++ b/src/gpu/GridGenerator/utilities/transformator/Transformator.cpp
@@ -0,0 +1,8 @@
+#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/utilities/transformator/Transformator.h b/src/gpu/GridGenerator/utilities/transformator/Transformator.h
new file mode 100644
index 000000000..0f092ddb9
--- /dev/null
+++ b/src/gpu/GridGenerator/utilities/transformator/Transformator.h
@@ -0,0 +1,37 @@
+#ifndef Transformator_h
+#define Transformator_h
+
+#include <memory>
+
+#include "global.h"
+
+class BoundingBox;
+struct Triangle;
+class TriangularMesh;
+struct Vertex;
+
+
+class Transformator
+{
+public:
+    static GRIDGENERATOR_EXPORT std::shared_ptr<Transformator> makeTransformator(real delta, real dx, real dy, real dz);
+	virtual ~Transformator() {}
+
+protected:
+	Transformator(){}
+
+public:
+	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
diff --git a/src/gpu/GridGenerator/utilities/transformator/TransformatorImp.cpp b/src/gpu/GridGenerator/utilities/transformator/TransformatorImp.cpp
new file mode 100644
index 000000000..224dda497
--- /dev/null
+++ b/src/gpu/GridGenerator/utilities/transformator/TransformatorImp.cpp
@@ -0,0 +1,158 @@
+#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 000000000..626abacaf
--- /dev/null
+++ b/src/gpu/GridGenerator/utilities/transformator/TransformatorImp.h
@@ -0,0 +1,71 @@
+#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
-- 
GitLab