diff --git a/.clang-tidy b/.clang-tidy
index 162294555c718c3912376188b34fa1fe3287c9ad..2c1bdff4123ca8349e16fedbd87d80064e1dfcd2 100644
--- a/.clang-tidy
+++ b/.clang-tidy
@@ -1,68 +1,54 @@
 ---
-Checks:          '-*,bugprone-*,-bugprone-exception-escape,misc-*,-misc-misplaced-const,modernize-*,-modernize-use-auto,-modernize-loop-convert,-modernize-pass-by-value,-modernize-raw-string-literal,-modernize-use-using,-modernize-avoid-bind,-modernize-return-braced-init-list,-modernize-use-transparent-functors,-modernize-redundant-void-arg,performance-*'
+Checks:          '
+
+-*,
+
+boost-*,
+
+bugprone-*,
+-bugprone-exception-escape,
+
+misc-*,
+-misc-misplaced-const,
+-misc-non-private-member-variables-in-classes,
+
+modernize-*,
+-modernize-use-auto,
+-modernize-loop-convert,
+-modernize-pass-by-value,
+-modernize-raw-string-literal,
+-modernize-use-using,
+-modernize-avoid-bind,
+-modernize-return-braced-init-list,
+-modernize-use-transparent-functors,
+-modernize-redundant-void-arg,
+-modernize-avoid-c-arrays,
+
+mpi-*,
+
+openmp-*,
+
+performance-*,
+
+portability-*,
+
+readability-const-return-type,
+readability-container-size-empty,
+readability-delete-null-pointer,
+readability-deleted-default,
+readability-misleading-indentation,
+readability-misplaced-array-index,
+readability-redundant-control-flow,
+readability-redundant-function-ptr-dereference,
+readability-redundant-smartptr-get,
+readability-redundant-string-cstr,
+readability-static-accessed-through-instance,
+readability-string-compare,
+readability-uniqueptr-delete-release
+
+'
 WarningsAsErrors: '*'
 HeaderFilterRegex: ''
 AnalyzeTemporaryDtors: false
-FormatStyle:     none
-User:            si11fita
-CheckOptions:    
-  - key:             modernize-loop-convert.MaxCopySize
-    value:           '16'
-  - key:             modernize-loop-convert.MinConfidence
-    value:           reasonable
-  - key:             modernize-loop-convert.NamingStyle
-    value:           CamelCase
-  - key:             modernize-make-shared.IgnoreMacros
-    value:           '1'
-  - key:             modernize-make-shared.IncludeStyle
-    value:           '0'
-  - key:             modernize-make-shared.MakeSmartPtrFunction
-    value:           'std::make_shared'
-  - key:             modernize-make-shared.MakeSmartPtrFunctionHeader
-    value:           memory
-  - key:             modernize-make-unique.IgnoreMacros
-    value:           '1'
-  - key:             modernize-make-unique.IncludeStyle
-    value:           '0'
-  - key:             modernize-make-unique.MakeSmartPtrFunction
-    value:           'std::make_unique'
-  - key:             modernize-make-unique.MakeSmartPtrFunctionHeader
-    value:           memory
-  - key:             modernize-pass-by-value.IncludeStyle
-    value:           llvm
-  - key:             modernize-pass-by-value.ValuesOnly
-    value:           '0'
-  - key:             modernize-raw-string-literal.ReplaceShorterLiterals
-    value:           '0'
-  - key:             modernize-replace-auto-ptr.IncludeStyle
-    value:           llvm
-  - key:             modernize-replace-random-shuffle.IncludeStyle
-    value:           llvm
-  - key:             modernize-use-auto.RemoveStars
-    value:           '0'
-  - key:             modernize-use-default-member-init.IgnoreMacros
-    value:           '1'
-  - key:             modernize-use-default-member-init.UseAssignment
-    value:           '0'
-  - key:             modernize-use-emplace.ContainersWithPushBack
-    value:           '::std::vector;::std::list;::std::deque'
-  - key:             modernize-use-emplace.SmartPointers
-    value:           '::std::shared_ptr;::std::unique_ptr;::std::auto_ptr;::std::weak_ptr'
-  - key:             modernize-use-emplace.TupleMakeFunctions
-    value:           '::std::make_pair;::std::make_tuple'
-  - key:             modernize-use-emplace.TupleTypes
-    value:           '::std::pair;::std::tuple'
-  - key:             modernize-use-equals-default.IgnoreMacros
-    value:           '1'
-  - key:             modernize-use-noexcept.ReplacementString
-    value:           ''
-  - key:             modernize-use-noexcept.UseNoexceptFalse
-    value:           '1'
-  - key:             modernize-use-nullptr.NullMacros
-    value:           'NULL'
-  - key:             modernize-use-transparent-functors.SafeMode
-    value:           '0'
-  - key:             modernize-use-using.IgnoreMacros
-    value:           '1'
 ...
 
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index e16e20a2378830a2a792c94db732fda93509120f..7c428c1dbf071d034dc1a633512d96ac529d19c3 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1399,7 +1399,7 @@ doc:
 ###############################################################################
 
 clang-tidy:
-   image: i10git.cs.fau.de:5005/walberla/buildenvs/clang:7.0
+   image: i10git.cs.fau.de:5005/walberla/buildenvs/clang:8.0
    script:
       - $CXX --version
       - clang-tidy -version
@@ -1877,4 +1877,4 @@ benchmark_gcc8:
 
 benchmark_clang8:
    <<: *benchmark_definition
-   image: i10git.cs.fau.de:5005/walberla/buildenvs/clang:8.0
\ No newline at end of file
+   image: i10git.cs.fau.de:5005/walberla/buildenvs/clang:8.0
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 65157e23f67017e850658c2a7679834e05189719..6de20290cdb6eed443d70b9fe3a06974bf91dd7c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -95,11 +95,13 @@ option ( WALBERLA_NO_OUTDATED_FEATURES      "Show warning/errors when outdated f
                                             "(i.e. features that will be deprecated) are used"   )
 
 # Profile guided optimization
-option ( WALBERLA_PROFILE_GENERATE  "Generates Profile for Optimization"             )
-option ( WALBERLA_PROFILE_USE       "Uses Profile to optimize"                       )
+option ( WALBERLA_PROFILE_GENERATE          "Generates Profile for Optimization"                 )
+option ( WALBERLA_PROFILE_USE               "Uses Profile to optimize"                           )
 
 # Compiler Optimization
-option ( WALBERLA_OPTIMIZE_FOR_LOCALHOST "Enable compiler optimizations spcific to localhost" )
+option ( WALBERLA_OPTIMIZE_FOR_LOCALHOST    "Enable compiler optimizations spcific to localhost" )
+
+option ( WALBERLA_LOG_SKIPPED               "Log skipped cmake targets"                      ON  )
 
 # Installation Directory
 set ( CMAKE_INSTALL_PREFIX /usr/local/waLBerla CACHE STRING "The default installation directory."   )
diff --git a/apps/benchmarks/CouetteFlow/CMakeLists.txt b/apps/benchmarks/CouetteFlow/CMakeLists.txt
index 90057e86e8286b869d6a25f72191416c4720128f..c4cb893e0e140e226ab4e75486a5fe36c714384f 100644
--- a/apps/benchmarks/CouetteFlow/CMakeLists.txt
+++ b/apps/benchmarks/CouetteFlow/CMakeLists.txt
@@ -1,7 +1,7 @@
 
 waLBerla_link_files_to_builddir( "*.dat" )                 
                                   
-waLBerla_add_executable( NAME CouetteFlow DEPENDS blockforest boundary core field lbm postprocessing stencil timeloop vtk )
+waLBerla_add_executable( NAME CouetteFlow DEPENDS blockforest boundary core field lbm postprocessing stencil timeloop vtk sqlite )
 
 ##############
 # Some tests #
diff --git a/apps/benchmarks/CouetteFlow/CouetteFlow.cpp b/apps/benchmarks/CouetteFlow/CouetteFlow.cpp
index 9ce1da4a306fdfc381026928ce534a14efd17ec3..4bedb57423a9e7f3f9e0267b05ec3d3f4dbf7d7b 100644
--- a/apps/benchmarks/CouetteFlow/CouetteFlow.cpp
+++ b/apps/benchmarks/CouetteFlow/CouetteFlow.cpp
@@ -79,7 +79,7 @@
 #include "lbm/vtk/NonEquilibrium.h"
 #include "lbm/vtk/Velocity.h"
 
-#include "postprocessing/sqlite/SQLite.h"
+#include "sqlite/SQLite.h"
 
 #include "stencil/D3Q15.h"
 #include "stencil/D3Q19.h"
@@ -871,10 +871,10 @@ void run( const shared_ptr< Config > & config, const LatticeModel_T & latticeMod
             
             realProperties[ "simulationProgress" ] = double_c( ( outerRun + uint_t(1) ) * innerTimeSteps ) / double_c( outerTimeSteps * innerTimeSteps );
 
-            auto runId = postprocessing::storeRunInSqliteDB( sqlFile, integerProperties, stringProperties, realProperties );
-            postprocessing::storeTimingPoolInSqliteDB( sqlFile, runId, *reducedTimeloopTiming, "Timeloop" );
-            postprocessing::storeTimingPoolInSqliteDB( sqlFile, runId, *reducedRTSTiming, "RefinementTimeStep" );
-            postprocessing::storeTimingPoolInSqliteDB( sqlFile, runId, *reducedRTSLTiming, "RefinementTimeStepLevelwise" );
+            auto runId = sqlite::storeRunInSqliteDB( sqlFile, integerProperties, stringProperties, realProperties );
+            sqlite::storeTimingPoolInSqliteDB( sqlFile, runId, *reducedTimeloopTiming, "Timeloop" );
+            sqlite::storeTimingPoolInSqliteDB( sqlFile, runId, *reducedRTSTiming, "RefinementTimeStep" );
+            sqlite::storeTimingPoolInSqliteDB( sqlFile, runId, *reducedRTSLTiming, "RefinementTimeStepLevelwise" );
          }
       }
    }
diff --git a/apps/benchmarks/FieldCommunication/CMakeLists.txt b/apps/benchmarks/FieldCommunication/CMakeLists.txt
index beec451f98a7fc6ca5db23ee2e3c718b58ef18ee..35a2f698a4514de3e9309cce56d977a25c470230 100644
--- a/apps/benchmarks/FieldCommunication/CMakeLists.txt
+++ b/apps/benchmarks/FieldCommunication/CMakeLists.txt
@@ -4,4 +4,4 @@ waLBerla_link_files_to_builddir( "*.py" )
 
 
 waLBerla_add_executable ( NAME FieldCommunication
-                          DEPENDS blockforest core domain_decomposition field postprocessing )
+                          DEPENDS blockforest core domain_decomposition field postprocessing sqlite )
diff --git a/apps/benchmarks/FieldCommunication/FieldCommunication.cpp b/apps/benchmarks/FieldCommunication/FieldCommunication.cpp
index 2273126b32cf7f9f8404098e6518c0b93d7fad62..fabde23e097a769713564842f3993baabe0a0fab 100644
--- a/apps/benchmarks/FieldCommunication/FieldCommunication.cpp
+++ b/apps/benchmarks/FieldCommunication/FieldCommunication.cpp
@@ -14,7 +14,7 @@
 #include "field/communication/PackInfo.h"
 #include "field/communication/StencilRestrictedPackInfo.h"
 #include "field/communication/UniformMPIDatatypeInfo.h"
-#include "postprocessing/sqlite/SQLite.h"
+#include "sqlite/SQLite.h"
 #include "python_coupling/CreateConfig.h"
 #include "stencil/D3Q7.h"
 #include "stencil/D3Q19.h"
@@ -414,9 +414,9 @@ int main( int argc, char **argv )
             stringProperties["buildType"] = std::string( WALBERLA_BUILD_TYPE );
             stringProperties["compilerFlags"] = std::string( WALBERLA_COMPILER_FLAGS );
 
-            auto runId = postprocessing::storeRunInSqliteDB( databaseFile, integerProperties, stringProperties, realProperties );
-            postprocessing::storeTimingPoolInSqliteDB( databaseFile, runId, timingPool, "TimingRoot" );
-            postprocessing::storeTimingPoolInSqliteDB( databaseFile, runId, *reducedTimingPool, "TimingReduced" );
+            auto runId = sqlite::storeRunInSqliteDB( databaseFile, integerProperties, stringProperties, realProperties );
+            sqlite::storeTimingPoolInSqliteDB( databaseFile, runId, timingPool, "TimingRoot" );
+            sqlite::storeTimingPoolInSqliteDB( databaseFile, runId, *reducedTimingPool, "TimingReduced" );
         }
 
     }
diff --git a/apps/benchmarks/GranularGas/CMakeLists.txt b/apps/benchmarks/GranularGas/CMakeLists.txt
index 7a4ef8f3e7d19535eb16b7bcfcfa3b5f610ebb72..b017add69e5080df42ac236dd5670ffbe466c020 100644
--- a/apps/benchmarks/GranularGas/CMakeLists.txt
+++ b/apps/benchmarks/GranularGas/CMakeLists.txt
@@ -3,24 +3,24 @@ waLBerla_link_files_to_builddir( *.py )
 
 waLBerla_add_executable ( NAME PE_GranularGas
                           FILES PE_GranularGas.cpp SQLProperties.cpp Parameters.cpp NodeTimings.cpp
-                          DEPENDS blockforest core pe postprocessing )
+                          DEPENDS blockforest core pe postprocessing sqlite )
 
 waLBerla_add_executable ( NAME PE_LoadBalancing
                           FILES PE_LoadBalancing.cpp SQLProperties.cpp Parameters.cpp NodeTimings.cpp
-                          DEPENDS blockforest core pe postprocessing )
+                          DEPENDS blockforest core pe postprocessing sqlite )
 
 waLBerla_add_executable ( NAME MESA_PD_LoadBalancing
                           FILES MESA_PD_LoadBalancing.cpp SQLProperties.cpp Parameters.cpp NodeTimings.cpp sortParticleStorage.cpp CreateParticles.cpp
-                          DEPENDS blockforest core pe mesa_pd postprocessing vtk )
+                          DEPENDS blockforest core pe mesa_pd postprocessing sqlite vtk )
 
 waLBerla_add_executable ( NAME MESA_PD_GranularGas
                           FILES MESA_PD_GranularGas.cpp SQLProperties.cpp Parameters.cpp NodeTimings.cpp sortParticleStorage.cpp CreateParticles.cpp
-                          DEPENDS blockforest core pe mesa_pd postprocessing vtk )
+                          DEPENDS blockforest core pe mesa_pd postprocessing sqlite vtk )
 
 waLBerla_add_executable ( NAME MESA_PD_KernelBenchmark
                           FILES MESA_PD_KernelBenchmark.cpp SQLProperties.cpp Parameters.cpp NodeTimings.cpp sortParticleStorage.cpp CreateParticles.cpp
-                          DEPENDS blockforest core pe mesa_pd postprocessing vtk )
+                          DEPENDS blockforest core pe mesa_pd postprocessing sqlite vtk )
 
 waLBerla_add_executable ( NAME MESA_PD_KernelLoadBalancing
                           FILES MESA_PD_KernelLoadBalancing.cpp SQLProperties.cpp Parameters.cpp NodeTimings.cpp sortParticleStorage.cpp CreateParticles.cpp
-                          DEPENDS blockforest core pe mesa_pd postprocessing vtk )
+                          DEPENDS blockforest core pe mesa_pd postprocessing sqlite vtk )
diff --git a/apps/benchmarks/GranularGas/MESA_PD_GranularGas.cpp b/apps/benchmarks/GranularGas/MESA_PD_GranularGas.cpp
index 01dab71ea3bd53df776639564753e9c499818115..7ff78bd1ae940ad0a3b88e0ae4fdb18e12babdf0 100644
--- a/apps/benchmarks/GranularGas/MESA_PD_GranularGas.cpp
+++ b/apps/benchmarks/GranularGas/MESA_PD_GranularGas.cpp
@@ -60,7 +60,7 @@
 #include <core/OpenMP.h>
 #include <core/timing/Timer.h>
 #include <core/waLBerlaBuildInfo.h>
-#include <postprocessing/sqlite/SQLite.h>
+#include <sqlite/SQLite.h>
 #include <vtk/VTKOutput.h>
 
 #include <functional>
@@ -380,14 +380,19 @@ int main( int argc, char ** argv )
          integerProperties["RPReceives"]          = RPReceives;
          realProperties["linkedCellsVolume"]      = linkedCellsVolume;
          integerProperties["numLinkedCells"]      = int64_c(numLinkedCells);
+         realProperties["PUpS"]                   = double_c(PUpS);
+         realProperties["timer_min"]              = timer_reduced->min();
+         realProperties["timer_max"]              = timer_reduced->max();
+         realProperties["timer_average"]          = timer_reduced->average();
+         realProperties["timer_total"]            = timer_reduced->total();
 
          addBuildInfoToSQL( integerProperties, realProperties, stringProperties );
          saveToSQL(params, integerProperties, realProperties, stringProperties );
          addDomainPropertiesToSQL(*forest, integerProperties, realProperties, stringProperties);
          addSlurmPropertiesToSQL(integerProperties, realProperties, stringProperties);
 
-         runId = postprocessing::storeRunInSqliteDB( params.sqlFile, integerProperties, stringProperties, realProperties );
-         postprocessing::storeTimingPoolInSqliteDB( params.sqlFile, runId, *tp_reduced, "Timeloop" );
+         runId = sqlite::storeRunInSqliteDB( params.sqlFile, integerProperties, stringProperties, realProperties );
+         sqlite::storeTimingPoolInSqliteDB( params.sqlFile, runId, *tp_reduced, "Timeloop" );
       }
 
       if (params.storeNodeTimings)
diff --git a/apps/benchmarks/GranularGas/MESA_PD_KernelBenchmark.cpp b/apps/benchmarks/GranularGas/MESA_PD_KernelBenchmark.cpp
index 669da955b8ac17cd29216f5208ab1b65ba0cf349..4b4d24256b3e0ab6916c155bb7f25bf22cc1fad3 100644
--- a/apps/benchmarks/GranularGas/MESA_PD_KernelBenchmark.cpp
+++ b/apps/benchmarks/GranularGas/MESA_PD_KernelBenchmark.cpp
@@ -64,7 +64,7 @@
 #include <core/timing/Timer.h>
 #include <core/timing/TimingPool.h>
 #include <core/waLBerlaBuildInfo.h>
-#include <postprocessing/sqlite/SQLite.h>
+#include <sqlite/SQLite.h>
 #include <vtk/VTKOutput.h>
 
 #include <functional>
@@ -378,8 +378,8 @@ int main( int argc, char ** argv )
          addDomainPropertiesToSQL(*forest, integerProperties, realProperties, stringProperties);
          addSlurmPropertiesToSQL(integerProperties, realProperties, stringProperties);
 
-         runId = postprocessing::storeRunInSqliteDB( params.sqlFile, integerProperties, stringProperties, realProperties );
-         postprocessing::storeTimingPoolInSqliteDB( params.sqlFile, runId, *tp_reduced, "Timeloop" );
+         runId = sqlite::storeRunInSqliteDB( params.sqlFile, integerProperties, stringProperties, realProperties );
+         sqlite::storeTimingPoolInSqliteDB( params.sqlFile, runId, *tp_reduced, "Timeloop" );
       }
       if (params.storeNodeTimings)
       {
diff --git a/apps/benchmarks/GranularGas/NodeTimings.cpp b/apps/benchmarks/GranularGas/NodeTimings.cpp
index 01b1a354b97acd3226f805ff8bd39b938a04cdd7..8336d7981753c0b5939c2b572daf5651bff20780 100644
--- a/apps/benchmarks/GranularGas/NodeTimings.cpp
+++ b/apps/benchmarks/GranularGas/NodeTimings.cpp
@@ -63,7 +63,7 @@ void storeNodeTimings( const uint_t                 runId,
             realProperties[v.first] = v.second.average();
          }
 
-         postprocessing::storeAdditionalRunInfoInSqliteDB( runId,
+         sqlite::storeAdditionalRunInfoInSqliteDB( runId,
                                                            dbFile,
                                                            tableName,
                                                            integerProperties,
diff --git a/apps/benchmarks/GranularGas/NodeTimings.h b/apps/benchmarks/GranularGas/NodeTimings.h
index cbe074b1b085b81822f652e805bc67c9c84f5f55..cc59fd547add479c4c8c0605dda66b698d4d79ed 100644
--- a/apps/benchmarks/GranularGas/NodeTimings.h
+++ b/apps/benchmarks/GranularGas/NodeTimings.h
@@ -23,7 +23,7 @@
 #include <core/mpi/Gatherv.h>
 #include <core/logging/Logging.h>
 #include <core/timing/TimingPool.h>
-#include <postprocessing/sqlite/SQLite.h>
+#include <sqlite/SQLite.h>
 
 namespace walberla {
 namespace mesa_pd {
diff --git a/apps/benchmarks/GranularGas/PE_GranularGas.cpp b/apps/benchmarks/GranularGas/PE_GranularGas.cpp
index be3fd973c4e5dcfacbee18e2ea6ae1ca893b793d..dd75b61287aa8195495ab4d2e7160f3830674aca 100644
--- a/apps/benchmarks/GranularGas/PE_GranularGas.cpp
+++ b/apps/benchmarks/GranularGas/PE_GranularGas.cpp
@@ -34,7 +34,7 @@
 #include <core/OpenMP.h>
 #include <core/timing/TimingTree.h>
 #include <core/waLBerlaBuildInfo.h>
-#include <postprocessing/sqlite/SQLite.h>
+#include <sqlite/SQLite.h>
 #include <vtk/VTKOutput.h>
 
 #include <functional>
@@ -325,8 +325,8 @@ int main( int argc, char ** argv )
          mesa_pd::addDomainPropertiesToSQL(*forest, integerProperties, realProperties, stringProperties);
          mesa_pd::addSlurmPropertiesToSQL(integerProperties, realProperties, stringProperties);
 
-         runId = postprocessing::storeRunInSqliteDB( params.sqlFile, integerProperties, stringProperties, realProperties );
-         postprocessing::storeTimingPoolInSqliteDB( params.sqlFile, runId, *tp_reduced, "Timeloop" );
+         runId = sqlite::storeRunInSqliteDB( params.sqlFile, integerProperties, stringProperties, realProperties );
+         sqlite::storeTimingPoolInSqliteDB( params.sqlFile, runId, *tp_reduced, "Timeloop" );
       }
       if (params.storeNodeTimings)
       {
diff --git a/apps/benchmarks/MotionSingleHeavySphere/MotionSingleHeavySphere.cpp b/apps/benchmarks/MotionSingleHeavySphere/MotionSingleHeavySphere.cpp
index 9c7b016f0d059a1f471df256c884b04055fe9e16..ddd54546f7bc8451b3353c2e1a7cf76b40961142 100644
--- a/apps/benchmarks/MotionSingleHeavySphere/MotionSingleHeavySphere.cpp
+++ b/apps/benchmarks/MotionSingleHeavySphere/MotionSingleHeavySphere.cpp
@@ -198,11 +198,11 @@ BoundaryHandling_T * MyBoundaryHandling::operator()( IBlock * const block, const
    const auto fluid = flagField->flagExists( Fluid_Flag ) ? flagField->getFlag( Fluid_Flag ) : flagField->registerFlag( Fluid_Flag );
 
    BoundaryHandling_T * handling = new BoundaryHandling_T( "moving obstacle boundary handling", flagField, fluid,
-                                    UBB_T( "UBB", UBB_Flag, pdfField, velocity_),
-                                    Outlet_T( "Outlet", Outlet_Flag, pdfField, real_t(1) ),
-                                    MEM_BB_T (  "MEM_BB",  MEM_BB_Flag, pdfField, flagField, bodyField, fluid, *storage, *block ),
-                                    MEM_CLI_T( "MEM_CLI", MEM_CLI_Flag, pdfField, flagField, bodyField, fluid, *storage, *block ),
-                                    MEM_MR_T (  "MEM_MR",  MEM_MR_Flag, pdfField, flagField, bodyField, fluid, *storage, *block, pdfFieldPreCol ) );
+                                                           UBB_T( "UBB", UBB_Flag, pdfField, velocity_),
+                                                           Outlet_T( "Outlet", Outlet_Flag, pdfField, real_t(1) ),
+                                                           MEM_BB_T (  "MEM_BB",  MEM_BB_Flag, pdfField, flagField, bodyField, fluid, *storage, *block ),
+                                                           MEM_CLI_T( "MEM_CLI", MEM_CLI_Flag, pdfField, flagField, bodyField, fluid, *storage, *block ),
+                                                           MEM_MR_T (  "MEM_MR",  MEM_MR_Flag, pdfField, flagField, bodyField, fluid, *storage, *block, pdfFieldPreCol ) );
 
    const auto ubb = flagField->getFlag( UBB_Flag );
    const auto outlet = flagField->getFlag( Outlet_Flag );
@@ -522,7 +522,7 @@ public:
    VTKInfoLogger( SweepTimeloop* timeloop, const shared_ptr< StructuredBlockStorage > & blocks,
                   const ConstBlockDataID & bodyStorageID, const std::string & baseFolder,
                   const Vector3<real_t>& u_infty ) :
-   timeloop_( timeloop ), blocks_( blocks ), bodyStorageID_( bodyStorageID ), baseFolder_( baseFolder ), u_infty_( u_infty )
+      timeloop_( timeloop ), blocks_( blocks ), bodyStorageID_( bodyStorageID ), baseFolder_( baseFolder ), u_infty_( u_infty )
    { }
 
    void operator()()
@@ -677,16 +677,44 @@ int main( int argc, char **argv )
 
    for( int i = 1; i < argc; ++i )
    {
-           if( std::strcmp( argv[i], "--Galileo"   ) == 0 ) Galileo   = real_c( std::atof( argv[++i] ) ); // targeted Galileo number
-      else if( std::strcmp( argv[i], "--diameter"  ) == 0 ) diameter  = real_c( std::atof( argv[++i] ) ); // diameter of the spheres, in cells per diameter
-      else if( std::strcmp( argv[i], "--noViscosityIterations" ) == 0 ) noViscosityIterations   = true; // keep viscosity unchanged in initial simulation
-      else if( std::strcmp( argv[i], "--vtkIOInit" ) == 0 ) vtkIOInit = true; // write vtk IO for initial simulation
-      else if( std::strcmp( argv[i], "--longDom"   ) == 0 ) longDom   = true; // use a domain that is extended by the original domain length in positive and negative streamwise direction
-      else if( std::strcmp( argv[i], "--useMEM"    ) == 0 ) // use momentum exchange coupling and the given MEM variant (BB, CLI, or MR)
-           { useMEM = true; memVariant = to_MEMVariant( argv[++i] ); }
-      else if( std::strcmp( argv[i], "--usePSM"    ) == 0 ) // use partially saturated cells method and the given PSM variant (SC1W1, SC1W2, SC2W1, SC2W2, SC3W1, or SC3W2)
-           { usePSM = true; psmVariant = to_PSMVariant( argv[++i] ); }
-      else WALBERLA_ABORT("command line argument unknown: " << argv[i] );
+      if( std::strcmp( argv[i], "--Galileo"   ) == 0 )
+      {
+         Galileo   = real_c( std::atof( argv[++i] ) ); // targeted Galileo number
+         continue;
+      }
+      if( std::strcmp( argv[i], "--diameter"  ) == 0 )
+      {
+         diameter  = real_c( std::atof( argv[++i] ) ); // diameter of the spheres, in cells per diameter
+         continue;
+      }
+      if( std::strcmp( argv[i], "--noViscosityIterations" ) == 0 )
+      {
+         noViscosityIterations   = true; // keep viscosity unchanged in initial simulation
+         continue;
+      }
+      if( std::strcmp( argv[i], "--vtkIOInit" ) == 0 )
+      {
+         vtkIOInit = true; // write vtk IO for initial simulation
+         continue;
+      }
+      if( std::strcmp( argv[i], "--longDom"   ) == 0 )
+      {
+         longDom   = true; // use a domain that is extended by the original domain length in positive and negative streamwise direction
+         continue;
+      }
+      if( std::strcmp( argv[i], "--useMEM"    ) == 0 ) // use momentum exchange coupling and the given MEM variant (BB, CLI, or MR)
+      {
+         useMEM = true;
+         memVariant = to_MEMVariant( argv[++i] );
+         continue;
+      }
+      if( std::strcmp( argv[i], "--usePSM"    ) == 0 ) // use partially saturated cells method and the given PSM variant (SC1W1, SC1W2, SC2W1, SC2W2, SC3W1, or SC3W2)
+      {
+         usePSM = true;
+         psmVariant = to_PSMVariant( argv[++i] );
+         continue;
+      }
+      WALBERLA_ABORT("command line argument unknown: " << argv[i] );
    }
    if( !useMEM && !usePSM ) WALBERLA_ABORT("No coupling method chosen via command line!\nChose either \"--useMEM MEMVARIANT\" or \"--usePSM PSMVARIANT\"!");
 
@@ -712,24 +740,24 @@ int main( int argc, char **argv )
    // values are taken from the original simulation of Uhlmann, Dusek
    switch( int(Galileo) )
    {
-      case 144:
-         Re_target = real_t(185.08);
-         timestepsNonDim = real_t(100);
-         break;
-      case 178:
-         Re_target = real_t(243.01);
-         timestepsNonDim = real_t(250);
-         break;
-      case 190:
-         Re_target = real_t(262.71);
-         timestepsNonDim = real_t(250);
-         break;
-      case 250:
-         Re_target = real_t(365.10);
-         timestepsNonDim = real_t(510);
-         break;
-      default:
-         WALBERLA_ABORT("Galileo number is different from the usual ones (144, 178, 190, or 250). No estimate of the Reynolds number available. Add this case manually!");
+   case 144:
+      Re_target = real_t(185.08);
+      timestepsNonDim = real_t(100);
+      break;
+   case 178:
+      Re_target = real_t(243.01);
+      timestepsNonDim = real_t(250);
+      break;
+   case 190:
+      Re_target = real_t(262.71);
+      timestepsNonDim = real_t(250);
+      break;
+   case 250:
+      Re_target = real_t(365.10);
+      timestepsNonDim = real_t(510);
+      break;
+   default:
+      WALBERLA_ABORT("Galileo number is different from the usual ones (144, 178, 190, or 250). No estimate of the Reynolds number available. Add this case manually!");
    }
 
    // estimate fitting inflow velocity (diffusive scaling, viscosity is fixed)
@@ -890,7 +918,7 @@ int main( int argc, char **argv )
 
    // add boundary handling & initialize outer domain boundaries
    BlockDataID boundaryHandlingID = blocks->addStructuredBlockData< BoundaryHandling_T >(
-                                    MyBoundaryHandling( flagFieldID, pdfFieldID, bodyFieldID, pdfFieldPreColID, uInfty ), "boundary handling" );
+                                       MyBoundaryHandling( flagFieldID, pdfFieldID, bodyFieldID, pdfFieldPreColID, uInfty ), "boundary handling" );
 
    if( usePSM ){
       // mapping of sphere required by PSM methods
@@ -969,8 +997,8 @@ int main( int argc, char **argv )
 
       // add LBM communication function and boundary handling sweep
       timeloopInit.add()
-         << BeforeFunction( commFunction, "LBM Communication" )
-         << Sweep( BoundaryHandling_T::getBlockSweep( boundaryHandlingID ), "Boundary Handling" );
+            << BeforeFunction( commFunction, "LBM Communication" )
+            << Sweep( BoundaryHandling_T::getBlockSweep( boundaryHandlingID ), "Boundary Handling" );
 
       // LBM stream collide sweep
       if( psmVariant == PSMVariant::SC1W1 )
@@ -1079,8 +1107,8 @@ int main( int argc, char **argv )
       }
       WALBERLA_LOG_INFO_ON_ROOT("Initial simulation has ended.")
 
-      //evaluate the gravitational force necessary to keep the sphere at a approximately fixed position
-      gravity = forceEval->getForce() / ( (densityRatio - real_t(1) ) * diameter * diameter * diameter * math::pi / real_t(6) );
+            //evaluate the gravitational force necessary to keep the sphere at a approximately fixed position
+            gravity = forceEval->getForce() / ( (densityRatio - real_t(1) ) * diameter * diameter * diameter * math::pi / real_t(6) );
       GalileoSim = std::sqrt( ( densityRatio - real_t(1) ) * gravity * diameter * diameter * diameter ) / viscosity;
       ReynoldsSim = uIn * diameter / viscosity;
       u_ref = std::sqrt( std::fabs(densityRatio - real_t(1)) * gravity * diameter );
@@ -1113,9 +1141,9 @@ int main( int argc, char **argv )
       // iterate all blocks with an iterator 'block' and change the collision model
       for( auto block = blocks->begin(); block != blocks->end(); ++block )
       {
-          // get the field data out of the block
-          auto pdf = block->getData< PdfField_T > ( pdfFieldID );
-          pdf->latticeModel().collisionModel().resetWithMagicNumber( newOmega, magicNumberTRT );
+         // get the field data out of the block
+         auto pdf = block->getData< PdfField_T > ( pdfFieldID );
+         pdf->latticeModel().collisionModel().resetWithMagicNumber( newOmega, magicNumberTRT );
       }
 
       WALBERLA_LOG_INFO_ON_ROOT("==> Adapting viscosity:");
@@ -1157,8 +1185,8 @@ int main( int argc, char **argv )
 
          // add LBM communication function and boundary handling sweep (does the hydro force calculations and the no-slip treatment)
          timeloop.add()
-            << BeforeFunction( commFunction, "LBM Communication" )
-            << Sweep( BoundaryHandling_T::getBlockSweep( boundaryHandlingID ), "Boundary Handling" );
+               << BeforeFunction( commFunction, "LBM Communication" )
+               << Sweep( BoundaryHandling_T::getBlockSweep( boundaryHandlingID ), "Boundary Handling" );
 
          // LBM stream collide sweep
          if( psmVariant == PSMVariant::SC1W1 )
diff --git a/apps/benchmarks/NonUniformGrid/CMakeLists.txt b/apps/benchmarks/NonUniformGrid/CMakeLists.txt
index 61e9e321e18584351f7e08839a94bceca92fe1a1..4e118017bfca8e2fb6dc90903870063f2c692c42 100644
--- a/apps/benchmarks/NonUniformGrid/CMakeLists.txt
+++ b/apps/benchmarks/NonUniformGrid/CMakeLists.txt
@@ -3,4 +3,4 @@ waLBerla_link_files_to_builddir( "*.dat" )
 
 
 waLBerla_add_executable ( NAME NonUniformGridBenchmark 
-                          DEPENDS blockforest boundary core domain_decomposition field lbm postprocessing timeloop vtk )
\ No newline at end of file
+                          DEPENDS blockforest boundary core domain_decomposition field lbm postprocessing timeloop vtk sqlite)
\ No newline at end of file
diff --git a/apps/benchmarks/NonUniformGrid/NonUniformGrid.cpp b/apps/benchmarks/NonUniformGrid/NonUniformGrid.cpp
index f4528cbf65db1514641c07921a1e71d3fcbacc91..618f29af9f70ce8e81ea1223734622116a6449d4 100644
--- a/apps/benchmarks/NonUniformGrid/NonUniformGrid.cpp
+++ b/apps/benchmarks/NonUniformGrid/NonUniformGrid.cpp
@@ -64,7 +64,7 @@
 #include "lbm/vtk/Density.h"
 #include "lbm/vtk/Velocity.h"
 
-#include "postprocessing/sqlite/SQLite.h"
+#include "sqlite/SQLite.h"
 
 #include "stencil/D3Q19.h"
 #include "stencil/D3Q27.h"
@@ -1034,12 +1034,12 @@ void run( const shared_ptr< Config > & config, const LatticeModel_T & latticeMod
                }
             }
 
-            auto runId = postprocessing::storeRunInSqliteDB( sqlFile, integerProperties, stringProperties, realProperties );
-            postprocessing::storeTimingPoolInSqliteDB( sqlFile, runId, *reducedTimeloopTiming, "Timeloop" );
-            postprocessing::storeTimingPoolInSqliteDB( sqlFile, runId, *reducedRTSTiming, "RefinementTimeStep" );
-            postprocessing::storeTimingPoolInSqliteDB( sqlFile, runId, *reducedRTSLTiming, "RefinementTimeStepLevelwise" );
+            auto runId = sqlite::storeRunInSqliteDB( sqlFile, integerProperties, stringProperties, realProperties );
+            sqlite::storeTimingPoolInSqliteDB( sqlFile, runId, *reducedTimeloopTiming, "Timeloop" );
+            sqlite::storeTimingPoolInSqliteDB( sqlFile, runId, *reducedRTSTiming, "RefinementTimeStep" );
+            sqlite::storeTimingPoolInSqliteDB( sqlFile, runId, *reducedRTSLTiming, "RefinementTimeStepLevelwise" );
             if( blockStructureRefreshDuringMeasurement )
-               postprocessing::storeTimingPoolInSqliteDB( sqlFile, runId, *reducedRefreshTiming, "BlockForestRefresh" );
+               sqlite::storeTimingPoolInSqliteDB( sqlFile, runId, *reducedRefreshTiming, "BlockForestRefresh" );
          }
       }
    }
diff --git a/apps/benchmarks/PoiseuilleChannel/CMakeLists.txt b/apps/benchmarks/PoiseuilleChannel/CMakeLists.txt
index 29c47a03635c1f90ce8ec33d902c0866a40c9beb..b5d3d42a7fc0cc67f07307324c198144dad97a99 100644
--- a/apps/benchmarks/PoiseuilleChannel/CMakeLists.txt
+++ b/apps/benchmarks/PoiseuilleChannel/CMakeLists.txt
@@ -1,7 +1,7 @@
 
 waLBerla_link_files_to_builddir( "*.dat" )                 
                                   
-waLBerla_add_executable( NAME PoiseuilleChannel DEPENDS blockforest boundary core field lbm postprocessing stencil timeloop vtk )
+waLBerla_add_executable( NAME PoiseuilleChannel DEPENDS blockforest boundary core field lbm postprocessing stencil timeloop vtk sqlite)
 
 ##############
 # Some tests #
diff --git a/apps/benchmarks/PoiseuilleChannel/PoiseuilleChannel.cpp b/apps/benchmarks/PoiseuilleChannel/PoiseuilleChannel.cpp
index 1a0482f5781a272ae6159653f4e39435556f2aa7..b72efbdcbfb90a2502523e3fff73122f36f2f65c 100644
--- a/apps/benchmarks/PoiseuilleChannel/PoiseuilleChannel.cpp
+++ b/apps/benchmarks/PoiseuilleChannel/PoiseuilleChannel.cpp
@@ -78,7 +78,7 @@
 #include "lbm/vtk/NonEquilibrium.h"
 #include "lbm/vtk/Velocity.h"
 
-#include "postprocessing/sqlite/SQLite.h"
+#include "sqlite/SQLite.h"
 
 #include "stencil/D3Q19.h"
 #include "stencil/D3Q27.h"
@@ -553,12 +553,12 @@ void setFlags( shared_ptr< StructuredBlockForest > & blocks, const BlockDataID &
       {
          CurvedDeltaValueCalculation< LatticeModel_T > deltaCalculation( blocks, *block, channel );
 
-         lbm::refinement::consistentlyForceBoundary< BoundaryHandling_T >( *blocks, dynamic_cast< blockforest::Block & >(*block.get()),
+         lbm::refinement::consistentlyForceBoundary< BoundaryHandling_T >( *blocks, dynamic_cast< blockforest::Block & >(*block),
                                                                            boundaryHandlingId, Curved_Flag, channel, deltaCalculation );
       }
       else // staircase (1st order bounce back no-slip boundary condition)
       {
-         lbm::refinement::consistentlyForceBoundary< BoundaryHandling_T >( *blocks, dynamic_cast< blockforest::Block & >(*block.get()),
+         lbm::refinement::consistentlyForceBoundary< BoundaryHandling_T >( *blocks, dynamic_cast< blockforest::Block & >(*block),
                                                                            boundaryHandlingId, NoSlip_Flag, channel );
       }
 
@@ -995,10 +995,10 @@ void run( const shared_ptr< Config > & config, const LatticeModel_T & latticeMod
             
             realProperties[ "simulationProgress" ] = double_c( ( outerRun + uint_t(1) ) * innerTimeSteps ) / double_c( outerTimeSteps * innerTimeSteps );
 
-            auto runId = postprocessing::storeRunInSqliteDB( sqlFile, integerProperties, stringProperties, realProperties );
-            postprocessing::storeTimingPoolInSqliteDB( sqlFile, runId, *reducedTimeloopTiming, "Timeloop" );
-            postprocessing::storeTimingPoolInSqliteDB( sqlFile, runId, *reducedRTSTiming, "RefinementTimeStep" );
-            postprocessing::storeTimingPoolInSqliteDB( sqlFile, runId, *reducedRTSLTiming, "RefinementTimeStepLevelwise" );
+            auto runId = sqlite::storeRunInSqliteDB( sqlFile, integerProperties, stringProperties, realProperties );
+            sqlite::storeTimingPoolInSqliteDB( sqlFile, runId, *reducedTimeloopTiming, "Timeloop" );
+            sqlite::storeTimingPoolInSqliteDB( sqlFile, runId, *reducedRTSTiming, "RefinementTimeStep" );
+            sqlite::storeTimingPoolInSqliteDB( sqlFile, runId, *reducedRTSLTiming, "RefinementTimeStepLevelwise" );
          }
       }
    }
diff --git a/apps/benchmarks/ProbeVsExtraMessage/CMakeLists.txt b/apps/benchmarks/ProbeVsExtraMessage/CMakeLists.txt
index a5cd53649d6ac5c011c026346d137dbcb862a20c..70ff75bc67f6f5992aadf87a5d6dbae75080cf58 100644
--- a/apps/benchmarks/ProbeVsExtraMessage/CMakeLists.txt
+++ b/apps/benchmarks/ProbeVsExtraMessage/CMakeLists.txt
@@ -4,4 +4,4 @@ waLBerla_add_executable ( NAME PackPerformance
 
 waLBerla_add_executable ( NAME ProbeVsExtraMessage 
                           FILES ProbeVsExtraMessage.cpp
-                          DEPENDS core postprocessing stencil )
+                          DEPENDS core postprocessing stencil sqlite)
diff --git a/apps/benchmarks/ProbeVsExtraMessage/ProbeVsExtraMessage.cpp b/apps/benchmarks/ProbeVsExtraMessage/ProbeVsExtraMessage.cpp
index 960bf1e9e7efd662d867ffe5c952cdceec9ee776..bb9adfd177d72d0fd503dc62e896598353eebcfa 100644
--- a/apps/benchmarks/ProbeVsExtraMessage/ProbeVsExtraMessage.cpp
+++ b/apps/benchmarks/ProbeVsExtraMessage/ProbeVsExtraMessage.cpp
@@ -26,7 +26,7 @@
 #include "core/mpi/BufferSystem.h"
 #include "core/mpi/MPIManager.h"
 #include "core/timing/TimingPool.h"
-#include "postprocessing/sqlite/SQLite.h"
+#include "sqlite/SQLite.h"
 #include "stencil/D3Q27.h"
 #include "stencil/D3Q19.h"
 #include "stencil/D3Q7.h"
@@ -250,9 +250,9 @@ int main( int argc, char ** argv )
       stringProperties["SLURM_NTASKS_PER_SOCKET"]  = envToString(std::getenv( "SLURM_NTASKS_PER_SOCKET" ));
       stringProperties["SLURM_TASKS_PER_NODE"]     = envToString(std::getenv( "SLURM_TASKS_PER_NODE" ));
 
-      auto runId = postprocessing::storeRunInSqliteDB( "ProbeVsTwoMessages.sqlite", integerProperties, stringProperties, realProperties );
-      postprocessing::storeTimingPoolInSqliteDB( "ProbeVsTwoMessages.sqlite", runId, tp_twoMessages, "twoMessages" );
-      postprocessing::storeTimingPoolInSqliteDB( "ProbeVsTwoMessages.sqlite", runId, tp_probe, "probe" );
+      auto runId = sqlite::storeRunInSqliteDB( "ProbeVsTwoMessages.sqlite", integerProperties, stringProperties, realProperties );
+      sqlite::storeTimingPoolInSqliteDB( "ProbeVsTwoMessages.sqlite", runId, tp_twoMessages, "twoMessages" );
+      sqlite::storeTimingPoolInSqliteDB( "ProbeVsTwoMessages.sqlite", runId, tp_probe, "probe" );
    }
 
    return 0;
diff --git a/apps/benchmarks/SchaeferTurek/CMakeLists.txt b/apps/benchmarks/SchaeferTurek/CMakeLists.txt
index 67fe8d84c23f811c28f2fb99f07dc3073190e86a..88463aaf3860249071e395f74a1bd1765127ef17 100644
--- a/apps/benchmarks/SchaeferTurek/CMakeLists.txt
+++ b/apps/benchmarks/SchaeferTurek/CMakeLists.txt
@@ -1,6 +1,6 @@
 
 waLBerla_link_files_to_builddir( "*.dat" )   
                                   
-waLBerla_add_executable( NAME SchaeferTurek DEPENDS blockforest boundary core field lbm postprocessing stencil timeloop vtk )
+waLBerla_add_executable( NAME SchaeferTurek DEPENDS blockforest boundary core field lbm postprocessing stencil timeloop vtk sqlite )
 
 waLBerla_execute_test( NO_MODULE_LABEL NAME SchaeferTurekTest COMMAND $<TARGET_FILE:SchaeferTurek> Test2D.dat PROCESSES 4 CONFIGURATIONS Release RelWithDbgInfo )
\ No newline at end of file
diff --git a/apps/benchmarks/SchaeferTurek/SchaeferTurek.cpp b/apps/benchmarks/SchaeferTurek/SchaeferTurek.cpp
index fcd8ba66932c1433b8c1ed4f7e11933982f277c3..50c3a9244da51ae3fa5dfec97d5b928ca8f56ced 100644
--- a/apps/benchmarks/SchaeferTurek/SchaeferTurek.cpp
+++ b/apps/benchmarks/SchaeferTurek/SchaeferTurek.cpp
@@ -93,7 +93,7 @@
 #include "lbm/vtk/NonEquilibrium.h"
 #include "lbm/vtk/Velocity.h"
 
-#include "postprocessing/sqlite/SQLite.h"
+#include "sqlite/SQLite.h"
 
 #include "stencil/D3Q15.h"
 #include "stencil/D3Q19.h"
@@ -961,12 +961,12 @@ void BoundarySetter< LatticeModel_T >::operator()()
       {
          CurvedDeltaValueCalculation< LatticeModel_T > deltaCalculation( blocks, *block, cylinder );
 
-         lbm::refinement::consistentlyForceBoundary< BoundaryHandling_T >( *blocks, dynamic_cast< blockforest::Block & >(*block.get()),
+         lbm::refinement::consistentlyForceBoundary< BoundaryHandling_T >( *blocks, dynamic_cast< blockforest::Block & >(*block),
                                                                            boundaryHandlingId_, Curved_Flag, cylinder, deltaCalculation );
       }
       else // staircase
       {
-         lbm::refinement::consistentlyForceBoundary< BoundaryHandling_T >( *blocks, dynamic_cast< blockforest::Block & >(*block.get()),
+         lbm::refinement::consistentlyForceBoundary< BoundaryHandling_T >( *blocks, dynamic_cast< blockforest::Block & >(*block),
                                                                            boundaryHandlingId_, Obstacle_Flag, cylinder );
       }
 
@@ -2787,12 +2787,12 @@ void run( const shared_ptr< Config > & config, const LatticeModel_T & latticeMod
             if( evaluationCheckFrequency != uint_t(0) )
                evaluation->getResultsForSQLOnRoot( realProperties, integerProperties );
 
-            auto runId = postprocessing::storeRunInSqliteDB( sqlFile, integerProperties, stringProperties, realProperties );
-            postprocessing::storeTimingPoolInSqliteDB( sqlFile, runId, *reducedTimeloopTiming, "Timeloop" );
-            postprocessing::storeTimingPoolInSqliteDB( sqlFile, runId, *reducedRTSTiming, "RefinementTimeStep" );
-            postprocessing::storeTimingPoolInSqliteDB( sqlFile, runId, *reducedRTSLTiming, "RefinementTimeStepLevelwise" );
+            auto runId = sqlite::storeRunInSqliteDB( sqlFile, integerProperties, stringProperties, realProperties );
+            sqlite::storeTimingPoolInSqliteDB( sqlFile, runId, *reducedTimeloopTiming, "Timeloop" );
+            sqlite::storeTimingPoolInSqliteDB( sqlFile, runId, *reducedRTSTiming, "RefinementTimeStep" );
+            sqlite::storeTimingPoolInSqliteDB( sqlFile, runId, *reducedRTSLTiming, "RefinementTimeStepLevelwise" );
             if( dynamicBlockStructure )
-               postprocessing::storeTimingPoolInSqliteDB( sqlFile, runId, *reducedRefreshTiming, "BlockForestRefresh" );
+               sqlite::storeTimingPoolInSqliteDB( sqlFile, runId, *reducedRefreshTiming, "BlockForestRefresh" );
          }
       }
    }
diff --git a/apps/benchmarks/UniformGrid/CMakeLists.txt b/apps/benchmarks/UniformGrid/CMakeLists.txt
index 512aa80fcaa360b526c976648c995a9a397ebedd..2f75f12b5bc13630028bfcd3c63f036c94d16dab 100644
--- a/apps/benchmarks/UniformGrid/CMakeLists.txt
+++ b/apps/benchmarks/UniformGrid/CMakeLists.txt
@@ -3,4 +3,4 @@ waLBerla_link_files_to_builddir( "*.dat" )
 
 
 waLBerla_add_executable ( NAME UniformGridBenchmark 
-                          DEPENDS blockforest boundary core domain_decomposition field lbm postprocessing timeloop vtk )
\ No newline at end of file
+                          DEPENDS blockforest boundary core domain_decomposition field lbm postprocessing timeloop vtk sqlite )
\ No newline at end of file
diff --git a/apps/benchmarks/UniformGrid/UniformGrid.cpp b/apps/benchmarks/UniformGrid/UniformGrid.cpp
index 96e50eb129069daa7b5006ca9fe144eb005bdf7a..bd9efc7d40ead02f4e7e041e7f774cbfff4fdfa2 100644
--- a/apps/benchmarks/UniformGrid/UniformGrid.cpp
+++ b/apps/benchmarks/UniformGrid/UniformGrid.cpp
@@ -70,7 +70,7 @@
 #include "lbm/vtk/Density.h"
 #include "lbm/vtk/Velocity.h"
 
-#include "postprocessing/sqlite/SQLite.h"
+#include "sqlite/SQLite.h"
 
 #include "stencil/D3Q19.h"
 #include "stencil/D3Q27.h"
@@ -783,8 +783,8 @@ void run( const shared_ptr< Config > & config, const LatticeModel_T & latticeMod
             stringProperties[ "fullCommunication" ] = ( fullComm ? "yes" : "no" );
             stringProperties[ "directComm"]         = ( directComm ? "yes" : "no" );
 
-            auto runId = postprocessing::storeRunInSqliteDB( sqlFile, integerProperties, stringProperties, realProperties );
-            postprocessing::storeTimingPoolInSqliteDB( sqlFile, runId, *reducedTimeloopTiming, "Timeloop" );
+            auto runId = sqlite::storeRunInSqliteDB( sqlFile, integerProperties, stringProperties, realProperties );
+            sqlite::storeTimingPoolInSqliteDB( sqlFile, runId, *reducedTimeloopTiming, "Timeloop" );
          }
       }
    }
diff --git a/apps/tutorials/pe/02_ConfinedGasExtended.cpp b/apps/tutorials/pe/02_ConfinedGasExtended.cpp
index b39cf5f3e636b8a654bf1f078c32fe306a3021d6..69629eba1e82294ecaff18e5f25c540df05e5c91 100644
--- a/apps/tutorials/pe/02_ConfinedGasExtended.cpp
+++ b/apps/tutorials/pe/02_ConfinedGasExtended.cpp
@@ -32,7 +32,7 @@
 #include <core/math/Random.h>
 #include <core/timing/TimingTree.h>
 #include <core/waLBerlaBuildInfo.h>
-#include <postprocessing/sqlite/SQLite.h>
+#include <sqlite/SQLite.h>
 #include <vtk/VTKOutput.h>
 
 #include <functional>
@@ -289,9 +289,9 @@ int main( int argc, char ** argv )
    //! [SQL Save]
    WALBERLA_ROOT_SECTION()
    {
-      auto runId = postprocessing::storeRunInSqliteDB( sqlFile, integerProperties, stringProperties, realProperties );
-      postprocessing::storeTimingPoolInSqliteDB( sqlFile, runId, *tpReduced, "Timeloop" );
-      postprocessing::storeTimingTreeInSqliteDB( sqlFile, runId, tt, "TimingTree" );
+      auto runId = sqlite::storeRunInSqliteDB( sqlFile, integerProperties, stringProperties, realProperties );
+      sqlite::storeTimingPoolInSqliteDB( sqlFile, runId, *tpReduced, "Timeloop" );
+      sqlite::storeTimingTreeInSqliteDB( sqlFile, runId, tt, "TimingTree" );
    }
    //! [SQL Save]
 
diff --git a/apps/tutorials/pe/CMakeLists.txt b/apps/tutorials/pe/CMakeLists.txt
index a41407eccd3e2306c1dda30e9bf6b65d3e534a29..4fda841130cfddf96965e100a1bdfa83d4df49ea 100644
--- a/apps/tutorials/pe/CMakeLists.txt
+++ b/apps/tutorials/pe/CMakeLists.txt
@@ -6,7 +6,7 @@ waLBerla_add_executable ( NAME 01_Tutorial_ConfinedGas
 
 waLBerla_add_executable ( NAME 02_Tutorial_ConfinedGasExtended
                           FILES 02_ConfinedGasExtended.cpp
-                          DEPENDS blockforest core pe postprocessing vtk )
+                          DEPENDS blockforest core pe postprocessing vtk sqlite )
 
 waLBerla_execute_test( NO_MODULE_LABEL NAME 01_Tutorial_ConfinedGas PROCESSES 8 )
 waLBerla_execute_test( NO_MODULE_LABEL NAME 02_Tutorial_ConfinedGasExtended
diff --git a/cmake/waLBerlaFunctions.cmake b/cmake/waLBerlaFunctions.cmake
index 091a9048bb9106c755d9aaf72fa3f96fc24bc2b3..841051458b2901be296cade1ad025c0e2b500757 100644
--- a/cmake/waLBerlaFunctions.cmake
+++ b/cmake/waLBerlaFunctions.cmake
@@ -193,7 +193,9 @@ function ( waLBerla_add_executable )
     foreach ( depMod ${ARG_DEPENDS} )
         get_module_library_name ( depModLibraryName ${depMod} )
         if( NOT TARGET ${depModLibraryName} )
-            message ( STATUS "Skipping ${ARG_NAME} since dependent module ${depMod} was not built" )
+            if( WALBERLA_LOG_SKIPPED )
+               message ( STATUS "Skipping ${ARG_NAME} since dependent module ${depMod} was not built" )
+            endif()
             return()
         endif()
     endforeach()
@@ -224,7 +226,9 @@ function ( waLBerla_add_executable )
                           codeGenRequired ${ARG_CODEGEN_CFG} ${sourceFiles} )
 
     if( NOT WALBERLA_BUILD_WITH_CODEGEN AND codeGenRequired)
-        message(STATUS "Skipping ${ARG_NAME} since pystencils code generation is not enabled")
+        if( WALBERLA_LOG_SKIPPED )
+           message(STATUS "Skipping ${ARG_NAME} since pystencils code generation is not enabled")
+        endif()
         return()
     endif()
 
@@ -383,13 +387,17 @@ function ( waLBerla_execute_test )
    endif()
 
    if( NOT ARG_COMMAND AND NOT TARGET ${ARG_NAME} )
-      message ( STATUS "Skipping test ${ARG_NAME} since the corresponding target is not built" )
+      if( WALBERLA_LOG_SKIPPED )
+         message ( STATUS "Skipping test ${ARG_NAME} since the corresponding target is not built" )
+      endif()
       return()
    endif()
 
    foreach( dependency_target ${ARG_DEPENDS_ON_TARGETS} )
       if( NOT TARGET ${dependency_target} )
-         message ( STATUS "Skipping test ${ARG_NAME} since the target ${dependency_target} is not built" )
+         if( WALBERLA_LOG_SKIPPED )
+            message ( STATUS "Skipping test ${ARG_NAME} since the target ${dependency_target} is not built" )
+         endif()
          return()
       endif()
    endforeach( dependency_target )
diff --git a/python/mesa_pd.py b/python/mesa_pd.py
index b010eb22336bdfcb44b709dc68b5288a10a88220..0ba17be6b76d5f60c39471b924b2fe6c95411471 100755
--- a/python/mesa_pd.py
+++ b/python/mesa_pd.py
@@ -94,7 +94,11 @@ if __name__ == '__main__':
    kernels.append( kernel.ExplicitEuler() )
    kernels.append( kernel.ExplicitEulerWithShape() )
    kernels.append( kernel.ForceLJ() )
+   kernels.append( kernel.HCSITSRelaxationStep() )
    kernels.append( kernel.HeatConduction() )
+   kernels.append( kernel.InitParticlesForHCSITS() )
+   kernels.append( kernel.InitContactsForHCSITS() )
+   kernels.append( kernel.IntegrateParticlesHCSITS() )
    kernels.append( kernel.InsertParticleIntoLinkedCells() )
    kernels.append( kernel.InsertParticleIntoSparseLinkedCells() )
    kernels.append( kernel.LinearSpringDashpot() )
diff --git a/python/mesa_pd/kernel/HCSITSRelaxationStep.py b/python/mesa_pd/kernel/HCSITSRelaxationStep.py
new file mode 100644
index 0000000000000000000000000000000000000000..bb80d20ac32ea60971076fa75d351a7110fa5d84
--- /dev/null
+++ b/python/mesa_pd/kernel/HCSITSRelaxationStep.py
@@ -0,0 +1,32 @@
+# -*- coding: utf-8 -*-
+
+from mesa_pd.accessor import Accessor
+from ..Container import Container
+from mesa_pd.utility import generateFile
+
+class HCSITSRelaxationStep(Container):
+   def __init__(self):
+      super().__init__()
+      self.addProperty("maxSubIterations", "size_t", defValue = "20")
+      self.addProperty("relaxationModel", "RelaxationModel", defValue = "InelasticFrictionlessContact")
+      self.addProperty("deltaMax", "real_t", defValue = "0")
+      self.addProperty("cor", "real_t", defValue = "real_t(0.2)")
+
+      self.accessor = Accessor()
+      self.accessor.require("uid",             "walberla::id_t",                                    access="g")
+      self.accessor.require("position",        "walberla::mesa_pd::Vec3",                           access="g")
+      self.accessor.require("linearVelocity",  "walberla::mesa_pd::Vec3",                           access="g")
+      self.accessor.require("angularVelocity", "walberla::mesa_pd::Vec3",                           access="g")
+      self.accessor.require("invMass",         "walberla::real_t",                                  access="g" )
+      self.accessor.require("invInertia",      "walberla::mesa_pd::Mat3",                           access="g" )
+      self.accessor.require("dv",              "walberla::mesa_pd::Vec3",                           access="gr" )
+      self.accessor.require("dw",              "walberla::mesa_pd::Vec3",                           access="gr" )
+
+   def getRequirements(self):
+      return self.accessor
+
+   def generate(self, path):
+      context = dict()
+      context["properties"]      = self.properties
+      context["interface"]        = self.accessor.properties
+      generateFile(path, 'kernel/HCSITSRelaxationStep.templ.h', context)
diff --git a/python/mesa_pd/kernel/InitContactsForHCSITS.py b/python/mesa_pd/kernel/InitContactsForHCSITS.py
new file mode 100644
index 0000000000000000000000000000000000000000..54da9536a4a2f3569a429357abd02bd7466974a3
--- /dev/null
+++ b/python/mesa_pd/kernel/InitContactsForHCSITS.py
@@ -0,0 +1,28 @@
+# -*- coding: utf-8 -*-
+
+from mesa_pd.accessor import Accessor
+from ..Container import Container
+from mesa_pd.utility import generateFile
+
+class InitContactsForHCSITS(Container):
+   def __init__(self):
+      super().__init__()
+      self.addProperty("erp", "real_t", defValue = "real_t(0.8)")
+      self.addProperty("maximumPenetration", "real_t", defValue ="0")
+
+      self.paccessor = Accessor()
+      self.paccessor.require("uid",             "walberla::id_t",                                    access="g")
+      self.paccessor.require("position",        "walberla::mesa_pd::Vec3",                           access="g")
+      self.paccessor.require("invInertia",      "walberla::mesa_pd::Mat3",                           access="g" )
+      self.paccessor.require("invMass",         "walberla::real_t",                                  access="g" )
+
+
+   def getRequirements(self):
+      return self.paccessor
+
+   def generate(self, path):
+      context = dict()
+      context["properties"]      = self.properties
+      context["material_parameters"] = ["friction"]
+      context["interface"]        = self.paccessor.properties
+      generateFile(path, 'kernel/InitContactsForHCSITS.templ.h', context)
diff --git a/python/mesa_pd/kernel/InitParticlesForHCSITS.py b/python/mesa_pd/kernel/InitParticlesForHCSITS.py
new file mode 100644
index 0000000000000000000000000000000000000000..ca0148cab20c55575aff787611076319ac2fe121
--- /dev/null
+++ b/python/mesa_pd/kernel/InitParticlesForHCSITS.py
@@ -0,0 +1,31 @@
+# -*- coding: utf-8 -*-
+
+from mesa_pd.accessor import Accessor
+from ..Container import Container
+from mesa_pd.utility import generateFile
+
+class InitParticlesForHCSITS(Container):
+   def __init__(self):
+      super().__init__()
+      self.addProperty("globalAcceleration", "walberla::mesa_pd::Vec3", defValue = "0")
+
+      self.accessor = Accessor()
+      self.accessor.require("uid",             "walberla::id_t",                                    access="g")
+      self.accessor.require("linearVelocity",  "walberla::mesa_pd::Vec3",                           access="gr")
+      self.accessor.require("angularVelocity", "walberla::mesa_pd::Vec3",                           access="gr")
+      self.accessor.require("invMass",         "walberla::real_t",                                  access="g" )
+      self.accessor.require("inertia",         "walberla::mesa_pd::Mat3",                           access="g" )
+      self.accessor.require("invInertia",      "walberla::mesa_pd::Mat3",                           access="g" )
+      self.accessor.require("dv",              "walberla::mesa_pd::Vec3",                           access="gr" )
+      self.accessor.require("dw",              "walberla::mesa_pd::Vec3",                           access="gr" )
+      self.accessor.require("torque",          "walberla::mesa_pd::Vec3",                           access="r" )
+      self.accessor.require("force",           "walberla::mesa_pd::Vec3",                           access="r" )
+
+   def getRequirements(self):
+      return self.accessor
+
+   def generate(self, path):
+      context = dict()
+      context["properties"]      = self.properties
+      context["interface"]       = self.accessor.properties
+      generateFile(path, 'kernel/InitParticlesForHCSITS.templ.h', context)
diff --git a/python/mesa_pd/kernel/IntegrateParticlesHCSITS.py b/python/mesa_pd/kernel/IntegrateParticlesHCSITS.py
new file mode 100644
index 0000000000000000000000000000000000000000..b869d5decd30a3cf05a58981544d1309545f93f7
--- /dev/null
+++ b/python/mesa_pd/kernel/IntegrateParticlesHCSITS.py
@@ -0,0 +1,30 @@
+# -*- coding: utf-8 -*-
+
+from mesa_pd.accessor import Accessor
+from ..Container import Container
+from mesa_pd.utility import generateFile
+
+class IntegrateParticlesHCSITS(Container):
+   def __init__(self):
+      super().__init__()
+      self.addProperty("speedLimiterActive", "bool", defValue = "false")
+      self.addProperty("speedLimitFactor",    "real_t", defValue ="real_t(1.0)")
+
+      self.accessor = Accessor()
+      self.accessor.require("uid",              "walberla::id_t",                                   access="g")
+      self.accessor.require("position",         "walberla::mesa_pd::Vec3",                          access="gr")
+      self.accessor.require("rotation",         "walberla::mesa_pd::Rot3",                          access="gr")
+      self.accessor.require("linearVelocity",   "walberla::mesa_pd::Vec3",                          access="gr")
+      self.accessor.require("angularVelocity",  "walberla::mesa_pd::Vec3",                          access="gr")
+      self.accessor.require("dv",               "walberla::mesa_pd::Vec3",                          access="g" )
+      self.accessor.require("dw",               "walberla::mesa_pd::Vec3",                          access="g" )
+      self.accessor.require("flags",            "walberla::mesa_pd::data::particle_flags::FlagT",   access="g")
+
+   def getRequirements(self):
+      return self.accessor
+
+   def generate(self, path):
+      context = dict()
+      context["properties"]      = self.properties
+      context["interface"]       = self.accessor.properties
+      generateFile(path, 'kernel/IntegrateParticlesHCSITS.templ.h', context)
diff --git a/python/mesa_pd/kernel/__init__.py b/python/mesa_pd/kernel/__init__.py
index 758512e84400e6a2442ffc568846942d33fb00b4..eef9907a547ca08e93d35a26eed6d89ef005580b 100644
--- a/python/mesa_pd/kernel/__init__.py
+++ b/python/mesa_pd/kernel/__init__.py
@@ -4,7 +4,11 @@ from .DoubleCast import DoubleCast
 from .ExplicitEuler import ExplicitEuler
 from .ExplicitEulerWithShape import ExplicitEulerWithShape
 from .ForceLJ import ForceLJ
+from .HCSITSRelaxationStep import HCSITSRelaxationStep
 from .HeatConduction import HeatConduction
+from .InitParticlesForHCSITS import InitParticlesForHCSITS
+from .InitContactsForHCSITS import InitContactsForHCSITS
+from .IntegrateParticlesHCSITS import IntegrateParticlesHCSITS
 from .InsertParticleIntoLinkedCells import InsertParticleIntoLinkedCells
 from .InsertParticleIntoSparseLinkedCells import InsertParticleIntoSparseLinkedCells
 from .LinearSpringDashpot import LinearSpringDashpot
@@ -20,7 +24,11 @@ __all__ = ['DoubleCast',
            'ExplicitEuler',
            'ExplicitEulerWithShape',
            'ForceLJ',
+           'HCSITSRelaxationStep',
            'HeatConduction',
+           'InitParticlesForHCSITS',
+           'InitContactsForHCSITS',
+           'IntegrateParticlesHCSITS',
            'InsertParticleIntoLinkedCells',
            'InsertParticleIntoSparseLinkedCells',
            'LinearSpringDashpot',
diff --git a/python/mesa_pd/templates/data/ContactAccessor.templ.h b/python/mesa_pd/templates/data/ContactAccessor.templ.h
index 50190bf636f3e81461634778c161d5abaafc6554..b51f5de7fd5f4f21d7f58f504da39043a652aeb0 100644
--- a/python/mesa_pd/templates/data/ContactAccessor.templ.h
+++ b/python/mesa_pd/templates/data/ContactAccessor.templ.h
@@ -26,7 +26,7 @@
 
 #pragma once
 
-#include <mesa_pd/data/IAccessor.h>
+#include <mesa_pd/data/IContactAccessor.h>
 #include <mesa_pd/data/ContactStorage.h>
 
 #include <core/UniqueID.h>
@@ -43,7 +43,7 @@ namespace data {
  * Provides get, set and getRef for all members of the ContactStorage.
  * Can be used as a basis class for a more advanced ContactAccessor.
  */
-class ContactAccessor : public IAccessor
+class ContactAccessor : public IContactAccessor
 {
 public:
    ContactAccessor(const std::shared_ptr<data::ContactStorage>& ps) : ps_(ps) {}
diff --git a/python/mesa_pd/templates/kernel/HCSITSRelaxationStep.templ.h b/python/mesa_pd/templates/kernel/HCSITSRelaxationStep.templ.h
new file mode 100644
index 0000000000000000000000000000000000000000..1523a57b348524dba5dd3ce1edba892cb19d912c
--- /dev/null
+++ b/python/mesa_pd/templates/kernel/HCSITSRelaxationStep.templ.h
@@ -0,0 +1,1049 @@
+//======================================================================================================================
+//
+//  This file is part of waLBerla. waLBerla is free software: you can
+//  redistribute it and/or modify it under the terms of the GNU General Public
+//  License as published by the Free Software Foundation, either version 3 of
+//  the License, or (at your option) any later version.
+//
+//  waLBerla is distributed in the hope that it will be useful, but WITHOUT
+//  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+//  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+//  for more details.
+//
+//  You should have received a copy of the GNU General Public License along
+//  with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file HCSITSRelaxationStep.h
+//! \author Sebastian Eibl <sebastian.eibl@fau.de>
+//! \author Tobias Leemann <tobias.leemann@fau.de>
+//
+//======================================================================================================================
+
+//======================================================================================================================
+//
+//  THIS FILE IS GENERATED - PLEASE CHANGE THE TEMPLATE !!!
+//
+//======================================================================================================================
+
+#pragma once
+
+#include <mesa_pd/common/ParticleFunctions.h>
+#include <mesa_pd/data/DataTypes.h>
+#include <mesa_pd/data/IAccessor.h>
+#include <mesa_pd/data/IContactAccessor.h>
+#include <mesa_pd/data/Flags.h>
+#include <core/logging/Logging.h>
+#include <core/math/Constants.h>
+#include <core/math/Limits.h>
+
+#include <vector>
+
+namespace walberla {
+namespace mesa_pd {
+namespace kernel {
+/**
+ * Apply a HCSITS (Hard-contact semi-implicit timestepping solver) relaxation to all contacts.
+ * Call this kernel on all bodies to perform on relaxation step of the solver.
+ * There exist different friction and relaxation models. See comments on their respective methods
+ * for an extended documentation. Use setRelaxationModel() to set it.
+ * getDeltaMax() can be used to query the maximum change in the impulses applied wrt to the last iteration.
+ *
+ * Use setMaxSubIterations() to set the maximum number of iterations performed to solve optimization problems arising
+ * during the relaxation (in InelasticGeneralizedMaximumDissipationContact and InelasticCoulombContactByDecoupling).
+ *
+ * Use setCor() to set the coefficient of restitution between 0 and 1 for the InelasticProjectedGaussSeidel model.
+ * All other models describe inelastic contacts.
+ *
+ * Example of Using the HCSITS kernels in a simulation:
+ * \code
+ *     // ps: Particle storage
+ *     // cs: Contact storage
+ *     // pa: Particle accessor
+ *     // ca: Contact accessor
+ *
+ *     // Detect contacts first and fill contact storage
+ *
+ *     mesa_pd::mpi::ReduceProperty reductionKernel;
+ *     mesa_pd::mpi::BroadcastProperty broadcastKernel;
+ *
+ *     kernel::IntegrateBodiesHCSITS integration;
+ *
+ *     kernel::InitContactsForHCSITS initContacts(1);
+ *     initContacts.setFriction(0,0,real_t(0.2));
+ *     kernel::InitBodiesForHCSITS initBodies;
+ *
+ *     kernel::HCSITSRelaxationStep relaxationStep;
+ *     relaxationStep.setCor(real_t(0.1)); // Only effective for PGSM
+ *
+ *     // Init Contacts and Bodies (order is arbitrary)
+ *     cs.forEachContact(false, kernel::SelectAll(), ca, initContacts, ca, pa);
+ *     ps.forEachParticle(false, kernel::SelectAll(), pa, initBodies, pa, dt);
+ *
+ *     // Reduce and Broadcast velocities with relaxation parameter 1 before the iteration
+ *     VelocityUpdateNotification::Parameters::relaxationParam = real_t(1.0);
+ *     reductionKernel.operator()<VelocityCorrectionNotification>(*ps);
+ *     broadcastKernel.operator()<VelocityUpdateNotification>(*ps);
+ *
+ *     VelocityUpdateNotification::Parameters::relaxationParam = real_t(0.8);
+ *     for(int j = 0; j < 10; j++){
+ *        cs.forEachContact(false, kernel::SelectAll(), ca, relaxationStep, ca, pa, dt);
+ *        reductionKernel.operator()<VelocityCorrectionNotification>(*ps);
+ *        broadcastKernel.operator()<VelocityUpdateNotification>(*ps);
+ *     }
+ *
+ *     ps.forEachParticle(false, kernel::SelectAll(), pa, integration, pa, dt);
+ * \endcode
+ * \ingroup mesa_pd_kernel
+ *
+ *
+ */
+class HCSITSRelaxationStep
+{
+public:
+   enum RelaxationModel {
+      InelasticFrictionlessContact,
+      ApproximateInelasticCoulombContactByDecoupling,
+      ApproximateInelasticCoulombContactByOrthogonalProjections,
+      InelasticCoulombContactByDecoupling,
+      InelasticCoulombContactByOrthogonalProjections,
+      InelasticGeneralizedMaximumDissipationContact,
+      InelasticProjectedGaussSeidel
+   };
+   
+   // Default constructor sets the default values
+   HCSITSRelaxationStep() :
+   {%- for prop in properties %}
+   {{prop.name}}_( {{prop.defValue}} ){{ "," if not loop.last}}
+   {%- endfor %}
+   {}
+
+   // Getter and Setter Functions
+   {%- for prop in properties %}
+   inline const {{prop.type}}& get{{prop.name | capFirst}}() const {return {{prop.name}}_;}
+   inline void set{{prop.name | capFirst}}({{prop.type}} v) { {{prop.name}}_ = v;}
+   {% endfor %}
+
+   /**
+    * Perform relaxation for a single contact.
+    * \param cid The index of the contact with the accessor ca.
+    * \param ca The contact accessor.
+    * \param pa The particle accessor.
+    * \param dt The timestep size used.
+    */
+   template <typename CAccessor, typename PAccessor>
+   void operator()(size_t cid, CAccessor &ca, PAccessor& pa,  real_t dt);
+
+   template <typename CAccessor, typename PAccessor>
+   real_t relaxInelasticFrictionlessContacts(size_t cid, real_t dtinv, CAccessor &ca, PAccessor& pa);
+
+   template <typename CAccessor, typename PAccessor>
+   real_t relaxApproximateInelasticCoulombContactsByDecoupling(size_t cid, real_t dtinv, CAccessor &ca, PAccessor& pa);
+
+   template <typename CAccessor, typename PAccessor>
+   real_t relaxInelasticCoulombContactsByDecoupling(size_t cid, real_t dtinv, CAccessor &ca, PAccessor& pa );
+
+   template <typename CAccessor, typename PAccessor>
+   real_t relaxInelasticCoulombContactsByOrthogonalProjections(size_t cid, real_t dtinv, bool approximate, CAccessor &ca, PAccessor& pa );
+
+   template <typename CAccessor, typename PAccessor>
+   real_t relaxInelasticGeneralizedMaximumDissipationContacts(size_t cid, real_t dtinv, CAccessor &ca, PAccessor& pa );
+
+   template <typename CAccessor, typename PAccessor>
+   real_t relaxInelasticContactsByProjectedGaussSeidel(size_t cid, real_t dtinv, CAccessor &ca, PAccessor& pa );
+
+private:
+   // List properties
+   {% for prop in properties %}
+   {{prop.type}} {{prop.name }}_;
+   {%- endfor %}
+};
+
+
+template <typename CAccessor, typename PAccessor>
+inline void HCSITSRelaxationStep::operator()(size_t cid, CAccessor &ca, PAccessor& pa,  real_t dt)
+{
+   static_assert(std::is_base_of<data::IContactAccessor, CAccessor>::value, "please provide a valid contact accessor");
+   static_assert(std::is_base_of<data::IAccessor, PAccessor>::value, "please provide a valid accessor");
+
+   real_t dtinv(real_t(1.0)/dt);
+   switch( getRelaxationModel() ) {
+      case InelasticFrictionlessContact:
+         setDeltaMax(std::max( getDeltaMax(), relaxInelasticFrictionlessContacts(cid, dtinv, ca, pa )));
+         break;
+
+      case ApproximateInelasticCoulombContactByDecoupling:
+         setDeltaMax(std::max( getDeltaMax(), relaxApproximateInelasticCoulombContactsByDecoupling( cid, dtinv, ca, pa )));
+         break;
+
+      case ApproximateInelasticCoulombContactByOrthogonalProjections:
+         setDeltaMax(std::max( getDeltaMax(), relaxInelasticCoulombContactsByOrthogonalProjections( cid, dtinv, true, ca, pa )));
+         break;
+
+      case InelasticCoulombContactByDecoupling:
+         setDeltaMax(std::max( getDeltaMax(), relaxInelasticCoulombContactsByDecoupling( cid, dtinv, ca, pa )));
+         break;
+
+      case InelasticCoulombContactByOrthogonalProjections:
+         setDeltaMax(std::max( getDeltaMax(), relaxInelasticCoulombContactsByOrthogonalProjections( cid, dtinv, false, ca, pa )));
+         break;
+
+      case InelasticGeneralizedMaximumDissipationContact:
+         setDeltaMax(std::max( getDeltaMax(), relaxInelasticGeneralizedMaximumDissipationContacts( cid, dtinv, ca, pa )));
+         break;
+
+      case InelasticProjectedGaussSeidel:
+         setDeltaMax(std::max( getDeltaMax(), relaxInelasticContactsByProjectedGaussSeidel( cid, dtinv, ca, pa )));
+         break;
+
+      default:
+         throw std::runtime_error( "Unsupported relaxation model." );
+}
+
+WALBERLA_LOG_DETAIL("Delta Max: " << getDeltaMax());
+
+}
+
+//*************************************************************************************************
+/*!\brief Relaxes The contact with ID cid once. The contact model is for inelastic unilateral contacts without friction.
+ *
+ * \param cid The index of the contact
+ * \param ca The contact accessor
+ * \param pa The particle accessor
+ * \return The largest variation of contact impulses in the L-infinity norm.
+ *
+ * This function is to be called from resolveContacts(). Separating contacts are preferred over
+ * persisting solutions if valid.
+ */
+template <typename CAccessor, typename PAccessor>
+inline real_t HCSITSRelaxationStep::relaxInelasticFrictionlessContacts(size_t cid, real_t dtinv, CAccessor &ca, PAccessor& pa)
+{
+   real_t delta_max( 0 );
+
+   // Remove velocity corrections of this contact's reaction.
+   size_t bId1 = ca.getId1(cid);
+   size_t bId2 = ca.getId2(cid);
+   pa.getDvRef(bId1) -= pa.getInvMass(bId1) * ca.getP(cid);
+   pa.getDwRef(bId1) -= pa.getInvInertia(bId1) * (ca.getR1(cid) % ca.getP(cid));
+   pa.getDvRef(bId2) += pa.getInvMass(bId2) * ca.getP(cid);
+   pa.getDwRef(bId2) += pa.getInvInertia(bId2) * (ca.getR2(cid) % ca.getP(cid));
+
+   // Calculate the relative contact VELOCITY in the global world frame (if no contact reaction is present at contact i)
+   Vec3 gdot    ( ( pa.getLinearVelocity(bId1)     + pa.getDv(bId1) ) -
+                  ( pa.getLinearVelocity(bId2)     + pa.getDv(bId2) ) +
+                  ( pa.getAngularVelocity(bId1)    + pa.getDw(bId1) ) % ca.getR1(cid) -
+                  ( pa.getAngularVelocity(bId2)    + pa.getDw(bId2) ) % ca.getR2(cid) /* + diag_[i] * p */ );
+
+
+   // Change from the global world frame to the contact frame
+   Mat3 contactframe( ca.getNormal(cid), ca.getT(cid), ca.getO(cid) );
+   Vec3 gdot_nto( contactframe.getTranspose() * gdot );
+
+   // The constraint in normal direction is actually a positional constraint but instead of g_n we use g_n/dt equivalently and call it gdot_n
+   gdot_nto[0] += ( /* + trans( contactCache.n_[i] ) * ( contactCache.body1_[i]->getPosition() + contactCache.r1_[i] ) - ( contactCache.body2_[i]->getPosition() + contactCache.r2_[i] ) */ + ca.getDistance(cid) ) * dtinv;
+
+   if( gdot_nto[0] >= 0 ) {
+      // Contact is separating if no contact reaction is present at contact i.
+
+      delta_max = std::max( delta_max, std::max( std::abs( ca.getP(cid)[0] ), std::max( std::abs( ca.getP(cid)[1] ), std::abs( ca.getP(cid)[2] ) ) ) );
+      ca.getPRef(cid) = Vec3();
+
+      // No need to apply zero impulse.
+   }
+   else {
+      // Contact is persisting.
+
+      // Calculate the impulse necessary for a static contact expressed as components in the contact frame.
+      Vec3 p_wf( ca.getNormal(cid) * ( -ca.getDiag_n_inv(cid) * gdot_nto[0] ) );
+      Vec3 dp( ca.getP(cid) - p_wf );
+      delta_max = std::max( delta_max, std::max( std::abs( dp[0] ), std::max( std::abs( dp[1] ), std::abs( dp[2] ) ) ) );
+
+      ca.getPRef(cid) = p_wf;
+
+      // Apply impulse right away.
+      pa.getDvRef(bId1) += pa.getInvMass(bId1) * ca.getP(cid);
+      pa.getDwRef(bId1) += pa.getInvInertia(bId1) * (ca.getR1(cid) % ca.getP(cid));
+      pa.getDvRef(bId2) -= pa.getInvMass(bId2) * ca.getP(cid);
+      pa.getDwRef(bId2) -= pa.getInvInertia(bId2) * (ca.getR2(cid) % ca.getP(cid));
+   }
+
+   return delta_max;
+}
+//*************************************************************************************************
+
+
+//*************************************************************************************************
+/*!\brief Relaxes all contacts once. The contact model is for inelastic unilateral contacts with approximate Coulomb friction.
+ *
+ * \return The largest variation of contact impulses in the L-infinity norm.
+ *
+ * This function is to be called from resolveContacts(). Separating contacts are preferred over
+ * other solutions if valid. Static solutions are preferred over dynamic solutions. Dynamic
+ * solutions are computed by decoupling the normal from the frictional components. That is
+ * for a dynamic contact the normal component is relaxed first followed by the frictional
+ * components. The determination of the frictional components does not perform any subiterations
+ * and guarantees that the friction partially opposes slip.
+ */
+template <typename CAccessor, typename PAccessor>
+inline real_t HCSITSRelaxationStep::relaxApproximateInelasticCoulombContactsByDecoupling(size_t cid, real_t dtinv, CAccessor &ca, PAccessor& pa )
+{
+   real_t delta_max( 0 );
+
+   // Remove velocity corrections of this contact's reaction.
+   size_t bId1 = ca.getId1(cid);
+   size_t bId2 = ca.getId2(cid);
+   pa.getDvRef(bId1) -= pa.getInvMass(bId1) * ca.getP(cid);
+   pa.getDwRef(bId1) -= pa.getInvInertia(bId1) * (ca.getR1(cid) % ca.getP(cid));
+   pa.getDvRef(bId2) += pa.getInvMass(bId2) * ca.getP(cid);
+   pa.getDwRef(bId2) += pa.getInvInertia(bId2) * (ca.getR2(cid) % ca.getP(cid));
+
+
+   // Calculate the relative contact VELOCITY in the global world frame (if no contact reaction is present at contact i)
+   Vec3 gdot    ( ( pa.getLinearVelocity(bId1)     + pa.getDv(bId1) ) -
+                  ( pa.getLinearVelocity(bId2)     + pa.getDv(bId2) ) +
+                  ( pa.getAngularVelocity(bId1)    + pa.getDw(bId1) ) % ca.getR1(cid) -
+                  ( pa.getAngularVelocity(bId2)    + pa.getDw(bId2) ) % ca.getR2(cid) /* + diag_[i] * p */ );
+
+   // Change from the global world frame to the contact frame
+   Mat3 contactframe( ca.getNormal(cid), ca.getT(cid), ca.getO(cid) );
+   Vec3 gdot_nto( contactframe.getTranspose() * gdot );
+
+   // The constraint in normal direction is actually a positional constraint but instead of g_n we use g_n/dt equivalently and call it gdot_n
+   gdot_nto[0] += ( /* + trans( contactCache.n_[i] ) * ( contactCache.body1_[i]->getPosition() + contactCache.r1_[i] ) - ( contactCache.body2_[i]->getPosition() + contactCache.r2_[i] ) */ + ca.getDistance(cid) ) * dtinv;
+
+
+   if( gdot_nto[0] >= 0 ) {
+      // Contact is separating if no contact reaction is present at contact i.
+      delta_max = std::max( delta_max, std::max( std::abs( ca.getP(cid)[0] ), std::max( std::abs( ca.getP(cid)[1] ), std::abs( ca.getP(cid)[2] ) ) ) );
+      ca.getPRef(cid) = Vec3();
+
+      // No need to apply zero impulse.
+   }
+   else {
+      // Contact is persisting (either static or dynamic).
+
+      // Calculate the impulse necessary for a static contact expressed as components in the contact frame.
+      //Vec3 p_cf( -( contactCache.diag_nto_inv_[i] * gdot_nto ) );
+      Vec3 p_cf( -( ca.getDiag_nto_inv(cid) * gdot_nto ) );
+
+      // Can p_cf[0] be negative even though -gdot_nto[0] > 0? Yes! Try:
+      // A = [0.5 -0.1 +0.1; -0.1 0.5 -0.1; +0.1 -0.1 1];
+      // b = [0.01 -1 -1]';
+      // A\b    \approx [-0.19 -2.28 -1.21]'
+      // eig(A) \approx [ 0.40  0.56  1.04]'
+
+      //real_t flimit( contactCache.mu_[i] * p_cf[0] );
+      real_t flimit( ca.getMu(cid) * p_cf[0] );
+      real_t fsq( p_cf[1] * p_cf[1] + p_cf[2] * p_cf[2] );
+      if( fsq > flimit * flimit || p_cf[0] < 0 ) {
+         // Contact cannot be static so it must be dynamic.
+         // => Complementarity condition on normal reaction now turns into an equation since we know that the normal reaction is definitely not zero.
+
+         // For simplicity we change to a simpler relaxation scheme here:
+         // 1. Relax normal reaction with the tangential components equal to the previous values
+         // 2. Relax tangential components with the newly relaxed normal reaction
+         // Note: The better approach would be to solve the true 3x3 block problem!
+         // Warning: Simply projecting the frictional components is wrong since then the normal action is no longer 0 and simulations break.
+
+         // Add the action of the frictional reactions from the last iteration to the relative contact velocity in normal direction so we can relax it separately.
+         // TODO This can be simplified:
+         //p_cf = trans( contactframe ) * contactCache.p_[i];
+         //p_cf[0] = 0;
+         //p_[i] = contactframe * p_cf;
+
+
+         //Vec3 p_tmp = ( contactCache.t_[i] * contactCache.p_[i] ) * contactCache.t_[i] + ( contactCache.o_[i] * contactCache.p_[i] ) * contactCache.o_[i];
+         Vec3 p_tmp = ( ca.getT(cid) * ca.getP(cid)  ) * ca.getT(cid)  + ( ca.getO(cid) * ca.getP(cid) ) * ca.getO(cid);
+
+
+         //real_t gdot_n = gdot_nto[0] + contactCache.n_[i] * ( ( contactCache.body1_[i]->getInvInertia() * ( contactCache.r1_[i] % p_tmp ) ) % contactCache.r1_[i] + ( contactCache.body2_[i]->getInvInertia() * ( contactCache.r2_[i] % p_tmp ) ) % contactCache.r2_[i] /* + diag_[i] * p */ );
+         real_t gdot_n = gdot_nto[0] + ca.getNormal(cid) * ( ( pa.getInvInertia(bId1) * ( ca.getR1(cid) % p_tmp ) ) % ca.getR1(cid) + ( pa.getInvInertia(bId2) * ( ca.getR2(cid) % p_tmp ) ) % ca.getR2(cid) /* + diag_[i] * p */ );
+
+         //p_cf[0] = -( contactCache.diag_n_inv_[i] * gdot_n );
+         p_cf[0] = -( ca.getDiag_n_inv(cid) * gdot_n );
+
+         // We cannot be sure that gdot_n <= 0 here and thus p_cf[0] >= 0 since we just modified it with the old values of the tangential reactions! => Project
+         p_cf[0] = std::max( real_c( 0 ), p_cf[0] );
+
+         // Now add the action of the normal reaction to the relative contact velocity in the tangential directions so we can relax the frictional components separately.
+         p_tmp = ca.getNormal(cid)  * p_cf[0];
+         Vec3 gdot2 = gdot + ( pa.getInvInertia(bId1) * ( ca.getR1(cid) % p_tmp ) ) % ca.getR1(cid) + ( pa.getInvInertia(bId2)* ( ca.getR2(cid) % p_tmp ) ) % ca.getR2(cid);
+         Vec2 gdot_to;
+         gdot_to[0] = ca.getT(cid) * gdot2;
+         gdot_to[1] = ca.getO(cid) * gdot2;
+
+         //Vec2 ret = -( contactCache.diag_to_inv_[i] * gdot_to );
+         Vec2 ret = -( ca.getDiag_to_inv(cid) * gdot_to );
+         p_cf[1] = ret[0];
+         p_cf[2] = ret[1];
+
+         flimit = ca.getMu(cid) * p_cf[0];
+         fsq = p_cf[1] * p_cf[1] + p_cf[2] * p_cf[2];
+         if( fsq > flimit * flimit ) {
+            const real_t f( flimit / std::sqrt( fsq ) );
+            p_cf[1] *= f;
+            p_cf[2] *= f;
+         }
+      }
+      else {
+         // Contact is static.
+      }
+      Vec3 p_wf( contactframe * p_cf );
+
+      Vec3 dp( ca.getP(cid) - p_wf );
+      delta_max = std::max( delta_max, std::max( std::abs( dp[0] ), std::max( std::abs( dp[1] ), std::abs( dp[2] ) ) ) );
+
+      ca.getPRef(cid) = p_wf;
+
+      // Apply impulse right away.
+      pa.getDvRef(bId1) += pa.getInvMass(bId1) * ca.getP(cid);
+      pa.getDwRef(bId1) += pa.getInvInertia(bId1) * (ca.getR1(cid) % ca.getP(cid));
+      pa.getDvRef(bId2) -= pa.getInvMass(bId2) * ca.getP(cid);
+      pa.getDwRef(bId2) -= pa.getInvInertia(bId2) * (ca.getR2(cid) % ca.getP(cid));
+   }
+   return delta_max;
+}
+//*************************************************************************************************
+
+
+//*************************************************************************************************
+
+/*!\brief Relaxes all contacts once. The contact model is for inelastic unilateral contacts with Coulomb friction.
+ *
+ * \return The largest variation of contact impulses in the L-infinity norm.
+ *
+ * This function is to be called from resolveContacts(). Separating contacts are preferred over
+ * other solutions if valid. Static solutions are preferred over dynamic solutions. Dynamic
+ * solutions are computed by decoupling the normal from the frictional components. That is
+ * for a dynamic contact the normal component is relaxed first followed by the frictional
+ * components. How much the frictional components directly oppose slip as required by the Coulomb
+ * friction model depends on the number of subiterations performed. If no subiterations are
+ * performed the friction is guaranteed to be at least partially dissipative.
+ */
+template <typename CAccessor, typename PAccessor>
+inline real_t HCSITSRelaxationStep::relaxInelasticCoulombContactsByDecoupling(size_t cid, real_t dtinv, CAccessor &ca, PAccessor& pa )
+{
+   real_t delta_max( 0 );
+
+   // Remove velocity corrections of this contact's reaction.
+   size_t bId1 = ca.getId1(cid);
+   size_t bId2 = ca.getId2(cid);
+   pa.getDvRef(bId1) -= pa.getInvMass(bId1) * ca.getP(cid);
+   pa.getDwRef(bId1) -= pa.getInvInertia(bId1) * (ca.getR1(cid) % ca.getP(cid));
+   pa.getDvRef(bId2) += pa.getInvMass(bId2) * ca.getP(cid);
+   pa.getDwRef(bId2) += pa.getInvInertia(bId2) * (ca.getR2(cid) % ca.getP(cid));
+
+
+   // Calculate the relative contact VELOCITY in the global world frame (if no contact reaction is present at contact i)
+   Vec3 gdot    ( ( pa.getLinearVelocity(bId1)     + pa.getDv(bId1) ) -
+                  ( pa.getLinearVelocity(bId2)     + pa.getDv(bId2) ) +
+                  ( pa.getAngularVelocity(bId1)    + pa.getDw(bId1) ) % ca.getR1(cid) -
+                  ( pa.getAngularVelocity(bId2)    + pa.getDw(bId2) ) % ca.getR2(cid) /* + diag_[i] * p */ );
+
+   // Change from the global world frame to the contact frame
+   Mat3 contactframe( ca.getNormal(cid), ca.getT(cid), ca.getO(cid) );
+   Vec3 gdot_nto( contactframe.getTranspose() * gdot );
+
+   // The constraint in normal direction is actually a positional constraint but instead of g_n we use g_n/dt equivalently and call it gdot_n
+   gdot_nto[0] += ( /* + trans( contactCache.n_[i] ) * ( contactCache.body1_[i]->getPosition() + contactCache.r1_[i] ) - ( contactCache.body2_[i]->getPosition() + contactCache.r2_[i] ) */ + ca.getDistance(cid) ) * dtinv;
+
+   //WALBERLA_LOG_WARNING( "Contact #" << i << " is\nA = \n" << contactCache.diag_nto_[i] << "\nb = \n" << gdot_nto << "\nmu = " << contactCache.mu_[i] );
+
+   if( gdot_nto[0] >= 0 ) {
+      // Contact is separating if no contact reaction is present at contact i.
+
+      delta_max = std::max( delta_max, std::max( std::abs( ca.getP(cid)[0] ), std::max( std::abs( ca.getP(cid)[1] ), std::abs( ca.getP(cid)[2] ) ) ) );
+      ca.getPRef(cid) = Vec3();
+      //WALBERLA_LOG_WARNING( "Contact #" << i << " is separating." );
+
+      // No need to apply zero impulse.
+   }
+   else {
+      // Contact is persisting (either static or dynamic).
+
+      // Calculate the impulse necessary for a static contact expressed as components in the contact frame.
+      Vec3 p_cf( -( ca.getDiag_nto_inv(cid) * gdot_nto ) );
+
+      // Can p_cf[0] be negative even though -gdot_nto[0] > 0? Yes! Try:
+      // A = [0.5 -0.1 +0.1; -0.1 0.5 -0.1; +0.1 -0.1 1];
+      // b = [0.01 -1 -1]';
+      // A\b    \approx [-0.19 -2.28 -1.21]'
+      // eig(A) \approx [ 0.40  0.56  1.04]'
+
+      real_t flimit( ca.getMu(cid) * p_cf[0] );
+      real_t fsq( p_cf[1] * p_cf[1] + p_cf[2] * p_cf[2] );
+      if( fsq > flimit * flimit || p_cf[0] < 0 ) {
+         // Contact cannot be static so it must be dynamic.
+         // => Complementarity condition on normal reaction now turns into an equation since we know that the normal reaction is definitely not zero.
+
+         for (int j = 0; j < 20; ++j) {
+            // For simplicity we change to a simpler relaxation scheme here:
+            // 1. Relax normal reaction with the tangential components equal to the previous values
+            // 2. Relax tangential components with the newly relaxed normal reaction
+            // Note: The better approach would be to solve the true 3x3 block problem!
+            // Warning: Simply projecting the frictional components is wrong since then the normal action is no longer 0 and simulations break.
+
+            Vec3 gdotCorrected;
+            real_t gdotCorrected_n;
+            Vec2 gdotCorrected_to;
+
+            // Calculate the relative contact velocity in the global world frame (if no normal contact reaction is present at contact i)
+            p_cf[0] = 0;
+            //                       |<- p_cf is orthogonal to the normal and drops out in next line ->|
+            gdotCorrected   = /* ( contactCache.body1_[i]->getInvMass() + contactCache.body2_[i]->getInvMass() ) * p_cf  */ gdot + ( pa.getInvInertia(bId1) * ( ca.getR1(cid) % ( ca.getT(cid) * p_cf[1] + ca.getO(cid) * p_cf[2] ) ) ) % ca.getR1(cid) + ( pa.getInvInertia(bId2) * ( ca.getR2(cid) % ( ca.getT(cid) * p_cf[1] + ca.getO(cid) * p_cf[2] ) ) ) % ca.getR2(cid);
+            gdotCorrected_n = ca.getNormal(cid) * gdotCorrected + ca.getDistance(cid) * dtinv;
+
+            // Relax normal component.
+            p_cf[0] = std::max( real_c( 0 ), -( ca.getDiag_n_inv(cid) * gdotCorrected_n ) );
+
+            // Calculate the relative contact velocity in the global world frame (if no frictional contact reaction is present at contact i)
+            p_cf[1] = p_cf[2] = real_c( 0 );
+            //                       |<- p_cf is orthogonal to the tangential plane and drops out   ->|
+            gdotCorrected   = /* ( contactCache.body1_[i]->getInvMass() + contactCache.body2_[i]->getInvMass() ) * p_cf */ gdot + ( pa.getInvInertia(bId1) * ( ca.getR1(cid) % ( ca.getNormal(cid) * p_cf[0] ) ) ) % ca.getR1(cid) + ( pa.getInvInertia(bId2) * ( ca.getR2(cid) % ( ca.getNormal(cid) * p_cf[0] ) ) ) % ca.getR2(cid);
+            gdotCorrected_to[0] = ca.getT(cid) * gdotCorrected;
+            gdotCorrected_to[1] = ca.getO(cid) * gdotCorrected;
+
+            // Relax frictional components.
+            Vec2 ret = -( ca.getDiag_to_inv(cid) * gdotCorrected_to );
+            p_cf[1] = ret[0];
+            p_cf[2] = ret[1];
+
+            flimit = ca.getMu(cid) * p_cf[0];
+            fsq = p_cf[1] * p_cf[1] + p_cf[2] * p_cf[2];
+            if( fsq > flimit * flimit ) {
+               // 3.2.1 Decoupling
+               // \tilde{x}^0 = p_cf[1..2]
+
+               // Determine \tilde{A}
+               Mat2 diag_to( ca.getDiag_nto(cid)(1, 1), ca.getDiag_nto(cid)(1, 2), ca.getDiag_nto(cid)(2, 1), ca.getDiag_nto(cid)(2, 2) );
+
+               const real_t f( flimit / std::sqrt( fsq ) );
+               //p_cf[1] *= f;
+               //p_cf[2] *= f;
+
+               // Determine search interval for Golden Section Search
+               const real_t phi( real_c(0.5) * ( real_c(1) + std::sqrt( real_c( 5 ) ) ) );
+               real_t shift( std::atan2( -p_cf[2], p_cf[1] ) );
+               real_t acos_f( std::acos( f ) );
+
+               //WALBERLA_LOG_WARNING( acos_f << " " << shift );
+
+               real_t alpha_left( -acos_f - shift );
+               //Vec2 x_left( flimit * std::cos( alpha_left ), flimit * std::sin( alpha_left ) );
+               //real_t f_left( 0.5 * trans( x_left ) * ( diag_to * x_left ) - trans( x_left ) * ( -gdot_to ) );
+
+               real_t alpha_right( acos_f - shift );
+               //Vec2 x_right( flimit * std::cos( alpha_right ), flimit * std::sin( alpha_right ) );
+               //real_t f_right( 0.5 * trans( x_right ) * ( diag_to * x_right ) - trans( x_right ) * ( -gdot_to ) );
+
+               real_t alpha_mid( ( alpha_right + alpha_left * phi ) / ( 1 + phi ) );
+               Vec2 x_mid( flimit * std::cos( alpha_mid ), flimit * std::sin( alpha_mid ) );
+               real_t f_mid( real_c(0.5) * x_mid * ( diag_to * x_mid ) - x_mid * ( -gdotCorrected_to ) );
+
+               bool leftlarger = false;
+               for( size_t k = 0; k < getMaxSubIterations(); ++k ) {
+                  real_t alpha_next( alpha_left + ( alpha_right - alpha_mid ) );
+                  Vec2 x_next( flimit * std::cos( alpha_next ), flimit * std::sin( alpha_next ) );
+                  real_t f_next( real_c(0.5) * x_next * ( diag_to * x_next ) - x_next * ( -gdotCorrected_to ) );
+                  //WALBERLA_LOG_WARNING( "[(" << alpha_left << ", ?); (" << alpha_mid << ", " << f_mid << "); (" << alpha_right << ", ?)] <- (" << alpha_next << ", " << f_next << ")" );
+                  //WALBERLA_LOG_WARNING( "left: " << alpha_mid - alpha_left << "  right: " << alpha_right - alpha_mid << "  ll: " << leftlarger );
+                  //WALBERLA_ASSERT(leftlarger ? (alpha_mid - alpha_left > alpha_right - alpha_mid) : (alpha_mid - alpha_left < alpha_right - alpha_mid), "ll inconsistent!" );
+
+                  if (leftlarger) {
+                     // left interval larger
+                     if( f_next < f_mid ) {
+                        alpha_right = alpha_mid;
+                        alpha_mid   = alpha_next;
+                        x_mid       = x_next;
+                        f_mid       = f_next;
+                        leftlarger = true;
+                     }
+                     else {
+                        alpha_left  = alpha_next;
+                        leftlarger = false;
+                     }
+                  }
+                  else {
+                     // right interval larger
+                     if( f_next < f_mid ) {
+                        alpha_left = alpha_mid;
+                        alpha_mid  = alpha_next;
+                        x_mid      = x_next;
+                        f_mid      = f_next;
+                        leftlarger = false;
+                     }
+                     else {
+                        alpha_right = alpha_next;
+                        leftlarger = true;
+                     }
+                  }
+               }
+               //WALBERLA_LOG_WARNING( "dalpha = " << alpha_right - alpha_left );
+
+               p_cf[1] = x_mid[0];
+               p_cf[2] = x_mid[1];
+            }
+         }
+         //WALBERLA_LOG_WARNING( "Contact #" << i << " is dynamic." );
+      }
+      else {
+         // Contact is static.
+         //WALBERLA_LOG_WARNING( "Contact #" << i << " is static." );
+      }
+
+      //WALBERLA_LOG_WARNING( "Contact reaction in contact frame: " << p_cf << "\n" << ca.getDiag_nto(cid)*p_cf + gdot_nto );
+      Vec3 p_wf( contactframe * p_cf );
+      Vec3 dp( ca.getP(cid) - p_wf );
+      delta_max = std::max( delta_max, std::max( std::abs( dp[0] ), std::max( std::abs( dp[1] ), std::abs( dp[2] ) ) ) );
+
+      ca.getPRef(cid) = p_wf;
+
+      // Apply impulse right away.
+      pa.getDvRef(bId1) += pa.getInvMass(bId1) * ca.getP(cid);
+      pa.getDwRef(bId1) += pa.getInvInertia(bId1) * (ca.getR1(cid) % ca.getP(cid));
+      pa.getDvRef(bId2) -= pa.getInvMass(bId2) * ca.getP(cid);
+      pa.getDwRef(bId2) -= pa.getInvInertia(bId2) * (ca.getR2(cid) % ca.getP(cid));
+   }
+
+   return delta_max;
+}
+//*************************************************************************************************
+
+
+//*************************************************************************************************
+/*!\brief Relaxes all contacts once. The contact model is for inelastic unilateral contacts with Coulomb friction.
+ *
+ * \param dtinv The inverse of the current time step.
+ * \param approximate Use the approximate model showing bouncing.
+ * \return The largest variation of contact impulses in the L-infinity norm.
+ *
+ * This function is to be called from resolveContacts(). The iterative method to solve the contact
+ * problem is e.g. described in the article "A matrix-free cone complementarity approach for
+ * solving large-scale, nonsmooth, rigid body dynamics" by A. Tasora and M. Anitescu in Computer
+ * Methods in Applied Mechanics and Engineering (Volume 200, Issues 5–8, 15 January 2011,
+ * Pages 439-453). The contact model is purely quadratic and convergence should be good but depends
+ * on a parameter. The one-contact problem has a unique solution. The frictional reactions
+ * for a dynamic contact converge to those that directly oppose slip. However, the contact is
+ * not perfectly inelastic for dynamic contacts but bounces. These vertical motions tend to
+ * go to zero for smaller time steps and can be interpreted as exaggerated vertical motions
+ * coming from micro asperities (see "Optimization-based simulation of nonsmooth rigid multibody
+ * dynamics" by M. Anitescu in Mathematical Programming (Volume 105, Issue 1, January 2006, Pages
+ * 113-143). These motions can be prevented by a small change in the iteration proposed in "The
+ * bipotential method: a constructive approach to design the complete contact law with friction and
+ * improved numerical algorithms" by G. De Saxce and Z-Q. Feng in Mathematical and Computer
+ * Modelling (Volume 28, Issue 4, 1998, Pages 225-245). Which iteration is used is controlled with
+ * the approximate parameter.
+ */
+template <typename CAccessor, typename PAccessor>
+inline real_t HCSITSRelaxationStep::relaxInelasticCoulombContactsByOrthogonalProjections(size_t cid, real_t dtinv, bool approximate, CAccessor &ca, PAccessor& pa )
+{
+   real_t delta_max( 0 );
+
+   // Remove velocity corrections of this contact's reaction.
+   size_t bId1 = ca.getId1(cid);
+   size_t bId2 = ca.getId2(cid);
+   pa.getDvRef(bId1) -= pa.getInvMass(bId1) * ca.getP(cid);
+   pa.getDwRef(bId1) -= pa.getInvInertia(bId1) * (ca.getR1(cid) % ca.getP(cid));
+   pa.getDvRef(bId2) += pa.getInvMass(bId2) * ca.getP(cid);
+   pa.getDwRef(bId2) += pa.getInvInertia(bId2) * (ca.getR2(cid) % ca.getP(cid));
+
+   // Calculate the relative contact VELOCITY in the global world frame (if no contact reaction is present at contact i)
+   Vec3 gdot    ( ( pa.getLinearVelocity(bId1)     + pa.getDv(bId1) ) -
+                  ( pa.getLinearVelocity(bId2)     + pa.getDv(bId2) ) +
+                  ( pa.getAngularVelocity(bId1)    + pa.getDw(bId1) ) % ca.getR1(cid) -
+                  ( pa.getAngularVelocity(bId2)    + pa.getDw(bId2) ) % ca.getR2(cid) /* + diag_[i] * p */ );
+
+   // Change from the global world frame to the contact frame
+   Mat3 contactframe( ca.getNormal(cid), ca.getT(cid), ca.getO(cid) );
+   Vec3 gdot_nto( contactframe.getTranspose() * gdot );
+
+   // The constraint in normal direction is actually a positional constraint but instead of g_n we use g_n/dt equivalently and call it gdot_n
+   gdot_nto[0] += ( /* + trans( contactCache.n_[i] ) * ( contactCache.body1_[i]->getPosition() + contactCache.r1_[i] ) - ( contactCache.body2_[i]->getPosition() + contactCache.r2_[i] ) */ + ca.getDistance(cid) ) * dtinv;
+
+
+   const real_t w( 1 ); // w > 0
+   Vec3 p_cf( contactframe.getTranspose() * ca.getP(cid) );
+   if( approximate ) {
+      // Calculate next iterate (Anitescu/Tasora).
+      p_cf = p_cf - w * ( ca.getDiag_nto(cid) * p_cf + gdot_nto );
+   }
+   else {
+      // Calculate next iterate (De Saxce/Feng).
+      Vec3 tmp( ca.getDiag_nto(cid) * p_cf + gdot_nto );
+      tmp[0] += std::sqrt( math::sq( tmp[1] ) + math::sq( tmp[2] ) ) * ca.getMu(cid);
+      p_cf = p_cf - w * tmp;
+   }
+
+   // Project.
+   real_t flimit( ca.getMu(cid) * p_cf[0] );
+   real_t fsq( p_cf[1] * p_cf[1] + p_cf[2] * p_cf[2] );
+   if( p_cf[0] > 0 && fsq < flimit * flimit ) {
+      // Unconstrained minimum is in cone leading to a static contact and no projection
+      // is necessary.
+   }
+   else if( p_cf[0] < 0 && fsq < math::sq( p_cf[0] )/ math::sq( ca.getMu(cid) ) ) {
+      // Unconstrained minimum is in dual cone leading to a separating contact where no contact
+      // reaction is present (the unconstrained minimum is projected to the tip of the cone).
+      p_cf = Vec3();
+   }
+   else {
+      // The contact is dynamic.
+      real_t f( std::sqrt( fsq ) );
+      p_cf[0] = ( f * ca.getMu(cid) + p_cf[0] ) / ( math::sq( ca.getMu(cid) ) + 1 );
+      real_t factor( ca.getMu(cid) * p_cf[0] / f );
+      p_cf[1] *= factor;
+      p_cf[2] *= factor;
+   }
+
+   Vec3 p_wf( contactframe * p_cf );
+   Vec3 dp( ca.getP(cid) - p_wf );
+   delta_max = std::max( delta_max, std::max( std::abs( dp[0] ), std::max( std::abs( dp[1] ), std::abs( dp[2] ) ) ) );
+
+   ca.getPRef(cid) = p_wf;
+
+   // Apply impulse right away.
+   pa.getDvRef(bId1) += pa.getInvMass(bId1) * ca.getP(cid);
+   pa.getDwRef(bId1) += pa.getInvInertia(bId1) * (ca.getR1(cid) % ca.getP(cid));
+   pa.getDvRef(bId2) -= pa.getInvMass(bId2) * ca.getP(cid);
+   pa.getDwRef(bId2) -= pa.getInvInertia(bId2) * (ca.getR2(cid) % ca.getP(cid));
+
+   return delta_max;
+}
+//*************************************************************************************************
+
+
+//*************************************************************************************************
+
+/*!\brief Relaxes all contacts once. The contact model is for inelastic unilateral contacts with the generalized maximum dissipation principle for friction.
+ *
+ * \return The largest variation of contact impulses in the L-infinity norm.
+ *
+ * This function is to be called from resolveContacts(). Dynamic solutions are computed by
+ * minimizing the kinetic energy along the intersection of the plane of maximum compression and
+ * the friction cone.
+ */
+template <typename CAccessor, typename PAccessor>
+inline real_t HCSITSRelaxationStep::relaxInelasticGeneralizedMaximumDissipationContacts(size_t cid, real_t dtinv, CAccessor &ca, PAccessor& pa )
+{
+   real_t delta_max( 0 );
+
+   // Remove velocity corrections of this contact's reaction.
+   size_t bId1 = ca.getId1(cid);
+   size_t bId2 = ca.getId2(cid);
+   pa.getDvRef(bId1) -= pa.getInvMass(bId1) * ca.getP(cid);
+   pa.getDwRef(bId1) -= pa.getInvInertia(bId1) * (ca.getR1(cid) % ca.getP(cid));
+   pa.getDvRef(bId2) += pa.getInvMass(bId2) * ca.getP(cid);
+   pa.getDwRef(bId2) += pa.getInvInertia(bId2) * (ca.getR2(cid) % ca.getP(cid));
+
+   // Calculate the relative contact VELOCITY in the global world frame (if no contact reaction is present at contact i)
+   Vec3 gdot    ( ( pa.getLinearVelocity(bId1)     + pa.getDv(bId1) ) -
+                  ( pa.getLinearVelocity(bId2)     + pa.getDv(bId2) ) +
+                  ( pa.getAngularVelocity(bId1)    + pa.getDw(bId1) ) % ca.getR1(cid) -
+                  ( pa.getAngularVelocity(bId2)    + pa.getDw(bId2) ) % ca.getR2(cid) /* + diag_[i] * p */ );
+
+   // Change from the global world frame to the contact frame
+   Mat3 contactframe( ca.getNormal(cid), ca.getT(cid), ca.getO(cid) );
+   Vec3 gdot_nto( contactframe.getTranspose() * gdot );
+
+   // The constraint in normal direction is actually a positional constraint but instead of g_n we use g_n/dt equivalently and call it gdot_n
+   gdot_nto[0] += ( /* + trans( contactCache.n_[i] ) * ( contactCache.body1_[i]->getPosition() + contactCache.r1_[i] ) - ( contactCache.body2_[i]->getPosition() + contactCache.r2_[i] ) */ + ca.getDistance(cid) ) * dtinv;
+
+
+   if( gdot_nto[0] >= 0 ) {
+      // Contact is separating if no contact reaction is present at contact i.
+      delta_max = std::max( delta_max, std::max( std::abs( ca.getP(cid)[0] ), std::max( std::abs( ca.getP(cid)[1] ), std::abs( ca.getP(cid)[2] ) ) ) );
+      ca.getPRef(cid) = Vec3();
+
+      // No need to apply zero impulse.
+   }
+   else {
+      // Contact is persisting (either static or dynamic).
+
+      // Calculate the impulse necessary for a static contact expressed as components in the contact frame.
+      Vec3 p_cf( -( ca.getDiag_nto_inv(cid) * gdot_nto ) );
+
+      // Can p_cf[0] be negative even though -gdot_nto[0] > 0? Yes! Try:
+      // A = [0.5 -0.1 +0.1; -0.1 0.5 -0.1; +0.1 -0.1 1];
+      // b = [0.01 -1 -1]';
+      // A\b    \approx [-0.19 -2.28 -1.21]'
+      // eig(A) \approx [ 0.40  0.56  1.04]'
+
+      real_t flimit( ca.getMu(cid) * p_cf[0] );
+      real_t fsq( p_cf[1] * p_cf[1] + p_cf[2] * p_cf[2] );
+      if( fsq > flimit * flimit || p_cf[0] < 0 ) {
+         // Contact cannot be static so it must be dynamic.
+         // => Complementarity condition on normal reaction now turns into an equation since we know that the normal reaction is definitely not zero.
+
+         // \breve{x}^0 = p_cf[1..2]
+
+         // Eliminate normal component from 3x3 system: ca.getDiag_nto(cid)*p_cf + gdot_nto => \breve{A} \breve{x} - \breve{b}
+         const real_t invA_nn( math::inv( ca.getDiag_nto(cid)(0, 0) ) );
+         const real_t offdiag( ca.getDiag_nto(cid)(1, 2) - invA_nn * ca.getDiag_nto(cid)(0, 1) * ca.getDiag_nto(cid)(0, 2) );
+         Mat2 A_breve( ca.getDiag_nto(cid)(1, 1) - invA_nn *math::sq( ca.getDiag_nto(cid)(0, 1) ), offdiag, offdiag, ca.getDiag_nto(cid)(2, 2) - invA_nn *math::sq( ca.getDiag_nto(cid)(0, 2) ) );
+         Vec2 b_breve( -gdot_nto[1] + invA_nn * ca.getDiag_nto(cid)(0, 1) * gdot_nto[0], -gdot_nto[2] + invA_nn * ca.getDiag_nto(cid)(0, 2) * gdot_nto[0] );
+
+         const real_t shiftI( std::atan2( -ca.getDiag_nto(cid)(0, 2), ca.getDiag_nto(cid)(0, 1) ) );
+         const real_t shiftJ( std::atan2( -p_cf[2], p_cf[1] ) );
+         const real_t a3( std::sqrt(math::sq( ca.getDiag_nto(cid)(0, 1) ) +math::sq( ca.getDiag_nto(cid)(0, 2) ) ) );
+         const real_t fractionI( -ca.getDiag_nto(cid)(0, 0) / ( ca.getMu(cid) * a3 ) );
+         const real_t fractionJ( std::min( invA_nn * ca.getMu(cid) * ( ( -gdot_nto[0] ) / std::sqrt( fsq ) - a3 * std::cos( shiftI - shiftJ ) ), real_c( 1 ) ) );
+
+         // Search interval determination.
+         real_t alpha_left, alpha_right;
+         if( fractionJ < -1 ) {
+            // J is complete
+            const real_t angleI( std::acos( fractionI ) );
+            alpha_left = -angleI - shiftI;
+            alpha_right = +angleI - shiftI;
+            if( alpha_left < 0 ) {
+               alpha_left += 2 * math::pi;
+               alpha_right += 2 * math::pi;
+            }
+         }
+         else if( ca.getDiag_nto(cid)(0, 0) > ca.getMu(cid) * a3 ) {
+            // I is complete
+            const real_t angleJ( std::acos( fractionJ ) );
+            alpha_left = -angleJ - shiftJ;
+            alpha_right = +angleJ - shiftJ;
+            if( alpha_left < 0 ) {
+               alpha_left += 2 * math::pi;
+               alpha_right += 2 * math::pi;
+            }
+         }
+         else {
+            // neither I nor J is complete
+            const real_t angleJ( std::acos( fractionJ ) );
+            real_t alpha1_left( -angleJ - shiftJ );
+            real_t alpha1_right( +angleJ - shiftJ );
+            if( alpha1_left < 0 ) {
+               alpha1_left += 2 * math::pi;
+               alpha1_right += 2 * math::pi;
+            }
+            const real_t angleI( std::acos( fractionI ) );
+            real_t alpha2_left( -angleI - shiftI );
+            real_t alpha2_right( +angleI - shiftI );
+            if( alpha2_left < 0 ) {
+               alpha2_left += 2 * math::pi;
+               alpha2_right += 2 * math::pi;
+            }
+
+            // Swap intervals if second interval does not start right of the first interval.
+            if( alpha1_left > alpha2_left ) {
+               std::swap( alpha1_left, alpha2_left );
+               std::swap( alpha1_right, alpha2_right );
+            }
+
+            if( alpha2_left > alpha1_right ) {
+               alpha2_right -= 2*math::pi;
+               if( alpha2_right > alpha1_right ) {
+                  // [alpha1_left; alpha1_right] \subset [alpha2_left; alpha2_right]
+               }
+               else {
+                  // [alpha2_left; alpha2_right] intersects the left end of [alpha1_left; alpha1_right]
+                  alpha1_right = alpha2_right;
+               }
+            }
+            else {
+               alpha1_left = alpha2_left;
+               if( alpha2_right > alpha1_right ) {
+                  // [alpha2_left; alpha2_right] intersects the right end of [alpha1_left; alpha1_right]
+               }
+               else {
+                  // [alpha2_left; alpha2_right] \subset [alpha1_left; alpha1_right]
+                  alpha1_right = alpha2_right;
+               }
+            }
+
+            alpha_left = alpha1_left;
+            alpha_right = alpha1_right;
+         }
+
+         const real_t phi( real_c(0.5) * ( real_c(1) + std::sqrt( real_c( 5 ) ) ) );
+         real_t alpha_mid( ( alpha_right + alpha_left * phi ) / ( 1 + phi ) );
+         Vec2 x_mid;
+         real_t f_mid;
+
+         {
+            real_t r_ub = ca.getMu(cid) * ( -gdot_nto[0] ) / ( ca.getDiag_nto(cid)(0, 0) + ca.getMu(cid) * a3 * std::cos( alpha_mid + shiftI ) );
+            if( r_ub < 0 )
+               r_ub = math::Limits<real_t>::inf();
+            x_mid = Vec2( r_ub * std::cos( alpha_mid ), r_ub * std::sin( alpha_mid ) );
+            f_mid = real_c(0.5) * x_mid * ( A_breve * x_mid ) - x_mid * b_breve;
+         }
+
+         bool leftlarger = false;
+         for( size_t k = 0; k < maxSubIterations_; ++k ) {
+            real_t alpha_next( alpha_left + ( alpha_right - alpha_mid ) );
+            real_t r_ub = ca.getMu(cid) * ( -gdot_nto[0] ) / ( ca.getDiag_nto(cid)(0, 0) + ca.getMu(cid) * a3 * std::cos( alpha_next + shiftI ) );
+            if( r_ub < 0 )
+               r_ub = math::Limits<real_t>::inf();
+            Vec2 x_next( r_ub * std::cos( alpha_next ), r_ub * std::sin( alpha_next ) );
+            real_t f_next( real_c(0.5) * x_next * ( A_breve * x_next ) - x_next * b_breve );
+
+            //WALBERLA_LOG_WARNING( "[(" << alpha_left << ", ?); (" << alpha_mid << ", " << f_mid << "); (" << alpha_right << ", ?)] <- (" << alpha_next << ", " << f_next << ")" );
+            //WALBERLA_LOG_WARNING( "left: " << alpha_mid - alpha_left << "  right: " << alpha_right - alpha_mid << "  ll: " << leftlarger );
+            //WALBERLA_ASSERT(leftlarger ? (alpha_mid - alpha_left > alpha_right - alpha_mid) : (alpha_mid - alpha_left < alpha_right - alpha_mid), "ll inconsistent!" );
+
+            if (leftlarger) {
+               // left interval larger
+               if( f_next < f_mid ) {
+                  alpha_right = alpha_mid;
+                  alpha_mid   = alpha_next;
+                  x_mid       = x_next;
+                  f_mid       = f_next;
+                  leftlarger = true;
+               }
+               else {
+                  alpha_left  = alpha_next;
+                  leftlarger = false;
+               }
+            }
+            else {
+               // right interval larger
+               if( f_next < f_mid ) {
+                  alpha_left = alpha_mid;
+                  alpha_mid  = alpha_next;
+                  x_mid      = x_next;
+                  f_mid      = f_next;
+                  leftlarger = false;
+               }
+               else {
+                  alpha_right = alpha_next;
+                  leftlarger = true;
+               }
+            }
+         }
+         //WALBERLA_LOG_DETAIL( "dalpha = " << alpha_right - alpha_left << "\n");
+         {
+            real_t alpha_init( std::atan2( p_cf[2], p_cf[1] ) );
+            real_t r_ub = ca.getMu(cid) * ( -gdot_nto[0] ) / ( ca.getDiag_nto(cid)(0, 0) + ca.getMu(cid) * a3 * std::cos( alpha_init + shiftI ) );
+            if( r_ub < 0 )
+               r_ub = math::Limits<real_t>::inf();
+            Vec2 x_init( r_ub * std::cos( alpha_init ), r_ub * std::sin( alpha_init ) );
+            real_t f_init( real_c(0.5) * x_init * ( A_breve * x_init ) - x_init * b_breve );
+
+            if( f_init < f_mid )
+            {
+               x_mid = x_init;
+               WALBERLA_LOG_DETAIL( "Replacing solution by primitive dissipative solution (" << f_init << " < " << f_mid << " at " << alpha_init << " vs. " << alpha_mid << ").\n");
+            }
+         }
+
+         p_cf[0] = invA_nn * ( -gdot_nto[0] - ca.getDiag_nto(cid)(0, 1) * x_mid[0] - ca.getDiag_nto(cid)(0, 2) * x_mid[1] );
+         p_cf[1] = x_mid[0];
+         p_cf[2] = x_mid[1];
+         //WALBERLA_LOG_DETAIL( "Contact #" << i << " is dynamic." );
+      }
+      else {
+         // Contact is static.
+         //WALBERLA_LOG_DETAIL( "Contact #" << i << " is static." );
+      }
+      Vec3 p_wf( contactframe * p_cf );
+      Vec3 dp( ca.getP(cid) - p_wf );
+      delta_max = std::max( delta_max, std::max( std::abs( dp[0] ), std::max( std::abs( dp[1] ), std::abs( dp[2] ) ) ) );
+      //WALBERLA_LOG_DETAIL( "Contact reaction in contact frame: " << p_cf << "\nContact action in contact frame: " << ca.getDiag_nto(cid)*p_cf + gdot_nto );
+
+      ca.getPRef(cid) = p_wf;
+
+      // Apply impulse right away.
+      pa.getDvRef(bId1) += pa.getInvMass(bId1) * ca.getP(cid);
+      pa.getDwRef(bId1) += pa.getInvInertia(bId1) * (ca.getR1(cid) % ca.getP(cid));
+      pa.getDvRef(bId2) -= pa.getInvMass(bId2) * ca.getP(cid);
+      pa.getDwRef(bId2) -= pa.getInvInertia(bId2) * (ca.getR2(cid) % ca.getP(cid));
+   }
+   return delta_max;
+}
+//*************************************************************************************************
+
+//*************************************************************************************************
+//*************************************************************************************************
+/*!\brief Relaxes all contacts once. The contact model is from the paper by Tschisgale et al.
+ * "A constraint-based collision model for Cosserat rods" and works with a coefficient of
+ * restitution cor with 0 < cor <= 1.
+ *
+ * \return The largest variation of contact impulses in the L-infinity norm.
+ *
+ */
+template <typename CAccessor, typename PAccessor>
+inline real_t HCSITSRelaxationStep::relaxInelasticContactsByProjectedGaussSeidel(size_t cid, real_t /*dtinv*/, CAccessor &ca, PAccessor& pa )
+{
+   real_t delta_max( 0 );
+   size_t bId1 = ca.getId1(cid);
+   size_t bId2 = ca.getId2(cid);
+   // Calculate the relative contact VELOCITY in the global world frame (if no contact reaction is present at contact i)
+   // This is the negative contact velocity as for the other methods
+   Vec3 gdot    ( ( pa.getLinearVelocity(bId2)     + pa.getDv(bId2) ) -
+                  ( pa.getLinearVelocity(bId1)     + pa.getDv(bId1) ) +
+                  ( pa.getAngularVelocity(bId2)    + pa.getDw(bId2) ) % ca.getR2(cid) -
+                  ( pa.getAngularVelocity(bId1)    + pa.getDw(bId1) ) % ca.getR1(cid) /* + diag_[i] * p */ );
+
+   // Use restitution hypothesis
+   gdot = gdot + getCor()*(gdot*ca.getNormal(cid))*ca.getNormal(cid);
+
+   Mat3 contactframe( ca.getNormal(cid), ca.getT(cid), ca.getO(cid) );
+
+   //
+   // Turn system matrix back to the world frame.
+   Mat3 K = contactframe * ca.getDiag_nto(cid) *  contactframe.getTranspose();
+   Mat3 Kinv = contactframe * ca.getDiag_nto_inv(cid) * contactframe.getTranspose();
+
+   // Compute impulse necessary in the world frame
+   Vec3 p_wf( - Kinv * gdot );
+
+
+
+   if( gdot * ca.getNormal(cid) <= 0 ) {
+      // Contact is separating if no contact reaction is present at contact i.
+      delta_max = std::max( delta_max, std::max( std::abs( ca.getP(cid)[0] ), std::max( std::abs( ca.getP(cid)[1] ), std::abs( ca.getP(cid)[2] ) ) ) );
+      ca.getPRef(cid) = Vec3();
+      // No need to apply zero impulse.
+   }
+   else {
+      // Dissect the impuls in a tangetial and normal directions
+      // Use the inverted contact frame with -n as in the publication
+      Mat3 reversedContactFrame( -ca.getNormal(cid), ca.getT(cid), ca.getO(cid) );
+      Vec3 p_rcf( reversedContactFrame.getTranspose() * p_wf );
+
+      // Check the frictional limit
+      real_t flimit( ca.getMu(cid) * p_rcf[0] );
+
+      // Square of tangential components of the impulse
+      real_t fsq( p_rcf[1] * p_rcf[1] + p_rcf[2] * p_rcf[2] );
+
+      if( fsq > flimit * flimit || p_rcf[0] < 0 ) {
+         // Contact cannot be static so it must be dynamic.
+         // Calculate corrected contact reaction by the method of Tschigale et al.
+         // Normal component is close to 0 or negative, and we cannot asses a tangential direction
+         // Treat this case with the 0 impulse
+         if (fsq < real_t(1e-8)) {
+            delta_max = std::max(delta_max, std::max(std::abs(ca.getP(cid)[0]),
+                                                     std::max(std::abs(ca.getP(cid)[1]), std::abs(ca.getP(cid)[2]))));
+            ca.getPRef(cid) = Vec3();
+         } else {
+            // tangential direction of sliding
+            Vec3 tan_dir = ((p_rcf[1] * ca.getT(cid)) + (p_rcf[2] * ca.getO(cid))).getNormalized();
+            // scalar magnitude of pv.
+            real_t abspv = ((K * p_wf) * ca.getNormal(cid)) /
+                           ((K * (-ca.getNormal(cid) + ca.getMu(cid) * tan_dir)) * ca.getNormal(cid));
+            p_wf = abspv * (-ca.getNormal(cid) + ca.getMu(cid) * tan_dir);
+
+         }
+      }
+      // Calculate variation
+      Vec3 dp(ca.getP(cid) - p_wf);
+      delta_max = std::max(delta_max, std::max(std::abs(dp[0]), std::max(std::abs(dp[1]), std::abs(dp[2]))));
+      ca.getPRef(cid) = p_wf;
+
+      // Apply impulse right away.
+      pa.getDvRef(bId1) -= pa.getInvMass(bId1) * ca.getP(cid);
+      pa.getDwRef(bId1) -= pa.getInvInertia(bId1) * (ca.getR1(cid) % ca.getP(cid));
+      pa.getDvRef(bId2) += pa.getInvMass(bId2) * ca.getP(cid);
+      pa.getDwRef(bId2) += pa.getInvInertia(bId2) * (ca.getR2(cid) % ca.getP(cid));
+   }
+   return delta_max;
+}
+//*************************************************************************************************
+
+
+} //namespace kernel
+} //namespace mesa_pd
+} //namespace walberla
diff --git a/python/mesa_pd/templates/kernel/InitContactsForHCSITS.templ.h b/python/mesa_pd/templates/kernel/InitContactsForHCSITS.templ.h
new file mode 100644
index 0000000000000000000000000000000000000000..eb48c9a5199d5b54d50f2a52d14ac68f63c74a34
--- /dev/null
+++ b/python/mesa_pd/templates/kernel/InitContactsForHCSITS.templ.h
@@ -0,0 +1,180 @@
+//======================================================================================================================
+//
+//  This file is part of waLBerla. waLBerla is free software: you can
+//  redistribute it and/or modify it under the terms of the GNU General Public
+//  License as published by the Free Software Foundation, either version 3 of
+//  the License, or (at your option) any later version.
+//
+//  waLBerla is distributed in the hope that it will be useful, but WITHOUT
+//  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+//  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+//  for more details.
+//
+//  You should have received a copy of the GNU General Public License along
+//  with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file InitContactsForHCSITS.h
+//! \author Tobias Leemann <tobias.leemann@fau.de>
+//
+//======================================================================================================================
+
+//======================================================================================================================
+//
+//  THIS FILE IS GENERATED - PLEASE CHANGE THE TEMPLATE !!!
+//
+//======================================================================================================================
+
+#pragma once
+
+#include <mesa_pd/common/ParticleFunctions.h>
+#include <mesa_pd/data/DataTypes.h>
+#include <mesa_pd/data/IAccessor.h>
+#include <mesa_pd/data/IContactAccessor.h>
+#include <mesa_pd/data/Flags.h>
+#include <core/logging/Logging.h>
+
+#include <vector>
+
+namespace walberla {
+namespace mesa_pd {
+namespace kernel {
+
+/**
+* Init the datastructures for a contact for later use of the HCSITS-Solver.
+* Call this kernel on all contacts that you want to treat with HCSITS before performing any relaxation timesteps.
+* Use setErp() to set the error reduction parameter, which defines the share of the overlap that is resolved in one step
+* (0 meaning after the relaxation the overlap is the same, 1 meaning the particles will have no overlap after relaxation).
+* Use setFriction(a,b, cof) to define the coefficient of friction cof between materials a and b. It is assumed to be
+ * symmetric w.r.t. the materials.
+* \ingroup mesa_pd_kernel
+*/
+class InitContactsForHCSITS{
+public:
+
+   // Default constructor sets the default values
+   explicit InitContactsForHCSITS(const uint_t numParticleTypes) :
+   numParticleTypes_ (numParticleTypes),
+   {%- for prop in properties %}
+   {{prop.name}}_( {{prop.defValue}} ){{ "," if not loop.last}}
+   {%- endfor %}
+   {
+
+      {% for param in material_parameters %}
+      {{param}}_.resize(numParticleTypes * numParticleTypes, real_t(0));
+      {%- endfor %}
+   }
+
+   // Getter and Setter Functions
+   {%- for prop in properties %}
+   inline const {{prop.type}}& get{{prop.name | capFirst}}() const {return {{prop.name}}_;}
+   inline void set{{prop.name | capFirst}}({{prop.type}} v) { {{prop.name}}_ = v;}
+   {% endfor %}
+
+   // Getter and Setter Functions for material parameter combinations (they are assumed symmetric).
+   {% for param in material_parameters %}
+   inline void set{{param | capFirst}}(const size_t type1, const size_t type2, const real_t& val)
+   {
+      WALBERLA_ASSERT_LESS( type1, numParticleTypes_ );
+      WALBERLA_ASSERT_LESS( type2, numParticleTypes_ );
+      {{param}}_[numParticleTypes_*type1 + type2] = val;
+      {{param}}_[numParticleTypes_*type2 + type1] = val;
+   }
+   {%- endfor %}
+
+   {% for param in material_parameters %}
+   inline real_t get{{param | capFirst}}(const size_t type1, const size_t type2) const
+   {
+      WALBERLA_ASSERT_LESS( type1, numParticleTypes_ );
+      WALBERLA_ASSERT_LESS( type2, numParticleTypes_ );
+      WALBERLA_ASSERT_FLOAT_EQUAL( {{param}}_[numParticleTypes_*type1 + type2],
+              {{param}}_[numParticleTypes_*type2 + type1],
+              "parameter matrix for {{param}} not symmetric!");
+      return {{param}}_[numParticleTypes_*type1 + type2];
+   }
+   {%- endfor %}
+
+   // List material parameters
+   {% for param in material_parameters %}
+   std::vector<real_t> {{param}}_ {};
+   {%- endfor %}
+
+   template<typename CAccessor, typename PAccessor>
+   void operator()(size_t c, CAccessor &ca, PAccessor &pa);
+
+private:
+   // List properties
+   const uint_t numParticleTypes_;
+
+   {% for prop in properties %}
+   {{prop.type}} {{prop.name }}_;
+   {%- endfor %}
+
+   {% for param in parameters %}
+   std::vector<real_t> {{param}}_ {};
+   {%- endfor %}
+
+};
+
+
+template<typename CAccessor, typename PAccessor>
+inline void InitContactsForHCSITS::operator()(size_t c, CAccessor &ca, PAccessor &pa) {
+
+      static_assert(std::is_base_of<data::IContactAccessor, CAccessor>::value, "please provide a valid contact accessor");
+      static_assert(std::is_base_of<data::IAccessor, PAccessor>::value, "please provide a valid particle accessor");
+
+   size_t bId1 = ca.getId1(c);
+   size_t bId2 = ca.getId2(c);
+   ca.setR1(c, ca.getPosition(c) - pa.getPosition(bId1));
+   ca.setR2(c, ca.getPosition(c) - pa.getPosition(bId2));
+
+
+   // construct vector perpendicular to the normal (cross product with cardinal basis vector where the 1 component is where the other vector has its component of smallest magnitude)
+   if (std::fabs(ca.getNormalRef(c)[0]) < std::fabs(ca.getNormalRef(c)[1])) {
+      if (std::fabs(ca.getNormalRef(c)[0]) < std::fabs(ca.getNormalRef(c)[2]))
+         ca.setT(c, Vec3(0, ca.getNormalRef(c)[2], -ca.getNormalRef(c)[1]));   // = n x (1, 0, 0)^T
+      else
+         ca.setT(c, Vec3(ca.getNormalRef(c)[1], -ca.getNormalRef(c)[0], 0));   // = n x (0, 0, 1)^T
+   } else {
+      if (std::fabs(ca.getNormalRef(c)[1]) < std::fabs(ca.getNormalRef(c)[2]))
+         ca.setT(c, Vec3(-ca.getNormalRef(c)[2], 0, ca.getNormalRef(c)[0]));   // = n x (0, 1, 0)^T
+      else
+         ca.setT(c, Vec3(ca.getNormalRef(c)[1], -ca.getNormalRef(c)[0], 0));   // = n x (0, 0, 1)^T
+   }
+   normalize(ca.getTRef(c));
+   ca.setO(c, ca.getNormal(c) % ca.getT(c));
+
+   Mat3 contactframe(ca.getNormal(c), ca.getT(c), ca.getO(c));
+
+   // If the distance is negative then penetration is present. This is an error and should be corrected.
+   // Correcting the whole error is not recommended since due to the linearization the errors cannot
+   // completely fixed anyway and the error reduction will introduce artificial restitution.
+   // However, if the distance is positive then it is not about error correction but the distance that
+   // can still be overcome without penetration and thus no error correction parameter should be applied.
+   if (ca.getDistance(c) < real_t(0.0)) {
+      setMaximumPenetration(std::max(getMaximumPenetration(), -ca.getDistance(c)));
+      ca.getDistanceRef(c) *= erp_;
+   }
+
+   ca.getMuRef(c) = getFriction(pa.getType(bId1), pa.getType(bId2));
+
+   Mat3 diag = -(
+           math::skewSymCrossProduct(ca.getR1(c),
+                                     math::skewSymCrossProduct(pa.getInvInertia(bId1), ca.getR1(c)))
+           + math::skewSymCrossProduct(ca.getR2(c),
+                                       math::skewSymCrossProduct(pa.getInvInertia(bId2), ca.getR2(c))));
+   diag[0] += pa.getInvMass(bId1) + pa.getInvMass(bId2);
+   diag[4] += pa.getInvMass(bId1) + pa.getInvMass(bId2);
+   diag[8] += pa.getInvMass(bId1) + pa.getInvMass(bId2);
+
+   diag = contactframe.getTranspose() * diag * contactframe;
+
+   // Diagonal block is known to be positive-definite and thus an inverse always exists.
+   ca.getDiag_ntoRef(c) = diag;
+   ca.getDiag_nto_invRef(c) = diag.getInverse();
+   ca.getDiag_n_invRef(c) = math::inv(diag[0]);
+   ca.getDiag_to_invRef(c) = Mat2(diag[4], diag[5], diag[7], diag[8]).getInverse();
+}
+
+}
+}
+}
diff --git a/python/mesa_pd/templates/kernel/InitParticlesForHCSITS.templ.h b/python/mesa_pd/templates/kernel/InitParticlesForHCSITS.templ.h
new file mode 100644
index 0000000000000000000000000000000000000000..1ef8698a49004622e5ddda143d07b70bc53edce3
--- /dev/null
+++ b/python/mesa_pd/templates/kernel/InitParticlesForHCSITS.templ.h
@@ -0,0 +1,123 @@
+//======================================================================================================================
+//
+//  This file is part of waLBerla. waLBerla is free software: you can
+//  redistribute it and/or modify it under the terms of the GNU General Public
+//  License as published by the Free Software Foundation, either version 3 of
+//  the License, or (at your option) any later version.
+//
+//  waLBerla is distributed in the hope that it will be useful, but WITHOUT
+//  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+//  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+//  for more details.
+//
+//  You should have received a copy of the GNU General Public License along
+//  with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file InitParticlesForHCSITS.h
+//! \author Tobias Leemann <tobias.leemann@fau.de>
+//
+//======================================================================================================================
+
+//======================================================================================================================
+//
+//  THIS FILE IS GENERATED - PLEASE CHANGE THE TEMPLATE !!!
+//
+//======================================================================================================================
+
+#pragma once
+
+#include <mesa_pd/common/ParticleFunctions.h>
+#include <mesa_pd/data/DataTypes.h>
+#include <mesa_pd/data/IAccessor.h>
+#include <mesa_pd/data/Flags.h>
+#include <core/logging/Logging.h>
+
+#include <vector>
+
+namespace walberla {
+namespace mesa_pd {
+namespace kernel {
+/**
+ * Init the datastructures for the particles for later use of the HCSITS-Solver.
+ * Call this kernel on all particles that will be treated with HCSITS before performing any relaxation timesteps.
+ * Use setGlobalAcceleration() to set an accelleration action uniformly across all particles (e.g. gravity)
+ * \ingroup mesa_pd_kernel
+ */
+class InitParticlesForHCSITS
+{
+public:
+   // Default constructor sets the default values
+   InitParticlesForHCSITS() :
+   {%- for prop in properties %}
+   {{prop.name}}_( {{prop.defValue}} ){{ "," if not loop.last}}
+   {%- endfor %}
+   {}
+
+   // Getter and Setter Functions for properties
+   {%- for prop in properties %}
+   inline const {{prop.type}}& get{{prop.name | capFirst}}() const {return {{prop.name}}_;}
+   inline void set{{prop.name | capFirst}}({{prop.type}} v) { {{prop.name}}_ = v;}
+   {% endfor %}
+
+   template <typename Accessor>
+   void operator()(size_t j, Accessor& ac, real_t dt);
+
+   template <typename Accessor>
+   void initializeVelocityCorrections(Accessor& ac, size_t body, Vec3& dv, Vec3& dw, real_t dt ) const;
+
+private:
+   // List properties
+   {% for prop in properties %}
+   {{prop.type}} {{prop.name }}_;
+   {%- endfor %}
+
+};
+
+
+template <typename Accessor>
+inline void InitParticlesForHCSITS::operator()(size_t j, Accessor& ac, real_t dt)
+{
+   using namespace data::particle_flags;
+   static_assert(std::is_base_of<data::IAccessor, Accessor>::value, "please provide a valid accessor");
+   auto particle_flags = ac.getFlagsRef(j);
+   if (isSet(particle_flags, GLOBAL)){
+      WALBERLA_CHECK( isSet(particle_flags, FIXED), "Global bodies need to have infinite mass as they are not communicated!" );
+      initializeVelocityCorrections( ac, j, ac.getDvRef(j), ac.getDwRef(j), dt ); // use applied external forces to calculate starting velocity
+   }else{
+      initializeVelocityCorrections( ac, j, ac.getDvRef(j), ac.getDwRef(j), dt ); // use applied external forces to calculate starting velocity
+      if(!isSet(particle_flags, FIXED)){ // Update velocities with global acceleration and angular velocity with euler eqn
+         ac.getLinearVelocityRef(j) = ac.getLinearVelocity(j) + getGlobalAcceleration() * dt;
+         ac.getAngularVelocityRef(j) = ac.getAngularVelocity(j) + dt * ( ac.getInvInertia(j) * ( ( ac.getInertia(j) * ac.getAngularVelocity(j) ) % ac.getAngularVelocity(j) ) );
+      }
+   }
+}
+
+
+//*************************************************************************************************
+/*!\brief Calculates the initial velocity corrections of a given body.
+ * \param ac The particle accessor
+ * \param body The body whose velocities to time integrate
+ * \param dv On return the initial linear velocity correction.
+ * \param w On return the initial angular velocity correction.
+ * \param dt The time step size.
+ * \return void
+ *
+ * Calculates the velocity corrections effected by external forces and torques in an explicit Euler
+ * time integration of the velocities of the given body. For fixed objects the velocity corrections
+ * are set to zero. External forces and torques are reset if indicated by the settings.
+ */
+template <typename Accessor>
+inline void InitParticlesForHCSITS::initializeVelocityCorrections(Accessor& ac, size_t body, Vec3& dv, Vec3& dw, real_t dt ) const
+{
+   dv = ( ac.getInvMass(body) * dt ) * ac.getForce(body);
+   dw = dt * ( ac.getInvInertia(body) * ac.getTorque(body) );
+
+   ac.getForceRef(body) = Vec3();
+   ac.getTorqueRef(body) = Vec3();
+}
+//*************************************************************************************************
+
+
+} //namespace kernel
+} //namespace mesa_pd
+} //namespace walberla
diff --git a/python/mesa_pd/templates/kernel/IntegrateParticlesHCSITS.templ.h b/python/mesa_pd/templates/kernel/IntegrateParticlesHCSITS.templ.h
new file mode 100644
index 0000000000000000000000000000000000000000..068b21e14f59d2c9a341a7f4899656dad054ec34
--- /dev/null
+++ b/python/mesa_pd/templates/kernel/IntegrateParticlesHCSITS.templ.h
@@ -0,0 +1,157 @@
+//======================================================================================================================
+//
+//  This file is part of waLBerla. waLBerla is free software: you can
+//  redistribute it and/or modify it under the terms of the GNU General Public
+//  License as published by the Free Software Foundation, either version 3 of
+//  the License, or (at your option) any later version.
+//
+//  waLBerla is distributed in the hope that it will be useful, but WITHOUT
+//  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+//  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+//  for more details.
+//
+//  You should have received a copy of the GNU General Public License along
+//  with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file IntegrateParticlesHCSITS.h
+//! \author Sebastian Eibl <sebastian.eibl@fau.de>
+//! \author Tobias Leemann <tobias.leemann@fau.de>
+//
+//======================================================================================================================
+
+//======================================================================================================================
+//
+//  THIS FILE IS GENERATED - PLEASE CHANGE THE TEMPLATE !!!
+//
+//======================================================================================================================
+
+#pragma once
+
+#include <mesa_pd/common/ParticleFunctions.h>
+#include <mesa_pd/data/DataTypes.h>
+#include <mesa_pd/data/IAccessor.h>
+#include <mesa_pd/data/ContactStorage.h>
+#include <mesa_pd/data/Flags.h>
+#include <core/logging/Logging.h>
+#include <core/math/Constants.h>
+
+#include <vector>
+
+namespace walberla {
+namespace mesa_pd {
+namespace kernel {
+
+/**
+ * Kernel performing integration of the particles after the HCSITS iteration is done.
+ * Call this kernel on all particles j to integrate them by a timestep of size dt.
+ * The Speed Limiter limits the number of body radii, a particle can travel in one timestep.
+ * The speed limit factor defines a number of radii that are allowed in a timestep, e.g. a factor of 1 means, that
+ * a particle can only travel one time its radius in each timestep.
+ *
+ * \ingroup mesa_pd_kernel
+ */
+class IntegrateParticlesHCSITS
+{
+   public:
+   // Default constructor sets the default values
+   IntegrateParticlesHCSITS() :
+   {%- for prop in properties %}
+   {{prop.name}}_( {{prop.defValue}} ){{ "," if not loop.last}}
+   {%- endfor %}
+   {}
+
+   // Getter and Setter Functions
+   {%- for prop in properties %}
+   inline const {{prop.type}}& get{{prop.name | capFirst}}() const {return {{prop.name}}_;}
+   inline void set{{prop.name | capFirst}}({{prop.type}} v) { {{prop.name}}_ = v;}
+   {% endfor %}
+
+   template <typename PAccessor>
+   void operator()(size_t j, PAccessor& ac, real_t dt);
+
+   template <typename PAccessor>
+   void integratePositions(PAccessor& ac, size_t body, Vec3 v, Vec3 w, real_t dt ) const;
+
+
+   private:
+   // List properties
+   {% for prop in properties %}
+   {{prop.type}} {{prop.name }}_;
+   {%- endfor %}
+};
+
+
+template <typename PAccessor>
+inline void IntegrateParticlesHCSITS::operator()(size_t j, PAccessor& ac, real_t dt)
+{
+   using namespace data::particle_flags;
+   static_assert(std::is_base_of<data::IAccessor, PAccessor>::value, "please provide a valid accessor");
+
+   auto body_flags = ac.getFlagsRef(j);
+   if (isSet(body_flags, FIXED)){
+      integratePositions(ac, j, ac.getLinearVelocity(j), ac.getAngularVelocity(j), dt );
+   }else{
+      integratePositions(ac, j, ac.getLinearVelocity(j) + ac.getDv(j), ac.getAngularVelocity(j) + ac.getDw(j), dt );
+   }
+}
+
+
+
+
+//*************************************************************************************************
+/*!\brief Time integration of the position and orientation of a given body.
+ *
+ * \param body The body whose position and orientation to time integrate
+ * \param v The linear velocity to use for time integration of the position.
+ * \param w The angular velocity to use for time integration of the orientation.
+ * \param dt The time step size.
+ * \return void
+ *
+ * Performs an Euler time integration of the positions of the given body. Velocities are damped if
+ * indicated by the settings and stored back in the body properties. The bounding box is
+ * recalculated and it is redetermined whether the body is awake or not. Also the data
+ * structure tracking the contacts attached to the body are cleared and
+ */
+template <typename PAccessor>
+inline void IntegrateParticlesHCSITS::integratePositions(PAccessor& ac, size_t body, Vec3 v, Vec3 w, real_t dt ) const {
+   using namespace data::particle_flags;
+   auto body_flags = ac.getFlags(body);
+   if (isSet(body_flags, FIXED))
+      return;
+
+
+   if (getSpeedLimiterActive()) {
+      const auto speed = v.length();
+      const auto edge = ac.getInteractionRadius(body);
+      if (speed * dt > edge * getSpeedLimitFactor()) {
+         v = v * (edge * getSpeedLimitFactor() / dt / speed);
+      }
+
+      const real_t maxPhi = real_t(2) * math::pi * getSpeedLimitFactor();
+      const real_t phi = w.length() * dt;
+      if (phi > maxPhi) {
+         w = w / phi * maxPhi;
+      }
+   }
+
+   // Calculating the translational displacement
+   ac.getPositionRef(body) = (ac.getPosition(body) + v * dt);
+
+   // Calculating the rotation angle
+   const Vec3 phi(w * dt);
+
+   // Calculating the new orientation
+   WALBERLA_ASSERT(!math::isnan(phi), " phi: " << phi << " w: " << w << " dt: " << dt );
+   ac.getRotationRef(body).rotate(phi, phi.length());
+
+   // Storing the velocities back in the body properties
+   ac.getLinearVelocityRef(body) = v;
+   ac.getAngularVelocityRef(body) = w;
+}
+//*************************************************************************************************
+
+
+
+} //namespace kernel
+} //namespace mesa_pd
+} //namespace walberla
diff --git a/src/blockforest/Initialization.cpp b/src/blockforest/Initialization.cpp
index eaf25ffbe3176a7cc1fb4e2b1f7ac15d4ea2e83e..8771996fbe2715a09e1a8f39876ad85403435848 100644
--- a/src/blockforest/Initialization.cpp
+++ b/src/blockforest/Initialization.cpp
@@ -222,7 +222,7 @@ createBlockForest(      const AABB& domainAABB,
 
    // if possible, create Cartesian MPI communicator
 
-   std::vector< uint_t >* processIdMap = nullptr;
+   std::vector< uint_t > processIdMap(0);
 
    WALBERLA_MPI_SECTION()
    {
@@ -233,13 +233,13 @@ createBlockForest(      const AABB& domainAABB,
          if ( mpiManager->isCartesianCommValid() ) {
             mpiManager->createCartesianComm( numberOfXProcesses, numberOfYProcesses, numberOfZProcesses, xPeriodic, yPeriodic, zPeriodic );
 
-            processIdMap = new std::vector< uint_t >( numberOfProcesses );
+            processIdMap.resize( numberOfProcesses );
 
             for( uint_t z = 0; z != numberOfZProcesses; ++z ) {
                for( uint_t y = 0; y != numberOfYProcesses; ++y ) {
                   for( uint_t x = 0; x != numberOfXProcesses; ++x ) {
 
-                     (*processIdMap)[ z * numberOfXProcesses * numberOfYProcesses + y * numberOfXProcesses + x ] =
+                     processIdMap[ z * numberOfXProcesses * numberOfYProcesses + y * numberOfXProcesses + x ] =
                            uint_c( MPIManager::instance()->cartesianRank(x,y,z) );
                   }
                }
@@ -256,11 +256,9 @@ createBlockForest(      const AABB& domainAABB,
 
    // calculate process distribution
 
-   sforest.balanceLoad( blockforest::CartesianDistribution( numberOfXProcesses, numberOfYProcesses, numberOfZProcesses, processIdMap ),
+   sforest.balanceLoad( blockforest::CartesianDistribution( numberOfXProcesses, numberOfYProcesses, numberOfZProcesses, &processIdMap ),
                         numberOfXProcesses * numberOfYProcesses * numberOfZProcesses );
 
-   if( processIdMap != nullptr ) delete processIdMap;
-
    // create StructuredBlockForest (encapsulates a newly created BlockForest)
 
    return std::make_shared< BlockForest >( uint_c( MPIManager::instance()->rank() ), sforest, keepGlobalBlockInformation );
diff --git a/src/blockforest/SetupBlockForest.cpp b/src/blockforest/SetupBlockForest.cpp
index a6c2e9a0a1e8ba22cae9c48d9b24bb8dfe442281..93281d111ead0972ff25c497e750a2f48d5f8a93 100644
--- a/src/blockforest/SetupBlockForest.cpp
+++ b/src/blockforest/SetupBlockForest.cpp
@@ -713,7 +713,7 @@ void SetupBlockForest::init( const AABB& domain, const uint_t xSize, const uint_
 
    RootBlockAABB rootBlockAABB( domain, rootBlockSize_[0], rootBlockSize_[1], rootBlockSize_[2], xSize, ySize, zSize );
 
-   if( rootBlockExclusionFunctions.size() > 0 )
+   if( !rootBlockExclusionFunctions.empty() )
       WALBERLA_LOG_PROGRESS( "Initializing SetupBlockForest: Calling root block exclusion callback functions ..." );
 
    for( uint_t i = 0; i != rootBlockExclusionFunctions.size(); ++i )
diff --git a/src/blockforest/loadbalancing/Cartesian.cpp b/src/blockforest/loadbalancing/Cartesian.cpp
index 13dbf50b7dba2147d7988683f58a0f45088b9fd4..4645286d55e015d92a79486f45c7dd24279b9390 100644
--- a/src/blockforest/loadbalancing/Cartesian.cpp
+++ b/src/blockforest/loadbalancing/Cartesian.cpp
@@ -48,7 +48,7 @@ uint_t CartesianDistribution::operator()( SetupBlockForest & forest, const uint_
       WALBERLA_ABORT( "Load balancing failed: \'Number of processes in z-direction\' must be in (0," << forest.getZSize() << "]. "
                       "You specified \'" << numberOfZProcesses_ << "\'." );
 
-   if( processIdMap_ != nullptr )
+   if( !processIdMap_->empty() )
       WALBERLA_CHECK_EQUAL( processIdMap_->size(), numberOfProcesses );
 
    uint_t partitions[3];
@@ -84,7 +84,7 @@ uint_t CartesianDistribution::operator()( SetupBlockForest & forest, const uint_
             {
                const uint_t index = z * partitions[0] * partitions[1] + y * partitions[0] + x;
 
-               (*block)->assignTargetProcess( ( processIdMap_ != nullptr ) ? (*processIdMap_)[ index ] : index );
+               (*block)->assignTargetProcess( ( !processIdMap_->empty() ) ? (*processIdMap_)[ index ] : index );
             }
          }
       }
diff --git a/src/blockforest/loadbalancing/DynamicParMetis.cpp b/src/blockforest/loadbalancing/DynamicParMetis.cpp
index ddc0cbe4cb67a9fc5f252897e1fddc90e7164724..94142b23766556f90fa5545b9414c9410ec52cc1 100644
--- a/src/blockforest/loadbalancing/DynamicParMetis.cpp
+++ b/src/blockforest/loadbalancing/DynamicParMetis.cpp
@@ -113,7 +113,7 @@ bool DynamicParMetis::operator()( std::vector< std::pair< const PhantomBlock *,
    MPI_Group allGroup, subGroup;
    MPI_Comm_group( MPIManager::instance()->comm(), &allGroup );
    std::vector<int> ranks;
-   if (targetProcess.size() > 0)
+   if (!targetProcess.empty())
       ranks.push_back( MPIManager::instance()->rank() );
    ranks = mpi::allGatherv( ranks, MPIManager::instance()->comm() );
    auto numSubProcesses = ranks.size();
diff --git a/src/core/cell/Cell.h b/src/core/cell/Cell.h
index 11fa7d1d1470084c6a6701bb3e9011b771270b22..8fc8ef14e29f216f173604b667807801b49e4f83 100644
--- a/src/core/cell/Cell.h
+++ b/src/core/cell/Cell.h
@@ -381,3 +381,15 @@ namespace mpi
 
 
 } // namespace walberla
+
+namespace std
+{
+   template<>
+   struct hash< walberla::Cell >
+   {
+      std::size_t operator()( walberla::Cell const & cell ) const noexcept
+      {
+         return walberla::cell::hash_value( cell );
+      }
+   };
+} // namespace std
diff --git a/src/core/config/Config.cpp b/src/core/config/Config.cpp
index d850e6c5a3b51c8f6db443cabbe67c6e88e88922..dfd7a683484a605ce9c9b6e66b9752ff2c86d01f 100644
--- a/src/core/config/Config.cpp
+++ b/src/core/config/Config.cpp
@@ -271,16 +271,16 @@ void Config::parseFromFile( const char* filename, Block& block, unsigned int lev
       else if( std::getline( input, value, ';' ) && !input.eof() )
       {
          input.ignore( 1 );
-         while( (value.find("$(") != value.npos) && (value.find(')') != value.npos) ) {
+         while( (value.find("$(") != std::string::npos) && (value.find(')') != std::string::npos) ) {
             size_t s = value.find("$("); size_t e = value.find(')');
             ValueReplacementMap::iterator mkey = valueReplacements_.find( value.substr( s+2, e-s+1-3 ) );
             if(mkey != valueReplacements_.end()) {
                value.replace( s,e-s+1, mkey->second );
             }
             else {
-               if(e!=value.npos)
+               if(e!=std::string::npos)
                   value.erase(e,1);
-               if(s!=value.npos)
+               if(s!=std::string::npos)
                   value.erase(s,2);
             }
          }
@@ -404,16 +404,16 @@ void Config::extractBlock( const char* filename, std::stringstream& input, Block
       else if( std::getline( input, value, ';' ) && !input.eof() )
       {
          input.ignore( 1 );
-         while( (value.find("$(") != value.npos) && (value.find(')') != value.npos) ) {
+         while( (value.find("$(") != std::string::npos) && (value.find(')') != std::string::npos) ) {
             size_t s = value.find("$("); size_t e = value.find(')');
             ValueReplacementMap::iterator mkey = valueReplacements_.find( value.substr( s+2, e-s+1-3 ) );
             if(mkey != valueReplacements_.end()) {
                value.replace( s,e-s+1, mkey->second );
             }
             else {
-               if(e!=value.npos)
+               if(e!=std::string::npos)
                   value.erase(e,1);
-               if(s!=value.npos)
+               if(s!=std::string::npos)
                   value.erase(s,2);
             }
          }
@@ -428,7 +428,6 @@ void Config::extractBlock( const char* filename, std::stringstream& input, Block
    error_ << "   Missing '}' for " << block.getKey()
       << " block starting in line " << lineNumber << "\n";
    stateFlag_ = false;
-   return;
 }
 //**********************************************************************************************************************
 
@@ -657,7 +656,7 @@ void Config::Block::getWritableBlocks( const std::string & key, std::vector<Bloc
 // \param value The value of the new parameter.
 // \return \a true if a new parameter was added, \a false if duplicate key is present.
  */
-bool Config::Block::addParameter( std::string key, const std::string& value )
+bool Config::Block::addParameter( const std::string& key, const std::string& value )
 {
    return params_.insert( std::pair<Key,Value>(key,value) ).second;
 }
diff --git a/src/core/config/Config.h b/src/core/config/Config.h
index 88ef3ae20d9b0761ebb9e87b10bd76cbd2305efe..9837b870c7f0151aad400f509958c69d5290f171 100644
--- a/src/core/config/Config.h
+++ b/src/core/config/Config.h
@@ -225,7 +225,7 @@ public:
       //**Utility functions*********************************************************************************************
       /*! \name Utility functions */
       //@{
-      bool addParameter( std::string key, const std::string& value );
+      bool addParameter( const std::string& key, const std::string& value );
       void listParameters() const;
       //@}
       //****************************************************************************************************************
diff --git a/src/core/config/Create.cpp b/src/core/config/Create.cpp
index 6bc78a70209c9aedb69d825531677fa3c3f5bbc0..1d3c7296540931f88508712b6dc58abded97bea1 100644
--- a/src/core/config/Create.cpp
+++ b/src/core/config/Create.cpp
@@ -83,7 +83,7 @@ namespace config {
    void createFromTextFile( Config & config, const std::string & pathToTextFile )
    {
       config.readParameterFile( pathToTextFile.c_str() );
-      if (config.error() != "" )
+      if ( !config.error().empty() )
          throw std::runtime_error( "FileReader returned an error reading the parameter file: \n" + config.error() );
    }
 
@@ -111,7 +111,7 @@ namespace config {
          vector< string > equalitySignSplitResult = string_split( *param, "=" );
 
          std::string value;
-         if ( equalitySignSplitResult.size() == 0 )
+         if ( equalitySignSplitResult.empty() )
          {
             WALBERLA_LOG_WARNING( "Ignoring empty parameter");
             continue;
diff --git a/src/core/math/Parser.cpp b/src/core/math/Parser.cpp
index a2d48044392490a797629e47ade6a4fc32ccc760..b3a4575677d319efd1cd2d198cbcedd228bb561e 100644
--- a/src/core/math/Parser.cpp
+++ b/src/core/math/Parser.cpp
@@ -111,7 +111,7 @@ void FunctionParser::parse( const std::string & eq )
    // check if this expression evaluates to constant zero
    std::vector< std::string > variables;
    symbolTable_->get_variable_list( variables );
-   isConstant_ = (variables.size() == 0);
+   isConstant_ = (variables.empty());
    if (isConstant_)
    {
       const double value = evaluate(std::map<std::string, double>());
diff --git a/src/core/math/PhysicalCheck.cpp b/src/core/math/PhysicalCheck.cpp
index 4800f192929bbcd0d60aa353e8955fae0f38d7ad..e6a3c26e8cf8c75b2d182a1323cb6b9640d40bb6 100644
--- a/src/core/math/PhysicalCheck.cpp
+++ b/src/core/math/PhysicalCheck.cpp
@@ -194,7 +194,7 @@ namespace math {
 
          if( i->second < 0 )
          {
-            if( denom.str().size() > 0 )
+            if( !denom.str().empty() )
                denom << " * ";
             denom << i->first;
          }
@@ -209,16 +209,16 @@ namespace math {
             num << " ^ " << i->second;
       }
 
-      if( num.str().size() == 0 && denom.str().size() == 0 )
+      if( num.str().empty() && denom.str().empty() )
          return std::string();
 
-      if( denom.str().size() == 0 )
+      if( denom.str().empty() )
       {
          num << " *";
          return num.str();
       }
 
-      if( num.str().size() == 0 )
+      if( num.str().empty() )
          num << " * 1";
 
       num << " / ( ";
@@ -321,7 +321,7 @@ namespace math {
       if( !isDefined(varName) )
       {
          WALBERLA_ABORT( "Error in PhysicalCheck::getVarUnit(). Variable not found: " << varName );
-         return nullptr;
+         return std::string();
       }
 
       std::stringstream num, denom;
@@ -341,13 +341,13 @@ namespace math {
             num << '^' << i->second;
       }
 
-      if( num.str().size() == 0 && denom.str().size() == 0 )
+      if( num.str().empty() && denom.str().empty() )
          return std::string();
 
-      if( denom.str().size() == 0 )
+      if( denom.str().empty() )
          return num.str();
 
-      if( num.str().size() == 0 )
+      if( num.str().empty() )
          num << 1;
 
       num << '/';
diff --git a/src/core/math/Vector2.h b/src/core/math/Vector2.h
index b62d58f4651a743e33a0b9c6f0e4f7c860d174dd..b0decf8ec0a2953fc2a2c3ab3a9e8c619de99e60 100644
--- a/src/core/math/Vector2.h
+++ b/src/core/math/Vector2.h
@@ -1689,3 +1689,15 @@ namespace walberla {
    };
 
 } // namespace walberla
+
+namespace std
+{
+    template<typename T>
+    struct hash< walberla::Vector2<T> >
+    {
+        std::size_t operator()( walberla::Vector2<T> const & v ) const noexcept
+        {
+            return walberla::Vector2<T>::hash_value( v );
+        }
+    };
+} // namespace std
diff --git a/src/core/math/Vector3.h b/src/core/math/Vector3.h
index 267e90c38f7b9752820a8397d7729c36134e3c96..7bc9e87af1f534aa694f1c8302dd4b9124b15a2b 100644
--- a/src/core/math/Vector3.h
+++ b/src/core/math/Vector3.h
@@ -1969,3 +1969,15 @@ inline bool check_float_equal_eps( const math::Vector3<real_t> & lhs, const math
 }
 }
 }
+
+namespace std
+{
+    template<typename T>
+    struct hash< walberla::Vector3<T> >
+    {
+        std::size_t operator()( walberla::Vector3<T> const & v ) const noexcept
+        {
+            return walberla::Vector3<T>::hash_value( v );
+        }
+    };
+} // namespace std
diff --git a/src/core/math/equation_system/EquationSystem.cpp b/src/core/math/equation_system/EquationSystem.cpp
index 433a1283c2f9e6350c80184ff36af6279f1ed611..30a9394cfe22e7e7b4f117525ee47b3e00e1519a 100644
--- a/src/core/math/equation_system/EquationSystem.cpp
+++ b/src/core/math/equation_system/EquationSystem.cpp
@@ -171,7 +171,7 @@ size_t EquationSystem::getNumberOfEquations() const
    return eqMap_.size();
 }
 
-const std::string EquationSystem::writeEquations() const
+std::string EquationSystem::writeEquations() const
 {
    std::stringstream ss;
    ss << "Equations to solve:" << std::endl;
@@ -182,7 +182,7 @@ const std::string EquationSystem::writeEquations() const
    return ss.str();
 }
 
-const std::string EquationSystem::writeVariables() const
+std::string EquationSystem::writeVariables() const
 {
    std::stringstream ss;
    ss << "Solution for each variable:" << std::endl;
diff --git a/src/core/math/equation_system/EquationSystem.h b/src/core/math/equation_system/EquationSystem.h
index 56a15bf8096b58fbd26dc007d7fb6522c4232166..e78df0345321a0e51a372941b0a96b46bfd88e29 100644
--- a/src/core/math/equation_system/EquationSystem.h
+++ b/src/core/math/equation_system/EquationSystem.h
@@ -100,8 +100,8 @@ namespace math {
       //**Output functions*************************************************************************
       /*! \name Output functions */
       //@{
-      const std::string writeEquations() const;
-      const std::string writeVariables() const;
+      std::string writeEquations() const;
+      std::string writeVariables() const;
       friend std::ostream& operator<<( std::ostream& os, EquationSystem& es );
       //@}
       //****************************************************************************************************************
diff --git a/src/core/math/extern/exprtk.h b/src/core/math/extern/exprtk.h
index f55657a617e1d7815b9f154fd073dcf843eed2ac..4c88bbdf6b501ccd95726cab45b0000597e49e49 100644
--- a/src/core/math/extern/exprtk.h
+++ b/src/core/math/extern/exprtk.h
@@ -2,7 +2,7 @@
  ******************************************************************
  *           C++ Mathematical Expression Toolkit Library          *
  *                                                                *
- * Author: Arash Partow (1999-2018)                               *
+ * Author: Arash Partow (1999-2019)                               *
  * URL: http://www.partow.net/programming/exprtk/index.html       *
  *                                                                *
  * Copyright notice:                                              *
@@ -580,46 +580,64 @@ namespace exprtk
 
       template <typename Iterator, typename Compare>
       inline bool match_impl(const Iterator pattern_begin,
-                             const Iterator pattern_end,
-                             const Iterator data_begin,
-                             const Iterator data_end,
+                             const Iterator pattern_end  ,
+                             const Iterator data_begin   ,
+                             const Iterator data_end     ,
                              const typename std::iterator_traits<Iterator>::value_type& zero_or_more,
-                             const typename std::iterator_traits<Iterator>::value_type& zero_or_one)
+                             const typename std::iterator_traits<Iterator>::value_type& zero_or_one )
       {
-         Iterator d_itr = data_begin;
-         Iterator p_itr = pattern_begin;
+         const Iterator null_itr(0);
 
-         while ((p_itr != pattern_end) && (d_itr != data_end))
+         Iterator d_itr    = data_begin;
+         Iterator p_itr    = pattern_begin;
+         Iterator tb_p_itr = null_itr;
+         Iterator tb_d_itr = null_itr;
+
+         while (d_itr != data_end)
          {
             if (zero_or_more == *p_itr)
             {
-               while ((p_itr != pattern_end) && (*p_itr == zero_or_more || *p_itr == zero_or_one))
+               while ((pattern_end != p_itr) && ((zero_or_more == *p_itr) || (zero_or_one == *p_itr)))
                {
                   ++p_itr;
                }
 
-               if (p_itr == pattern_end)
+               if (pattern_end == p_itr)
                   return true;
 
-               const typename std::iterator_traits<Iterator>::value_type c = *(p_itr++);
+               const typename std::iterator_traits<Iterator>::value_type c = *(p_itr);
 
-               while ((d_itr != data_end) && !Compare::cmp(c,*d_itr))
+               while ((data_end != d_itr) && !Compare::cmp(c,*d_itr))
                {
                   ++d_itr;
                }
 
-               ++d_itr;
+               tb_p_itr = p_itr;
+               tb_d_itr = d_itr;
+
+               continue;
             }
-            else if ((*p_itr == zero_or_one) || Compare::cmp(*p_itr, *d_itr))
+            else if (!Compare::cmp(*p_itr, *d_itr) && (zero_or_one != *p_itr))
             {
-               ++d_itr;
-               ++p_itr;
+               if (null_itr == tb_d_itr)
+                  return false;
+
+               d_itr = tb_d_itr++;
+               p_itr = tb_p_itr;
+
+               continue;
             }
-            else
-               return false;
+
+            ++p_itr;
+            ++d_itr;
          }
 
-         return (d_itr == data_end) && (p_itr == pattern_end);
+         while ((pattern_end != p_itr) && ((zero_or_more == *p_itr) || (zero_or_one == *p_itr)))
+         {
+            ++p_itr;
+         }
+
+         return (pattern_end == p_itr);
       }
 
       inline bool wc_match(const std::string& wild_card,
@@ -1828,7 +1846,7 @@ namespace exprtk
 
          bool instate = false;
 
-         static const char zero = static_cast<uchar_t>('0');
+         static const char_t zero = static_cast<uchar_t>('0');
 
          #define parse_digit_1(d)          \
          if ((digit = (*itr - zero)) < 10) \
@@ -2305,8 +2323,8 @@ namespace exprtk
 
          inline std::string substr(const std::size_t& begin, const std::size_t& end)
          {
-            details::char_cptr begin_itr = ((base_itr_ + begin) < s_end_) ? (base_itr_ + begin) : s_end_;
-            details::char_cptr end_itr   = ((base_itr_ +   end) < s_end_) ? (base_itr_ +   end) : s_end_;
+            const details::char_cptr begin_itr = ((base_itr_ + begin) < s_end_) ? (base_itr_ + begin) : s_end_;
+            const details::char_cptr end_itr   = ((base_itr_ +   end) < s_end_) ? (base_itr_ +   end) : s_end_;
 
             return std::string(begin_itr,end_itr);
          }
@@ -3099,7 +3117,7 @@ namespace exprtk
 
             std::size_t changes = 0;
 
-            for (std::size_t i = 0; i < (g.token_list_.size() - 1); ++i)
+            for (int i = 0;  i < static_cast<int>(g.token_list_.size() - 1); ++i)
             {
                token t;
 
@@ -3110,6 +3128,9 @@ namespace exprtk
                   g.token_list_.erase(g.token_list_.begin() + static_cast<diff_t>(i + 1));
 
                   ++changes;
+
+                  if (static_cast<std::size_t>(i + 1) >= g.token_list_.size())
+                     break;
                }
             }
 
@@ -3125,7 +3146,7 @@ namespace exprtk
 
             std::size_t changes = 0;
 
-            for (std::size_t i = 0; i < (g.token_list_.size() - 2); ++i)
+            for (int i = 0;  i < static_cast<int>(g.token_list_.size() - 2); ++i)
             {
                token t;
 
@@ -3136,6 +3157,9 @@ namespace exprtk
                   g.token_list_.erase(g.token_list_.begin() + static_cast<diff_t>(i + 1),
                                       g.token_list_.begin() + static_cast<diff_t>(i + 3));
                   ++changes;
+
+                  if (static_cast<std::size_t>(i + 2) >= g.token_list_.size())
+                     break;
                }
             }
 
@@ -3213,6 +3237,7 @@ namespace exprtk
                else if ((t0.type == lexer::token::e_rbracket   ) && (t1.type == lexer::token::e_symbol     )) match = true;
                else if ((t0.type == lexer::token::e_rcrlbracket) && (t1.type == lexer::token::e_symbol     )) match = true;
                else if ((t0.type == lexer::token::e_rsqrbracket) && (t1.type == lexer::token::e_symbol     )) match = true;
+               else if ((t0.type == lexer::token::e_symbol     ) && (t1.type == lexer::token::e_symbol     )) match = true;
 
                return (match) ? 1 : -1;
             }
@@ -3655,7 +3680,7 @@ namespace exprtk
 
             bool operator() (const lexer::token& t0, const lexer::token& t1)
             {
-               set_t::value_type p = std::make_pair(t0.type,t1.type);
+               const set_t::value_type p = std::make_pair(t0.type,t1.type);
 
                if (invalid_bracket_check(t0.type,t1.type))
                {
@@ -3669,7 +3694,7 @@ namespace exprtk
                return true;
             }
 
-            std::size_t error_count()
+            std::size_t error_count() const
             {
                return error_list_.size();
             }
@@ -3781,6 +3806,91 @@ namespace exprtk
             std::vector<std::pair<lexer::token,lexer::token> > error_list_;
          };
 
+         class sequence_validator_3tokens : public lexer::token_scanner
+         {
+         private:
+
+            typedef lexer::token::token_type token_t;
+            typedef std::pair<token_t,std::pair<token_t,token_t> > token_triplet_t;
+            typedef std::set<token_triplet_t> set_t;
+
+         public:
+
+            using lexer::token_scanner::operator();
+
+            sequence_validator_3tokens()
+            : lexer::token_scanner(3)
+            {
+               add_invalid(lexer::token::e_number , lexer::token::e_number , lexer::token::e_number);
+               add_invalid(lexer::token::e_string , lexer::token::e_string , lexer::token::e_string);
+               add_invalid(lexer::token::e_comma  , lexer::token::e_comma  , lexer::token::e_comma );
+
+               add_invalid(lexer::token::e_add ,lexer::token::e_add , lexer::token::e_add);
+               add_invalid(lexer::token::e_sub ,lexer::token::e_sub , lexer::token::e_sub);
+               add_invalid(lexer::token::e_div ,lexer::token::e_div , lexer::token::e_div);
+               add_invalid(lexer::token::e_mul ,lexer::token::e_mul , lexer::token::e_mul);
+               add_invalid(lexer::token::e_mod ,lexer::token::e_mod , lexer::token::e_mod);
+               add_invalid(lexer::token::e_pow ,lexer::token::e_pow , lexer::token::e_pow);
+
+               add_invalid(lexer::token::e_add ,lexer::token::e_sub , lexer::token::e_add);
+               add_invalid(lexer::token::e_sub ,lexer::token::e_add , lexer::token::e_sub);
+               add_invalid(lexer::token::e_div ,lexer::token::e_mul , lexer::token::e_div);
+               add_invalid(lexer::token::e_mul ,lexer::token::e_div , lexer::token::e_mul);
+               add_invalid(lexer::token::e_mod ,lexer::token::e_pow , lexer::token::e_mod);
+               add_invalid(lexer::token::e_pow ,lexer::token::e_mod , lexer::token::e_pow);
+            }
+
+            bool result()
+            {
+               return error_list_.empty();
+            }
+
+            bool operator() (const lexer::token& t0, const lexer::token& t1, const lexer::token& t2)
+            {
+               const set_t::value_type p = std::make_pair(t0.type,std::make_pair(t1.type,t2.type));
+
+               if (invalid_comb_.find(p) != invalid_comb_.end())
+               {
+                  error_list_.push_back(std::make_pair(t0,t1));
+               }
+
+               return true;
+            }
+
+            std::size_t error_count() const
+            {
+               return error_list_.size();
+            }
+
+            std::pair<lexer::token,lexer::token> error(const std::size_t index)
+            {
+               if (index < error_list_.size())
+               {
+                  return error_list_[index];
+               }
+               else
+               {
+                  static const lexer::token error_token;
+                  return std::make_pair(error_token,error_token);
+               }
+            }
+
+            void clear_errors()
+            {
+               error_list_.clear();
+            }
+
+         private:
+
+            void add_invalid(token_t t0, token_t t1, token_t t2)
+            {
+               invalid_comb_.insert(std::make_pair(t0,std::make_pair(t1,t2)));
+            }
+
+            set_t invalid_comb_;
+            std::vector<std::pair<lexer::token,lexer::token> > error_list_;
+         };
+
          struct helper_assembly
          {
             inline bool register_scanner(lexer::token_scanner* scanner)
@@ -4035,40 +4145,6 @@ namespace exprtk
             return true;
          }
 
-         inline bool token_is_then_assign(const token_t::token_type& ttype,
-                                          std::string& token,
-                                          const token_advance_mode mode = e_advance)
-         {
-            if (current_token_.type != ttype)
-            {
-               return false;
-            }
-
-            token = current_token_.value;
-
-            advance_token(mode);
-
-            return true;
-         }
-
-         template <typename Allocator,
-                   template <typename,typename> class Container>
-         inline bool token_is_then_assign(const token_t::token_type& ttype,
-                                          Container<std::string,Allocator>& token_list,
-                                          const token_advance_mode mode = e_advance)
-         {
-            if (current_token_.type != ttype)
-            {
-               return false;
-            }
-
-            token_list.push_back(current_token_.value);
-
-            advance_token(mode);
-
-            return true;
-         }
-
          inline bool peek_token_is(const token_t::token_type& ttype)
          {
             return (lexer_.peek_next_token().type == ttype);
@@ -4179,13 +4255,18 @@ namespace exprtk
       };
 
       type_store()
-      : size(0),
-        data(0),
+      : data(0),
+        size(0),
         type(e_unknown)
       {}
 
+      union
+      {
+          void*  data;
+          T*     vec_data;
+      };
+
       std::size_t size;
-      void*       data;
       store_type  type;
 
       class parameter_list
@@ -4585,16 +4666,16 @@ namespace exprtk
             {}
 
             control_block(const std::size_t& dsize)
-            : ref_count(1),
+            : ref_count(1    ),
               size     (dsize),
-              data     (0),
-              destruct (true)
+              data     (0    ),
+              destruct (true )
             { create_data(); }
 
             control_block(const std::size_t& dsize, data_t dptr, bool dstrct = false)
-            : ref_count(1),
-              size     (dsize),
-              data     (dptr ),
+            : ref_count(1     ),
+              size     (dsize ),
+              data     (dptr  ),
               destruct (dstrct)
             {}
 
@@ -4757,8 +4838,8 @@ namespace exprtk
 
          static inline std::size_t min_size(control_block* cb0, control_block* cb1)
          {
-            std::size_t size0 = cb0->size;
-            std::size_t size1 = cb1->size;
+            const std::size_t size0 = cb0->size;
+            const std::size_t size1 = cb1->size;
 
             if (size0 && size1)
                return std::min(size0,size1);
@@ -4845,19 +4926,19 @@ namespace exprtk
                   case e_ne     : return std::not_equal_to<T>()(arg0,arg1) ? T(1) : T(0);
                   case e_gte    : return (arg0 >= arg1) ? T(1) : T(0);
                   case e_gt     : return (arg0 >  arg1) ? T(1) : T(0);
-                  case e_and    : return and_opr<T> (arg0,arg1);
+                  case e_and    : return and_opr <T>(arg0,arg1);
                   case e_nand   : return nand_opr<T>(arg0,arg1);
-                  case e_or     : return or_opr<T>  (arg0,arg1);
-                  case e_nor    : return nor_opr<T> (arg0,arg1);
-                  case e_xor    : return xor_opr<T> (arg0,arg1);
+                  case e_or     : return or_opr  <T>(arg0,arg1);
+                  case e_nor    : return nor_opr <T>(arg0,arg1);
+                  case e_xor    : return xor_opr <T>(arg0,arg1);
                   case e_xnor   : return xnor_opr<T>(arg0,arg1);
-                  case e_root   : return root<T>    (arg0,arg1);
-                  case e_roundn : return roundn<T>  (arg0,arg1);
+                  case e_root   : return root    <T>(arg0,arg1);
+                  case e_roundn : return roundn  <T>(arg0,arg1);
                   case e_equal  : return equal      (arg0,arg1);
                   case e_nequal : return nequal     (arg0,arg1);
-                  case e_hypot  : return hypot<T>   (arg0,arg1);
-                  case e_shr    : return shr<T>     (arg0,arg1);
-                  case e_shl    : return shl<T>     (arg0,arg1);
+                  case e_hypot  : return hypot   <T>(arg0,arg1);
+                  case e_shr    : return shr     <T>(arg0,arg1);
+                  case e_shl    : return shl     <T>(arg0,arg1);
 
                   default       : exprtk_debug(("numeric::details::process_impl<T> - Invalid binary operation.\n"));
                                   return std::numeric_limits<T>::quiet_NaN();
@@ -5179,7 +5260,7 @@ namespace exprtk
 
       template <typename T,
                 typename Allocator,
-                template <typename,typename> class Sequence>
+                template <typename, typename> class Sequence>
       inline bool all_nodes_valid(const Sequence<expression_node<T>*,Allocator>& b)
       {
          for (std::size_t i = 0; i < b.size(); ++i)
@@ -5206,7 +5287,7 @@ namespace exprtk
 
       template <typename T,
                 typename Allocator,
-                template <typename,typename> class Sequence>
+                template <typename, typename> class Sequence>
       inline bool all_nodes_variables(Sequence<expression_node<T>*,Allocator>& b)
       {
          for (std::size_t i = 0; i < b.size(); ++i)
@@ -5232,7 +5313,7 @@ namespace exprtk
       template <typename NodeAllocator,
                 typename T,
                 typename Allocator,
-                template <typename,typename> class Sequence>
+                template <typename, typename> class Sequence>
       inline void free_all_nodes(NodeAllocator& node_allocator, Sequence<expression_node<T>*,Allocator>& b)
       {
          for (std::size_t i = 0; i < b.size(); ++i)
@@ -5342,7 +5423,7 @@ namespace exprtk
          };
 
          template <typename Allocator,
-                   template <typename,typename> class Sequence>
+                   template <typename, typename> class Sequence>
          class sequence_vector_impl : public vector_holder_base
          {
          public:
@@ -5790,7 +5871,7 @@ namespace exprtk
 
          template <typename T,
                    typename Allocator,
-                   template <typename,typename> class Sequence>
+                   template <typename, typename> class Sequence>
          static inline void execute(Sequence<std::pair<expression_node<T>*,bool>,Allocator>& branch)
          {
             for (std::size_t i = 0; i < branch.size(); ++i)
@@ -6618,7 +6699,7 @@ namespace exprtk
          typedef expression_node<T>* expression_ptr;
 
          template <typename Allocator,
-                   template <typename,typename> class Sequence>
+                   template <typename, typename> class Sequence>
          switch_node(const Sequence<expression_ptr,Allocator>& arg_list)
          {
             if (1 != (arg_list.size() & 1))
@@ -6696,7 +6777,7 @@ namespace exprtk
          typedef expression_node<T>* expression_ptr;
 
          template <typename Allocator,
-                   template <typename,typename> class Sequence>
+                   template <typename, typename> class Sequence>
          switch_n_node(const Sequence<expression_ptr,Allocator>& arg_list)
          : switch_node<T>(arg_list)
          {}
@@ -6715,7 +6796,7 @@ namespace exprtk
          typedef expression_node<T>* expression_ptr;
 
          template <typename Allocator,
-                   template <typename,typename> class Sequence>
+                   template <typename, typename> class Sequence>
          multi_switch_node(const Sequence<expression_ptr,Allocator>& arg_list)
          {
             if (0 != (arg_list.size() & 1))
@@ -8677,7 +8758,7 @@ namespace exprtk
 
                   range_t& range = str0_range_ptr_->range_ref();
 
-                  if (range(r0,r1,str0_base_ptr_->size()))
+                  if (range(r0, r1, str0_base_ptr_->size()))
                   {
                      const std::size_t size = (r1 - r0) + 1;
 
@@ -8695,7 +8776,7 @@ namespace exprtk
 
                   range_t& range = str1_range_ptr_->range_ref();
 
-                  if (range(r0,r1,str1_base_ptr_->size()))
+                  if (range(r0, r1, str1_base_ptr_->size()))
                   {
                      const std::size_t size = (r1 - r0) + 1;
 
@@ -8815,7 +8896,7 @@ namespace exprtk
                   std::size_t r0 = 0;
                   std::size_t r1 = 0;
 
-                  if (range(r0,r1,str0_base_ptr_->size()))
+                  if (range(r0, r1, str0_base_ptr_->size()))
                   {
                      const std::size_t size = (r1 - r0) + 1;
 
@@ -8889,7 +8970,7 @@ namespace exprtk
          typedef irange_t*                 irange_ptr;
 
          template <typename Allocator,
-                   template <typename,typename> class Sequence>
+                   template <typename, typename> class Sequence>
          str_vararg_node(const Sequence<expression_ptr,Allocator>& arg_list)
          : final_node_(arg_list.back()),
            final_deletable_(branch_deletable(final_node_)),
@@ -9355,7 +9436,7 @@ namespace exprtk
          typedef expression_node<T>* expression_ptr;
 
          template <typename Allocator,
-                   template <typename,typename> class Sequence>
+                   template <typename, typename> class Sequence>
          vararg_node(const Sequence<expression_ptr,Allocator>& arg_list)
          {
             arg_list_     .resize(arg_list.size());
@@ -9415,7 +9496,7 @@ namespace exprtk
          typedef expression_node<T>* expression_ptr;
 
          template <typename Allocator,
-                   template <typename,typename> class Sequence>
+                   template <typename, typename> class Sequence>
          vararg_varnode(const Sequence<expression_ptr,Allocator>& arg_list)
          {
             arg_list_.resize(arg_list.size());
@@ -11486,6 +11567,7 @@ namespace exprtk
                   ts.size = vi->size();
                   ts.data = vi->vds().data();
                   ts.type = type_store_t::e_vector;
+                  vi->vec()->vec_holder().set_ref(&ts.vec_data);
                }
                #ifndef exprtk_disable_string_capabilities
                else if (is_generally_string_node(arg_list_[i]))
@@ -11651,16 +11733,14 @@ namespace exprtk
 
          inline T value() const
          {
-            T result = std::numeric_limits<T>::quiet_NaN();
-
             if (gen_function_t::function_)
             {
                if (gen_function_t::populate_value_list())
                {
                   typedef typename StringFunction::parameter_list_t parameter_list_t;
 
-                  result = (*gen_function_t::function_)(ret_string_,
-                                                        parameter_list_t(gen_function_t::typestore_list_));
+                  const T result = (*gen_function_t::function_)
+                                      (ret_string_, parameter_list_t(gen_function_t::typestore_list_));
 
                   range_.n1_c.second  = ret_string_.size() - 1;
                   range_.cache.second = range_.n1_c.second;
@@ -11669,7 +11749,7 @@ namespace exprtk
                }
             }
 
-            return result;
+            return std::numeric_limits<T>::quiet_NaN();
          }
 
          inline typename expression_node<T>::node_type type() const
@@ -11726,8 +11806,6 @@ namespace exprtk
 
          inline T value() const
          {
-            T result = std::numeric_limits<T>::quiet_NaN();
-
             if (gen_function_t::function_)
             {
                if (gen_function_t::populate_value_list())
@@ -11739,7 +11817,7 @@ namespace exprtk
                }
             }
 
-            return result;
+            return std::numeric_limits<T>::quiet_NaN();
          }
 
          inline typename expression_node<T>::node_type type() const
@@ -11770,17 +11848,15 @@ namespace exprtk
 
          inline T value() const
          {
-            T result = std::numeric_limits<T>::quiet_NaN();
-
             if (str_function_t::function_)
             {
                if (str_function_t::populate_value_list())
                {
                   typedef typename StringFunction::parameter_list_t parameter_list_t;
 
-                  result = (*str_function_t::function_)(param_seq_index_,
-                                                        str_function_t::ret_string_,
-                                                        parameter_list_t(str_function_t::typestore_list_));
+                  const T result = (*str_function_t::function_)(param_seq_index_,
+                                                                str_function_t::ret_string_,
+                                                                parameter_list_t(str_function_t::typestore_list_));
 
                   str_function_t::range_.n1_c.second  = str_function_t::ret_string_.size() - 1;
                   str_function_t::range_.cache.second = str_function_t::range_.n1_c.second;
@@ -11789,7 +11865,7 @@ namespace exprtk
                }
             }
 
-            return result;
+            return std::numeric_limits<T>::quiet_NaN();
          }
 
          inline typename expression_node<T>::node_type type() const
@@ -11994,20 +12070,21 @@ namespace exprtk
       template <typename T>
       struct opr_base
       {
-         typedef typename details::functor_t<T>::Type Type;
+         typedef typename details::functor_t<T>::Type    Type;
          typedef typename details::functor_t<T>::RefType RefType;
-         typedef typename details::functor_t<T> functor_t;
-         typedef typename functor_t::qfunc_t quaternary_functor_t;
-         typedef typename functor_t::tfunc_t    trinary_functor_t;
-         typedef typename functor_t::bfunc_t     binary_functor_t;
-         typedef typename functor_t::ufunc_t      unary_functor_t;
+         typedef typename details::functor_t<T>          functor_t;
+         typedef typename functor_t::qfunc_t  quaternary_functor_t;
+         typedef typename functor_t::tfunc_t     trinary_functor_t;
+         typedef typename functor_t::bfunc_t      binary_functor_t;
+         typedef typename functor_t::ufunc_t       unary_functor_t;
       };
 
       template <typename T>
       struct add_op : public opr_base<T>
       {
-         typedef typename opr_base<T>::Type Type;
+         typedef typename opr_base<T>::Type    Type;
          typedef typename opr_base<T>::RefType RefType;
+
          static inline T process(Type t1, Type t2) { return t1 + t2; }
          static inline T process(Type t1, Type t2, Type t3) { return t1 + t2 + t3; }
          static inline void assign(RefType t1, Type t2) { t1 += t2; }
@@ -12018,8 +12095,9 @@ namespace exprtk
       template <typename T>
       struct mul_op : public opr_base<T>
       {
-         typedef typename opr_base<T>::Type Type;
+         typedef typename opr_base<T>::Type    Type;
          typedef typename opr_base<T>::RefType RefType;
+
          static inline T process(Type t1, Type t2) { return t1 * t2; }
          static inline T process(Type t1, Type t2, Type t3) { return t1 * t2 * t3; }
          static inline void assign(RefType t1, Type t2) { t1 *= t2; }
@@ -12030,8 +12108,9 @@ namespace exprtk
       template <typename T>
       struct sub_op : public opr_base<T>
       {
-         typedef typename opr_base<T>::Type Type;
+         typedef typename opr_base<T>::Type    Type;
          typedef typename opr_base<T>::RefType RefType;
+
          static inline T process(Type t1, Type t2) { return t1 - t2; }
          static inline T process(Type t1, Type t2, Type t3) { return t1 - t2 - t3; }
          static inline void assign(RefType t1, Type t2) { t1 -= t2; }
@@ -12042,8 +12121,9 @@ namespace exprtk
       template <typename T>
       struct div_op : public opr_base<T>
       {
-         typedef typename opr_base<T>::Type Type;
+         typedef typename opr_base<T>::Type    Type;
          typedef typename opr_base<T>::RefType RefType;
+
          static inline T process(Type t1, Type t2) { return t1 / t2; }
          static inline T process(Type t1, Type t2, Type t3) { return t1 / t2 / t3; }
          static inline void assign(RefType t1, Type t2) { t1 /= t2; }
@@ -12054,8 +12134,9 @@ namespace exprtk
       template <typename T>
       struct mod_op : public opr_base<T>
       {
-         typedef typename opr_base<T>::Type Type;
+         typedef typename opr_base<T>::Type    Type;
          typedef typename opr_base<T>::RefType RefType;
+
          static inline T process(Type t1, Type t2) { return numeric::modulus<T>(t1,t2); }
          static inline void assign(RefType t1, Type t2) { t1 = numeric::modulus<T>(t1,t2); }
          static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_mod; }
@@ -12065,8 +12146,9 @@ namespace exprtk
       template <typename T>
       struct pow_op : public opr_base<T>
       {
-         typedef typename opr_base<T>::Type Type;
+         typedef typename opr_base<T>::Type    Type;
          typedef typename opr_base<T>::RefType RefType;
+
          static inline T process(Type t1, Type t2) { return numeric::pow<T>(t1,t2); }
          static inline void assign(RefType t1, Type t2) { t1 = numeric::pow<T>(t1,t2); }
          static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_pow; }
@@ -12077,6 +12159,7 @@ namespace exprtk
       struct lt_op : public opr_base<T>
       {
          typedef typename opr_base<T>::Type Type;
+
          static inline T process(Type t1, Type t2) { return ((t1 < t2) ? T(1) : T(0)); }
          static inline T process(const std::string& t1, const std::string& t2) { return ((t1 < t2) ? T(1) : T(0)); }
          static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_lt; }
@@ -12087,6 +12170,7 @@ namespace exprtk
       struct lte_op : public opr_base<T>
       {
          typedef typename opr_base<T>::Type Type;
+
          static inline T process(Type t1, Type t2) { return ((t1 <= t2) ? T(1) : T(0)); }
          static inline T process(const std::string& t1, const std::string& t2) { return ((t1 <= t2) ? T(1) : T(0)); }
          static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_lte; }
@@ -12097,6 +12181,7 @@ namespace exprtk
       struct gt_op : public opr_base<T>
       {
          typedef typename opr_base<T>::Type Type;
+
          static inline T process(Type t1, Type t2) { return ((t1 > t2) ? T(1) : T(0)); }
          static inline T process(const std::string& t1, const std::string& t2) { return ((t1 > t2) ? T(1) : T(0)); }
          static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_gt; }
@@ -12107,6 +12192,7 @@ namespace exprtk
       struct gte_op : public opr_base<T>
       {
          typedef typename opr_base<T>::Type Type;
+
          static inline T process(Type t1, Type t2) { return ((t1 >= t2) ? T(1) : T(0)); }
          static inline T process(const std::string& t1, const std::string& t2) { return ((t1 >= t2) ? T(1) : T(0)); }
          static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_gte; }
@@ -12127,6 +12213,7 @@ namespace exprtk
       struct equal_op : public opr_base<T>
       {
          typedef typename opr_base<T>::Type Type;
+
          static inline T process(Type t1, Type t2) { return numeric::equal(t1,t2); }
          static inline T process(const std::string& t1, const std::string& t2) { return ((t1 == t2) ? T(1) : T(0)); }
          static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_eq; }
@@ -12137,6 +12224,7 @@ namespace exprtk
       struct ne_op : public opr_base<T>
       {
          typedef typename opr_base<T>::Type Type;
+
          static inline T process(Type t1, Type t2) { return (std::not_equal_to<T>()(t1,t2) ? T(1) : T(0)); }
          static inline T process(const std::string& t1, const std::string& t2) { return ((t1 != t2) ? T(1) : T(0)); }
          static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_ne; }
@@ -12147,6 +12235,7 @@ namespace exprtk
       struct and_op : public opr_base<T>
       {
          typedef typename opr_base<T>::Type Type;
+
          static inline T process(Type t1, Type t2) { return (details::is_true(t1) && details::is_true(t2)) ? T(1) : T(0); }
          static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_and; }
          static inline details::operator_type operation() { return details::e_and; }
@@ -12156,6 +12245,7 @@ namespace exprtk
       struct nand_op : public opr_base<T>
       {
          typedef typename opr_base<T>::Type Type;
+
          static inline T process(Type t1, Type t2) { return (details::is_true(t1) && details::is_true(t2)) ? T(0) : T(1); }
          static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_nand; }
          static inline details::operator_type operation() { return details::e_nand; }
@@ -12165,6 +12255,7 @@ namespace exprtk
       struct or_op : public opr_base<T>
       {
          typedef typename opr_base<T>::Type Type;
+
          static inline T process(Type t1, Type t2) { return (details::is_true(t1) || details::is_true(t2)) ? T(1) : T(0); }
          static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_or; }
          static inline details::operator_type operation() { return details::e_or; }
@@ -12174,6 +12265,7 @@ namespace exprtk
       struct nor_op : public opr_base<T>
       {
          typedef typename opr_base<T>::Type Type;
+
          static inline T process(Type t1, Type t2) { return (details::is_true(t1) || details::is_true(t2)) ? T(0) : T(1); }
          static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_nor; }
          static inline details::operator_type operation() { return details::e_nor; }
@@ -12183,6 +12275,7 @@ namespace exprtk
       struct xor_op : public opr_base<T>
       {
          typedef typename opr_base<T>::Type Type;
+
          static inline T process(Type t1, Type t2) { return numeric::xor_opr<T>(t1,t2); }
          static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_nor; }
          static inline details::operator_type operation() { return details::e_xor; }
@@ -12192,6 +12285,7 @@ namespace exprtk
       struct xnor_op : public opr_base<T>
       {
          typedef typename opr_base<T>::Type Type;
+
          static inline T process(Type t1, Type t2) { return numeric::xnor_opr<T>(t1,t2); }
          static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_nor; }
          static inline details::operator_type operation() { return details::e_xnor; }
@@ -12201,6 +12295,7 @@ namespace exprtk
       struct in_op : public opr_base<T>
       {
          typedef typename opr_base<T>::Type Type;
+
          static inline T process(const T&, const T&) { return std::numeric_limits<T>::quiet_NaN(); }
          static inline T process(const std::string& t1, const std::string& t2) { return ((std::string::npos != t2.find(t1)) ? T(1) : T(0)); }
          static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_in; }
@@ -12211,6 +12306,7 @@ namespace exprtk
       struct like_op : public opr_base<T>
       {
          typedef typename opr_base<T>::Type Type;
+
          static inline T process(const T&, const T&) { return std::numeric_limits<T>::quiet_NaN(); }
          static inline T process(const std::string& t1, const std::string& t2) { return (details::wc_match(t2,t1) ? T(1) : T(0)); }
          static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_like; }
@@ -12221,6 +12317,7 @@ namespace exprtk
       struct ilike_op : public opr_base<T>
       {
          typedef typename opr_base<T>::Type Type;
+
          static inline T process(const T&, const T&) { return std::numeric_limits<T>::quiet_NaN(); }
          static inline T process(const std::string& t1, const std::string& t2) { return (details::wc_imatch(t2,t1) ? T(1) : T(0)); }
          static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_ilike; }
@@ -12231,6 +12328,7 @@ namespace exprtk
       struct inrange_op : public opr_base<T>
       {
          typedef typename opr_base<T>::Type Type;
+
          static inline T process(const T& t0, const T& t1, const T& t2) { return ((t0 <= t1) && (t1 <= t2)) ? T(1) : T(0); }
          static inline T process(const std::string& t0, const std::string& t1, const std::string& t2)
          {
@@ -12259,7 +12357,7 @@ namespace exprtk
 
          template <typename Type,
                    typename Allocator,
-                   template <typename,typename> class Sequence>
+                   template <typename, typename> class Sequence>
          static inline T process(const Sequence<Type,Allocator>& arg_list)
          {
             switch (arg_list.size())
@@ -12300,14 +12398,14 @@ namespace exprtk
          static inline T process_3(const Sequence& arg_list)
          {
             return value(arg_list[0]) + value(arg_list[1]) +
-                   value(arg_list[2]);
+                   value(arg_list[2]) ;
          }
 
          template <typename Sequence>
          static inline T process_4(const Sequence& arg_list)
          {
             return value(arg_list[0]) + value(arg_list[1]) +
-                   value(arg_list[2]) + value(arg_list[3]);
+                   value(arg_list[2]) + value(arg_list[3]) ;
          }
 
          template <typename Sequence>
@@ -12315,7 +12413,7 @@ namespace exprtk
          {
             return value(arg_list[0]) + value(arg_list[1]) +
                    value(arg_list[2]) + value(arg_list[3]) +
-                   value(arg_list[4]);
+                   value(arg_list[4]) ;
          }
       };
 
@@ -12326,7 +12424,7 @@ namespace exprtk
 
          template <typename Type,
                    typename Allocator,
-                   template <typename,typename> class Sequence>
+                   template <typename, typename> class Sequence>
          static inline T process(const Sequence<Type,Allocator>& arg_list)
          {
             switch (arg_list.size())
@@ -12367,14 +12465,14 @@ namespace exprtk
          static inline T process_3(const Sequence& arg_list)
          {
             return value(arg_list[0]) * value(arg_list[1]) *
-                   value(arg_list[2]);
+                   value(arg_list[2]) ;
          }
 
          template <typename Sequence>
          static inline T process_4(const Sequence& arg_list)
          {
             return value(arg_list[0]) * value(arg_list[1]) *
-                   value(arg_list[2]) * value(arg_list[3]);
+                   value(arg_list[2]) * value(arg_list[3]) ;
          }
 
          template <typename Sequence>
@@ -12382,7 +12480,7 @@ namespace exprtk
          {
             return value(arg_list[0]) * value(arg_list[1]) *
                    value(arg_list[2]) * value(arg_list[3]) *
-                   value(arg_list[4]);
+                   value(arg_list[4]) ;
          }
       };
 
@@ -12393,7 +12491,7 @@ namespace exprtk
 
          template <typename Type,
                    typename Allocator,
-                   template <typename,typename> class Sequence>
+                   template <typename, typename> class Sequence>
          static inline T process(const Sequence<Type,Allocator>& arg_list)
          {
             switch (arg_list.size())
@@ -12449,7 +12547,7 @@ namespace exprtk
 
          template <typename Type,
                    typename Allocator,
-                   template <typename,typename> class Sequence>
+                   template <typename, typename> class Sequence>
          static inline T process(const Sequence<Type,Allocator>& arg_list)
          {
             switch (arg_list.size())
@@ -12520,7 +12618,7 @@ namespace exprtk
 
          template <typename Type,
                    typename Allocator,
-                   template <typename,typename> class Sequence>
+                   template <typename, typename> class Sequence>
          static inline T process(const Sequence<Type,Allocator>& arg_list)
          {
             switch (arg_list.size())
@@ -12591,7 +12689,7 @@ namespace exprtk
 
          template <typename Type,
                    typename Allocator,
-                   template <typename,typename> class Sequence>
+                   template <typename, typename> class Sequence>
          static inline T process(const Sequence<Type,Allocator>& arg_list)
          {
             switch (arg_list.size())
@@ -12605,7 +12703,7 @@ namespace exprtk
                          {
                             for (std::size_t i = 0; i < arg_list.size(); ++i)
                             {
-                               if (std::equal_to<T>()(T(0),value(arg_list[i])))
+                               if (std::equal_to<T>()(T(0), value(arg_list[i])))
                                   return T(0);
                             }
 
@@ -12618,15 +12716,15 @@ namespace exprtk
          static inline T process_1(const Sequence& arg_list)
          {
             return std::not_equal_to<T>()
-                      (T(0),value(arg_list[0])) ? T(1) : T(0);
+                      (T(0), value(arg_list[0])) ? T(1) : T(0);
          }
 
          template <typename Sequence>
          static inline T process_2(const Sequence& arg_list)
          {
             return (
-                     std::not_equal_to<T>()(T(0),value(arg_list[0])) &&
-                     std::not_equal_to<T>()(T(0),value(arg_list[1]))
+                     std::not_equal_to<T>()(T(0), value(arg_list[0])) &&
+                     std::not_equal_to<T>()(T(0), value(arg_list[1]))
                    ) ? T(1) : T(0);
          }
 
@@ -12634,9 +12732,9 @@ namespace exprtk
          static inline T process_3(const Sequence& arg_list)
          {
             return (
-                     std::not_equal_to<T>()(T(0),value(arg_list[0])) &&
-                     std::not_equal_to<T>()(T(0),value(arg_list[1])) &&
-                     std::not_equal_to<T>()(T(0),value(arg_list[2]))
+                     std::not_equal_to<T>()(T(0), value(arg_list[0])) &&
+                     std::not_equal_to<T>()(T(0), value(arg_list[1])) &&
+                     std::not_equal_to<T>()(T(0), value(arg_list[2]))
                    ) ? T(1) : T(0);
          }
 
@@ -12644,10 +12742,10 @@ namespace exprtk
          static inline T process_4(const Sequence& arg_list)
          {
             return (
-                     std::not_equal_to<T>()(T(0),value(arg_list[0])) &&
-                     std::not_equal_to<T>()(T(0),value(arg_list[1])) &&
-                     std::not_equal_to<T>()(T(0),value(arg_list[2])) &&
-                     std::not_equal_to<T>()(T(0),value(arg_list[3]))
+                     std::not_equal_to<T>()(T(0), value(arg_list[0])) &&
+                     std::not_equal_to<T>()(T(0), value(arg_list[1])) &&
+                     std::not_equal_to<T>()(T(0), value(arg_list[2])) &&
+                     std::not_equal_to<T>()(T(0), value(arg_list[3]))
                    ) ? T(1) : T(0);
          }
 
@@ -12655,11 +12753,11 @@ namespace exprtk
          static inline T process_5(const Sequence& arg_list)
          {
             return (
-                     std::not_equal_to<T>()(T(0),value(arg_list[0])) &&
-                     std::not_equal_to<T>()(T(0),value(arg_list[1])) &&
-                     std::not_equal_to<T>()(T(0),value(arg_list[2])) &&
-                     std::not_equal_to<T>()(T(0),value(arg_list[3])) &&
-                     std::not_equal_to<T>()(T(0),value(arg_list[4]))
+                     std::not_equal_to<T>()(T(0), value(arg_list[0])) &&
+                     std::not_equal_to<T>()(T(0), value(arg_list[1])) &&
+                     std::not_equal_to<T>()(T(0), value(arg_list[2])) &&
+                     std::not_equal_to<T>()(T(0), value(arg_list[3])) &&
+                     std::not_equal_to<T>()(T(0), value(arg_list[4]))
                    ) ? T(1) : T(0);
          }
       };
@@ -12671,7 +12769,7 @@ namespace exprtk
 
          template <typename Type,
                    typename Allocator,
-                   template <typename,typename> class Sequence>
+                   template <typename, typename> class Sequence>
          static inline T process(const Sequence<Type,Allocator>& arg_list)
          {
             switch (arg_list.size())
@@ -12685,7 +12783,7 @@ namespace exprtk
                          {
                             for (std::size_t i = 0; i < arg_list.size(); ++i)
                             {
-                               if (std::not_equal_to<T>()(T(0),value(arg_list[i])))
+                               if (std::not_equal_to<T>()(T(0), value(arg_list[i])))
                                   return T(1);
                             }
 
@@ -12698,15 +12796,15 @@ namespace exprtk
          static inline T process_1(const Sequence& arg_list)
          {
             return std::not_equal_to<T>()
-                      (T(0),value(arg_list[0])) ? T(1) : T(0);
+                      (T(0), value(arg_list[0])) ? T(1) : T(0);
          }
 
          template <typename Sequence>
          static inline T process_2(const Sequence& arg_list)
          {
             return (
-                     std::not_equal_to<T>()(T(0),value(arg_list[0])) ||
-                     std::not_equal_to<T>()(T(0),value(arg_list[1]))
+                     std::not_equal_to<T>()(T(0), value(arg_list[0])) ||
+                     std::not_equal_to<T>()(T(0), value(arg_list[1]))
                    ) ? T(1) : T(0);
          }
 
@@ -12714,9 +12812,9 @@ namespace exprtk
          static inline T process_3(const Sequence& arg_list)
          {
             return (
-                     std::not_equal_to<T>()(T(0),value(arg_list[0])) ||
-                     std::not_equal_to<T>()(T(0),value(arg_list[1])) ||
-                     std::not_equal_to<T>()(T(0),value(arg_list[2]))
+                     std::not_equal_to<T>()(T(0), value(arg_list[0])) ||
+                     std::not_equal_to<T>()(T(0), value(arg_list[1])) ||
+                     std::not_equal_to<T>()(T(0), value(arg_list[2]))
                    ) ? T(1) : T(0);
          }
 
@@ -12724,10 +12822,10 @@ namespace exprtk
          static inline T process_4(const Sequence& arg_list)
          {
             return (
-                     std::not_equal_to<T>()(T(0),value(arg_list[0])) ||
-                     std::not_equal_to<T>()(T(0),value(arg_list[1])) ||
-                     std::not_equal_to<T>()(T(0),value(arg_list[2])) ||
-                     std::not_equal_to<T>()(T(0),value(arg_list[3]))
+                     std::not_equal_to<T>()(T(0), value(arg_list[0])) ||
+                     std::not_equal_to<T>()(T(0), value(arg_list[1])) ||
+                     std::not_equal_to<T>()(T(0), value(arg_list[2])) ||
+                     std::not_equal_to<T>()(T(0), value(arg_list[3]))
                    ) ? T(1) : T(0);
          }
 
@@ -12735,11 +12833,11 @@ namespace exprtk
          static inline T process_5(const Sequence& arg_list)
          {
             return (
-                     std::not_equal_to<T>()(T(0),value(arg_list[0])) ||
-                     std::not_equal_to<T>()(T(0),value(arg_list[1])) ||
-                     std::not_equal_to<T>()(T(0),value(arg_list[2])) ||
-                     std::not_equal_to<T>()(T(0),value(arg_list[3])) ||
-                     std::not_equal_to<T>()(T(0),value(arg_list[4]))
+                     std::not_equal_to<T>()(T(0), value(arg_list[0])) ||
+                     std::not_equal_to<T>()(T(0), value(arg_list[1])) ||
+                     std::not_equal_to<T>()(T(0), value(arg_list[2])) ||
+                     std::not_equal_to<T>()(T(0), value(arg_list[3])) ||
+                     std::not_equal_to<T>()(T(0), value(arg_list[4]))
                    ) ? T(1) : T(0);
          }
       };
@@ -12751,7 +12849,7 @@ namespace exprtk
 
          template <typename Type,
                    typename Allocator,
-                   template <typename,typename> class Sequence>
+                   template <typename, typename> class Sequence>
          static inline T process(const Sequence<Type,Allocator>& arg_list)
          {
             switch (arg_list.size())
@@ -13651,15 +13749,15 @@ namespace exprtk
       template <typename T, typename T0, typename T1>                                                           \
       const typename expression_node<T>::node_type nodetype_T0oT1<T,T0_,T1_>::result = expression_node<T>:: v_; \
 
-      synthesis_node_type_define(const T0&,const T1&, e_vov)
-      synthesis_node_type_define(const T0&,const T1 , e_voc)
-      synthesis_node_type_define(const T0 ,const T1&, e_cov)
-      synthesis_node_type_define(      T0&,      T1&,e_none)
-      synthesis_node_type_define(const T0 ,const T1 ,e_none)
-      synthesis_node_type_define(      T0&,const T1 ,e_none)
-      synthesis_node_type_define(const T0 ,      T1&,e_none)
-      synthesis_node_type_define(const T0&,      T1&,e_none)
-      synthesis_node_type_define(      T0&,const T1&,e_none)
+      synthesis_node_type_define(const T0&, const T1&,  e_vov)
+      synthesis_node_type_define(const T0&, const T1 ,  e_voc)
+      synthesis_node_type_define(const T0 , const T1&,  e_cov)
+      synthesis_node_type_define(      T0&,       T1&, e_none)
+      synthesis_node_type_define(const T0 , const T1 , e_none)
+      synthesis_node_type_define(      T0&, const T1 , e_none)
+      synthesis_node_type_define(const T0 ,       T1&, e_none)
+      synthesis_node_type_define(const T0&,       T1&, e_none)
+      synthesis_node_type_define(      T0&, const T1&, e_none)
       #undef synthesis_node_type_define
 
       template <typename T, typename T0, typename T1, typename T2>
@@ -13673,15 +13771,15 @@ namespace exprtk
       template <typename T, typename T0, typename T1, typename T2>                                                     \
       const typename expression_node<T>::node_type nodetype_T0oT1oT2<T,T0_,T1_,T2_>::result = expression_node<T>:: v_; \
 
-      synthesis_node_type_define(const T0&,const T1&,const T2&, e_vovov)
-      synthesis_node_type_define(const T0&,const T1&,const T2 , e_vovoc)
-      synthesis_node_type_define(const T0&,const T1 ,const T2&, e_vocov)
-      synthesis_node_type_define(const T0 ,const T1&,const T2&, e_covov)
-      synthesis_node_type_define(const T0 ,const T1&,const T2 , e_covoc)
-      synthesis_node_type_define(const T0 ,const T1 ,const T2 , e_none )
-      synthesis_node_type_define(const T0 ,const T1 ,const T2&, e_none )
-      synthesis_node_type_define(const T0&,const T1 ,const T2 , e_none )
-      synthesis_node_type_define(      T0&,      T1&,      T2&, e_none )
+      synthesis_node_type_define(const T0&, const T1&, const T2&, e_vovov)
+      synthesis_node_type_define(const T0&, const T1&, const T2 , e_vovoc)
+      synthesis_node_type_define(const T0&, const T1 , const T2&, e_vocov)
+      synthesis_node_type_define(const T0 , const T1&, const T2&, e_covov)
+      synthesis_node_type_define(const T0 , const T1&, const T2 , e_covoc)
+      synthesis_node_type_define(const T0 , const T1 , const T2 , e_none )
+      synthesis_node_type_define(const T0 , const T1 , const T2&, e_none )
+      synthesis_node_type_define(const T0&, const T1 , const T2 , e_none )
+      synthesis_node_type_define(      T0&,       T1&,       T2&, e_none )
       #undef synthesis_node_type_define
 
       template <typename T, typename T0, typename T1, typename T2, typename T3>
@@ -13695,22 +13793,22 @@ namespace exprtk
       template <typename T, typename T0, typename T1, typename T2, typename T3>                                               \
       const typename expression_node<T>::node_type nodetype_T0oT1oT2oT3<T,T0_,T1_,T2_,T3_>::result = expression_node<T>:: v_; \
 
-      synthesis_node_type_define(const T0&,const T1&,const T2&, const T3&,e_vovovov)
-      synthesis_node_type_define(const T0&,const T1&,const T2&, const T3 ,e_vovovoc)
-      synthesis_node_type_define(const T0&,const T1&,const T2 , const T3&,e_vovocov)
-      synthesis_node_type_define(const T0&,const T1 ,const T2&, const T3&,e_vocovov)
-      synthesis_node_type_define(const T0 ,const T1&,const T2&, const T3&,e_covovov)
-      synthesis_node_type_define(const T0 ,const T1&,const T2 , const T3&,e_covocov)
-      synthesis_node_type_define(const T0&,const T1 ,const T2&, const T3 ,e_vocovoc)
-      synthesis_node_type_define(const T0 ,const T1&,const T2&, const T3 ,e_covovoc)
-      synthesis_node_type_define(const T0&,const T1 ,const T2 , const T3&,e_vococov)
-      synthesis_node_type_define(const T0 ,const T1 ,const T2 , const T3 ,e_none   )
-      synthesis_node_type_define(const T0 ,const T1 ,const T2 , const T3&,e_none   )
-      synthesis_node_type_define(const T0 ,const T1 ,const T2&, const T3 ,e_none   )
-      synthesis_node_type_define(const T0 ,const T1&,const T2 , const T3 ,e_none   )
-      synthesis_node_type_define(const T0&,const T1 ,const T2 , const T3 ,e_none   )
-      synthesis_node_type_define(const T0 ,const T1 ,const T2&, const T3&,e_none   )
-      synthesis_node_type_define(const T0&,const T1&,const T2 , const T3 ,e_none   )
+      synthesis_node_type_define(const T0&, const T1&, const T2&, const T3&, e_vovovov)
+      synthesis_node_type_define(const T0&, const T1&, const T2&, const T3 , e_vovovoc)
+      synthesis_node_type_define(const T0&, const T1&, const T2 , const T3&, e_vovocov)
+      synthesis_node_type_define(const T0&, const T1 , const T2&, const T3&, e_vocovov)
+      synthesis_node_type_define(const T0 , const T1&, const T2&, const T3&, e_covovov)
+      synthesis_node_type_define(const T0 , const T1&, const T2 , const T3&, e_covocov)
+      synthesis_node_type_define(const T0&, const T1 , const T2&, const T3 , e_vocovoc)
+      synthesis_node_type_define(const T0 , const T1&, const T2&, const T3 , e_covovoc)
+      synthesis_node_type_define(const T0&, const T1 , const T2 , const T3&, e_vococov)
+      synthesis_node_type_define(const T0 , const T1 , const T2 , const T3 , e_none   )
+      synthesis_node_type_define(const T0 , const T1 , const T2 , const T3&, e_none   )
+      synthesis_node_type_define(const T0 , const T1 , const T2&, const T3 , e_none   )
+      synthesis_node_type_define(const T0 , const T1&, const T2 , const T3 , e_none   )
+      synthesis_node_type_define(const T0&, const T1 , const T2 , const T3 , e_none   )
+      synthesis_node_type_define(const T0 , const T1 , const T2&, const T3&, e_none   )
+      synthesis_node_type_define(const T0&, const T1&, const T2 , const T3 , e_none   )
       #undef synthesis_node_type_define
 
       template <typename T, typename T0, typename T1>
@@ -13766,7 +13864,7 @@ namespace exprtk
                                                     bfunc_t p2)
          {
             return allocator
-                     .template allocate_type<node_type,T0,T1,bfunc_t&>
+                     .template allocate_type<node_type, T0, T1, bfunc_t&>
                         (p0, p1, p2);
          }
 
@@ -13812,7 +13910,7 @@ namespace exprtk
 
          inline T value() const
          {
-            return ProcessMode::process(t0_,t1_,t2_,f0_,f1_);
+            return ProcessMode::process(t0_, t1_, t2_, f0_, f1_);
          }
 
          inline T0 t0() const
@@ -13854,7 +13952,7 @@ namespace exprtk
          static inline expression_node<T>* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2, bfunc_t p3, bfunc_t p4)
          {
             return allocator
-                      .template allocate_type<node_type,T0,T1,T2,bfunc_t,bfunc_t>
+                      .template allocate_type<node_type, T0, T1, T2, bfunc_t, bfunc_t>
                          (p0, p1, p2, p3, p4);
          }
 
@@ -13942,7 +14040,7 @@ namespace exprtk
 
          static inline std::string id()
          {
-            return process_mode_t::template id<T0,T1,T2,T3>();
+            return process_mode_t::template id<T0, T1, T2, T3>();
          }
 
          template <typename Allocator>
@@ -13951,7 +14049,7 @@ namespace exprtk
                                                     bfunc_t p4, bfunc_t p5, bfunc_t p6)
          {
             return allocator
-                      .template allocate_type<node_type,T0,T1,T2,T3,bfunc_t,bfunc_t>
+                      .template allocate_type<node_type, T0, T1, T2, T3, bfunc_t, bfunc_t>
                          (p0, p1, p2, p3, p4, p5, p6);
          }
 
@@ -14036,7 +14134,7 @@ namespace exprtk
          static inline expression_node<T>* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2, tfunc_t p3)
          {
             return allocator
-                     .template allocate_type<node_type,T0,T1,T2,tfunc_t>
+                     .template allocate_type<node_type, T0, T1, T2, tfunc_t>
                         (p0, p1, p2, p3);
          }
 
@@ -14127,7 +14225,7 @@ namespace exprtk
          static inline expression_node<T>* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2)
          {
             return allocator
-                     .template allocate_type<node_type,T0,T1,T2>
+                     .template allocate_type<node_type, T0, T1, T2>
                         (p0, p1, p2);
          }
 
@@ -14228,7 +14326,7 @@ namespace exprtk
          static inline expression_node<T>* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2, T3 p3, qfunc_t p4)
          {
             return allocator
-                     .template allocate_type<node_type,T0,T1,T2,T3,qfunc_t>
+                     .template allocate_type<node_type, T0, T1, T2, T3, qfunc_t>
                         (p0, p1, p2, p3, p4);
          }
 
@@ -14311,7 +14409,7 @@ namespace exprtk
          static inline expression_node<T>* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2, T3 p3)
          {
             return allocator
-                     .template allocate_type<node_type,T0,T1,T2,T3>
+                     .template allocate_type<node_type, T0, T1, T2, T3>
                         (p0, p1, p2, p3);
          }
 
@@ -14347,27 +14445,27 @@ namespace exprtk
       template <typename T, typename T0, typename T1>
       struct T0oT1_define
       {
-         typedef details::T0oT1<T,T0,T1> type0;
+         typedef details::T0oT1<T, T0, T1> type0;
       };
 
       template <typename T, typename T0, typename T1, typename T2>
       struct T0oT1oT2_define
       {
-         typedef details::T0oT1oT2<T,T0,T1,T2,typename T0oT1oT2process<T>::mode0> type0;
-         typedef details::T0oT1oT2<T,T0,T1,T2,typename T0oT1oT2process<T>::mode1> type1;
-         typedef details::T0oT1oT2_sf3<T,T0,T1,T2> sf3_type;
-         typedef details::sf3ext_type_node<T,T0,T1,T2> sf3_type_node;
+         typedef details::T0oT1oT2<T, T0, T1, T2, typename T0oT1oT2process<T>::mode0> type0;
+         typedef details::T0oT1oT2<T, T0, T1, T2, typename T0oT1oT2process<T>::mode1> type1;
+         typedef details::T0oT1oT2_sf3<T, T0, T1, T2> sf3_type;
+         typedef details::sf3ext_type_node<T, T0, T1, T2> sf3_type_node;
       };
 
       template <typename T, typename T0, typename T1, typename T2, typename T3>
       struct T0oT1oT2oT3_define
       {
-         typedef details::T0oT1oT2oT3<T,T0,T1,T2,T3,typename T0oT1oT20T3process<T>::mode0> type0;
-         typedef details::T0oT1oT2oT3<T,T0,T1,T2,T3,typename T0oT1oT20T3process<T>::mode1> type1;
-         typedef details::T0oT1oT2oT3<T,T0,T1,T2,T3,typename T0oT1oT20T3process<T>::mode2> type2;
-         typedef details::T0oT1oT2oT3<T,T0,T1,T2,T3,typename T0oT1oT20T3process<T>::mode3> type3;
-         typedef details::T0oT1oT2oT3<T,T0,T1,T2,T3,typename T0oT1oT20T3process<T>::mode4> type4;
-         typedef details::T0oT1oT2oT3_sf4<T,T0,T1,T2,T3> sf4_type;
+         typedef details::T0oT1oT2oT3<T, T0, T1, T2, T3, typename T0oT1oT20T3process<T>::mode0> type0;
+         typedef details::T0oT1oT2oT3<T, T0, T1, T2, T3, typename T0oT1oT20T3process<T>::mode1> type1;
+         typedef details::T0oT1oT2oT3<T, T0, T1, T2, T3, typename T0oT1oT20T3process<T>::mode2> type2;
+         typedef details::T0oT1oT2oT3<T, T0, T1, T2, T3, typename T0oT1oT20T3process<T>::mode3> type3;
+         typedef details::T0oT1oT2oT3<T, T0, T1, T2, T3, typename T0oT1oT20T3process<T>::mode4> type4;
+         typedef details::T0oT1oT2oT3_sf4<T, T0, T1, T2, T3> sf4_type;
       };
 
       template <typename T, typename Operation>
@@ -15437,37 +15535,37 @@ namespace exprtk
          template <typename ResultNode, typename OpType, typename ExprNode>
          inline expression_node<typename ResultNode::value_type>* allocate(OpType& operation, ExprNode (&branch)[1])
          {
-            return allocate<ResultNode>(operation,branch[0]);
+            return allocate<ResultNode>(operation, branch[0]);
          }
 
          template <typename ResultNode, typename OpType, typename ExprNode>
          inline expression_node<typename ResultNode::value_type>* allocate(OpType& operation, ExprNode (&branch)[2])
          {
-            return allocate<ResultNode>(operation,branch[0],branch[1]);
+            return allocate<ResultNode>(operation, branch[0], branch[1]);
          }
 
          template <typename ResultNode, typename OpType, typename ExprNode>
          inline expression_node<typename ResultNode::value_type>* allocate(OpType& operation, ExprNode (&branch)[3])
          {
-            return allocate<ResultNode>(operation,branch[0],branch[1],branch[2]);
+            return allocate<ResultNode>(operation, branch[0], branch[1], branch[2]);
          }
 
          template <typename ResultNode, typename OpType, typename ExprNode>
          inline expression_node<typename ResultNode::value_type>* allocate(OpType& operation, ExprNode (&branch)[4])
          {
-            return allocate<ResultNode>(operation,branch[0],branch[1],branch[2],branch[3]);
+            return allocate<ResultNode>(operation, branch[0], branch[1], branch[2], branch[3]);
          }
 
          template <typename ResultNode, typename OpType, typename ExprNode>
          inline expression_node<typename ResultNode::value_type>* allocate(OpType& operation, ExprNode (&branch)[5])
          {
-            return allocate<ResultNode>(operation,branch[0],branch[1],branch[2],branch[3],branch[4]);
+            return allocate<ResultNode>(operation, branch[0],branch[1], branch[2], branch[3], branch[4]);
          }
 
          template <typename ResultNode, typename OpType, typename ExprNode>
          inline expression_node<typename ResultNode::value_type>* allocate(OpType& operation, ExprNode (&branch)[6])
          {
-            return allocate<ResultNode>(operation,branch[0],branch[1],branch[2],branch[3],branch[4],branch[5]);
+            return allocate<ResultNode>(operation, branch[0], branch[1], branch[2], branch[3], branch[4], branch[5]);
          }
 
          template <typename node_type>
@@ -15479,7 +15577,7 @@ namespace exprtk
          template <typename node_type,
                    typename Type,
                    typename Allocator,
-                   template <typename,typename> class Sequence>
+                   template <typename, typename> class Sequence>
          inline expression_node<typename node_type::value_type>* allocate(const Sequence<Type,Allocator>& seq) const
          {
             return (new node_type(seq));
@@ -15978,8 +16076,9 @@ namespace exprtk
 
       enum return_type
       {
-         e_rtrn_scalar = 0,
-         e_rtrn_string = 1
+         e_rtrn_scalar   = 0,
+         e_rtrn_string   = 1,
+         e_rtrn_overload = 2
       };
 
       typedef T type;
@@ -16030,20 +16129,20 @@ namespace exprtk
 
       typedef T (*ff00_functor)();
       typedef T (*ff01_functor)(T);
-      typedef T (*ff02_functor)(T,T);
-      typedef T (*ff03_functor)(T,T,T);
-      typedef T (*ff04_functor)(T,T,T,T);
-      typedef T (*ff05_functor)(T,T,T,T,T);
-      typedef T (*ff06_functor)(T,T,T,T,T,T);
-      typedef T (*ff07_functor)(T,T,T,T,T,T,T);
-      typedef T (*ff08_functor)(T,T,T,T,T,T,T,T);
-      typedef T (*ff09_functor)(T,T,T,T,T,T,T,T,T);
-      typedef T (*ff10_functor)(T,T,T,T,T,T,T,T,T,T);
-      typedef T (*ff11_functor)(T,T,T,T,T,T,T,T,T,T,T);
-      typedef T (*ff12_functor)(T,T,T,T,T,T,T,T,T,T,T,T);
-      typedef T (*ff13_functor)(T,T,T,T,T,T,T,T,T,T,T,T,T);
-      typedef T (*ff14_functor)(T,T,T,T,T,T,T,T,T,T,T,T,T,T);
-      typedef T (*ff15_functor)(T,T,T,T,T,T,T,T,T,T,T,T,T,T,T);
+      typedef T (*ff02_functor)(T, T);
+      typedef T (*ff03_functor)(T, T, T);
+      typedef T (*ff04_functor)(T, T, T, T);
+      typedef T (*ff05_functor)(T, T, T, T, T);
+      typedef T (*ff06_functor)(T, T, T, T, T, T);
+      typedef T (*ff07_functor)(T, T, T, T, T, T, T);
+      typedef T (*ff08_functor)(T, T, T, T, T, T, T, T);
+      typedef T (*ff09_functor)(T, T, T, T, T, T, T, T, T);
+      typedef T (*ff10_functor)(T, T, T, T, T, T, T, T, T, T);
+      typedef T (*ff11_functor)(T, T, T, T, T, T, T, T, T, T, T);
+      typedef T (*ff12_functor)(T, T, T, T, T, T, T, T, T, T, T, T);
+      typedef T (*ff13_functor)(T, T, T, T, T, T, T, T, T, T, T, T, T);
+      typedef T (*ff14_functor)(T, T, T, T, T, T, T, T, T, T, T, T, T, T);
+      typedef T (*ff15_functor)(T, T, T, T, T, T, T, T, T, T, T, T, T, T, T);
 
    protected:
 
@@ -16631,11 +16730,12 @@ namespace exprtk
             #ifndef exprtk_disable_string_capabilities
             type_store<typename details::stringvar_node<T>,std::string> stringvar_store;
             #endif
-            type_store<ifunction<T>,ifunction<T> > function_store;
+            type_store<ifunction<T>,ifunction<T> >                 function_store;
             type_store<ivararg_function <T>,ivararg_function <T> > vararg_function_store;
             type_store<igeneric_function<T>,igeneric_function<T> > generic_function_store;
             type_store<igeneric_function<T>,igeneric_function<T> > string_function_store;
-            type_store<vector_holder_t,vector_holder_t> vector_store;
+            type_store<igeneric_function<T>,igeneric_function<T> > overload_function_store;
+            type_store<vector_holder_t,vector_holder_t>            vector_store;
 
             st_data()
             {
@@ -16759,7 +16859,7 @@ namespace exprtk
          return (*this);
       }
 
-      inline bool operator==(const symbol_table<T>& st)
+      inline bool operator==(const symbol_table<T>& st) const
       {
          return (this == &st) || (control_block_ == st.control_block_);
       }
@@ -16906,6 +17006,16 @@ namespace exprtk
             return local_data().string_function_store.get(function_name);
       }
 
+      inline generic_function_ptr get_overload_function(const std::string& function_name) const
+      {
+         if (!valid())
+            return reinterpret_cast<generic_function_ptr>(0);
+         else if (!valid_symbol(function_name))
+            return reinterpret_cast<generic_function_ptr>(0);
+         else
+            return local_data().overload_function_store.get(function_name);
+      }
+
       typedef vector_holder_t* vector_holder_ptr;
 
       inline vector_holder_ptr get_vector(const std::string& vector_name) const
@@ -17071,14 +17181,33 @@ namespace exprtk
             return false;
          else if (symbol_exists(function_name))
             return false;
-         else if (std::string::npos != function.parameter_sequence.find_first_not_of("STVZ*?|"))
+         else if (
+                   (
+                     (generic_function_t::e_rtrn_scalar == function.rtrn_type) ||
+                     (generic_function_t::e_rtrn_string == function.rtrn_type)
+                   ) &&
+                   std::string::npos != function.parameter_sequence.find_first_not_of("STVZ*?|")
+                 )
             return false;
-         else if (generic_function_t::e_rtrn_scalar == function.rtrn_type)
-            return local_data().generic_function_store.add(function_name,function);
-         else if (generic_function_t::e_rtrn_string == function.rtrn_type)
-            return local_data().string_function_store.add(function_name, function);
-         else
+         else if (
+                   (generic_function_t::e_rtrn_overload  == function.rtrn_type) &&
+                   std::string::npos != function.parameter_sequence.find_first_not_of("STVZ*?|:")
+                 )
             return false;
+
+         switch (function.rtrn_type)
+         {
+            case generic_function_t::e_rtrn_scalar :
+               return local_data().generic_function_store.add(function_name,function);
+
+            case generic_function_t::e_rtrn_string :
+               return local_data().string_function_store.add(function_name,function);
+
+            case generic_function_t::e_rtrn_overload :
+               return local_data().overload_function_store.add(function_name,function);
+         }
+
+         return false;
       }
 
       #define exprtk_define_freefunction(NN)                                                \
@@ -17141,14 +17270,33 @@ namespace exprtk
             return false;
          else if (symbol_exists(function_name,false))
             return false;
-         else if (std::string::npos != function.parameter_sequence.find_first_not_of("STV*?|"))
+         else if (
+                   (
+                     (generic_function_t::e_rtrn_scalar == function.rtrn_type) ||
+                     (generic_function_t::e_rtrn_string == function.rtrn_type)
+                   ) &&
+                   std::string::npos != function.parameter_sequence.find_first_not_of("STV*?|")
+                 )
             return false;
-         else if (generic_function_t::e_rtrn_scalar == function.rtrn_type)
-            return local_data().generic_function_store.add(function_name,function);
-         else if (generic_function_t::e_rtrn_string == function.rtrn_type)
-            return local_data().string_function_store.add(function_name, function);
-         else
+         else if (
+                   generic_function_t::e_rtrn_overload &&
+                   std::string::npos != function.parameter_sequence.find_first_not_of("STV*?|:")
+                 )
             return false;
+
+         switch (function.rtrn_type)
+         {
+            case generic_function_t::e_rtrn_scalar :
+               return local_data().generic_function_store.add(function_name,function);
+
+            case generic_function_t::e_rtrn_string :
+               return local_data().string_function_store.add(function_name,function);
+
+            case generic_function_t::e_rtrn_overload :
+               return local_data().overload_function_store.add(function_name,function);
+         }
+
+         return false;
       }
 
       template <std::size_t N>
@@ -17337,8 +17485,8 @@ namespace exprtk
       {
          /*
             Function will return true if symbol_name exists as either a
-            reserved symbol, variable, stringvar or function name in any
-            of the type stores.
+            reserved symbol, variable, stringvar, vector or function name
+            in any of the type stores.
          */
          if (!valid())
             return false;
@@ -17348,6 +17496,8 @@ namespace exprtk
          else if (local_data().stringvar_store.symbol_exists(symbol_name))
             return true;
          #endif
+         else if (local_data().vector_store.symbol_exists(symbol_name))
+            return true;
          else if (local_data().function_store.symbol_exists(symbol_name))
             return true;
          else if (check_reserved_symb && local_data().is_reserved_symbol(symbol_name))
@@ -17502,6 +17652,21 @@ namespace exprtk
                }
             }
          }
+
+         {
+            std::vector<std::string> name_list;
+
+            st.local_data().overload_function_store.get_list(name_list);
+
+            if (!name_list.empty())
+            {
+               for (std::size_t i = 0; i < name_list.size(); ++i)
+               {
+                  exprtk::igeneric_function<T>& ifunc = *st.get_overload_function(name_list[i]);
+                  add_function(name_list[i],ifunc);
+               }
+            }
+         }
       }
 
    private:
@@ -17754,7 +17919,7 @@ namespace exprtk
          return *this;
       }
 
-      inline bool operator==(const expression<T>& e)
+      inline bool operator==(const expression<T>& e) const
       {
          return (this == &e);
       }
@@ -17903,7 +18068,7 @@ namespace exprtk
                control_block_->
                   local_data_list.push_back(
                      typename expression<T>::control_block::
-                        data_pack(reinterpret_cast<void*>(data),dt,size));
+                        data_pack(reinterpret_cast<void*>(data), dt, size));
             }
          }
       }
@@ -18454,6 +18619,10 @@ namespace exprtk
 
          inline void free_element(scope_element& se)
          {
+            #ifdef exprtk_enable_debugging
+            exprtk_debug(("free_element() - se[%s]\n", se.name.c_str()));
+            #endif
+
             switch (se.type)
             {
                case scope_element::e_variable   : if (se.data    ) delete (T*) se.data;
@@ -18541,7 +18710,7 @@ namespace exprtk
          {
             parser_.state_.scope_depth++;
             #ifdef exprtk_enable_debugging
-            std::string depth(2 * parser_.state_.scope_depth,'-');
+            const std::string depth(2 * parser_.state_.scope_depth,'-');
             exprtk_debug(("%s> Scope Depth: %02d\n",
                           depth.c_str(),
                           static_cast<int>(parser_.state_.scope_depth)));
@@ -18553,7 +18722,7 @@ namespace exprtk
             parser_.sem_.deactivate(parser_.state_.scope_depth);
             parser_.state_.scope_depth--;
             #ifdef exprtk_enable_debugging
-            std::string depth(2 * parser_.state_.scope_depth,'-');
+            const std::string depth(2 * parser_.state_.scope_depth,'-');
             exprtk_debug(("<%s Scope Depth: %02d\n",
                           depth.c_str(),
                           static_cast<int>(parser_.state_.scope_depth)));
@@ -18767,6 +18936,27 @@ namespace exprtk
             return result;
          }
 
+         inline generic_function_ptr get_overload_function(const std::string& function_name) const
+         {
+            if (!valid_function_name(function_name))
+               return reinterpret_cast<generic_function_ptr>(0);
+
+            generic_function_ptr result = reinterpret_cast<generic_function_ptr>(0);
+
+            for (std::size_t i = 0; i < symtab_list_.size(); ++i)
+            {
+               if (!symtab_list_[i].valid())
+                  continue;
+               else
+                  result =
+                     local_data(i).overload_function_store.get(function_name);
+
+               if (result) break;
+            }
+
+            return result;
+         }
+
          inline vector_holder_ptr get_vector(const std::string& vector_name) const
          {
             if (!valid_symbol(vector_name))
@@ -19025,8 +19215,9 @@ namespace exprtk
 
          enum usr_symbol_type
          {
-            e_usr_variable_type = 0,
-            e_usr_constant_type = 1
+            e_usr_unknown_type  = 0,
+            e_usr_variable_type = 1,
+            e_usr_constant_type = 2
          };
 
          enum usr_mode
@@ -19105,7 +19296,7 @@ namespace exprtk
          {}
 
          template <typename Allocator,
-                   template <typename,typename> class Sequence>
+                   template <typename, typename> class Sequence>
          inline std::size_t symbols(Sequence<symbol_t,Allocator>& symbols_list)
          {
             if (!collect_variables_ && !collect_functions_)
@@ -19128,7 +19319,7 @@ namespace exprtk
          }
 
          template <typename Allocator,
-                   template <typename,typename> class Sequence>
+                   template <typename, typename> class Sequence>
          inline std::size_t assignment_symbols(Sequence<symbol_t,Allocator>& assignment_list)
          {
             if (!collect_assignments_)
@@ -19461,7 +19652,7 @@ namespace exprtk
          bool rsrvd_sym_usr_disabled     () const { return disable_rsrvd_sym_usr_;     }
          bool zero_return_disabled       () const { return disable_zero_return_;       }
 
-         bool function_enabled(const std::string& function_name)
+         bool function_enabled(const std::string& function_name) const
          {
             if (disabled_func_set_.empty())
                return true;
@@ -19469,7 +19660,7 @@ namespace exprtk
                return (disabled_func_set_.end() == disabled_func_set_.find(function_name));
          }
 
-         bool control_struct_enabled(const std::string& control_struct)
+         bool control_struct_enabled(const std::string& control_struct) const
          {
             if (disabled_ctrl_set_.empty())
                return true;
@@ -19477,7 +19668,7 @@ namespace exprtk
                return (disabled_ctrl_set_.end() == disabled_ctrl_set_.find(control_struct));
          }
 
-         bool logic_enabled(const std::string& logic_operation)
+         bool logic_enabled(const std::string& logic_operation) const
          {
             if (disabled_logic_set_.empty())
                return true;
@@ -19485,7 +19676,7 @@ namespace exprtk
                return (disabled_logic_set_.end() == disabled_logic_set_.find(logic_operation));
          }
 
-         bool arithmetic_enabled(const details::operator_type& arithmetic_operation)
+         bool arithmetic_enabled(const details::operator_type& arithmetic_operation) const
          {
             if (disabled_logic_set_.empty())
                return true;
@@ -19494,7 +19685,7 @@ namespace exprtk
                                                             .find(arith_opr_to_string(arithmetic_operation));
          }
 
-         bool assignment_enabled(const details::operator_type& assignment)
+         bool assignment_enabled(const details::operator_type& assignment) const
          {
             if (disabled_assignment_set_.empty())
                return true;
@@ -19503,7 +19694,7 @@ namespace exprtk
                                                            .find(assign_opr_to_string(assignment));
          }
 
-         bool inequality_enabled(const details::operator_type& inequality)
+         bool inequality_enabled(const details::operator_type& inequality) const
          {
             if (disabled_inequality_set_.empty())
                return true;
@@ -19512,7 +19703,7 @@ namespace exprtk
                                                            .find(inequality_opr_to_string(inequality));
          }
 
-         bool function_disabled(const std::string& function_name)
+         bool function_disabled(const std::string& function_name) const
          {
             if (disabled_func_set_.empty())
                return false;
@@ -19520,7 +19711,7 @@ namespace exprtk
                return (disabled_func_set_.end() != disabled_func_set_.find(function_name));
          }
 
-         bool control_struct_disabled(const std::string& control_struct)
+         bool control_struct_disabled(const std::string& control_struct) const
          {
             if (disabled_ctrl_set_.empty())
                return false;
@@ -19528,7 +19719,7 @@ namespace exprtk
                return (disabled_ctrl_set_.end() != disabled_ctrl_set_.find(control_struct));
          }
 
-         bool logic_disabled(const std::string& logic_operation)
+         bool logic_disabled(const std::string& logic_operation) const
          {
             if (disabled_logic_set_.empty())
                return false;
@@ -19536,7 +19727,7 @@ namespace exprtk
                return (disabled_logic_set_.end() != disabled_logic_set_.find(logic_operation));
          }
 
-         bool assignment_disabled(const details::operator_type assignment_operation)
+         bool assignment_disabled(const details::operator_type assignment_operation) const
          {
             if (disabled_assignment_set_.empty())
                return false;
@@ -19545,7 +19736,7 @@ namespace exprtk
                                                            .find(assign_opr_to_string(assignment_operation));
          }
 
-         bool arithmetic_disabled(const details::operator_type arithmetic_operation)
+         bool arithmetic_disabled(const details::operator_type arithmetic_operation) const
          {
             if (disabled_arithmetic_set_.empty())
                return false;
@@ -19554,7 +19745,7 @@ namespace exprtk
                                                            .find(arith_opr_to_string(arithmetic_operation));
          }
 
-         bool inequality_disabled(const details::operator_type& inequality)
+         bool inequality_disabled(const details::operator_type& inequality) const
          {
             if (disabled_inequality_set_.empty())
                return false;
@@ -19768,7 +19959,7 @@ namespace exprtk
             disable_zero_return_       = (compile_options & e_disable_zero_return ) == e_disable_zero_return;
          }
 
-         std::string assign_opr_to_string(details::operator_type opr)
+         std::string assign_opr_to_string(details::operator_type opr) const
          {
             switch (opr)
             {
@@ -19782,7 +19973,7 @@ namespace exprtk
             }
          }
 
-         std::string arith_opr_to_string(details::operator_type opr)
+         std::string arith_opr_to_string(details::operator_type opr) const
          {
             switch (opr)
             {
@@ -19795,7 +19986,7 @@ namespace exprtk
             }
          }
 
-         std::string inequality_opr_to_string(details::operator_type opr)
+         std::string inequality_opr_to_string(details::operator_type opr) const
          {
             switch (opr)
             {
@@ -19933,7 +20124,8 @@ namespace exprtk
 
             if (settings_.sequence_check_enabled())
             {
-               helper_assembly_.register_scanner(&sequence_validator_);
+               helper_assembly_.register_scanner(&sequence_validator_      );
+               helper_assembly_.register_scanner(&sequence_validator_3tkns_);
             }
          }
       }
@@ -20021,15 +20213,15 @@ namespace exprtk
                              exprtk_error_location));
             }
 
-            dec_.clear    ();
-            sem_.cleanup  ();
-            return_cleanup();
-
             if ((0 != e) && branch_deletable(e))
             {
                destroy_node(e);
             }
 
+            dec_.clear    ();
+            sem_.cleanup  ();
+            return_cleanup();
+
             return false;
          }
       }
@@ -20109,9 +20301,10 @@ namespace exprtk
             {
                if (helper_assembly_.error_token_scanner)
                {
-                  lexer::helper::bracket_checker*    bracket_checker_ptr    = 0;
-                  lexer::helper::numeric_checker*    numeric_checker_ptr    = 0;
-                  lexer::helper::sequence_validator* sequence_validator_ptr = 0;
+                  lexer::helper::bracket_checker*            bracket_checker_ptr     = 0;
+                  lexer::helper::numeric_checker*            numeric_checker_ptr     = 0;
+                  lexer::helper::sequence_validator*         sequence_validator_ptr  = 0;
+                  lexer::helper::sequence_validator_3tokens* sequence_validator3_ptr = 0;
 
                   if (0 != (bracket_checker_ptr = dynamic_cast<lexer::helper::bracket_checker*>(helper_assembly_.error_token_scanner)))
                   {
@@ -20159,6 +20352,26 @@ namespace exprtk
                         sequence_validator_ptr->clear_errors();
                      }
                   }
+                  else if (0 != (sequence_validator3_ptr = dynamic_cast<lexer::helper::sequence_validator_3tokens*>(helper_assembly_.error_token_scanner)))
+                  {
+                     for (std::size_t i = 0; i < sequence_validator3_ptr->error_count(); ++i)
+                     {
+                        std::pair<lexer::token,lexer::token> error_token = sequence_validator3_ptr->error(i);
+
+                        set_error(
+                           make_error(parser_error::e_token,
+                                      error_token.first,
+                                      "ERR007 - Invalid token sequence: '" +
+                                      error_token.first.value  + "' and '" +
+                                      error_token.second.value + "'",
+                                      exprtk_error_location));
+                     }
+
+                     if (sequence_validator3_ptr->error_count())
+                     {
+                        sequence_validator3_ptr->clear_errors();
+                     }
+                  }
                }
 
                return false;
@@ -20173,7 +20386,7 @@ namespace exprtk
          return settings_;
       }
 
-      inline parser_error::type get_error(const std::size_t& index)
+      inline parser_error::type get_error(const std::size_t& index) const
       {
          if (index < error_list_.size())
             return error_list_[index];
@@ -20244,7 +20457,7 @@ namespace exprtk
 
    private:
 
-      inline bool valid_base_operation(const std::string& symbol)
+      inline bool valid_base_operation(const std::string& symbol) const
       {
          const std::size_t length = symbol.size();
 
@@ -20258,7 +20471,7 @@ namespace exprtk
                    (base_ops_map_.end() != base_ops_map_.find(symbol));
       }
 
-      inline bool valid_vararg_operation(const std::string& symbol)
+      inline bool valid_vararg_operation(const std::string& symbol) const
       {
          static const std::string s_sum     = "sum" ;
          static const std::string s_mul     = "mul" ;
@@ -20285,17 +20498,17 @@ namespace exprtk
                settings_.function_enabled(symbol);
       }
 
-      bool is_invalid_arithmetic_operation(const details::operator_type operation)
+      bool is_invalid_arithmetic_operation(const details::operator_type operation) const
       {
          return settings_.arithmetic_disabled(operation);
       }
 
-      bool is_invalid_assignment_operation(const details::operator_type operation)
+      bool is_invalid_assignment_operation(const details::operator_type operation) const
       {
          return settings_.assignment_disabled(operation);
       }
 
-      bool is_invalid_inequality_operation(const details::operator_type operation)
+      bool is_invalid_inequality_operation(const details::operator_type operation) const
       {
          return settings_.inequality_disabled(operation);
       }
@@ -20303,9 +20516,9 @@ namespace exprtk
       #ifdef exprtk_enable_debugging
       inline void next_token()
       {
-         std::string ct_str = current_token().value;
+         const std::string ct_str = current_token().value;
          parser_helper::next_token();
-         std::string depth(2 * state_.scope_depth,' ');
+         const std::string depth(2 * state_.scope_depth,' ');
          exprtk_debug(("%s"
                        "prev[%s] --> curr[%s]\n",
                        depth.c_str(),
@@ -20341,7 +20554,7 @@ namespace exprtk
                   set_error(
                      make_error(parser_error::e_syntax,
                                 current_token(),
-                                "ERR007 - Invalid expression encountered",
+                                "ERR008 - Invalid expression encountered",
                                 exprtk_error_location));
                }
 
@@ -20355,7 +20568,7 @@ namespace exprtk
 
                end_token = current_token();
 
-               std::string sub_expr = construct_subexpr(begin_token,end_token);
+               const std::string sub_expr = construct_subexpr(begin_token, end_token);
 
                exprtk_debug(("parse_corpus(%02d) Subexpr: %s\n",
                              static_cast<int>(arg_list.size() - 1),
@@ -20564,7 +20777,7 @@ namespace exprtk
             else if (current_state.left < precedence)
                break;
 
-            lexer::token prev_token = current_token();
+            const lexer::token prev_token = current_token();
 
             next_token();
 
@@ -20578,7 +20791,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              prev_token,
-                             "ERR008 - Invalid arithmetic operation '" + details::to_str(current_state.operation) + "'",
+                             "ERR009 - Invalid arithmetic operation '" + details::to_str(current_state.operation) + "'",
                              exprtk_error_location));
 
                return error_node();
@@ -20590,7 +20803,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              prev_token,
-                             "ERR009 - Invalid inequality operation '" + details::to_str(current_state.operation) + "'",
+                             "ERR010 - Invalid inequality operation '" + details::to_str(current_state.operation) + "'",
                              exprtk_error_location));
 
                return error_node();
@@ -20602,7 +20815,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              prev_token,
-                             "ERR010 - Invalid assignment operation '" + details::to_str(current_state.operation) + "'",
+                             "ERR011 - Invalid assignment operation '" + details::to_str(current_state.operation) + "'",
                              exprtk_error_location));
 
                return error_node();
@@ -20615,13 +20828,13 @@ namespace exprtk
                     details::is_return_node(right_branch)
                   )
                {
-                  free_node(node_allocator_,  expression);
-                  free_node(node_allocator_,right_branch);
+                  free_node(node_allocator_,   expression);
+                  free_node(node_allocator_, right_branch);
 
                   set_error(
                      make_error(parser_error::e_syntax,
                                 prev_token,
-                                "ERR011 - Return statements cannot be part of sub-expressions",
+                                "ERR012 - Return statements cannot be part of sub-expressions",
                                 exprtk_error_location));
 
                   return error_node();
@@ -20644,11 +20857,12 @@ namespace exprtk
                                 prev_token,
                                 !synthesis_error_.empty() ?
                                 synthesis_error_ :
-                                "ERR012 - General parsing error at token: '" + prev_token.value + "'",
+                                "ERR013 - General parsing error at token: '" + prev_token.value + "'",
                                 exprtk_error_location));
                }
 
-               free_node(node_allocator_,expression);
+               free_node(node_allocator_,   expression);
+               free_node(node_allocator_, right_branch);
 
                return error_node();
             }
@@ -20713,7 +20927,7 @@ namespace exprtk
                   set_error(
                      make_error(parser_error::e_syntax,
                                 current_token(),
-                                "ERR013 - Failed to find variable node in symbol table",
+                                "ERR014 - Failed to find variable node in symbol table",
                                 exprtk_error_location));
 
                   free_node(node_allocator_,node);
@@ -20893,7 +21107,7 @@ namespace exprtk
                          set_error(
                             make_error(parser_error::e_syntax,
                                        current_token(),
-                                       "ERR014 - Invalid number of parameters for function: '" + function_name + "'",
+                                       "ERR015 - Invalid number of parameters for function: '" + function_name + "'",
                                        exprtk_error_location));
 
                          return error_node();
@@ -20907,7 +21121,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR015 - Failed to generate call to function: '" + function_name + "'",
+                          "ERR016 - Failed to generate call to function: '" + function_name + "'",
                           exprtk_error_location));
 
             return error_node();
@@ -20926,7 +21140,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR016 - Expecting ifunction '" + function_name + "' to have non-zero parameter count",
+                          "ERR017 - Expecting ifunction '" + function_name + "' to have non-zero parameter count",
                           exprtk_error_location));
 
             return error_node();
@@ -20949,7 +21163,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR017 - Expecting argument list for function: '" + function_name + "'",
+                          "ERR018 - Expecting argument list for function: '" + function_name + "'",
                           exprtk_error_location));
 
             return error_node();
@@ -20964,7 +21178,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR018 - Failed to parse argument " + details::to_str(i) + " for function: '" + function_name + "'",
+                             "ERR019 - Failed to parse argument " + details::to_str(i) + " for function: '" + function_name + "'",
                              exprtk_error_location));
 
                return error_node();
@@ -20976,7 +21190,7 @@ namespace exprtk
                   set_error(
                      make_error(parser_error::e_syntax,
                                 current_token(),
-                                "ERR019 - Invalid number of arguments for function: '" + function_name + "'",
+                                "ERR020 - Invalid number of arguments for function: '" + function_name + "'",
                                 exprtk_error_location));
 
                   return error_node();
@@ -20989,7 +21203,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR020 - Invalid number of arguments for function: '" + function_name + "'",
+                          "ERR021 - Invalid number of arguments for function: '" + function_name + "'",
                           exprtk_error_location));
 
             return error_node();
@@ -21018,7 +21232,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR021 - Expecting '()' to proceed call to function: '" + function_name + "'",
+                          "ERR022 - Expecting '()' to proceed call to function: '" + function_name + "'",
                           exprtk_error_location));
 
             free_node(node_allocator_,result);
@@ -21043,7 +21257,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR022 - Expected a '(' at start of function call to '" + function_name  +
+                          "ERR023 - Expected a '(' at start of function call to '" + function_name  +
                           "', instead got: '" + current_token().value + "'",
                           exprtk_error_location));
 
@@ -21055,7 +21269,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR023 - Expected at least one input parameter for function call '" + function_name + "'",
+                          "ERR024 - Expected at least one input parameter for function call '" + function_name + "'",
                           exprtk_error_location));
 
             return 0;
@@ -21081,7 +21295,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR024 - Expected a ',' between function input parameters, instead got: '" + current_token().value + "'",
+                             "ERR025 - Expected a ',' between function input parameters, instead got: '" + current_token().value + "'",
                              exprtk_error_location));
 
                return 0;
@@ -21093,7 +21307,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR025 - Invalid number of input parameters passed to function '" + function_name  + "'",
+                          "ERR026 - Invalid number of input parameters passed to function '" + function_name  + "'",
                           exprtk_error_location));
 
             return 0;
@@ -21116,7 +21330,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           diagnostic_token,
-                          "ERR026 - No entry found for base operation: " + operation_name,
+                          "ERR027 - No entry found for base operation: " + operation_name,
                           exprtk_error_location));
 
             return error_node();
@@ -21131,7 +21345,7 @@ namespace exprtk
          {
             for (base_ops_map_t::iterator itr = itr_range.first; itr != itr_range.second; ++itr)
             {
-               details::base_operation_t& operation = itr->second;
+               const details::base_operation_t& operation = itr->second;
 
                if (operation.num_params == parameter_count)
                {
@@ -21163,7 +21377,7 @@ namespace exprtk
          set_error(
             make_error(parser_error::e_syntax,
                        diagnostic_token,
-                       "ERR027 - Invalid number of input parameters for call to function: '" + operation_name + "'",
+                       "ERR028 - Invalid number of input parameters for call to function: '" + operation_name + "'",
                        exprtk_error_location));
 
          return error_node();
@@ -21183,7 +21397,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR028 - Expected ',' between if-statement condition and consequent",
+                          "ERR029 - Expected ',' between if-statement condition and consequent",
                           exprtk_error_location));
             result = false;
          }
@@ -21192,7 +21406,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR029 - Failed to parse consequent for if-statement",
+                          "ERR030 - Failed to parse consequent for if-statement",
                           exprtk_error_location));
             result = false;
          }
@@ -21201,7 +21415,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR030 - Expected ',' between if-statement consequent and alternative",
+                          "ERR031 - Expected ',' between if-statement consequent and alternative",
                           exprtk_error_location));
             result = false;
          }
@@ -21210,7 +21424,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR031 - Failed to parse alternative for if-statement",
+                          "ERR032 - Failed to parse alternative for if-statement",
                           exprtk_error_location));
             result = false;
          }
@@ -21219,7 +21433,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR032 - Expected ')' at the end of if-statement",
+                          "ERR033 - Expected ')' at the end of if-statement",
                           exprtk_error_location));
             result = false;
          }
@@ -21241,7 +21455,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR033 - Return types of ternary if-statement differ",
+                             "ERR034 - Return types of ternary if-statement differ",
                              exprtk_error_location));
 
                result = false;
@@ -21276,7 +21490,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR034 - Failed to parse body of consequent for if-statement",
+                             "ERR035 - Failed to parse body of consequent for if-statement",
                              exprtk_error_location));
 
                result = false;
@@ -21299,7 +21513,7 @@ namespace exprtk
                   set_error(
                      make_error(parser_error::e_syntax,
                                 current_token(),
-                                "ERR035 - Expected ';' at the end of the consequent for if-statement",
+                                "ERR036 - Expected ';' at the end of the consequent for if-statement",
                                 exprtk_error_location));
 
                   result = false;
@@ -21310,7 +21524,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR036 - Failed to parse body of consequent for if-statement",
+                             "ERR037 - Failed to parse body of consequent for if-statement",
                              exprtk_error_location));
 
                result = false;
@@ -21330,7 +21544,7 @@ namespace exprtk
                      set_error(
                         make_error(parser_error::e_syntax,
                                    current_token(),
-                                   "ERR037 - Failed to parse body of the 'else' for if-statement",
+                                   "ERR038 - Failed to parse body of the 'else' for if-statement",
                                    exprtk_error_location));
 
                      result = false;
@@ -21343,7 +21557,7 @@ namespace exprtk
                      set_error(
                         make_error(parser_error::e_syntax,
                                    current_token(),
-                                   "ERR038 - Failed to parse body of if-else statement",
+                                   "ERR039 - Failed to parse body of if-else statement",
                                    exprtk_error_location));
 
                      result = false;
@@ -21356,7 +21570,7 @@ namespace exprtk
                      set_error(
                         make_error(parser_error::e_syntax,
                                    current_token(),
-                                   "ERR039 - Expected ';' at the end of the 'else-if' for the if-statement",
+                                   "ERR040 - Expected ';' at the end of the 'else-if' for the if-statement",
                                    exprtk_error_location));
 
                      result = false;
@@ -21367,7 +21581,7 @@ namespace exprtk
                   set_error(
                      make_error(parser_error::e_syntax,
                                 current_token(),
-                                "ERR040 - Failed to parse body of the 'else' for if-statement",
+                                "ERR041 - Failed to parse body of the 'else' for if-statement",
                                 exprtk_error_location));
 
                   result = false;
@@ -21392,7 +21606,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR041 - Return types of ternary if-statement differ",
+                             "ERR042 - Return types of ternary if-statement differ",
                              exprtk_error_location));
 
                result = false;
@@ -21424,7 +21638,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR042 - Expected '(' at start of if-statement, instead got: '" + current_token().value + "'",
+                          "ERR043 - Expected '(' at start of if-statement, instead got: '" + current_token().value + "'",
                           exprtk_error_location));
 
             return error_node();
@@ -21434,7 +21648,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR043 - Failed to parse condition for if-statement",
+                          "ERR044 - Failed to parse condition for if-statement",
                           exprtk_error_location));
 
             return error_node();
@@ -21466,7 +21680,7 @@ namespace exprtk
          set_error(
             make_error(parser_error::e_syntax,
                        current_token(),
-                       "ERR044 - Invalid if-statement",
+                       "ERR045 - Invalid if-statement",
                        exprtk_error_location));
 
          free_node(node_allocator_,condition);
@@ -21487,7 +21701,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR045 - Encountered invalid condition branch for ternary if-statement",
+                          "ERR046 - Encountered invalid condition branch for ternary if-statement",
                           exprtk_error_location));
 
             return error_node();
@@ -21497,7 +21711,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR046 - Expected '?' after condition of ternary if-statement",
+                          "ERR047 - Expected '?' after condition of ternary if-statement",
                           exprtk_error_location));
 
             result = false;
@@ -21507,7 +21721,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR047 - Failed to parse consequent for ternary if-statement",
+                          "ERR048 - Failed to parse consequent for ternary if-statement",
                           exprtk_error_location));
 
             result = false;
@@ -21517,7 +21731,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR048 - Expected ':' between ternary if-statement consequent and alternative",
+                          "ERR049 - Expected ':' between ternary if-statement consequent and alternative",
                           exprtk_error_location));
 
             result = false;
@@ -21527,7 +21741,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR049 - Failed to parse alternative for ternary if-statement",
+                          "ERR050 - Failed to parse alternative for ternary if-statement",
                           exprtk_error_location));
 
             result = false;
@@ -21550,7 +21764,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR050 - Return types of ternary if-statement differ",
+                             "ERR051 - Return types of ternary if-statement differ",
                              exprtk_error_location));
 
                result = false;
@@ -21587,7 +21801,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR051 - Expected '(' at start of while-loop condition statement",
+                          "ERR052 - Expected '(' at start of while-loop condition statement",
                           exprtk_error_location));
 
             return error_node();
@@ -21597,7 +21811,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR052 - Failed to parse condition for while-loop",
+                          "ERR053 - Failed to parse condition for while-loop",
                           exprtk_error_location));
 
             return error_node();
@@ -21607,7 +21821,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR053 - Expected ')' at end of while-loop condition statement",
+                          "ERR054 - Expected ')' at end of while-loop condition statement",
                           exprtk_error_location));
 
             result = false;
@@ -21622,7 +21836,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR054 - Failed to parse body of while-loop"));
+                             "ERR055 - Failed to parse body of while-loop"));
                result = false;
             }
             else if (0 == (result_node = expression_generator_.while_loop(condition,
@@ -21632,7 +21846,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR055 - Failed to synthesize while-loop",
+                             "ERR056 - Failed to synthesize while-loop",
                              exprtk_error_location));
 
                result = false;
@@ -21674,7 +21888,7 @@ namespace exprtk
          }
          else
          {
-            token_t::token_type seperator = token_t::e_eof;
+            const token_t::token_type seperator = token_t::e_eof;
 
             scope_handler sh(*this);
 
@@ -21700,15 +21914,15 @@ namespace exprtk
                   break;
                }
 
-               bool is_next_until = peek_token_is(token_t::e_symbol) &&
-                                    peek_token_is("until");
+               const bool is_next_until = peek_token_is(token_t::e_symbol) &&
+                                          peek_token_is("until");
 
                if (!token_is(seperator) && is_next_until)
                {
                   set_error(
                      make_error(parser_error::e_syntax,
                                 current_token(),
-                                "ERR056 - Expected '" + token_t::to_str(seperator) + "' in body of repeat until loop",
+                                "ERR057 - Expected '" + token_t::to_str(seperator) + "' in body of repeat until loop",
                                 exprtk_error_location));
 
                   return error_node();
@@ -21732,7 +21946,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR057 - Failed to parse body of repeat until loop",
+                             "ERR058 - Failed to parse body of repeat until loop",
                              exprtk_error_location));
 
                return error_node();
@@ -21746,7 +21960,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR058 - Expected '(' before condition statement of repeat until loop",
+                          "ERR059 - Expected '(' before condition statement of repeat until loop",
                           exprtk_error_location));
 
             free_node(node_allocator_,branch);
@@ -21760,7 +21974,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR059 - Failed to parse condition for repeat until loop",
+                          "ERR060 - Failed to parse condition for repeat until loop",
                           exprtk_error_location));
 
             free_node(node_allocator_,branch);
@@ -21772,7 +21986,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR060 - Expected ')' after condition of repeat until loop",
+                          "ERR061 - Expected ')' after condition of repeat until loop",
                           exprtk_error_location));
 
             free_node(node_allocator_,    branch);
@@ -21793,7 +22007,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR061 - Failed to synthesize repeat until loop",
+                          "ERR062 - Failed to synthesize repeat until loop",
                           exprtk_error_location));
 
             free_node(node_allocator_,condition);
@@ -21818,7 +22032,6 @@ namespace exprtk
 
          scope_element* se = 0;
          bool result       = true;
-         std::string loop_counter_symbol;
 
          next_token();
 
@@ -21829,7 +22042,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR062 - Expected '(' at start of for-loop",
+                          "ERR063 - Expected '(' at start of for-loop",
                           exprtk_error_location));
 
             return error_node();
@@ -21849,7 +22062,7 @@ namespace exprtk
                   set_error(
                      make_error(parser_error::e_syntax,
                                 current_token(),
-                                "ERR063 - Expected a variable at the start of initialiser section of for-loop",
+                                "ERR064 - Expected a variable at the start of initialiser section of for-loop",
                                 exprtk_error_location));
 
                   return error_node();
@@ -21859,13 +22072,13 @@ namespace exprtk
                   set_error(
                      make_error(parser_error::e_syntax,
                                 current_token(),
-                                "ERR064 - Expected variable assignment of initialiser section of for-loop",
+                                "ERR065 - Expected variable assignment of initialiser section of for-loop",
                                 exprtk_error_location));
 
                   return error_node();
                }
 
-               loop_counter_symbol = current_token().value;
+               const std::string loop_counter_symbol = current_token().value;
 
                se = &sem_.get_element(loop_counter_symbol);
 
@@ -21874,7 +22087,7 @@ namespace exprtk
                   set_error(
                      make_error(parser_error::e_syntax,
                                 current_token(),
-                                "ERR065 - For-loop variable '" + loop_counter_symbol+ "' is being shadowed by a previous declaration",
+                                "ERR066 - For-loop variable '" + loop_counter_symbol+ "' is being shadowed by a previous declaration",
                                 exprtk_error_location));
 
                   return error_node();
@@ -21906,7 +22119,7 @@ namespace exprtk
                         set_error(
                            make_error(parser_error::e_syntax,
                                       current_token(),
-                                      "ERR066 - Failed to add new local variable '" + loop_counter_symbol + "' to SEM",
+                                      "ERR067 - Failed to add new local variable '" + loop_counter_symbol + "' to SEM",
                                       exprtk_error_location));
 
                         sem_.free_element(nse);
@@ -21928,7 +22141,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR067 - Failed to parse initialiser of for-loop",
+                             "ERR068 - Failed to parse initialiser of for-loop",
                              exprtk_error_location));
 
                result = false;
@@ -21938,7 +22151,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR068 - Expected ';' after initialiser of for-loop",
+                             "ERR069 - Expected ';' after initialiser of for-loop",
                              exprtk_error_location));
 
                result = false;
@@ -21952,7 +22165,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR069 - Failed to parse condition of for-loop",
+                             "ERR070 - Failed to parse condition of for-loop",
                              exprtk_error_location));
 
                result = false;
@@ -21962,7 +22175,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR070 - Expected ';' after condition section of for-loop",
+                             "ERR071 - Expected ';' after condition section of for-loop",
                              exprtk_error_location));
 
                result = false;
@@ -21976,7 +22189,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR071 - Failed to parse incrementor of for-loop",
+                             "ERR072 - Failed to parse incrementor of for-loop",
                              exprtk_error_location));
 
                result = false;
@@ -21986,7 +22199,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR072 - Expected ')' after incrementor section of for-loop",
+                             "ERR073 - Expected ')' after incrementor section of for-loop",
                              exprtk_error_location));
 
                result = false;
@@ -22002,7 +22215,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR073 - Failed to parse body of for-loop",
+                             "ERR074 - Failed to parse body of for-loop",
                              exprtk_error_location));
 
                result = false;
@@ -22016,8 +22229,6 @@ namespace exprtk
                se->ref_count--;
             }
 
-            sem_.cleanup();
-
             free_node(node_allocator_, initialiser);
             free_node(node_allocator_,   condition);
             free_node(node_allocator_, incrementor);
@@ -22054,7 +22265,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR074 - Expected keyword 'switch'",
+                          "ERR075 - Expected keyword 'switch'",
                           exprtk_error_location));
 
             return error_node();
@@ -22069,7 +22280,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR075 - Expected '{' for call to switch statement",
+                          "ERR076 - Expected '{' for call to switch statement",
                           exprtk_error_location));
 
             return error_node();
@@ -22082,7 +22293,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR076 - Expected either a 'case' or 'default' statement",
+                             "ERR077 - Expected either a 'case' or 'default' statement",
                              exprtk_error_location));
 
                return error_node();
@@ -22099,7 +22310,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR077 - Expected ':' for case of switch statement",
+                             "ERR078 - Expected ':' for case of switch statement",
                              exprtk_error_location));
 
                return error_node();
@@ -22114,7 +22325,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR078 - Expected ';' at end of case for switch statement",
+                             "ERR079 - Expected ';' at end of case for switch statement",
                              exprtk_error_location));
 
                return error_node();
@@ -22140,7 +22351,7 @@ namespace exprtk
                   set_error(
                      make_error(parser_error::e_syntax,
                                 current_token(),
-                                "ERR079 - Expected ':' for default of switch statement",
+                                "ERR080 - Expected ':' for default of switch statement",
                                 exprtk_error_location));
 
                   return error_node();
@@ -22162,7 +22373,7 @@ namespace exprtk
                   set_error(
                      make_error(parser_error::e_syntax,
                                 current_token(),
-                                "ERR080 - Expected ';' at end of default for switch statement",
+                                "ERR081 - Expected ';' at end of default for switch statement",
                                 exprtk_error_location));
 
                   return error_node();
@@ -22178,7 +22389,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR081 - Expected '}' at end of switch statement",
+                          "ERR082 - Expected '}' at end of switch statement",
                           exprtk_error_location));
 
             return error_node();
@@ -22201,7 +22412,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR082 - Expected token '[*]'",
+                          "ERR083 - Expected token '[*]'",
                           exprtk_error_location));
 
             return error_node();
@@ -22216,7 +22427,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR083 - Expected '{' for call to [*] statement",
+                          "ERR084 - Expected '{' for call to [*] statement",
                           exprtk_error_location));
 
             return error_node();
@@ -22229,7 +22440,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR084 - Expected a 'case' statement for multi-switch",
+                             "ERR085 - Expected a 'case' statement for multi-switch",
                              exprtk_error_location));
 
                return error_node();
@@ -22247,7 +22458,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR085 - Expected ':' for case of [*] statement",
+                             "ERR086 - Expected ':' for case of [*] statement",
                              exprtk_error_location));
 
                return error_node();
@@ -22263,7 +22474,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR086 - Expected ';' at end of case for [*] statement",
+                             "ERR087 - Expected ';' at end of case for [*] statement",
                              exprtk_error_location));
 
                return error_node();
@@ -22277,7 +22488,7 @@ namespace exprtk
             }
             else
             {
-               arg_list.push_back(condition);
+               arg_list.push_back( condition);
                arg_list.push_back(consequent);
             }
 
@@ -22292,7 +22503,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR087 - Expected '}' at end of [*] statement",
+                          "ERR088 - Expected '}' at end of [*] statement",
                           exprtk_error_location));
 
             return error_node();
@@ -22334,7 +22545,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR088 - Unsupported vararg function: " + symbol,
+                          "ERR089 - Unsupported vararg function: " + symbol,
                           exprtk_error_location));
 
             return error_node();
@@ -22342,7 +22553,7 @@ namespace exprtk
 
          scoped_vec_delete<expression_node_t> sdd((*this),arg_list);
 
-         lodge_symbol(symbol,e_st_function);
+         lodge_symbol(symbol, e_st_function);
 
          next_token();
 
@@ -22351,7 +22562,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR089 - Expected '(' for call to vararg function: " + symbol,
+                          "ERR090 - Expected '(' for call to vararg function: " + symbol,
                           exprtk_error_location));
 
             return error_node();
@@ -22373,7 +22584,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR090 - Expected ',' for call to vararg function: " + symbol,
+                             "ERR091 - Expected ',' for call to vararg function: " + symbol,
                              exprtk_error_location));
 
                return error_node();
@@ -22394,7 +22605,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR091 - Expected '[' as start of string range definition",
+                          "ERR092 - Expected '[' as start of string range definition",
                           exprtk_error_location));
 
             free_node(node_allocator_,expression);
@@ -22422,7 +22633,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR092 - Failed to generate string range node",
+                          "ERR093 - Failed to generate string range node",
                           exprtk_error_location));
 
             free_node(node_allocator_,expression);
@@ -22461,7 +22672,7 @@ namespace exprtk
 
       template <typename Allocator1,
                 typename Allocator2,
-                template <typename,typename> class Sequence>
+                template <typename, typename> class Sequence>
       inline expression_node_ptr simplify(Sequence<expression_node_ptr,Allocator1>& expression_list,
                                           Sequence<bool,Allocator2>& side_effect_list,
                                           const bool specialise_on_final_type = false)
@@ -22558,7 +22769,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR093 - Expected '" + token_t::to_str(close_bracket) + "' for call to multi-sequence" +
+                             "ERR094 - Expected '" + token_t::to_str(close_bracket) + "' for call to multi-sequence" +
                              ((!source.empty()) ? std::string(" section of " + source): ""),
                              exprtk_error_location));
 
@@ -22605,7 +22816,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR094 - Expected '" + details::to_str(seperator) + "' for call to multi-sequence section of " + source,
+                             "ERR095 - Expected '" + details::to_str(seperator) + "' for call to multi-sequence section of " + source,
                              exprtk_error_location));
 
                return error_node();
@@ -22639,7 +22850,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR095 - Expected '[' for start of range",
+                          "ERR096 - Expected '[' for start of range",
                           exprtk_error_location));
 
             return false;
@@ -22660,11 +22871,10 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR096 - Failed parse begin section of range",
+                             "ERR097 - Failed parse begin section of range",
                              exprtk_error_location));
 
                return false;
-
             }
             else if (is_constant_node(r0))
             {
@@ -22684,7 +22894,7 @@ namespace exprtk
                   set_error(
                      make_error(parser_error::e_syntax,
                                 current_token(),
-                                "ERR097 - Range lower bound less than zero! Constraint: r0 >= 0",
+                                "ERR098 - Range lower bound less than zero! Constraint: r0 >= 0",
                                 exprtk_error_location));
 
                   return false;
@@ -22701,7 +22911,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR098 - Expected ':' for break  in range",
+                             "ERR099 - Expected ':' for break  in range",
                              exprtk_error_location));
 
                rp.free();
@@ -22724,13 +22934,12 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR099 - Failed parse end section of range",
+                             "ERR100 - Failed parse end section of range",
                              exprtk_error_location));
 
                rp.free();
 
                return false;
-
             }
             else if (is_constant_node(r1))
             {
@@ -22750,7 +22959,7 @@ namespace exprtk
                   set_error(
                      make_error(parser_error::e_syntax,
                                 current_token(),
-                                "ERR100 - Range upper bound less than zero! Constraint: r1 >= 0",
+                                "ERR101 - Range upper bound less than zero! Constraint: r1 >= 0",
                                 exprtk_error_location));
 
                   return false;
@@ -22767,7 +22976,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR101 - Expected ']' for start of range",
+                             "ERR102 - Expected ']' for start of range",
                              exprtk_error_location));
 
                rp.free();
@@ -22788,7 +22997,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR102 - Invalid range, Constraint: r0 <= r1",
+                             "ERR103 - Invalid range, Constraint: r0 <= r1",
                              exprtk_error_location));
 
                return false;
@@ -22820,7 +23029,7 @@ namespace exprtk
          {
             se.active = true;
             result    = se.str_node;
-            lodge_symbol(symbol,e_st_local_string);
+            lodge_symbol(symbol, e_st_local_string);
          }
          else
          {
@@ -22829,7 +23038,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR103 - Unknown string symbol",
+                             "ERR104 - Unknown string symbol",
                              exprtk_error_location));
 
                return error_node();
@@ -22843,7 +23052,7 @@ namespace exprtk
                result = expression_generator_(const_str_node->str());
             }
 
-            lodge_symbol(symbol,e_st_string);
+            lodge_symbol(symbol, e_st_string);
          }
 
          if (peek_token_is(token_t::e_lsqrbracket))
@@ -22943,7 +23152,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR104 - Overflow in range for string: '" + const_str + "'[" +
+                             "ERR105 - Overflow in range for string: '" + const_str + "'[" +
                              (rp.n0_c.first ? details::to_str(static_cast<int>(rp.n0_c.second)) : "?") + ":" +
                              (rp.n1_c.first ? details::to_str(static_cast<int>(rp.n1_c.second)) : "?") + "]",
                              exprtk_error_location));
@@ -22987,7 +23196,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR105 - Symbol '" + symbol+ " not a vector",
+                             "ERR106 - Symbol '" + symbol+ " not a vector",
                              exprtk_error_location));
 
                return error_node();
@@ -23013,7 +23222,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR106 - Failed to parse index for vector: '" + symbol + "'",
+                          "ERR107 - Failed to parse index for vector: '" + symbol + "'",
                           exprtk_error_location));
 
             return error_node();
@@ -23023,7 +23232,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR107 - Expected ']' for index of vector: '" + symbol + "'",
+                          "ERR108 - Expected ']' for index of vector: '" + symbol + "'",
                           exprtk_error_location));
 
             free_node(node_allocator_,index_expr);
@@ -23042,7 +23251,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR108 - Index of " + details::to_str(index) + " out of range for "
+                             "ERR109 - Index of " + details::to_str(index) + " out of range for "
                              "vector '" + symbol + "' of size " + details::to_str(vec_size),
                              exprtk_error_location));
 
@@ -23074,7 +23283,7 @@ namespace exprtk
                   set_error(
                      make_error(parser_error::e_syntax,
                                 current_token(),
-                                "ERR109 - Zero parameter call to vararg function: "
+                                "ERR110 - Zero parameter call to vararg function: "
                                 + vararg_function_name + " not allowed",
                                 exprtk_error_location));
 
@@ -23099,7 +23308,7 @@ namespace exprtk
                      set_error(
                         make_error(parser_error::e_syntax,
                                    current_token(),
-                                   "ERR110 - Expected ',' for call to vararg function: "
+                                   "ERR111 - Expected ',' for call to vararg function: "
                                    + vararg_function_name,
                                    exprtk_error_location));
 
@@ -23113,7 +23322,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR111 - Zero parameter call to vararg function: "
+                          "ERR112 - Zero parameter call to vararg function: "
                           + vararg_function_name + " not allowed",
                           exprtk_error_location));
 
@@ -23125,7 +23334,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR112 - Invalid number of parameters to call to vararg function: "
+                          "ERR113 - Invalid number of parameters to call to vararg function: "
                           + vararg_function_name + ", require at least "
                           + details::to_str(static_cast<int>(vararg_function->min_num_args())) + " parameters",
                           exprtk_error_location));
@@ -23137,7 +23346,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR113 - Invalid number of parameters to call to vararg function: "
+                          "ERR114 - Invalid number of parameters to call to vararg function: "
                           + vararg_function_name + ", require no more than "
                           + details::to_str(static_cast<int>(vararg_function->max_num_args())) + " parameters",
                           exprtk_error_location));
@@ -23156,34 +23365,54 @@ namespace exprtk
       {
       public:
 
+         enum return_type_t
+         {
+            e_overload = ' ',
+            e_numeric  = 'T',
+            e_string   = 'S'
+         };
+
+         struct function_prototype_t
+         {
+             return_type_t return_type;
+             std::string   param_seq;
+         };
+
          typedef parser<T> parser_t;
-         typedef std::vector<std::string> param_seq_list_t;
+         typedef std::vector<function_prototype_t> function_definition_list_t;
 
          type_checker(parser_t& p,
                       const std::string& func_name,
-                      const std::string& param_seq)
+                      const std::string& func_prototypes,
+                      const return_type_t default_return_type)
          : invalid_state_(true),
            parser_(p),
-           function_name_(func_name)
+           function_name_(func_name),
+           default_return_type_(default_return_type)
+         {
+            parse_function_prototypes(func_prototypes);
+         }
+
+         void set_default_return_type(const std::string& return_type)
          {
-            split(param_seq);
+            default_return_type_ = return_type;
          }
 
          bool verify(const std::string& param_seq, std::size_t& pseq_index)
          {
-            if (param_seq_list_.empty())
+            if (function_definition_list_.empty())
                return true;
 
             std::vector<std::pair<std::size_t,char> > error_list;
 
-            for (std::size_t i = 0; i < param_seq_list_.size(); ++i)
+            for (std::size_t i = 0; i < function_definition_list_.size(); ++i)
             {
                details::char_t diff_value = 0;
                std::size_t     diff_index = 0;
 
-               bool result = details::sequence_match(param_seq_list_[i],
-                                                     param_seq,
-                                                     diff_index,diff_value);
+               const bool result = details::sequence_match(function_definition_list_[i].param_seq,
+                                                           param_seq,
+                                                           diff_index, diff_value);
 
               if (result)
               {
@@ -23191,7 +23420,7 @@ namespace exprtk
                  return true;
               }
               else
-                 error_list.push_back(std::make_pair(diff_index,diff_value));
+                 error_list.push_back(std::make_pair(diff_index, diff_value));
             }
 
             if (1 == error_list.size())
@@ -23200,8 +23429,9 @@ namespace exprtk
                   set_error(
                      make_error(parser_error::e_syntax,
                                 parser_.current_token(),
-                                "ERR114 - Failed parameter type check for function '" + function_name_ + "', "
-                                "Expected '" + param_seq_list_[0] + "'  call set: '" + param_seq +"'",
+                                "ERR115 - Failed parameter type check for function '" + function_name_ + "', "
+                                "Expected '" + function_definition_list_[0].param_seq +
+                                "'  call set: '" + param_seq + "'",
                                 exprtk_error_location));
             }
             else
@@ -23221,8 +23451,9 @@ namespace exprtk
                   set_error(
                      make_error(parser_error::e_syntax,
                                 parser_.current_token(),
-                                "ERR115 - Failed parameter type check for function '" + function_name_ + "', "
-                                "Best match: '" + param_seq_list_[max_diff_index] + "'  call set: '" + param_seq +"'",
+                                "ERR116 - Failed parameter type check for function '" + function_name_ + "', "
+                                "Best match: '" + function_definition_list_[max_diff_index].param_seq +
+                                "'  call set: '" + param_seq + "'",
                                 exprtk_error_location));
             }
 
@@ -23231,12 +23462,17 @@ namespace exprtk
 
          std::size_t paramseq_count() const
          {
-            return param_seq_list_.size();
+            return function_definition_list_.size();
          }
 
          std::string paramseq(const std::size_t& index) const
          {
-            return param_seq_list_[index];
+            return function_definition_list_[index].param_seq;
+         }
+
+         return_type_t return_type(const std::size_t& index) const
+         {
+            return function_definition_list_[index].return_type;
          }
 
          bool invalid() const
@@ -23246,93 +23482,143 @@ namespace exprtk
 
          bool allow_zero_parameters() const
          {
-            return
-               param_seq_list_.end() != std::find(param_seq_list_.begin(),
-                                                  param_seq_list_.end(),
-                                                  "Z");
+
+            for (std::size_t i = 0; i < function_definition_list_.size(); ++i)
+            {
+               if (std::string::npos != function_definition_list_[i].param_seq.find("Z"))
+               {
+                  return true;
+               }
+            }
+
+            return false;
          }
 
       private:
 
-         void split(const std::string& s)
+         std::vector<std::string> split_param_seq(const std::string& param_seq, const details::char_t delimiter = '|') const
          {
-            if (s.empty())
-               return;
+             std::string::const_iterator current_begin = param_seq.begin();
+             std::string::const_iterator iter          = param_seq.begin();
+
+             std::vector<std::string> result;
 
-            std::size_t start = 0;
-            std::size_t end   = 0;
+             while (iter != param_seq.end())
+             {
+                 if (*iter == delimiter)
+                 {
+                     result.push_back(std::string(current_begin, iter));
+                     ++iter;
+                     current_begin = iter;
+                 }
+                 else
+                     ++iter;
+             }
 
-            param_seq_list_t param_seq_list;
+             if (current_begin != iter)
+             {
+                 result.push_back(std::string(current_begin, iter));
+             }
+
+             return result;
+         }
+
+         inline bool is_valid_token(std::string param_seq,
+                                    function_prototype_t& funcproto) const
+         {
+            // Determine return type
+            funcproto.return_type = default_return_type_;
 
-            struct token_validator
+            if (param_seq.size() > 2)
             {
-               static inline bool process(const std::string& str,
-                                          std::size_t s, std::size_t e,
-                                          param_seq_list_t& psl)
+               if (':' == param_seq[1])
                {
-                  if (
-                       (e - s) &&
-                       (std::string::npos == str.find("?*")) &&
-                       (std::string::npos == str.find("**"))
-                     )
+                  // Note: Only overloaded igeneric functions can have return
+                  // type definitions.
+                  if (type_checker::e_overload != default_return_type_)
+                     return false;
+
+                  switch (param_seq[0])
                   {
-                     const std::string curr_str = str.substr(s, e - s);
+                     case 'T' : funcproto.return_type = type_checker::e_numeric;
+                                break;
 
-                     if ("Z" == curr_str)
-                     {
-                        psl.push_back(curr_str);
-                        return true;
-                     }
-                     else if (std::string::npos == curr_str.find_first_not_of("STV*?|"))
-                     {
-                        psl.push_back(curr_str);
-                        return true;
-                     }
+                     case 'S' : funcproto.return_type = type_checker::e_string;
+                                break;
+
+                     default  : return false;
                   }
 
-                  return false;
+                  param_seq.erase(0,2);
                }
-            };
+            }
 
-            while (std::string::npos != (end = s.find('|',start)))
+            if (
+                 (std::string::npos != param_seq.find("?*")) ||
+                 (std::string::npos != param_seq.find("**"))
+               )
             {
-               if (!token_validator::process(s, start, end, param_seq_list))
+               return false;
+            }
+            else if (
+                      (std::string::npos == param_seq.find_first_not_of("STV*?|")) ||
+                      ("Z" == param_seq)
+                    )
+            {
+               funcproto.param_seq = param_seq;
+               return true;
+            }
+
+            return false;
+         }
+
+         void parse_function_prototypes(const std::string& func_prototypes)
+         {
+            if (func_prototypes.empty())
+               return;
+
+            std::vector<std::string> param_seq_list = split_param_seq(func_prototypes);
+
+            typedef std::map<std::string,std::size_t> param_seq_map_t;
+            param_seq_map_t param_seq_map;
+
+            for (std::size_t i = 0; i < param_seq_list.size(); ++i)
+            {
+               function_prototype_t func_proto;
+
+               if (!is_valid_token(param_seq_list[i], func_proto))
                {
                   invalid_state_ = false;
 
-                  const std::string err_param_seq = s.substr(start, end - start);
-
                   parser_.
                      set_error(
                         make_error(parser_error::e_syntax,
                                    parser_.current_token(),
-                                   "ERR116 - Invalid parameter sequence of '" + err_param_seq +
-                                   "'  for function: " + function_name_,
+                                   "ERR117 - Invalid parameter sequence of '" + param_seq_list[i] +
+                                   "' for function: " + function_name_,
                                    exprtk_error_location));
-
                   return;
                }
-               else
-                  start = end + 1;
-            }
 
-            if (start < s.size())
-            {
-               if (token_validator::process(s, start, s.size(), param_seq_list))
-                  param_seq_list_ = param_seq_list;
-               else
+               param_seq_map_t::const_iterator seq_itr = param_seq_map.find(param_seq_list[i]);
+
+               if (param_seq_map.end() != seq_itr)
                {
-                  const std::string err_param_seq = s.substr(start, s.size() - start);
+                  invalid_state_ = false;
 
                   parser_.
                      set_error(
                         make_error(parser_error::e_syntax,
                                    parser_.current_token(),
-                                   "ERR117 - Invalid parameter sequence of '" + err_param_seq +
-                                   "'  for function: " + function_name_,
+                                   "ERR118 - Function '" + function_name_ + "' has a parameter sequence conflict between " +
+                                   "pseq_idx[" + details::to_str(seq_itr->second) + "] and" +
+                                   "pseq_idx[" + details::to_str(i) + "] " +
+                                   "param seq: " + param_seq_list[i],
                                    exprtk_error_location));
                   return;
                }
+
+               function_definition_list_.push_back(func_proto);
             }
          }
 
@@ -23342,7 +23628,8 @@ namespace exprtk
          bool invalid_state_;
          parser_t& parser_;
          std::string function_name_;
-         param_seq_list_t param_seq_list_;
+         const return_type_t default_return_type_;
+         function_definition_list_t function_definition_list_;
       };
 
       inline expression_node_ptr parse_generic_function_call(igeneric_function<T>* function, const std::string& function_name)
@@ -23355,30 +23642,14 @@ namespace exprtk
 
          std::string param_type_list;
 
-         type_checker tc((*this), function_name, function->parameter_sequence);
+         type_checker tc((*this), function_name, function->parameter_sequence, type_checker::e_string);
 
          if (tc.invalid())
          {
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR118 - Type checker instantiation failure for generic function: " + function_name,
-                          exprtk_error_location));
-
-            return error_node();
-         }
-
-         if (
-              !function->parameter_sequence.empty() &&
-              function->allow_zero_parameters    () &&
-              !tc      .allow_zero_parameters    ()
-            )
-         {
-            set_error(
-               make_error(parser_error::e_syntax,
-                          current_token(),
-                          "ERR119 - Mismatch in zero parameter condition for generic function: "
-                          + function_name,
+                          "ERR119 - Type checker instantiation failure for generic function: " + function_name,
                           exprtk_error_location));
 
             return error_node();
@@ -23462,7 +23733,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR123 - Expected ',' for call to generic function: " + function_name,
+                          "ERR123 - Invalid input parameter sequence for call to generic function: " + function_name,
                           exprtk_error_location));
 
             return error_node();
@@ -23482,37 +23753,39 @@ namespace exprtk
          return result;
       }
 
-      #ifndef exprtk_disable_string_capabilities
-      inline expression_node_ptr parse_string_function_call(igeneric_function<T>* function, const std::string& function_name)
+      inline bool parse_igeneric_function_params(std::string& param_type_list,
+                                                 std::vector<expression_node_ptr>& arg_list,
+                                                 const std::string function_name,
+                                                 igeneric_function<T>* function,
+                                                 const type_checker& tc)
       {
-         std::vector<expression_node_ptr> arg_list;
-
-         scoped_vec_delete<expression_node_t> sdd((*this),arg_list);
-
-         next_token();
-
-         std::string param_type_list;
-
-         type_checker tc((*this), function_name, function->parameter_sequence);
-
-         if (
-              (!function->parameter_sequence.empty()) &&
-              (0 == tc.paramseq_count())
-            )
-         {
-            return error_node();
-         }
-
          if (token_is(token_t::e_lbracket))
          {
-            if (!token_is(token_t::e_rbracket))
+            if (token_is(token_t::e_rbracket))
+            {
+               if (
+                    !function->allow_zero_parameters() &&
+                    !tc       .allow_zero_parameters()
+                  )
+               {
+                  set_error(
+                     make_error(parser_error::e_syntax,
+                                current_token(),
+                                "ERR124 - Zero parameter call to generic function: "
+                                + function_name + " not allowed",
+                                exprtk_error_location));
+
+                  return false;
+               }
+            }
+            else
             {
                for ( ; ; )
                {
                   expression_node_ptr arg = parse_expression();
 
                   if (0 == arg)
-                     return error_node();
+                     return false;
 
                   if (is_ivector_node(arg))
                      param_type_list += 'V';
@@ -23530,13 +23803,44 @@ namespace exprtk
                      set_error(
                         make_error(parser_error::e_syntax,
                                    current_token(),
-                                   "ERR124 - Expected ',' for call to string function: " + function_name,
+                                   "ERR125 - Expected ',' for call to string function: " + function_name,
                                    exprtk_error_location));
 
-                     return error_node();
+                     return false;
                   }
                }
             }
+
+            return true;
+         }
+         else
+            return false;
+      }
+
+      #ifndef exprtk_disable_string_capabilities
+      inline expression_node_ptr parse_string_function_call(igeneric_function<T>* function, const std::string& function_name)
+      {
+         // Move pass the function name
+         next_token();
+
+         std::string param_type_list;
+
+         type_checker tc((*this), function_name, function->parameter_sequence, type_checker::e_string);
+
+         if (
+              (!function->parameter_sequence.empty()) &&
+              (0 == tc.paramseq_count())
+            )
+         {
+            return error_node();
+         }
+
+         std::vector<expression_node_ptr> arg_list;
+         scoped_vec_delete<expression_node_t> sdd((*this),arg_list);
+
+         if (!parse_igeneric_function_params(param_type_list, arg_list, function_name, function, tc))
+         {
+            return error_node();
          }
 
          std::size_t param_seq_index = 0;
@@ -23546,7 +23850,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR125 - Expected ',' for call to string function: " + function_name,
+                          "ERR126 - Invalid input parameter sequence for call to string function: " + function_name,
                           exprtk_error_location));
 
             return error_node();
@@ -23565,6 +23869,77 @@ namespace exprtk
 
          return result;
       }
+
+      inline expression_node_ptr parse_overload_function_call(igeneric_function<T>* function, const std::string& function_name)
+      {
+         // Move pass the function name
+         next_token();
+
+         std::string param_type_list;
+
+         type_checker tc((*this), function_name, function->parameter_sequence, type_checker::e_overload);
+
+         if (
+              (!function->parameter_sequence.empty()) &&
+              (0 == tc.paramseq_count())
+            )
+         {
+            return error_node();
+         }
+
+         std::vector<expression_node_ptr> arg_list;
+         scoped_vec_delete<expression_node_t> sdd((*this),arg_list);
+
+         if (!parse_igeneric_function_params(param_type_list, arg_list, function_name, function, tc))
+         {
+            return error_node();
+         }
+
+         std::size_t param_seq_index = 0;
+
+         if (!tc.verify(param_type_list, param_seq_index))
+         {
+            set_error(
+               make_error(parser_error::e_syntax,
+                          current_token(),
+                          "ERR127 - Invalid input parameter sequence for call to overloaded function: " + function_name,
+                          exprtk_error_location));
+
+            return error_node();
+         }
+
+         expression_node_ptr result = error_node();
+
+         if (type_checker::e_numeric == tc.return_type(param_seq_index))
+         {
+            if (tc.paramseq_count() <= 1)
+               result = expression_generator_
+                          .generic_function_call(function, arg_list);
+            else
+               result = expression_generator_
+                          .generic_function_call(function, arg_list, param_seq_index);
+         }
+         else if (type_checker::e_string == tc.return_type(param_seq_index))
+         {
+            if (tc.paramseq_count() <= 1)
+               result = expression_generator_
+                          .string_function_call(function, arg_list);
+            else
+               result = expression_generator_
+                          .string_function_call(function, arg_list, param_seq_index);
+         }
+         else
+         {
+            set_error(
+               make_error(parser_error::e_syntax,
+                          current_token(),
+                          "ERR128 - Invalid return type for call to overloaded function: " + function_name,
+                          exprtk_error_location));
+         }
+
+         sdd.delete_ptr = (0 == result);
+         return result;
+      }
       #endif
 
       template <typename Type, std::size_t NumberOfParameters>
@@ -23586,7 +23961,7 @@ namespace exprtk
                p.set_error(
                     make_error(parser_error::e_syntax,
                                p.current_token(),
-                               "ERR126 - Expected '(' for special function '" + sf_name + "'",
+                               "ERR129 - Expected '(' for special function '" + sf_name + "'",
                                exprtk_error_location));
 
                return error_node();
@@ -23607,7 +23982,7 @@ namespace exprtk
                      p.set_error(
                           make_error(parser_error::e_syntax,
                                      p.current_token(),
-                                     "ERR127 - Expected ',' before next parameter of special function '" + sf_name + "'",
+                                     "ERR130 - Expected ',' before next parameter of special function '" + sf_name + "'",
                                      exprtk_error_location));
 
                      return p.error_node();
@@ -23620,7 +23995,7 @@ namespace exprtk
                p.set_error(
                     make_error(parser_error::e_syntax,
                                p.current_token(),
-                               "ERR128 - Invalid number of parameters for special function '" + sf_name + "'",
+                               "ERR131 - Invalid number of parameters for special function '" + sf_name + "'",
                                exprtk_error_location));
 
                return p.error_node();
@@ -23647,7 +24022,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_token,
                           current_token(),
-                          "ERR129 - Invalid special function[1]: " + sf_name,
+                          "ERR132 - Invalid special function[1]: " + sf_name,
                           exprtk_error_location));
 
             return error_node();
@@ -23661,7 +24036,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_token,
                           current_token(),
-                          "ERR130 - Invalid special function[2]: " + sf_name,
+                          "ERR133 - Invalid special function[2]: " + sf_name,
                           exprtk_error_location));
 
             return error_node();
@@ -23693,7 +24068,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR131 - Break call within a break call is not allowed",
+                          "ERR134 - Break call within a break call is not allowed",
                           exprtk_error_location));
 
             return error_node();
@@ -23716,7 +24091,7 @@ namespace exprtk
                   set_error(
                      make_error(parser_error::e_syntax,
                                 current_token(),
-                                "ERR132 - Failed to parse return expression for 'break' statement",
+                                "ERR135 - Failed to parse return expression for 'break' statement",
                                 exprtk_error_location));
 
                   return error_node();
@@ -23726,7 +24101,7 @@ namespace exprtk
                   set_error(
                      make_error(parser_error::e_syntax,
                                 current_token(),
-                                "ERR133 - Expected ']' at the completion of break's return expression",
+                                "ERR136 - Expected ']' at the completion of break's return expression",
                                 exprtk_error_location));
 
                   free_node(node_allocator_,return_expr);
@@ -23744,7 +24119,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR134 - Invalid use of 'break', allowed only in the scope of a loop",
+                          "ERR137 - Invalid use of 'break', allowed only in the scope of a loop",
                           exprtk_error_location));
          }
 
@@ -23767,7 +24142,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR135 - Invalid use of 'continue', allowed only in the scope of a loop",
+                          "ERR138 - Invalid use of 'continue', allowed only in the scope of a loop",
                           exprtk_error_location));
 
             return error_node();
@@ -23784,7 +24159,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR136 - Expected '[' as part of vector size definition",
+                          "ERR139 - Expected '[' as part of vector size definition",
                           exprtk_error_location));
 
             return error_node();
@@ -23794,7 +24169,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR137 - Failed to determine size of vector '" + vec_name + "'",
+                          "ERR140 - Failed to determine size of vector '" + vec_name + "'",
                           exprtk_error_location));
 
             return error_node();
@@ -23806,7 +24181,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR138 - Expected a literal number as size of vector '" + vec_name + "'",
+                          "ERR141 - Expected a literal number as size of vector '" + vec_name + "'",
                           exprtk_error_location));
 
             return error_node();
@@ -23816,16 +24191,19 @@ namespace exprtk
 
          free_node(node_allocator_,size_expr);
 
+         const T max_vector_size = T(2000000000.0);
+
          if (
               (vector_size <= T(0)) ||
               std::not_equal_to<T>()
-              (T(0),vector_size - details::numeric::trunc(vector_size))
+              (T(0),vector_size - details::numeric::trunc(vector_size)) ||
+              (vector_size > max_vector_size)
             )
          {
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR139 - Invalid vector size. Must be an integer greater than zero, size: " +
+                          "ERR142 - Invalid vector size. Must be an integer in the range [0,2e9], size: " +
                           details::to_str(details::numeric::to_int32(vector_size)),
                           exprtk_error_location));
 
@@ -23845,7 +24223,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR140 - Expected ']' as part of vector size definition",
+                          "ERR143 - Expected ']' as part of vector size definition",
                           exprtk_error_location));
 
             return error_node();
@@ -23857,7 +24235,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR141 - Expected ':=' as part of vector definition",
+                             "ERR144 - Expected ':=' as part of vector definition",
                              exprtk_error_location));
 
                return error_node();
@@ -23871,7 +24249,7 @@ namespace exprtk
                   set_error(
                      make_error(parser_error::e_syntax,
                                 current_token(),
-                                "ERR142 - Failed to parse single vector initialiser",
+                                "ERR145 - Failed to parse single vector initialiser",
                                 exprtk_error_location));
 
                   return error_node();
@@ -23884,7 +24262,7 @@ namespace exprtk
                   set_error(
                      make_error(parser_error::e_syntax,
                                 current_token(),
-                                "ERR143 - Expected ']' to close single value vector initialiser",
+                                "ERR146 - Expected ']' to close single value vector initialiser",
                                 exprtk_error_location));
 
                   return error_node();
@@ -23912,7 +24290,7 @@ namespace exprtk
                   // Are we dealing with a user defined vector?
                   else if (symtab_store_.is_vector(current_token().value))
                   {
-                     lodge_symbol(current_token().value,e_st_vector);
+                     lodge_symbol(current_token().value, e_st_vector);
 
                      if (0 != (initialiser = parse_expression()))
                         vec_initilizer_list.push_back(initialiser);
@@ -23931,7 +24309,7 @@ namespace exprtk
                      set_error(
                         make_error(parser_error::e_syntax,
                                    current_token(),
-                                   "ERR144 - Expected '{' as part of vector initialiser list",
+                                   "ERR147 - Expected '{' as part of vector initialiser list",
                                    exprtk_error_location));
 
                      return error_node();
@@ -23951,7 +24329,7 @@ namespace exprtk
                      set_error(
                         make_error(parser_error::e_syntax,
                                    current_token(),
-                                   "ERR145 - Expected '{' as part of vector initialiser list",
+                                   "ERR148 - Expected '{' as part of vector initialiser list",
                                    exprtk_error_location));
 
                      return error_node();
@@ -23969,7 +24347,7 @@ namespace exprtk
                      set_error(
                         make_error(parser_error::e_syntax,
                                    current_token(),
-                                   "ERR146 - Expected ',' between vector initialisers",
+                                   "ERR149 - Expected ',' between vector initialisers",
                                    exprtk_error_location));
 
                      return error_node();
@@ -23981,9 +24359,9 @@ namespace exprtk
             }
 
             if (
-                 !token_is(token_t::e_rbracket   ,prsrhlpr_t::e_hold) &&
-                 !token_is(token_t::e_rcrlbracket,prsrhlpr_t::e_hold) &&
-                 !token_is(token_t::e_rsqrbracket,prsrhlpr_t::e_hold)
+                 !token_is(token_t::e_rbracket   , prsrhlpr_t::e_hold) &&
+                 !token_is(token_t::e_rcrlbracket, prsrhlpr_t::e_hold) &&
+                 !token_is(token_t::e_rsqrbracket, prsrhlpr_t::e_hold)
                )
             {
                if (!token_is(token_t::e_eof))
@@ -23991,7 +24369,7 @@ namespace exprtk
                   set_error(
                      make_error(parser_error::e_syntax,
                                 current_token(),
-                                "ERR147 - Expected ';' at end of vector definition",
+                                "ERR150 - Expected ';' at end of vector definition",
                                 exprtk_error_location));
 
                   return error_node();
@@ -24003,7 +24381,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR148 - Initialiser list larger than the number of elements in the vector: '" + vec_name + "'",
+                             "ERR151 - Initialiser list larger than the number of elements in the vector: '" + vec_name + "'",
                              exprtk_error_location));
 
                return error_node();
@@ -24023,7 +24401,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR149 - Illegal redefinition of local vector: '" + vec_name + "'",
+                             "ERR152 - Illegal redefinition of local vector: '" + vec_name + "'",
                              exprtk_error_location));
 
                return error_node();
@@ -24057,7 +24435,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR150 - Failed to add new local vector '" + vec_name + "' to SEM",
+                             "ERR153 - Failed to add new local vector '" + vec_name + "' to SEM",
                              exprtk_error_location));
 
                sem_.free_element(nse);
@@ -24074,17 +24452,21 @@ namespace exprtk
 
          state_.activate_side_effect("parse_define_vector_statement()");
 
-         lodge_symbol(vec_name,e_st_local_vector);
+         lodge_symbol(vec_name, e_st_local_vector);
 
          expression_node_ptr result = error_node();
 
          if (null_initialisation)
             result = expression_generator_(T(0.0));
          else if (vec_to_vec_initialiser)
+         {
+            expression_node_ptr vec_node = node_allocator_.allocate<vector_node_t>(vec_holder);
+
             result = expression_generator_(
                         details::e_assign,
-                        node_allocator_.allocate<vector_node_t>(vec_holder),
+                        vec_node,
                         vec_initilizer_list[0]);
+         }
          else
             result = node_allocator_
                         .allocate<details::vector_assignment_node<T> >(
@@ -24112,7 +24494,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR151 - Illegal redefinition of local variable: '" + str_name + "'",
+                             "ERR154 - Illegal redefinition of local variable: '" + str_name + "'",
                              exprtk_error_location));
 
                free_node(node_allocator_,initialisation_expression);
@@ -24144,7 +24526,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR152 - Failed to add new local string variable '" + str_name + "' to SEM",
+                             "ERR155 - Failed to add new local string variable '" + str_name + "' to SEM",
                              exprtk_error_location));
 
                free_node(node_allocator_,initialisation_expression);
@@ -24159,7 +24541,7 @@ namespace exprtk
             exprtk_debug(("parse_define_string_statement() - INFO - Added new local string variable: %s\n",nse.name.c_str()));
          }
 
-         lodge_symbol(str_name,e_st_local_string);
+         lodge_symbol(str_name, e_st_local_string);
 
          state_.activate_side_effect("parse_define_string_statement()");
 
@@ -24190,7 +24572,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR153 - Illegal variable definition",
+                          "ERR156 - Illegal variable definition",
                           exprtk_error_location));
 
             return error_node();
@@ -24211,7 +24593,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR154 - Expected a symbol for variable definition",
+                          "ERR157 - Expected a symbol for variable definition",
                           exprtk_error_location));
 
             return error_node();
@@ -24221,7 +24603,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR155 - Illegal redefinition of reserved keyword: '" + var_name + "'",
+                          "ERR158 - Illegal redefinition of reserved keyword: '" + var_name + "'",
                           exprtk_error_location));
 
             return error_node();
@@ -24231,7 +24613,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR156 - Illegal redefinition of variable '" + var_name + "'",
+                          "ERR159 - Illegal redefinition of variable '" + var_name + "'",
                           exprtk_error_location));
 
             return error_node();
@@ -24241,7 +24623,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR157 - Illegal redefinition of local variable: '" + var_name + "'",
+                          "ERR160 - Illegal redefinition of local variable: '" + var_name + "'",
                           exprtk_error_location));
 
             return error_node();
@@ -24261,7 +24643,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR158 - Failed to parse initialisation expression",
+                             "ERR161 - Failed to parse initialisation expression",
                              exprtk_error_location));
 
                return error_node();
@@ -24269,9 +24651,9 @@ namespace exprtk
          }
 
          if (
-              !token_is(token_t::e_rbracket   ,prsrhlpr_t::e_hold) &&
-              !token_is(token_t::e_rcrlbracket,prsrhlpr_t::e_hold) &&
-              !token_is(token_t::e_rsqrbracket,prsrhlpr_t::e_hold)
+              !token_is(token_t::e_rbracket   , prsrhlpr_t::e_hold) &&
+              !token_is(token_t::e_rcrlbracket, prsrhlpr_t::e_hold) &&
+              !token_is(token_t::e_rsqrbracket, prsrhlpr_t::e_hold)
             )
          {
             if (!token_is(token_t::e_eof,prsrhlpr_t::e_hold))
@@ -24279,7 +24661,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR159 - Expected ';' after variable definition",
+                             "ERR162 - Expected ';' after variable definition",
                              exprtk_error_location));
 
                free_node(node_allocator_,initialisation_expression);
@@ -24307,7 +24689,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR160 - Illegal redefinition of local variable: '" + var_name + "'",
+                             "ERR163 - Illegal redefinition of local variable: '" + var_name + "'",
                              exprtk_error_location));
 
                free_node(node_allocator_, initialisation_expression);
@@ -24339,7 +24721,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR161 - Failed to add new local variable '" + var_name + "' to SEM",
+                             "ERR164 - Failed to add new local variable '" + var_name + "' to SEM",
                              exprtk_error_location));
 
                free_node(node_allocator_, initialisation_expression);
@@ -24356,7 +24738,7 @@ namespace exprtk
 
          state_.activate_side_effect("parse_define_var_statement()");
 
-         lodge_symbol(var_name,e_st_local_variable);
+         lodge_symbol(var_name, e_st_local_variable);
 
          expression_node_ptr branch[2] = {0};
 
@@ -24376,7 +24758,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR162 - Expected a '{}' for uninitialised var definition",
+                          "ERR165 - Expected a '{}' for uninitialised var definition",
                           exprtk_error_location));
 
             return error_node();
@@ -24386,7 +24768,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR163 - Expected ';' after uninitialised variable definition",
+                          "ERR166 - Expected ';' after uninitialised variable definition",
                           exprtk_error_location));
 
             return error_node();
@@ -24403,7 +24785,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR164 - Illegal redefinition of local variable: '" + var_name + "'",
+                             "ERR167 - Illegal redefinition of local variable: '" + var_name + "'",
                              exprtk_error_location));
 
                return error_node();
@@ -24433,7 +24815,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR165 - Failed to add new local variable '" + var_name + "' to SEM",
+                             "ERR168 - Failed to add new local variable '" + var_name + "' to SEM",
                              exprtk_error_location));
 
                sem_.free_element(nse);
@@ -24445,7 +24827,7 @@ namespace exprtk
                           nse.name.c_str()));
          }
 
-         lodge_symbol(var_name,e_st_local_variable);
+         lodge_symbol(var_name, e_st_local_variable);
 
          state_.activate_side_effect("parse_uninitialised_var_statement()");
 
@@ -24466,7 +24848,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR166 - Expected '(' at start of swap statement",
+                          "ERR169 - Expected '(' at start of swap statement",
                           exprtk_error_location));
 
             return error_node();
@@ -24485,7 +24867,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR167 - Expected a symbol for variable or vector element definition",
+                          "ERR170 - Expected a symbol for variable or vector element definition",
                           exprtk_error_location));
 
             return error_node();
@@ -24497,7 +24879,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR168 - First parameter to swap is an invalid vector element: '" + var0_name + "'",
+                             "ERR171 - First parameter to swap is an invalid vector element: '" + var0_name + "'",
                              exprtk_error_location));
 
                return error_node();
@@ -24523,14 +24905,14 @@ namespace exprtk
                variable0 = se.var_node;
             }
 
-            lodge_symbol(var0_name,e_st_variable);
+            lodge_symbol(var0_name, e_st_variable);
 
             if (0 == variable0)
             {
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR169 - First parameter to swap is an invalid variable: '" + var0_name + "'",
+                             "ERR172 - First parameter to swap is an invalid variable: '" + var0_name + "'",
                              exprtk_error_location));
 
                return error_node();
@@ -24544,7 +24926,7 @@ namespace exprtk
             set_error(
                 make_error(parser_error::e_syntax,
                            current_token(),
-                           "ERR170 - Expected ',' between parameters to swap",
+                           "ERR173 - Expected ',' between parameters to swap",
                            exprtk_error_location));
 
             if (variable0_generated)
@@ -24562,7 +24944,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR171 - Expected a symbol for variable or vector element definition",
+                          "ERR174 - Expected a symbol for variable or vector element definition",
                           exprtk_error_location));
 
             if (variable0_generated)
@@ -24579,7 +24961,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR172 - Second parameter to swap is an invalid vector element: '" + var1_name + "'",
+                             "ERR175 - Second parameter to swap is an invalid vector element: '" + var1_name + "'",
                              exprtk_error_location));
 
                if (variable0_generated)
@@ -24610,14 +24992,14 @@ namespace exprtk
                variable1 = se.var_node;
             }
 
-            lodge_symbol(var1_name,e_st_variable);
+            lodge_symbol(var1_name, e_st_variable);
 
             if (0 == variable1)
             {
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR173 - Second parameter to swap is an invalid variable: '" + var1_name + "'",
+                             "ERR176 - Second parameter to swap is an invalid variable: '" + var1_name + "'",
                              exprtk_error_location));
 
                if (variable0_generated)
@@ -24636,7 +25018,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR174 - Expected ')' at end of swap statement",
+                          "ERR177 - Expected ')' at end of swap statement",
                           exprtk_error_location));
 
             if (variable0_generated)
@@ -24693,7 +25075,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR175 - Return call within a return call is not allowed",
+                          "ERR178 - Return call within a return call is not allowed",
                           exprtk_error_location));
 
             return error_node();
@@ -24717,7 +25099,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR176 - Expected '[' at start of return statement",
+                          "ERR179 - Expected '[' at start of return statement",
                           exprtk_error_location));
 
             return error_node();
@@ -24740,7 +25122,7 @@ namespace exprtk
                   set_error(
                      make_error(parser_error::e_syntax,
                                 current_token(),
-                                "ERR177 - Expected ',' between values during call to return",
+                                "ERR180 - Expected ',' between values during call to return",
                                 exprtk_error_location));
 
                   return error_node();
@@ -24752,13 +25134,13 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR178 - Zero parameter return statement not allowed",
+                          "ERR181 - Zero parameter return statement not allowed",
                           exprtk_error_location));
 
             return error_node();
          }
 
-         lexer::token prev_token = current_token();
+         const lexer::token prev_token = current_token();
 
          if (token_is(token_t::e_rsqrbracket))
          {
@@ -24767,7 +25149,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              prev_token,
-                             "ERR179 - Invalid ']' found during return call",
+                             "ERR182 - Invalid ']' found during return call",
                              exprtk_error_location));
 
                return error_node();
@@ -24820,7 +25202,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR180 - Invalid sequence of variable '"+ symbol + "' and bracket",
+                             "ERR183 - Invalid sequence of variable '"+ symbol + "' and bracket",
                              exprtk_error_location));
 
                return false;
@@ -24868,7 +25250,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR181 - Invalid sequence of brackets",
+                             "ERR184 - Invalid sequence of brackets",
                              exprtk_error_location));
 
                return false;
@@ -24901,7 +25283,7 @@ namespace exprtk
             if (!post_variable_process(symbol))
                return error_node();
 
-            lodge_symbol(symbol,e_st_variable);
+            lodge_symbol(symbol, e_st_variable);
             next_token();
 
             return variable;
@@ -24917,7 +25299,7 @@ namespace exprtk
                if (scope_element::e_variable == se.type)
                {
                   se.active = true;
-                  lodge_symbol(symbol,e_st_local_variable);
+                  lodge_symbol(symbol, e_st_local_variable);
 
                   if (!post_variable_process(symbol))
                      return error_node();
@@ -24953,7 +25335,7 @@ namespace exprtk
 
             if (function)
             {
-               lodge_symbol(symbol,e_st_function);
+               lodge_symbol(symbol, e_st_function);
 
                expression_node_ptr func_node =
                                       parse_function_invocation(function,symbol);
@@ -24965,7 +25347,7 @@ namespace exprtk
                   set_error(
                      make_error(parser_error::e_syntax,
                                 current_token(),
-                                "ERR182 - Failed to generate node for function: '" + symbol + "'",
+                                "ERR185 - Failed to generate node for function: '" + symbol + "'",
                                 exprtk_error_location));
 
                   return error_node();
@@ -24979,7 +25361,7 @@ namespace exprtk
 
             if (vararg_function)
             {
-               lodge_symbol(symbol,e_st_function);
+               lodge_symbol(symbol, e_st_function);
 
                expression_node_ptr vararg_func_node =
                                       parse_vararg_function_call(vararg_function, symbol);
@@ -24991,7 +25373,7 @@ namespace exprtk
                   set_error(
                      make_error(parser_error::e_syntax,
                                 current_token(),
-                                "ERR183 - Failed to generate node for vararg function: '" + symbol + "'",
+                                "ERR186 - Failed to generate node for vararg function: '" + symbol + "'",
                                 exprtk_error_location));
 
                   return error_node();
@@ -25005,7 +25387,7 @@ namespace exprtk
 
             if (generic_function)
             {
-               lodge_symbol(symbol,e_st_function);
+               lodge_symbol(symbol, e_st_function);
 
                expression_node_ptr genericfunc_node =
                                       parse_generic_function_call(generic_function, symbol);
@@ -25017,7 +25399,7 @@ namespace exprtk
                   set_error(
                      make_error(parser_error::e_syntax,
                                 current_token(),
-                                "ERR184 - Failed to generate node for generic function: '" + symbol + "'",
+                                "ERR187 - Failed to generate node for generic function: '" + symbol + "'",
                                 exprtk_error_location));
 
                   return error_node();
@@ -25032,7 +25414,7 @@ namespace exprtk
 
             if (string_function)
             {
-               lodge_symbol(symbol,e_st_function);
+               lodge_symbol(symbol, e_st_function);
 
                expression_node_ptr stringfunc_node =
                                       parse_string_function_call(string_function, symbol);
@@ -25044,7 +25426,33 @@ namespace exprtk
                   set_error(
                      make_error(parser_error::e_syntax,
                                 current_token(),
-                                "ERR185 - Failed to generate node for string function: '" + symbol + "'",
+                                "ERR188 - Failed to generate node for string function: '" + symbol + "'",
+                                exprtk_error_location));
+
+                  return error_node();
+               }
+            }
+         }
+
+         {
+            // Are we dealing with a vararg overloaded scalar/string returning function?
+            igeneric_function<T>* overload_function = symtab_store_.get_overload_function(symbol);
+
+            if (overload_function)
+            {
+               lodge_symbol(symbol, e_st_function);
+
+               expression_node_ptr overloadfunc_node =
+                                      parse_overload_function_call(overload_function, symbol);
+
+               if (overloadfunc_node)
+                  return overloadfunc_node;
+               else
+               {
+                  set_error(
+                     make_error(parser_error::e_syntax,
+                                current_token(),
+                                "ERR189 - Failed to generate node for overload function: '" + symbol + "'",
                                 exprtk_error_location));
 
                   return error_node();
@@ -25056,7 +25464,7 @@ namespace exprtk
          // Are we dealing with a vector?
          if (symtab_store_.is_vector(symbol))
          {
-            lodge_symbol(symbol,e_st_vector);
+            lodge_symbol(symbol, e_st_vector);
             return parse_vector();
          }
 
@@ -25070,7 +25478,7 @@ namespace exprtk
                   set_error(
                      make_error(parser_error::e_syntax,
                                 current_token(),
-                                "ERR186 - Invalid use of reserved symbol '" + symbol + "'",
+                                "ERR190 - Invalid use of reserved symbol '" + symbol + "'",
                                 exprtk_error_location));
 
                   return error_node();
@@ -25090,7 +25498,7 @@ namespace exprtk
                {
                   T default_value = T(0);
 
-                  typename unknown_symbol_resolver::usr_symbol_type usr_symbol_type;
+                  typename unknown_symbol_resolver::usr_symbol_type usr_symbol_type = unknown_symbol_resolver::e_usr_unknown_type;
 
                   if (unknown_symbol_resolver_->process(symbol, usr_symbol_type, default_value, error_message))
                   {
@@ -25118,7 +25526,7 @@ namespace exprtk
                               var = expression_generator_(var->value());
                            }
 
-                           lodge_symbol(symbol,e_st_variable);
+                           lodge_symbol(symbol, e_st_variable);
 
                            if (!post_variable_process(symbol))
                               return error_node();
@@ -25133,7 +25541,7 @@ namespace exprtk
                   set_error(
                      make_error(parser_error::e_symtab,
                                 current_token(),
-                                "ERR187 - Failed to create variable: '" + symbol + "'" +
+                                "ERR191 - Failed to create variable: '" + symbol + "'" +
                                 (error_message.empty() ? "" : " - " + error_message),
                                 exprtk_error_location));
 
@@ -25153,7 +25561,7 @@ namespace exprtk
                   set_error(
                      make_error(parser_error::e_symtab,
                                 current_token(),
-                                "ERR188 - Failed to resolve symbol: '" + symbol + "'" +
+                                "ERR192 - Failed to resolve symbol: '" + symbol + "'" +
                                 (error_message.empty() ? "" : " - " + error_message),
                                 exprtk_error_location));
                }
@@ -25165,7 +25573,7 @@ namespace exprtk
          set_error(
             make_error(parser_error::e_syntax,
                        current_token(),
-                       "ERR189 - Undefined symbol: '" + symbol + "'",
+                       "ERR193 - Undefined symbol: '" + symbol + "'",
                        exprtk_error_location));
 
          return error_node();
@@ -25272,7 +25680,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_symtab,
                           current_token(),
-                          "ERR190 - Variable or function detected, yet symbol-table is invalid, Symbol: " + current_token().value,
+                          "ERR194 - Variable or function detected, yet symbol-table is invalid, Symbol: " + current_token().value,
                           exprtk_error_location));
 
             return error_node();
@@ -25296,7 +25704,7 @@ namespace exprtk
                   set_error(
                      make_error(parser_error::e_numeric,
                                 current_token(),
-                                "ERR191 - Failed generate node for scalar: '" + current_token().value + "'",
+                                "ERR195 - Failed generate node for scalar: '" + current_token().value + "'",
                                 exprtk_error_location));
 
                   return error_node();
@@ -25310,7 +25718,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_numeric,
                              current_token(),
-                             "ERR192 - Failed to convert '" + current_token().value + "' to a number",
+                             "ERR196 - Failed to convert '" + current_token().value + "' to a number",
                              exprtk_error_location));
 
                return error_node();
@@ -25337,7 +25745,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR193 - Expected ')' instead of: '" + current_token().value + "'",
+                             "ERR197 - Expected ')' instead of: '" + current_token().value + "'",
                              exprtk_error_location));
 
                free_node(node_allocator_,branch);
@@ -25362,7 +25770,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR194 - Expected ']' instead of: '" + current_token().value + "'",
+                             "ERR198 - Expected ']' instead of: '" + current_token().value + "'",
                              exprtk_error_location));
 
                free_node(node_allocator_,branch);
@@ -25387,7 +25795,7 @@ namespace exprtk
                set_error(
                   make_error(parser_error::e_syntax,
                              current_token(),
-                             "ERR195 - Expected '}' instead of: '" + current_token().value + "'",
+                             "ERR199 - Expected '}' instead of: '" + current_token().value + "'",
                              exprtk_error_location));
 
                free_node(node_allocator_,branch);
@@ -25427,7 +25835,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR196 - Premature end of expression[1]",
+                          "ERR200 - Premature end of expression[1]",
                           exprtk_error_location));
 
             return error_node();
@@ -25437,7 +25845,7 @@ namespace exprtk
             set_error(
                make_error(parser_error::e_syntax,
                           current_token(),
-                          "ERR197 - Premature end of expression[2]",
+                          "ERR201 - Premature end of expression[2]",
                           exprtk_error_location));
 
             return error_node();
@@ -25611,7 +26019,7 @@ namespace exprtk
             return true;
          }
 
-         inline details::operator_type get_operator(const binary_functor_t& bop)
+         inline details::operator_type get_operator(const binary_functor_t& bop) const
          {
             return (*inv_binary_op_map_).find(bop)->second;
          }
@@ -25670,9 +26078,9 @@ namespace exprtk
                    (details::e_frac  == operation) || (details::e_trunc == operation) ;
          }
 
-         inline bool sf3_optimisable(const std::string& sf3id, trinary_functor_t& tfunc)
+         inline bool sf3_optimisable(const std::string& sf3id, trinary_functor_t& tfunc) const
          {
-            typename sf3_map_t::iterator itr = sf3_map_->find(sf3id);
+            typename sf3_map_t::const_iterator itr = sf3_map_->find(sf3id);
 
             if (sf3_map_->end() == itr)
                return false;
@@ -25682,9 +26090,9 @@ namespace exprtk
             return true;
          }
 
-         inline bool sf4_optimisable(const std::string& sf4id, quaternary_functor_t& qfunc)
+         inline bool sf4_optimisable(const std::string& sf4id, quaternary_functor_t& qfunc) const
          {
-            typename sf4_map_t::iterator itr = sf4_map_->find(sf4id);
+            typename sf4_map_t::const_iterator itr = sf4_map_->find(sf4id);
 
             if (sf4_map_->end() == itr)
                return false;
@@ -25694,9 +26102,9 @@ namespace exprtk
             return true;
          }
 
-         inline bool sf3_optimisable(const std::string& sf3id, details::operator_type& operation)
+         inline bool sf3_optimisable(const std::string& sf3id, details::operator_type& operation) const
          {
-            typename sf3_map_t::iterator itr = sf3_map_->find(sf3id);
+            typename sf3_map_t::const_iterator itr = sf3_map_->find(sf3id);
 
             if (sf3_map_->end() == itr)
                return false;
@@ -25706,9 +26114,9 @@ namespace exprtk
             return true;
          }
 
-         inline bool sf4_optimisable(const std::string& sf4id, details::operator_type& operation)
+         inline bool sf4_optimisable(const std::string& sf4id, details::operator_type& operation) const
          {
-            typename sf4_map_t::iterator itr = sf4_map_->find(sf4id);
+            typename sf4_map_t::const_iterator itr = sf4_map_->find(sf4id);
 
             if (sf4_map_->end() == itr)
                return false;
@@ -25836,7 +26244,7 @@ namespace exprtk
                    (details::e_xnor == operation) ;
          }
 
-         inline std::string branch_to_id(expression_node_ptr branch)
+         inline std::string branch_to_id(expression_node_ptr branch) const
          {
             static const std::string null_str   ("(null)" );
             static const std::string const_str  ("(c)"    );
@@ -25877,7 +26285,7 @@ namespace exprtk
                return "ERROR";
          }
 
-         inline std::string branch_to_id(expression_node_ptr (&branch)[2])
+         inline std::string branch_to_id(expression_node_ptr (&branch)[2]) const
          {
             return branch_to_id(branch[0]) + std::string("o") + branch_to_id(branch[1]);
          }
@@ -25995,7 +26403,7 @@ namespace exprtk
                       !details::is_constant_node(branch[1]) ;
          }
 
-         inline bool is_invalid_assignment_op(const details::operator_type& operation, expression_node_ptr (&branch)[2])
+         inline bool is_invalid_assignment_op(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const
          {
             if (is_assignment_operation(operation))
             {
@@ -26017,14 +26425,14 @@ namespace exprtk
                return false;
          }
 
-         inline bool is_constpow_operation(const details::operator_type& operation, expression_node_ptr(&branch)[2])
+         inline bool is_constpow_operation(const details::operator_type& operation, expression_node_ptr(&branch)[2]) const
          {
             if (
-                 !is_constant_node(branch[1]) ||
-                  is_constant_node(branch[0]) ||
-                  is_variable_node(branch[0]) ||
-                  is_vector_node  (branch[0]) ||
-                  is_generally_string_node(branch[0])
+                 !details::is_constant_node(branch[1]) ||
+                  details::is_constant_node(branch[0]) ||
+                  details::is_variable_node(branch[0]) ||
+                  details::is_vector_node  (branch[0]) ||
+                  details::is_generally_string_node(branch[0])
                )
                return false;
 
@@ -26033,7 +26441,7 @@ namespace exprtk
             return cardinal_pow_optimisable(operation, c);
          }
 
-         inline bool is_invalid_break_continue_op(expression_node_ptr (&branch)[2])
+         inline bool is_invalid_break_continue_op(expression_node_ptr (&branch)[2]) const
          {
             return (
                      details::is_break_node   (branch[0]) ||
@@ -26043,7 +26451,7 @@ namespace exprtk
                    );
          }
 
-         inline bool is_invalid_string_op(const details::operator_type& operation, expression_node_ptr (&branch)[2])
+         inline bool is_invalid_string_op(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const
          {
             const bool b0_string = is_generally_string_node(branch[0]);
             const bool b1_string = is_generally_string_node(branch[1]);
@@ -26063,7 +26471,7 @@ namespace exprtk
             return result;
          }
 
-         inline bool is_invalid_string_op(const details::operator_type& operation, expression_node_ptr (&branch)[3])
+         inline bool is_invalid_string_op(const details::operator_type& operation, expression_node_ptr (&branch)[3]) const
          {
             const bool b0_string = is_generally_string_node(branch[0]);
             const bool b1_string = is_generally_string_node(branch[1]);
@@ -26084,7 +26492,7 @@ namespace exprtk
             return result;
          }
 
-         inline bool is_string_operation(const details::operator_type& operation, expression_node_ptr (&branch)[2])
+         inline bool is_string_operation(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const
          {
             const bool b0_string = is_generally_string_node(branch[0]);
             const bool b1_string = is_generally_string_node(branch[1]);
@@ -26092,7 +26500,7 @@ namespace exprtk
             return (b0_string && b1_string && valid_string_operation(operation));
          }
 
-         inline bool is_string_operation(const details::operator_type& operation, expression_node_ptr (&branch)[3])
+         inline bool is_string_operation(const details::operator_type& operation, expression_node_ptr (&branch)[3]) const
          {
             const bool b0_string = is_generally_string_node(branch[0]);
             const bool b1_string = is_generally_string_node(branch[1]);
@@ -26102,7 +26510,7 @@ namespace exprtk
          }
 
          #ifndef exprtk_disable_sc_andor
-         inline bool is_shortcircuit_expression(const details::operator_type& operation)
+         inline bool is_shortcircuit_expression(const details::operator_type& operation) const
          {
             return (
                      (details::e_scand == operation) ||
@@ -26110,13 +26518,13 @@ namespace exprtk
                    );
          }
          #else
-         inline bool is_shortcircuit_expression(const details::operator_type&)
+         inline bool is_shortcircuit_expression(const details::operator_type&) const
          {
             return false;
          }
          #endif
 
-         inline bool is_null_present(expression_node_ptr (&branch)[2])
+         inline bool is_null_present(expression_node_ptr (&branch)[2]) const
          {
             return (
                      details::is_null_node(branch[0]) ||
@@ -26124,7 +26532,7 @@ namespace exprtk
                    );
          }
 
-         inline bool is_vector_eqineq_logic_operation(const details::operator_type& operation, expression_node_ptr (&branch)[2])
+         inline bool is_vector_eqineq_logic_operation(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const
          {
             if (!is_ivector_node(branch[0]) && !is_ivector_node(branch[1]))
                return false;
@@ -26146,7 +26554,7 @@ namespace exprtk
                       );
          }
 
-         inline bool is_vector_arithmetic_operation(const details::operator_type& operation, expression_node_ptr (&branch)[2])
+         inline bool is_vector_arithmetic_operation(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const
          {
             if (!is_ivector_node(branch[0]) && !is_ivector_node(branch[1]))
                return false;
@@ -26319,15 +26727,19 @@ namespace exprtk
             return (*this)(operation,branch);
          }
 
-         inline expression_node_ptr operator() (const details::operator_type& operation, expression_node_ptr b0, expression_node_ptr b1)
+         inline expression_node_ptr operator() (const details::operator_type& operation, expression_node_ptr& b0, expression_node_ptr& b1)
          {
-            if ((0 == b0) || (0 == b1))
-               return error_node();
-            else
+            expression_node_ptr result = error_node();
+
+            if ((0 != b0) && (0 != b1))
             {
                expression_node_ptr branch[2] = { b0, b1 };
-               return expression_generator<Type>::operator()(operation,branch);
+               result = expression_generator<Type>::operator()(operation, branch);
+               b0 = branch[0];
+               b1 = branch[1];
             }
+
+            return result;
          }
 
          inline expression_node_ptr conditional(expression_node_ptr condition,
@@ -26521,7 +26933,7 @@ namespace exprtk
 
                return result;
             }
-            else if (details::is_null_node(condition))
+            else if (details::is_null_node(condition) || (0 == condition))
             {
                free_node(*node_allocator_, initialiser);
                free_node(*node_allocator_,   condition);
@@ -26553,7 +26965,7 @@ namespace exprtk
          }
 
          template <typename Allocator,
-                   template <typename,typename> class Sequence>
+                   template <typename, typename> class Sequence>
          inline expression_node_ptr const_optimise_switch(Sequence<expression_node_ptr,Allocator>& arg_list)
          {
             expression_node_ptr result = error_node();
@@ -26589,7 +27001,7 @@ namespace exprtk
          }
 
          template <typename Allocator,
-                   template <typename,typename> class Sequence>
+                   template <typename, typename> class Sequence>
          inline expression_node_ptr const_optimise_mswitch(Sequence<expression_node_ptr,Allocator>& arg_list)
          {
             expression_node_ptr result = error_node();
@@ -26714,7 +27126,7 @@ namespace exprtk
          };
 
          template <typename Allocator,
-                   template <typename,typename> class Sequence>
+                   template <typename, typename> class Sequence>
          inline expression_node_ptr switch_statement(Sequence<expression_node_ptr,Allocator>& arg_list)
          {
             if (arg_list.empty())
@@ -26754,7 +27166,7 @@ namespace exprtk
          }
 
          template <typename Allocator,
-                   template <typename,typename> class Sequence>
+                   template <typename, typename> class Sequence>
          inline expression_node_ptr multi_switch_statement(Sequence<expression_node_ptr,Allocator>& arg_list)
          {
             if (!all_nodes_valid(arg_list))
@@ -27066,7 +27478,7 @@ namespace exprtk
          }
 
          template <typename Allocator,
-                   template <typename,typename> class Sequence>
+                   template <typename, typename> class Sequence>
          inline expression_node_ptr const_optimise_varargfunc(const details::operator_type& operation, Sequence<expression_node_ptr,Allocator>& arg_list)
          {
             expression_node_ptr temp_node = error_node();
@@ -27098,7 +27510,7 @@ namespace exprtk
             return node_allocator_->allocate<literal_node_t>(v);
          }
 
-         inline bool special_one_parameter_vararg(const details::operator_type& operation)
+         inline bool special_one_parameter_vararg(const details::operator_type& operation) const
          {
             return (
                      (details::e_sum  == operation) ||
@@ -27110,7 +27522,7 @@ namespace exprtk
          }
 
          template <typename Allocator,
-                   template <typename,typename> class Sequence>
+                   template <typename, typename> class Sequence>
          inline expression_node_ptr varnode_optimise_varargfunc(const details::operator_type& operation, Sequence<expression_node_ptr,Allocator>& arg_list)
          {
             switch (operation)
@@ -27133,7 +27545,7 @@ namespace exprtk
          }
 
          template <typename Allocator,
-                   template <typename,typename> class Sequence>
+                   template <typename, typename> class Sequence>
          inline expression_node_ptr vectorize_func(const details::operator_type& operation, Sequence<expression_node_ptr,Allocator>& arg_list)
          {
             if (1 == arg_list.size())
@@ -27158,7 +27570,7 @@ namespace exprtk
          }
 
          template <typename Allocator,
-                   template <typename,typename> class Sequence>
+                   template <typename, typename> class Sequence>
          inline expression_node_ptr vararg_function(const details::operator_type& operation, Sequence<expression_node_ptr,Allocator>& arg_list)
          {
             if (!all_nodes_valid(arg_list))
@@ -27520,7 +27932,7 @@ namespace exprtk
 
          template <typename NodePtr,
                    typename Allocator,
-                   template <typename,typename> class Sequence>
+                   template <typename, typename> class Sequence>
          inline bool is_constant_foldable(const Sequence<NodePtr,Allocator>& b) const
          {
             for (std::size_t i = 0; i < b.size(); ++i)
@@ -27666,6 +28078,8 @@ namespace exprtk
             }
             else if (details::is_vector_elem_node(branch[0]))
             {
+               lodge_assignment(e_st_vecelem,branch[0]);
+
                switch (operation)
                {
                   #define case_stmt(op0,op1)                                                                            \
@@ -27684,6 +28098,8 @@ namespace exprtk
             }
             else if (details::is_rebasevector_elem_node(branch[0]))
             {
+               lodge_assignment(e_st_vecelem,branch[0]);
+
                switch (operation)
                {
                   #define case_stmt(op0,op1)                                                                                  \
@@ -27702,6 +28118,8 @@ namespace exprtk
             }
             else if (details::is_rebasevector_celem_node(branch[0]))
             {
+               lodge_assignment(e_st_vecelem,branch[0]);
+
                switch (operation)
                {
                   #define case_stmt(op0,op1)                                                                                   \
@@ -28052,7 +28470,7 @@ namespace exprtk
          case_stmt(details::e_xnor, details::xnor_op) \
 
          #ifndef exprtk_disable_cardinal_pow_optimisation
-         template <typename TType, template <typename,typename> class IPowNode>
+         template <typename TType, template <typename, typename> class IPowNode>
          inline expression_node_ptr cardinal_pow_optimisation_impl(const TType& v, const unsigned int& p)
          {
             switch (p)
@@ -28102,7 +28520,7 @@ namespace exprtk
             }
          }
 
-         inline bool cardinal_pow_optimisable(const details::operator_type& operation, const T& c)
+         inline bool cardinal_pow_optimisable(const details::operator_type& operation, const T& c) const
          {
             return (details::e_pow == operation) && (details::numeric::abs(c) <= T(60)) && details::numeric::is_integer(c);
          }
@@ -29228,7 +29646,8 @@ namespace exprtk
                if (!expr_gen.sf3_optimisable(id,sf3opr))
                   return false;
                else
-                  result = synthesize_sf3ext_expression::template process<T0,T1,T2>(expr_gen,sf3opr,t0,t1,t2);
+                  result = synthesize_sf3ext_expression::template process<T0, T1, T2>
+                              (expr_gen, sf3opr, t0, t1, t2);
 
                return true;
             }
@@ -29295,7 +29714,7 @@ namespace exprtk
                if (!expr_gen.sf4_optimisable(id,sf4opr))
                   return false;
                else
-                  result = synthesize_sf4ext_expression::template process<T0,T1,T2,T3>
+                  result = synthesize_sf4ext_expression::template process<T0, T1, T2, T3>
                               (expr_gen, sf4opr, t0, t1, t2, t3);
 
                return true;
@@ -29315,28 +29734,28 @@ namespace exprtk
                typedef details::T0oT1oT2_base_node<Type>* sf3ext_base_ptr;
 
                sf3ext_base_ptr n = static_cast<sf3ext_base_ptr>(sf3node);
-               std::string id = "t" + expr_gen.to_str(operation) + "(" + n->type_id() + ")";
+               const std::string id = "t" + expr_gen.to_str(operation) + "(" + n->type_id() + ")";
 
                switch (n->type())
                {
                   case details::expression_node<Type>::e_covoc : return compile_right_impl
-                                                                    <typename covoc_t::sf3_type_node,ExternalType,ctype,vtype,ctype>
+                                                                    <typename covoc_t::sf3_type_node,ExternalType, ctype, vtype, ctype>
                                                                        (expr_gen, id, t, sf3node, result);
 
                   case details::expression_node<Type>::e_covov : return compile_right_impl
-                                                                    <typename covov_t::sf3_type_node,ExternalType,ctype,vtype,vtype>
+                                                                    <typename covov_t::sf3_type_node,ExternalType, ctype, vtype, vtype>
                                                                        (expr_gen, id, t, sf3node, result);
 
                   case details::expression_node<Type>::e_vocov : return compile_right_impl
-                                                                    <typename vocov_t::sf3_type_node,ExternalType,vtype,ctype,vtype>
+                                                                    <typename vocov_t::sf3_type_node,ExternalType, vtype, ctype, vtype>
                                                                        (expr_gen, id, t, sf3node, result);
 
                   case details::expression_node<Type>::e_vovoc : return compile_right_impl
-                                                                    <typename vovoc_t::sf3_type_node,ExternalType,vtype,vtype,ctype>
+                                                                    <typename vovoc_t::sf3_type_node,ExternalType, vtype, vtype, ctype>
                                                                        (expr_gen, id, t, sf3node, result);
 
                   case details::expression_node<Type>::e_vovov : return compile_right_impl
-                                                                    <typename vovov_t::sf3_type_node,ExternalType,vtype,vtype,vtype>
+                                                                    <typename vovov_t::sf3_type_node,ExternalType, vtype, vtype, vtype>
                                                                        (expr_gen, id, t, sf3node, result);
 
                   default                                      : return false;
@@ -29358,28 +29777,28 @@ namespace exprtk
 
                sf3ext_base_ptr n = static_cast<sf3ext_base_ptr>(sf3node);
 
-               std::string id = "(" + n->type_id() + ")" + expr_gen.to_str(operation) + "t";
+               const std::string id = "(" + n->type_id() + ")" + expr_gen.to_str(operation) + "t";
 
                switch (n->type())
                {
                   case details::expression_node<Type>::e_covoc : return compile_left_impl
-                                                                    <typename covoc_t::sf3_type_node,ExternalType,ctype,vtype,ctype>
+                                                                    <typename covoc_t::sf3_type_node,ExternalType, ctype, vtype, ctype>
                                                                        (expr_gen, id, t, sf3node, result);
 
                   case details::expression_node<Type>::e_covov : return compile_left_impl
-                                                                    <typename covov_t::sf3_type_node,ExternalType,ctype,vtype,vtype>
+                                                                    <typename covov_t::sf3_type_node,ExternalType, ctype, vtype, vtype>
                                                                        (expr_gen, id, t, sf3node, result);
 
                   case details::expression_node<Type>::e_vocov : return compile_left_impl
-                                                                    <typename vocov_t::sf3_type_node,ExternalType,vtype,ctype,vtype>
+                                                                    <typename vocov_t::sf3_type_node,ExternalType, vtype, ctype, vtype>
                                                                        (expr_gen, id, t, sf3node, result);
 
                   case details::expression_node<Type>::e_vovoc : return compile_left_impl
-                                                                    <typename vovoc_t::sf3_type_node,ExternalType,vtype,vtype,ctype>
+                                                                    <typename vovoc_t::sf3_type_node,ExternalType, vtype, vtype, ctype>
                                                                        (expr_gen, id, t, sf3node, result);
 
                   case details::expression_node<Type>::e_vovov : return compile_left_impl
-                                                                    <typename vovov_t::sf3_type_node,ExternalType,vtype,vtype,vtype>
+                                                                    <typename vovov_t::sf3_type_node,ExternalType, vtype, vtype, vtype>
                                                                        (expr_gen, id, t, sf3node, result);
 
                   default                                      : return false;
@@ -29401,7 +29820,7 @@ namespace exprtk
                   T1 t1 = n->t1();
                   T2 t2 = n->t2();
 
-                  return synthesize_sf4ext_expression::template compile<ExternalType,T0,T1,T2>
+                  return synthesize_sf4ext_expression::template compile<ExternalType, T0, T1, T2>
                             (expr_gen, id, t, t0, t1, t2, result);
                }
                else
@@ -29423,7 +29842,7 @@ namespace exprtk
                   T1 t1 = n->t1();
                   T2 t2 = n->t2();
 
-                  return synthesize_sf4ext_expression::template compile<T0,T1,T2,ExternalType>
+                  return synthesize_sf4ext_expression::template compile<T0, T1, T2, ExternalType>
                             (expr_gen, id, t0, t1, t2, t, result);
                }
                else
@@ -29487,7 +29906,10 @@ namespace exprtk
             static inline std::string id(expression_generator<Type>& expr_gen,
                                          const details::operator_type o0, const details::operator_type o1)
             {
-               return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t");
+               return details::build_string()
+                         << "(t" << expr_gen.to_str(o0)
+                         << "t)" << expr_gen.to_str(o1)
+                         << "t";
             }
          };
 
@@ -29547,7 +29969,10 @@ namespace exprtk
             static inline std::string id(expression_generator<Type>& expr_gen,
                                          const details::operator_type o0, const details::operator_type o1)
             {
-               return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)");
+               return details::build_string()
+                         << "t"  << expr_gen.to_str(o0)
+                         << "(t" << expr_gen.to_str(o1)
+                         << "t)";
             }
          };
 
@@ -29608,7 +30033,10 @@ namespace exprtk
             static inline std::string id(expression_generator<Type>& expr_gen,
                                          const details::operator_type o0, const details::operator_type o1)
             {
-               return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t");
+               return details::build_string()
+                         << "(t" << expr_gen.to_str(o0)
+                         << "t)" << expr_gen.to_str(o1)
+                         << "t";
             }
          };
 
@@ -29668,7 +30096,10 @@ namespace exprtk
             static inline std::string id(expression_generator<Type>& expr_gen,
                                          const details::operator_type o0, const details::operator_type o1)
             {
-               return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)");
+               return details::build_string()
+                         << "t"  << expr_gen.to_str(o0)
+                         << "(t" << expr_gen.to_str(o1)
+                         << "t)";
             }
          };
 
@@ -29728,7 +30159,10 @@ namespace exprtk
             static inline std::string id(expression_generator<Type>& expr_gen,
                                          const details::operator_type o0, const details::operator_type o1)
             {
-               return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t");
+               return details::build_string()
+                         << "(t" << expr_gen.to_str(o0)
+                         << "t)" << expr_gen.to_str(o1)
+                         << "t";
             }
          };
 
@@ -29788,7 +30222,10 @@ namespace exprtk
             static inline std::string id(expression_generator<Type>& expr_gen,
                                          const details::operator_type o0, const details::operator_type o1)
             {
-               return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)");
+               return details::build_string()
+                         << "t"  << expr_gen.to_str(o0)
+                         << "(t" << expr_gen.to_str(o1)
+                         << "t)";
             }
          };
 
@@ -29848,7 +30285,10 @@ namespace exprtk
             static inline std::string id(expression_generator<Type>& expr_gen,
                                          const details::operator_type o0, const details::operator_type o1)
             {
-               return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t");
+               return details::build_string()
+                         << "(t" << expr_gen.to_str(o0)
+                         << "t)" << expr_gen.to_str(o1)
+                         << "t";
             }
          };
 
@@ -29908,7 +30348,10 @@ namespace exprtk
 
             static inline std::string id(expression_generator<Type>& expr_gen, const details::operator_type o0, const details::operator_type o1)
             {
-               return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)");
+               return details::build_string()
+                         << "t"  << expr_gen.to_str(o0)
+                         << "(t" << expr_gen.to_str(o1)
+                         << "t)";
             }
          };
 
@@ -30022,7 +30465,10 @@ namespace exprtk
             static inline std::string id(expression_generator<Type>& expr_gen,
                                          const details::operator_type o0, const details::operator_type o1)
             {
-               return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t");
+               return details::build_string()
+                         << "(t" << expr_gen.to_str(o0)
+                         << "t)" << expr_gen.to_str(o1)
+                         << "t";
             }
          };
 
@@ -30136,7 +30582,10 @@ namespace exprtk
             static inline std::string id(expression_generator<Type>& expr_gen,
                                          const details::operator_type o0, const details::operator_type o1)
             {
-               return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)");
+               return details::build_string()
+                         << "t"  << expr_gen.to_str(o0)
+                         << "(t" << expr_gen.to_str(o1)
+                         << "t)";
             }
          };
 
@@ -30259,7 +30708,10 @@ namespace exprtk
 
             static inline std::string id(expression_generator<Type>& expr_gen, const details::operator_type o0, const details::operator_type o1)
             {
-               return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)");
+               return details::build_string()
+                         << "t"  << expr_gen.to_str(o0)
+                         << "(t" << expr_gen.to_str(o1)
+                         << "t)";
             }
          };
 
@@ -30381,7 +30833,10 @@ namespace exprtk
             static inline std::string id(expression_generator<Type>& expr_gen,
                                          const details::operator_type o0, const details::operator_type o1)
             {
-               return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t");
+               return details::build_string()
+                         << "(t" << expr_gen.to_str(o0)
+                         << "t)" << expr_gen.to_str(o1)
+                         << "t";
             }
          };
 
@@ -30510,7 +30965,11 @@ namespace exprtk
                                          const details::operator_type o1,
                                          const details::operator_type o2)
             {
-               return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)");
+               return details::build_string()
+                         << "(t" << expr_gen.to_str(o0)
+                         << "t)" << expr_gen.to_str(o1)
+                         << "(t" << expr_gen.to_str(o2)
+                         << "t)";
             }
          };
 
@@ -30594,7 +31053,11 @@ namespace exprtk
                                          const details::operator_type o1,
                                          const details::operator_type o2)
             {
-               return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)");
+               return details::build_string()
+                         << "(t" << expr_gen.to_str(o0)
+                         << "t)" << expr_gen.to_str(o1)
+                         << "(t" << expr_gen.to_str(o2)
+                         << "t)";
             }
          };
 
@@ -30678,7 +31141,11 @@ namespace exprtk
                                          const details::operator_type o1,
                                          const details::operator_type o2)
             {
-               return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)");
+               return details::build_string()
+                         << "(t" << expr_gen.to_str(o0)
+                         << "t)" << expr_gen.to_str(o1)
+                         << "(t" << expr_gen.to_str(o2)
+                         << "t)";
             }
          };
 
@@ -30762,7 +31229,11 @@ namespace exprtk
                                          const details::operator_type o1,
                                          const details::operator_type o2)
             {
-               return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)");
+               return details::build_string()
+                         << "(t" << expr_gen.to_str(o0)
+                         << "t)" << expr_gen.to_str(o1)
+                         << "(t" << expr_gen.to_str(o2)
+                         << "t)";
             }
          };
 
@@ -30846,7 +31317,11 @@ namespace exprtk
                                          const details::operator_type o1,
                                          const details::operator_type o2)
             {
-               return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)");
+               return details::build_string()
+                         << "(t" << expr_gen.to_str(o0)
+                         << "t)" << expr_gen.to_str(o1)
+                         << "(t" << expr_gen.to_str(o2)
+                         << "t)";
             }
          };
 
@@ -31035,7 +31510,11 @@ namespace exprtk
                                          const details::operator_type o1,
                                          const details::operator_type o2)
             {
-               return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)");
+               return details::build_string()
+                         << "(t" << expr_gen.to_str(o0)
+                         << "t)" << expr_gen.to_str(o1)
+                         << "(t" << expr_gen.to_str(o2)
+                         << "t)";
             }
          };
 
@@ -31274,7 +31753,11 @@ namespace exprtk
                                          const details::operator_type o1,
                                          const details::operator_type o2)
             {
-               return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)");
+               return details::build_string()
+                         << "(t" << expr_gen.to_str(o0)
+                         << "t)" << expr_gen.to_str(o1)
+                         << "(t" << expr_gen.to_str(o2)
+                         << "t)";
             }
          };
 
@@ -31463,7 +31946,11 @@ namespace exprtk
                                          const details::operator_type o1,
                                          const details::operator_type o2)
             {
-               return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)");
+               return details::build_string()
+                         << "(t" << expr_gen.to_str(o0)
+                         << "t)" << expr_gen.to_str(o1)
+                         << "(t" << expr_gen.to_str(o2)
+                         << "t)";
             }
          };
 
@@ -31651,7 +32138,11 @@ namespace exprtk
                                          const details::operator_type o1,
                                          const details::operator_type o2)
             {
-               return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)");
+               return details::build_string()
+                         << "(t" << expr_gen.to_str(o0)
+                         << "t)" << expr_gen.to_str(o1)
+                         << "(t" << expr_gen.to_str(o2)
+                         << "t)";
             }
          };
 
@@ -31703,7 +32194,11 @@ namespace exprtk
                                          const details::operator_type o1,
                                          const details::operator_type o2)
             {
-               return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))");
+               return details::build_string()
+                         << "t"  << expr_gen.to_str(o0)
+                         << "(t" << expr_gen.to_str(o1)
+                         << "(t" << expr_gen.to_str(o2)
+                         << "t))";
             }
          };
 
@@ -31759,7 +32254,11 @@ namespace exprtk
                                          const details::operator_type o1,
                                          const details::operator_type o2)
             {
-               return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))");
+               return details::build_string()
+                         << "t"  << expr_gen.to_str(o0)
+                         << "(t" << expr_gen.to_str(o1)
+                         << "(t" << expr_gen.to_str(o2)
+                         << "t))";
             }
          };
 
@@ -31815,7 +32314,11 @@ namespace exprtk
                                          const details::operator_type o1,
                                          const details::operator_type o2)
             {
-               return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))");
+               return details::build_string()
+                         << "t"  << expr_gen.to_str(o0)
+                         << "(t" << expr_gen.to_str(o1)
+                         << "(t" << expr_gen.to_str(o2)
+                         << "t))";
             }
          };
 
@@ -31871,7 +32374,11 @@ namespace exprtk
                                          const details::operator_type o1,
                                          const details::operator_type o2)
             {
-               return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))");
+               return details::build_string()
+                         << "t"  << expr_gen.to_str(o0)
+                         << "(t" << expr_gen.to_str(o1)
+                         << "(t" << expr_gen.to_str(o2)
+                         << "t))";
             }
          };
 
@@ -31928,7 +32435,11 @@ namespace exprtk
                                          const details::operator_type o1,
                                          const details::operator_type o2)
             {
-               return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))");
+               return details::build_string()
+                         << "t"  << expr_gen.to_str(o0)
+                         << "(t" << expr_gen.to_str(o1)
+                         << "(t" << expr_gen.to_str(o2)
+                         << "t))";
             }
          };
 
@@ -31985,7 +32496,11 @@ namespace exprtk
                                          const details::operator_type o1,
                                          const details::operator_type o2)
             {
-               return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))");
+               return details::build_string()
+                         << "t"  << expr_gen.to_str(o0)
+                         << "(t" << expr_gen.to_str(o1)
+                         << "(t" << expr_gen.to_str(o2)
+                         << "t))";
             }
          };
 
@@ -32041,7 +32556,11 @@ namespace exprtk
                                          const details::operator_type o1,
                                          const details::operator_type o2)
             {
-               return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))");
+               return details::build_string()
+                         << "t"  << expr_gen.to_str(o0)
+                         << "(t" << expr_gen.to_str(o1)
+                         << "(t" << expr_gen.to_str(o2)
+                         << "t))";
             }
          };
 
@@ -32097,7 +32616,11 @@ namespace exprtk
                                          const details::operator_type o1,
                                          const details::operator_type o2)
             {
-               return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))");
+               return details::build_string()
+                         << "t"  << expr_gen.to_str(o0)
+                         << "(t" << expr_gen.to_str(o1)
+                         << "(t" << expr_gen.to_str(o2)
+                         << "t))";
             }
          };
 
@@ -32153,7 +32676,11 @@ namespace exprtk
                                          const details::operator_type o1,
                                          const details::operator_type o2)
             {
-               return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))");
+               return details::build_string()
+                         << "t"  << expr_gen.to_str(o0)
+                         << "(t" << expr_gen.to_str(o1)
+                         << "(t" << expr_gen.to_str(o2)
+                         << "t))";
             }
          };
 
@@ -32209,7 +32736,11 @@ namespace exprtk
                                          const details::operator_type o1,
                                          const details::operator_type o2)
             {
-               return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)");
+               return details::build_string()
+                         << "t"   << expr_gen.to_str(o0)
+                         << "((t" << expr_gen.to_str(o1)
+                         << "t)"  << expr_gen.to_str(o2)
+                         << "t)";
             }
          };
 
@@ -32265,7 +32796,11 @@ namespace exprtk
                                          const details::operator_type o1,
                                          const details::operator_type o2)
             {
-               return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)");
+               return details::build_string()
+                         << "t"   << expr_gen.to_str(o0)
+                         << "((t" << expr_gen.to_str(o1)
+                         << "t)"  << expr_gen.to_str(o2)
+                         << "t)";
             }
          };
 
@@ -32321,7 +32856,11 @@ namespace exprtk
                                          const details::operator_type o1,
                                          const details::operator_type o2)
             {
-               return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)");
+               return details::build_string()
+                         << "t"   << expr_gen.to_str(o0)
+                         << "((t" << expr_gen.to_str(o1)
+                         << "t)"  << expr_gen.to_str(o2)
+                         << "t)";
             }
          };
 
@@ -32377,7 +32916,11 @@ namespace exprtk
                                          const details::operator_type o1,
                                          const details::operator_type o2)
             {
-               return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)");
+               return details::build_string()
+                         << "t"   << expr_gen.to_str(o0)
+                         << "((t" << expr_gen.to_str(o1)
+                         << "t)"  << expr_gen.to_str(o2)
+                         << "t)";
             }
          };
 
@@ -32434,7 +32977,11 @@ namespace exprtk
                                          const details::operator_type o1,
                                          const details::operator_type o2)
             {
-               return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)");
+               return details::build_string()
+                         << "t"   << expr_gen.to_str(o0)
+                         << "((t" << expr_gen.to_str(o1)
+                         << "t)"  << expr_gen.to_str(o2)
+                         << "t)";
             }
         };
 
@@ -32491,7 +33038,11 @@ namespace exprtk
                                          const details::operator_type o1,
                                          const details::operator_type o2)
             {
-               return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)");
+               return details::build_string()
+                         << "t"   << expr_gen.to_str(o0)
+                         << "((t" << expr_gen.to_str(o1)
+                         << "t)"  << expr_gen.to_str(o2)
+                         << "t)";
             }
          };
 
@@ -32547,7 +33098,11 @@ namespace exprtk
                                          const details::operator_type o1,
                                          const details::operator_type o2)
             {
-               return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)");
+               return details::build_string()
+                         << "t"   << expr_gen.to_str(o0)
+                         << "((t" << expr_gen.to_str(o1)
+                         << "t)"  << expr_gen.to_str(o2)
+                         << "t)";
             }
          };
 
@@ -32604,7 +33159,11 @@ namespace exprtk
                                          const details::operator_type o1,
                                          const details::operator_type o2)
             {
-               return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)");
+               return details::build_string()
+                         << "t"   << expr_gen.to_str(o0)
+                         << "((t" << expr_gen.to_str(o1)
+                         << "t)"  << expr_gen.to_str(o2)
+                         << "t)";
             }
          };
 
@@ -32677,7 +33236,11 @@ namespace exprtk
                                          const details::operator_type o1,
                                          const details::operator_type o2)
             {
-               return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t");
+               return details::build_string()
+                         << "((t" << expr_gen.to_str(o0)
+                         << "t)"  << expr_gen.to_str(o1)
+                         << "t)"  << expr_gen.to_str(o2)
+                         << "t";
             }
          };
 
@@ -32734,7 +33297,11 @@ namespace exprtk
                                          const details::operator_type o1,
                                          const details::operator_type o2)
             {
-               return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t");
+               return details::build_string()
+                         << "((t" << expr_gen.to_str(o0)
+                         << "t)"  << expr_gen.to_str(o1)
+                         << "t)"  << expr_gen.to_str(o2)
+                         << "t";
             }
          };
 
@@ -32790,7 +33357,11 @@ namespace exprtk
                                          const details::operator_type o1,
                                          const details::operator_type o2)
             {
-               return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t");
+               return details::build_string()
+                         << "((t" << expr_gen.to_str(o0)
+                         << "t)"  << expr_gen.to_str(o1)
+                         << "t)"  << expr_gen.to_str(o2)
+                         << "t";
             }
          };
 
@@ -32846,7 +33417,11 @@ namespace exprtk
                                          const details::operator_type o1,
                                          const details::operator_type o2)
             {
-               return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t");
+               return details::build_string()
+                         << "((t" << expr_gen.to_str(o0)
+                         << "t)"  << expr_gen.to_str(o1)
+                         << "t)"  << expr_gen.to_str(o2)
+                         << "t";
             }
          };
 
@@ -32902,7 +33477,11 @@ namespace exprtk
                                          const details::operator_type o1,
                                          const details::operator_type o2)
             {
-               return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t");
+               return details::build_string()
+                         << "((t" << expr_gen.to_str(o0)
+                         << "t)"  << expr_gen.to_str(o1)
+                         << "t)"  << expr_gen.to_str(o2)
+                         << "t";
             }
          };
 
@@ -32958,7 +33537,11 @@ namespace exprtk
                                          const details::operator_type o1,
                                          const details::operator_type o2)
             {
-               return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t");
+               return details::build_string()
+                         << "((t" << expr_gen.to_str(o0)
+                         << "t)"  << expr_gen.to_str(o1)
+                         << "t)"  << expr_gen.to_str(o2)
+                         << "t";
             }
          };
 
@@ -33015,7 +33598,11 @@ namespace exprtk
                                          const details::operator_type o1,
                                          const details::operator_type o2)
             {
-               return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t");
+               return details::build_string()
+                         << "((t" << expr_gen.to_str(o0)
+                         << "t)"  << expr_gen.to_str(o1)
+                         << "t)"  << expr_gen.to_str(o2)
+                         << "t";
             }
          };
 
@@ -33072,7 +33659,11 @@ namespace exprtk
                                          const details::operator_type o1,
                                          const details::operator_type o2)
             {
-               return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t");
+               return details::build_string()
+                         << "((t" << expr_gen.to_str(o0)
+                         << "t)"  << expr_gen.to_str(o1)
+                         << "t)"  << expr_gen.to_str(o2)
+                         << "t";
             }
          };
 
@@ -33128,7 +33719,11 @@ namespace exprtk
                                          const details::operator_type o1,
                                          const details::operator_type o2)
             {
-               return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t");
+               return details::build_string()
+                         << "((t" << expr_gen.to_str(o0)
+                         << "t)"  << expr_gen.to_str(o1)
+                         << "t)"  << expr_gen.to_str(o2)
+                         << "t";
             }
          };
 
@@ -33184,7 +33779,11 @@ namespace exprtk
                                          const details::operator_type o1,
                                          const details::operator_type o2)
             {
-               return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t");
+               return details::build_string()
+                         << "(t" << expr_gen.to_str(o0)
+                         << "(t" << expr_gen.to_str(o1)
+                         << "t)" << expr_gen.to_str(o2)
+                         << "t";
             }
          };
 
@@ -33241,7 +33840,11 @@ namespace exprtk
                                          const details::operator_type o1,
                                          const details::operator_type o2)
             {
-               return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t");
+               return details::build_string()
+                         << "(t" << expr_gen.to_str(o0)
+                         << "(t" << expr_gen.to_str(o1)
+                         << "t)" << expr_gen.to_str(o2)
+                         << "t";
             }
          };
 
@@ -33297,7 +33900,11 @@ namespace exprtk
                                          const details::operator_type o1,
                                          const details::operator_type o2)
             {
-               return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t");
+               return details::build_string()
+                         << "(t" << expr_gen.to_str(o0)
+                         << "(t" << expr_gen.to_str(o1)
+                         << "t)" << expr_gen.to_str(o2)
+                         << "t";
             }
          };
 
@@ -33352,7 +33959,11 @@ namespace exprtk
                                          const details::operator_type o1,
                                          const details::operator_type o2)
             {
-               return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t");
+               return details::build_string()
+                         << "(t" << expr_gen.to_str(o0)
+                         << "(t" << expr_gen.to_str(o1)
+                         << "t)" << expr_gen.to_str(o2)
+                         << "t";
             }
          };
 
@@ -33408,7 +34019,11 @@ namespace exprtk
                                          const details::operator_type o1,
                                          const details::operator_type o2)
             {
-               return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t");
+               return details::build_string()
+                         << "(t" << expr_gen.to_str(o0)
+                         << "(t" << expr_gen.to_str(o1)
+                         << "t)" << expr_gen.to_str(o2)
+                         << "t";
             }
          };
 
@@ -33464,7 +34079,11 @@ namespace exprtk
                                          const details::operator_type o1,
                                          const details::operator_type o2)
             {
-               return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t");
+               return details::build_string()
+                         << "(t" << expr_gen.to_str(o0)
+                         << "(t" << expr_gen.to_str(o1)
+                         << "t)" << expr_gen.to_str(o2)
+                         << "t";
             }
          };
 
@@ -33521,7 +34140,11 @@ namespace exprtk
                                          const details::operator_type o1,
                                          const details::operator_type o2)
             {
-               return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t");
+               return details::build_string()
+                         << "(t" << expr_gen.to_str(o0)
+                         << "(t" << expr_gen.to_str(o1)
+                         << "t)" << expr_gen.to_str(o2)
+                         << "t";
             }
          };
 
@@ -33578,7 +34201,11 @@ namespace exprtk
                                          const details::operator_type o1,
                                          const details::operator_type o2)
             {
-               return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t");
+               return details::build_string()
+                         << "(t" << expr_gen.to_str(o0)
+                         << "(t" << expr_gen.to_str(o1)
+                         << "t)" << expr_gen.to_str(o2)
+                         << "t";
             }
          };
 
@@ -34125,9 +34752,9 @@ namespace exprtk
                std::string& s1 = static_cast<details::stringvar_node<Type>*>(branch[1])->ref();
                std::string& s2 = static_cast<details::stringvar_node<Type>*>(branch[2])->ref();
 
-               typedef typename details::sosos_node<Type,std::string&,std::string&,std::string&,details::inrange_op<Type> > inrange_t;
+               typedef typename details::sosos_node<Type, std::string&, std::string&, std::string&, details::inrange_op<Type> > inrange_t;
 
-               return node_allocator_->allocate_type<inrange_t,std::string&,std::string&,std::string&>(s0,s1,s2);
+               return node_allocator_->allocate_type<inrange_t, std::string&, std::string&, std::string&>(s0, s1, s2);
             }
             else if (
                       details::is_const_string_node(branch[0]) &&
@@ -34139,12 +34766,12 @@ namespace exprtk
                std::string& s1 = static_cast<     details::stringvar_node<Type>*>(branch[1])->ref();
                std::string  s2 = static_cast<details::string_literal_node<Type>*>(branch[2])->str();
 
-               typedef typename details::sosos_node<Type,std::string,std::string&,std::string,details::inrange_op<Type> > inrange_t;
+               typedef typename details::sosos_node<Type, std::string, std::string&, std::string, details::inrange_op<Type> > inrange_t;
 
                details::free_node(*node_allocator_,branch[0]);
                details::free_node(*node_allocator_,branch[2]);
 
-               return node_allocator_->allocate_type<inrange_t,std::string,std::string&,std::string>(s0,s1,s2);
+               return node_allocator_->allocate_type<inrange_t, std::string, std::string&, std::string>(s0, s1, s2);
             }
             else if (
                             details::is_string_node(branch[0]) &&
@@ -34156,11 +34783,11 @@ namespace exprtk
                std::string   s1 = static_cast<details::string_literal_node<Type>*>(branch[1])->str();
                std::string&  s2 = static_cast<     details::stringvar_node<Type>*>(branch[2])->ref();
 
-               typedef typename details::sosos_node<Type,std::string&,std::string,std::string&,details::inrange_op<Type> > inrange_t;
+               typedef typename details::sosos_node<Type, std::string&, std::string, std::string&, details::inrange_op<Type> > inrange_t;
 
                details::free_node(*node_allocator_,branch[1]);
 
-               return node_allocator_->allocate_type<inrange_t,std::string&,std::string,std::string&>(s0,s1,s2);
+               return node_allocator_->allocate_type<inrange_t, std::string&, std::string, std::string&>(s0, s1, s2);
             }
             else if (
                       details::is_string_node(branch[0]) &&
@@ -34172,11 +34799,11 @@ namespace exprtk
                std::string& s1 = static_cast<     details::stringvar_node<Type>*>(branch[1])->ref();
                std::string  s2 = static_cast<details::string_literal_node<Type>*>(branch[2])->str();
 
-               typedef typename details::sosos_node<Type,std::string&,std::string&,std::string,details::inrange_op<Type> > inrange_t;
+               typedef typename details::sosos_node<Type, std::string&, std::string&, std::string, details::inrange_op<Type> > inrange_t;
 
                details::free_node(*node_allocator_,branch[2]);
 
-               return node_allocator_->allocate_type<inrange_t,std::string&,std::string&,std::string>(s0,s1,s2);
+               return node_allocator_->allocate_type<inrange_t, std::string&, std::string&, std::string>(s0, s1, s2);
             }
             else if (
                       details::is_const_string_node(branch[0]) &&
@@ -34188,11 +34815,11 @@ namespace exprtk
                std::string& s1 = static_cast<     details::stringvar_node<Type>*>(branch[1])->ref();
                std::string& s2 = static_cast<     details::stringvar_node<Type>*>(branch[2])->ref();
 
-               typedef typename details::sosos_node<Type,std::string,std::string&,std::string&,details::inrange_op<Type> > inrange_t;
+               typedef typename details::sosos_node<Type, std::string, std::string&, std::string&, details::inrange_op<Type> > inrange_t;
 
                details::free_node(*node_allocator_,branch[0]);
 
-               return node_allocator_->allocate_type<inrange_t,std::string,std::string&,std::string&>(s0,s1,s2);
+               return node_allocator_->allocate_type<inrange_t, std::string, std::string&, std::string&>(s0, s1, s2);
             }
             else
                return error_node();
@@ -34692,13 +35319,14 @@ namespace exprtk
 
       lexer::helper::helper_assembly helper_assembly_;
 
-      lexer::helper::commutative_inserter commutative_inserter_;
-      lexer::helper::operator_joiner      operator_joiner_2_;
-      lexer::helper::operator_joiner      operator_joiner_3_;
-      lexer::helper::symbol_replacer      symbol_replacer_;
-      lexer::helper::bracket_checker      bracket_checker_;
-      lexer::helper::numeric_checker      numeric_checker_;
-      lexer::helper::sequence_validator   sequence_validator_;
+      lexer::helper::commutative_inserter       commutative_inserter_;
+      lexer::helper::operator_joiner            operator_joiner_2_;
+      lexer::helper::operator_joiner            operator_joiner_3_;
+      lexer::helper::symbol_replacer            symbol_replacer_;
+      lexer::helper::bracket_checker            bracket_checker_;
+      lexer::helper::numeric_checker            numeric_checker_;
+      lexer::helper::sequence_validator         sequence_validator_;
+      lexer::helper::sequence_validator_3tokens sequence_validator_3tkns_;
 
       template <typename ParserType>
       friend void details::disable_type_checking(ParserType& p);
@@ -35875,7 +36503,7 @@ namespace exprtk
       def_fp_retval(6)
 
       template <typename Allocator,
-                template <typename,typename> class Sequence>
+                template <typename, typename> class Sequence>
       inline bool add(const std::string& name,
                       const std::string& expression,
                       const Sequence<std::string,Allocator>& var_list,
@@ -35971,7 +36599,7 @@ namespace exprtk
    private:
 
       template <typename Allocator,
-                template <typename,typename> class Sequence>
+                template <typename, typename> class Sequence>
       bool compile_expression(const std::string& name,
                               const std::string& expression,
                               const Sequence<std::string,Allocator>& input_var_list,
@@ -36290,8 +36918,8 @@ namespace exprtk
          {
             static const T lower_bound = T(-20);
             static const T upper_bound = T(+20);
+            static const T delta       = T(0.1);
 
-            T delta = T(0.1);
             T total = T(0);
 
             for (x = lower_bound; x <= upper_bound; x += delta)
@@ -36315,7 +36943,7 @@ namespace exprtk
       {
          for (std::size_t i = 0; i < 10000; ++i)
          {
-            T v = T(123.456 + i);
+            const T v = T(123.456 + i);
 
             if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T, 1>::result(v),details::numeric::pow(v,T( 1)))))
                return false;
@@ -36758,7 +37386,7 @@ namespace exprtk
             }
          }
 
-         bool eof()
+         bool eof() const
          {
             switch (mode)
             {
@@ -36769,7 +37397,7 @@ namespace exprtk
             }
          }
 
-         file_mode get_file_mode(const std::string& access)
+         file_mode get_file_mode(const std::string& access) const
          {
             if (access.empty() || access.size() > 2)
                return e_error;
@@ -36847,11 +37475,9 @@ namespace exprtk
 
       inline T operator() (const std::size_t& ps_index, parameter_list_t parameters)
       {
-         std::string file_name;
+         std::string file_name = to_str(string_t(parameters[0]));
          std::string access;
 
-         file_name = to_str(string_t(parameters[0]));
-
          if (file_name.empty())
             return T(0);
 
@@ -36932,27 +37558,27 @@ namespace exprtk
             case 0  : {
                          const string_t buffer(parameters[1]);
                          amount = buffer.size();
-                         return T(fd->write(buffer,amount) ? 1 : 0);
+                         return T(fd->write(buffer, amount) ? 1 : 0);
                       }
 
             case 1  : {
                          const string_t buffer(parameters[1]);
                          amount = std::min(buffer.size(),
                                            static_cast<std::size_t>(scalar_t(parameters[2])()));
-                         return T(fd->write(buffer,amount) ? 1 : 0);
+                         return T(fd->write(buffer, amount) ? 1 : 0);
                       }
 
             case 2  : {
                          const vector_t vec(parameters[1]);
                          amount = vec.size();
-                         return T(fd->write(vec,amount) ? 1 : 0);
+                         return T(fd->write(vec, amount) ? 1 : 0);
                       }
 
             case 3  : {
                          const vector_t vec(parameters[1]);
                          amount = std::min(vec.size(),
                                            static_cast<std::size_t>(scalar_t(parameters[2])()));
-                         return T(fd->write(vec,amount) ? 1 : 0);
+                         return T(fd->write(vec, amount) ? 1 : 0);
                       }
          }
 
@@ -37153,10 +37779,10 @@ namespace exprtk
    namespace details
    {
       template <typename T>
-      inline void kahan_sum(T& sum, T& error, T v)
+      inline void kahan_sum(T& sum, T& error, const T v)
       {
-         T x = v - error;
-         T y = sum + x;
+         const T x = v - error;
+         const T y = sum + x;
          error = (y - sum) - x;
          sum = y;
       }
@@ -37877,10 +38503,10 @@ namespace exprtk
 
          if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters, r0, r1, 3, 4, 1))
             return std::numeric_limits<T>::quiet_NaN();
-         else if (helper::invalid_range(y,r0,r1))
+         else if (helper::invalid_range(y, r0, r1))
             return std::numeric_limits<T>::quiet_NaN();
 
-         T a = scalar_t(parameters[0])();
+         const T a = scalar_t(parameters[0])();
 
          for (std::size_t i = r0; i <= r1; ++i)
          {
@@ -37924,7 +38550,7 @@ namespace exprtk
 
          if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters, r0, r1, 4, 5, 1))
             return std::numeric_limits<T>::quiet_NaN();
-         else if (helper::invalid_range(y,r0,r1))
+         else if (helper::invalid_range(y, r0, r1))
             return std::numeric_limits<T>::quiet_NaN();
 
          const T a = scalar_t(parameters[0])();
@@ -37973,12 +38599,12 @@ namespace exprtk
 
          if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters, r0, r1, 3, 4, 1))
             return std::numeric_limits<T>::quiet_NaN();
-         else if (helper::invalid_range(y,r0,r1))
+         else if (helper::invalid_range(y, r0, r1))
             return std::numeric_limits<T>::quiet_NaN();
-         else if (helper::invalid_range(z,r0,r1))
+         else if (helper::invalid_range(z, r0, r1))
             return std::numeric_limits<T>::quiet_NaN();
 
-         T a = scalar_t(parameters[0])();
+         const T a = scalar_t(parameters[0])();
 
          for (std::size_t i = r0; i <= r1; ++i)
          {
@@ -38023,9 +38649,9 @@ namespace exprtk
 
          if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters, r0, r1, 4, 5, 1))
             return std::numeric_limits<T>::quiet_NaN();
-         else if (helper::invalid_range(y,r0,r1))
+         else if (helper::invalid_range(y, r0, r1))
             return std::numeric_limits<T>::quiet_NaN();
-         else if (helper::invalid_range(z,r0,r1))
+         else if (helper::invalid_range(z, r0, r1))
             return std::numeric_limits<T>::quiet_NaN();
 
          const T a = scalar_t(parameters[0])();
@@ -38073,7 +38699,7 @@ namespace exprtk
 
          if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters, r0, r1, 4, 5, 1))
             return std::numeric_limits<T>::quiet_NaN();
-         else if (helper::invalid_range(z,r0,r1))
+         else if (helper::invalid_range(z, r0, r1))
             return std::numeric_limits<T>::quiet_NaN();
 
          const T a = scalar_t(parameters[0])();
@@ -38120,7 +38746,7 @@ namespace exprtk
 
          if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters, r0, r1, 2, 3, 0))
             return std::numeric_limits<T>::quiet_NaN();
-         else if (helper::invalid_range(y,r0,r1))
+         else if (helper::invalid_range(y, r0, r1))
             return std::numeric_limits<T>::quiet_NaN();
 
          T result = T(0);
@@ -38166,7 +38792,7 @@ namespace exprtk
 
          if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters, r0, r1, 2, 3, 0))
             return std::numeric_limits<T>::quiet_NaN();
-         else if (helper::invalid_range(y,r0,r1))
+         else if (helper::invalid_range(y, r0, r1))
             return std::numeric_limits<T>::quiet_NaN();
 
          T result = T(0);
@@ -38222,7 +38848,7 @@ namespace exprtk
          exprtk_register_function("any_true"     ,nt)
          exprtk_register_function("any_false"    ,nf)
          exprtk_register_function("count"        , c)
-         exprtk_register_function("copy"        , cp)
+         exprtk_register_function("copy"         ,cp)
          exprtk_register_function("rotate_left"  ,rl)
          exprtk_register_function("rol"          ,rl)
          exprtk_register_function("rotate_right" ,rr)
@@ -38256,9 +38882,9 @@ namespace exprtk
    namespace information
    {
       static const char* library = "Mathematical Expression Toolkit";
-      static const char* version = "2.71828182845904523536028747135266249775724709369"
-                                   "9959574966967627724076630353547594571382178525166";
-      static const char* date    = "20180101";
+      static const char* version = "2.71828182845904523536028747135266249775724709369995957"
+                                   "4966967627724076630353547594571382178525166427427466391";
+      static const char* date    = "20190818";
 
       static inline std::string data()
       {
diff --git a/src/executiontree/ExecutionTree.cpp b/src/executiontree/ExecutionTree.cpp
index b273897077c8acaa14be191596c6b1b7ca272b21..346b089ecd22d2072bd7ca47fa2054ca684767f2 100644
--- a/src/executiontree/ExecutionTree.cpp
+++ b/src/executiontree/ExecutionTree.cpp
@@ -125,7 +125,7 @@ void EveryNth::operator()()
    ++calls_;
 }
 
-const std::string EveryNth::getName() const
+std::string EveryNth::getName() const
 {
    std::stringstream ss;
    ss << "every " << interval_ << "th step:";
@@ -208,7 +208,7 @@ void Loop::synchronizedStop( bool stopVar )
    mpi::allReduceInplace( stop_, mpi::LOGICAL_OR );
 }
 
-const std::string Loop::getName() const
+std::string Loop::getName() const
 {
    std::stringstream ss;
    ss << "Loop [" << iterations_ << "]";
diff --git a/src/executiontree/ExecutionTree.h b/src/executiontree/ExecutionTree.h
index 99b3515a5c834a5c70e5327f344edc1766f56a73..f9c838ec63cc7ff8b5f01e02d962d3b9c9d6e36f 100644
--- a/src/executiontree/ExecutionTree.h
+++ b/src/executiontree/ExecutionTree.h
@@ -109,8 +109,8 @@ class IFunctionNode
 public:
    virtual ~IFunctionNode() {}
    virtual void operator()() = 0;
-   virtual const std::string getName() const = 0;
-   virtual const std::deque< shared_ptr< IFunctionNode > > getChildren() const { return {}; }
+   virtual std::string getName() const = 0;
+   virtual std::deque< shared_ptr< IFunctionNode > > getChildren() const { return {}; }
 };
 
 
@@ -122,7 +122,7 @@ public:
            const std::string &name,
            const TimingTreePtr & timingTree );
 
-   const std::string getName() const override { return name_ != "" ? name_ : "Functor"; };
+   std::string getName() const override { return name_ != "" ? name_ : "Functor"; };
    void operator() () override;
 
 private:
@@ -138,8 +138,8 @@ public:
    EveryNth( const IFunctionNodePtr &node, uint_t interval, bool onFirst = false, uint_t startValue = 0 );
 
    void operator()() override;
-   const std::string getName() const override;
-   const std::deque< shared_ptr< IFunctionNode > > getChildren() const override { return { wrapped_ }; }
+   std::string getName() const override;
+   std::deque< shared_ptr< IFunctionNode > > getChildren() const override { return { wrapped_ }; }
 
 private:
    IFunctionNodePtr wrapped_;
@@ -158,8 +158,8 @@ public:
 
    void push_back( const IFunctionNodePtr &fct ) { children_.push_back( fct ); }
    void push_front( const IFunctionNodePtr &fct ) { children_.push_front( fct ); }
-   const std::string getName() const override { return name_ != "" ? name_ : "Sequence"; };
-   const std::deque< IFunctionNodePtr > getChildren() const override { return children_; };
+   std::string getName() const override { return name_ != "" ? name_ : "Sequence"; };
+   std::deque< IFunctionNodePtr > getChildren() const override { return children_; };
 
 private:
    std::string name_;
@@ -185,8 +185,8 @@ public:
    uint_t getCurrentTimeStep() const override { return currentIteration_; }
    uint_t getNrOfTimeSteps() const override { return iterations_; }
 
-   const std::deque< shared_ptr< IFunctionNode > > getChildren() const override { return { body_ }; }
-   const std::string getName()  const override;
+   std::deque< shared_ptr< IFunctionNode > > getChildren() const override { return { body_ }; }
+   std::string getName()  const override;
 
 private:
    IFunctionNodePtr body_;
@@ -203,4 +203,4 @@ private:
 } // namespace walberla
 
 
-#include "ExecutionTree.impl.h"
\ No newline at end of file
+#include "ExecutionTree.impl.h"
diff --git a/src/gather/MPIGatherScheme.cpp b/src/gather/MPIGatherScheme.cpp
index c40a63c691255072678aa70c9621fc38583e08f9..1fc309303fbced68844561da221c1fd833f6a008 100644
--- a/src/gather/MPIGatherScheme.cpp
+++ b/src/gather/MPIGatherScheme.cpp
@@ -169,7 +169,7 @@ void MPIGatherScheme::communicate()
 
    auto mpiManager = MPIManager::instance();
 
-   if ( packInfos_.size() == 0 ) {
+   if ( packInfos_.empty() ) {
       WALBERLA_LOG_WARNING( "Communicating MPIGatherScheme without registered PackInfos");
       return;
    }
diff --git a/src/geometry/bodies/Sphere.cpp b/src/geometry/bodies/Sphere.cpp
index f7fc0dce0f1bc57ca1da2e0d686c832552ebb8dd..ffd62b51aa7799e18743b286b86eaf3e6acafe5d 100644
--- a/src/geometry/bodies/Sphere.cpp
+++ b/src/geometry/bodies/Sphere.cpp
@@ -57,9 +57,9 @@ namespace geometry {
    template<>
    FastOverlapResult fastOverlapCheck ( const Sphere & sphere, const AABB & box )
    {
-           if ( ! sphere.boundingBox().intersects( box ) ) return COMPLETELY_OUTSIDE;
-      else if (   sphere.innerBox()   .contains( box ) )   return CONTAINED_INSIDE_BODY;
-      else                                                 return DONT_KNOW;
+      if ( ! sphere.boundingBox().intersects( box ) ) return COMPLETELY_OUTSIDE;
+      if (   sphere.innerBox()   .contains( box ) )   return CONTAINED_INSIDE_BODY;
+      return DONT_KNOW;
    }
 
    template<>
diff --git a/src/geometry/mesh/TriangleMeshIO.cpp b/src/geometry/mesh/TriangleMeshIO.cpp
index 3581637e30e278fa638b72a7cbbf0d466c2f229b..1161e086540dc8a195f03354f61ac2c22041cd65 100644
--- a/src/geometry/mesh/TriangleMeshIO.cpp
+++ b/src/geometry/mesh/TriangleMeshIO.cpp
@@ -493,16 +493,15 @@ namespace geometry {
       bool hasVertexNormals = mesh.hasVertexNormals();
 
       size_t j;
-      TriangleMesh::index_t i;
 
-      for( i = 0u; i < mesh.getNumVertices(); ++i ){
+      for( TriangleMesh::index_t i = 0; i < mesh.getNumVertices(); ++i ){
          j = i / itemsPerMesh;
          meshVec[j].addVertex( mesh.getVertex(i) );
          if( hasVertexNormals )
             meshVec[j].addVertexNormal( mesh.getVertexNormal(i) );
       }
 
-      for( i = 0u; i < mesh.getNumTriangles(); ++i ){
+      for( size_t i = 0; i < mesh.getNumTriangles(); ++i ){
          TriangleMesh::index_t ix = mesh.getVertexIndex( i, 0 );
          TriangleMesh::index_t iy = mesh.getVertexIndex( i, 1 );
          TriangleMesh::index_t iz = mesh.getVertexIndex( i, 2 );
diff --git a/src/mesa_pd/collision_detection/AnalyticContactDetection.h b/src/mesa_pd/collision_detection/AnalyticContactDetection.h
index bb3f8f1f21ba9356d0a4385c8de871efe0ec5dc6..284cd1eb9470b155d8ae7bedd034070f09319182 100644
--- a/src/mesa_pd/collision_detection/AnalyticContactDetection.h
+++ b/src/mesa_pd/collision_detection/AnalyticContactDetection.h
@@ -147,11 +147,11 @@ public:
                     Accessor& ac);
 
 protected:
-   size_t idx1_;
-   size_t idx2_;
-   Vec3   contactPoint_;
-   Vec3   contactNormal_;
-   real_t penetrationDepth_;
+   size_t idx1_ = std::numeric_limits<size_t>::max();
+   size_t idx2_ = std::numeric_limits<size_t>::max();
+   Vec3   contactPoint_ = Vec3();
+   Vec3   contactNormal_ = Vec3();
+   real_t penetrationDepth_ = real_t(0);
 
    real_t contactThreshold_ = real_t(0.0);
 };
diff --git a/src/mesa_pd/collision_detection/EPA.cpp b/src/mesa_pd/collision_detection/EPA.cpp
index 304b4e6f16a3b2229ea0ff72648b0c9d1fcef838..3fb4ced431d587865cd0e5a454979823c2d31988 100644
--- a/src/mesa_pd/collision_detection/EPA.cpp
+++ b/src/mesa_pd/collision_detection/EPA.cpp
@@ -275,7 +275,7 @@ bool EPA::doEPA( Support &geom1,
       }
    }
 
-   if(entryHeap.size() == 0) {
+   if(entryHeap.empty()) {
       //unrecoverable error.
       return false;
    }
@@ -473,7 +473,7 @@ bool EPA::doEPA( Support &geom1,
 
          firstTriangle->link(2, lastTriangle, 1);
       }
-   } while (entryHeap.size() > 0 && entryHeap[0]->getSqrDist() <= upperBoundSqr);
+   } while (!entryHeap.empty() && entryHeap[0]->getSqrDist() <= upperBoundSqr);
 
    //Normal must be inverted
    retNormal   = -current->getClosest().getNormalizedOrZero();
diff --git a/src/mesa_pd/collision_detection/GJK.cpp b/src/mesa_pd/collision_detection/GJK.cpp
index edd2a963ff1cf5678e2363af7aa28e3e202c23e7..d111caccdd28eeb7070607df748059c824a78b6f 100644
--- a/src/mesa_pd/collision_detection/GJK.cpp
+++ b/src/mesa_pd/collision_detection/GJK.cpp
@@ -47,7 +47,7 @@ GJK::GJK()
  * \param dir The support point direction.
  * \param threshold Extension of the particle.
  */
-const Vec3 GJK::putSupport(const Support &geom1,
+Vec3 GJK::putSupport(const Support &geom1,
                            const Support &geom2,
                            const Vec3& dir,
                            const real_t margin,
@@ -313,7 +313,7 @@ inline real_t GJK::calcDistance( Vec3& normal, Vec3& contactPoint )
    //its distance to the origin is the distance of the two objects
    real_t dist= 0.0;
 
-   real_t barCoords[3] = { 0.0, 0.0, 0.0};
+   std::array<real_t, 3> barCoords = {{ 0.0, 0.0, 0.0 }};
    real_t& u = barCoords[0];
    real_t& v = barCoords[1];
    real_t& w = barCoords[2];
diff --git a/src/mesa_pd/collision_detection/GJK.h b/src/mesa_pd/collision_detection/GJK.h
index 96d6d5be8220dd16ef93e73a4951a5a65af67277..47b4247319d95229fbce258ab570092034524272 100644
--- a/src/mesa_pd/collision_detection/GJK.h
+++ b/src/mesa_pd/collision_detection/GJK.h
@@ -81,7 +81,7 @@ private:
    inline bool zeroLengthVector( const Vec3& vec )                    const { return vec.sqrLength() < math::Limits<real_t>::fpuAccuracy(); }
    real_t calcDistance    ( Vec3& normal, Vec3& contactPoint );
 
-   inline const Vec3 putSupport(const Support &geom1,
+   inline Vec3 putSupport(const Support &geom1,
                                 const Support &geom2,
                                 const Vec3& dir,
                                 const real_t margin,
diff --git a/src/mesa_pd/data/ContactAccessor.h b/src/mesa_pd/data/ContactAccessor.h
index b0f76962491472c0f0efb436d67a2a919ec43cab..470eb0b7c72670d141e58325b2a0106d8c097a64 100644
--- a/src/mesa_pd/data/ContactAccessor.h
+++ b/src/mesa_pd/data/ContactAccessor.h
@@ -26,7 +26,7 @@
 
 #pragma once
 
-#include <mesa_pd/data/IAccessor.h>
+#include <mesa_pd/data/IContactAccessor.h>
 #include <mesa_pd/data/ContactStorage.h>
 
 #include <core/UniqueID.h>
@@ -43,7 +43,7 @@ namespace data {
  * Provides get, set and getRef for all members of the ContactStorage.
  * Can be used as a basis class for a more advanced ContactAccessor.
  */
-class ContactAccessor : public IAccessor
+class ContactAccessor : public IContactAccessor
 {
 public:
    ContactAccessor(const std::shared_ptr<data::ContactStorage>& ps) : ps_(ps) {}
diff --git a/src/mesa_pd/data/IContactAccessor.h b/src/mesa_pd/data/IContactAccessor.h
new file mode 100644
index 0000000000000000000000000000000000000000..68382fa9b4d38492055050b148b016f0d7821e77
--- /dev/null
+++ b/src/mesa_pd/data/IContactAccessor.h
@@ -0,0 +1,48 @@
+//======================================================================================================================
+//
+//  This file is part of waLBerla. waLBerla is free software: you can
+//  redistribute it and/or modify it under the terms of the GNU General Public
+//  License as published by the Free Software Foundation, either version 3 of
+//  the License, or (at your option) any later version.
+//
+//  waLBerla is distributed in the hope that it will be useful, but WITHOUT
+//  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+//  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+//  for more details.
+//
+//  You should have received a copy of the GNU General Public License along
+//  with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file IContactAccessor.h
+//! \author Tobias Leemann <tobias.leemann@fau.de>
+//
+//======================================================================================================================
+
+#pragma once
+
+#include <core/DataTypes.h>
+
+#include <typeinfo>
+#include <type_traits>
+
+namespace walberla {
+namespace mesa_pd {
+namespace data {
+
+/**
+ * @brief Add this as a base class to identify your class as an accessor for contact objects.
+ *
+ * Contact Accessors passed via templated arguments might be checked like
+ * \code
+ * static_assert(std::is_base_of<IContactAccessor, X>::value, typeid(X).name() + " is not a accessor");
+ * \endcode
+ */
+class IContactAccessor
+{
+public:
+   virtual ~IContactAccessor() = default;
+};
+
+} //namespace data
+} //namespace mesa_pd
+} //namespace walberla
diff --git a/src/mesa_pd/kernel/HCSITSRelaxationStep.h b/src/mesa_pd/kernel/HCSITSRelaxationStep.h
new file mode 100644
index 0000000000000000000000000000000000000000..10d87699963103261cbe32cd411f2af46429739a
--- /dev/null
+++ b/src/mesa_pd/kernel/HCSITSRelaxationStep.h
@@ -0,0 +1,1060 @@
+//======================================================================================================================
+//
+//  This file is part of waLBerla. waLBerla is free software: you can
+//  redistribute it and/or modify it under the terms of the GNU General Public
+//  License as published by the Free Software Foundation, either version 3 of
+//  the License, or (at your option) any later version.
+//
+//  waLBerla is distributed in the hope that it will be useful, but WITHOUT
+//  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+//  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+//  for more details.
+//
+//  You should have received a copy of the GNU General Public License along
+//  with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file HCSITSRelaxationStep.h
+//! \author Sebastian Eibl <sebastian.eibl@fau.de>
+//! \author Tobias Leemann <tobias.leemann@fau.de>
+//
+//======================================================================================================================
+
+//======================================================================================================================
+//
+//  THIS FILE IS GENERATED - PLEASE CHANGE THE TEMPLATE !!!
+//
+//======================================================================================================================
+
+#pragma once
+
+#include <mesa_pd/common/ParticleFunctions.h>
+#include <mesa_pd/data/DataTypes.h>
+#include <mesa_pd/data/IAccessor.h>
+#include <mesa_pd/data/IContactAccessor.h>
+#include <mesa_pd/data/Flags.h>
+#include <core/logging/Logging.h>
+#include <core/math/Constants.h>
+#include <core/math/Limits.h>
+
+#include <vector>
+
+namespace walberla {
+namespace mesa_pd {
+namespace kernel {
+/**
+ * Apply a HCSITS (Hard-contact semi-implicit timestepping solver) relaxation to all contacts.
+ * Call this kernel on all bodies to perform on relaxation step of the solver.
+ * There exist different friction and relaxation models. See comments on their respective methods
+ * for an extended documentation. Use setRelaxationModel() to set it.
+ * getDeltaMax() can be used to query the maximum change in the impulses applied wrt to the last iteration.
+ *
+ * Use setMaxSubIterations() to set the maximum number of iterations performed to solve optimization problems arising
+ * during the relaxation (in InelasticGeneralizedMaximumDissipationContact and InelasticCoulombContactByDecoupling).
+ *
+ * Use setCor() to set the coefficient of restitution between 0 and 1 for the InelasticProjectedGaussSeidel model.
+ * All other models describe inelastic contacts.
+ *
+ * Example of Using the HCSITS kernels in a simulation:
+ * \code
+ *     // ps: Particle storage
+ *     // cs: Contact storage
+ *     // pa: Particle accessor
+ *     // ca: Contact accessor
+ *
+ *     // Detect contacts first and fill contact storage
+ *
+ *     mesa_pd::mpi::ReduceProperty reductionKernel;
+ *     mesa_pd::mpi::BroadcastProperty broadcastKernel;
+ *
+ *     kernel::IntegrateBodiesHCSITS integration;
+ *
+ *     kernel::InitContactsForHCSITS initContacts(1);
+ *     initContacts.setFriction(0,0,real_t(0.2));
+ *     kernel::InitBodiesForHCSITS initBodies;
+ *
+ *     kernel::HCSITSRelaxationStep relaxationStep;
+ *     relaxationStep.setCor(real_t(0.1)); // Only effective for PGSM
+ *
+ *     // Init Contacts and Bodies (order is arbitrary)
+ *     cs.forEachContact(false, kernel::SelectAll(), ca, initContacts, ca, pa);
+ *     ps.forEachParticle(false, kernel::SelectAll(), pa, initBodies, pa, dt);
+ *
+ *     // Reduce and Broadcast velocities with relaxation parameter 1 before the iteration
+ *     VelocityUpdateNotification::Parameters::relaxationParam = real_t(1.0);
+ *     reductionKernel.operator()<VelocityCorrectionNotification>(*ps);
+ *     broadcastKernel.operator()<VelocityUpdateNotification>(*ps);
+ *
+ *     VelocityUpdateNotification::Parameters::relaxationParam = real_t(0.8);
+ *     for(int j = 0; j < 10; j++){
+ *        cs.forEachContact(false, kernel::SelectAll(), ca, relaxationStep, ca, pa, dt);
+ *        reductionKernel.operator()<VelocityCorrectionNotification>(*ps);
+ *        broadcastKernel.operator()<VelocityUpdateNotification>(*ps);
+ *     }
+ *
+ *     ps.forEachParticle(false, kernel::SelectAll(), pa, integration, pa, dt);
+ * \endcode
+ * \ingroup mesa_pd_kernel
+ *
+ *
+ */
+class HCSITSRelaxationStep
+{
+public:
+   enum RelaxationModel {
+      InelasticFrictionlessContact,
+      ApproximateInelasticCoulombContactByDecoupling,
+      ApproximateInelasticCoulombContactByOrthogonalProjections,
+      InelasticCoulombContactByDecoupling,
+      InelasticCoulombContactByOrthogonalProjections,
+      InelasticGeneralizedMaximumDissipationContact,
+      InelasticProjectedGaussSeidel
+   };
+   
+   // Default constructor sets the default values
+   HCSITSRelaxationStep() :
+   maxSubIterations_( 20 ),
+   relaxationModel_( InelasticFrictionlessContact ),
+   deltaMax_( 0 ),
+   cor_( real_t(0.2) )
+   {}
+
+   // Getter and Setter Functions
+   inline const size_t& getMaxSubIterations() const {return maxSubIterations_;}
+   inline void setMaxSubIterations(size_t v) { maxSubIterations_ = v;}
+   
+   inline const RelaxationModel& getRelaxationModel() const {return relaxationModel_;}
+   inline void setRelaxationModel(RelaxationModel v) { relaxationModel_ = v;}
+   
+   inline const real_t& getDeltaMax() const {return deltaMax_;}
+   inline void setDeltaMax(real_t v) { deltaMax_ = v;}
+   
+   inline const real_t& getCor() const {return cor_;}
+   inline void setCor(real_t v) { cor_ = v;}
+   
+
+   /**
+    * Perform relaxation for a single contact.
+    * \param cid The index of the contact with the accessor ca.
+    * \param ca The contact accessor.
+    * \param pa The particle accessor.
+    * \param dt The timestep size used.
+    */
+   template <typename CAccessor, typename PAccessor>
+   void operator()(size_t cid, CAccessor &ca, PAccessor& pa,  real_t dt);
+
+   template <typename CAccessor, typename PAccessor>
+   real_t relaxInelasticFrictionlessContacts(size_t cid, real_t dtinv, CAccessor &ca, PAccessor& pa);
+
+   template <typename CAccessor, typename PAccessor>
+   real_t relaxApproximateInelasticCoulombContactsByDecoupling(size_t cid, real_t dtinv, CAccessor &ca, PAccessor& pa);
+
+   template <typename CAccessor, typename PAccessor>
+   real_t relaxInelasticCoulombContactsByDecoupling(size_t cid, real_t dtinv, CAccessor &ca, PAccessor& pa );
+
+   template <typename CAccessor, typename PAccessor>
+   real_t relaxInelasticCoulombContactsByOrthogonalProjections(size_t cid, real_t dtinv, bool approximate, CAccessor &ca, PAccessor& pa );
+
+   template <typename CAccessor, typename PAccessor>
+   real_t relaxInelasticGeneralizedMaximumDissipationContacts(size_t cid, real_t dtinv, CAccessor &ca, PAccessor& pa );
+
+   template <typename CAccessor, typename PAccessor>
+   real_t relaxInelasticContactsByProjectedGaussSeidel(size_t cid, real_t dtinv, CAccessor &ca, PAccessor& pa );
+
+private:
+   // List properties
+   
+   size_t maxSubIterations_;
+   RelaxationModel relaxationModel_;
+   real_t deltaMax_;
+   real_t cor_;
+};
+
+
+template <typename CAccessor, typename PAccessor>
+inline void HCSITSRelaxationStep::operator()(size_t cid, CAccessor &ca, PAccessor& pa,  real_t dt)
+{
+   static_assert(std::is_base_of<data::IContactAccessor, CAccessor>::value, "please provide a valid contact accessor");
+   static_assert(std::is_base_of<data::IAccessor, PAccessor>::value, "please provide a valid accessor");
+
+   real_t dtinv(real_t(1.0)/dt);
+   switch( getRelaxationModel() ) {
+      case InelasticFrictionlessContact:
+         setDeltaMax(std::max( getDeltaMax(), relaxInelasticFrictionlessContacts(cid, dtinv, ca, pa )));
+         break;
+
+      case ApproximateInelasticCoulombContactByDecoupling:
+         setDeltaMax(std::max( getDeltaMax(), relaxApproximateInelasticCoulombContactsByDecoupling( cid, dtinv, ca, pa )));
+         break;
+
+      case ApproximateInelasticCoulombContactByOrthogonalProjections:
+         setDeltaMax(std::max( getDeltaMax(), relaxInelasticCoulombContactsByOrthogonalProjections( cid, dtinv, true, ca, pa )));
+         break;
+
+      case InelasticCoulombContactByDecoupling:
+         setDeltaMax(std::max( getDeltaMax(), relaxInelasticCoulombContactsByDecoupling( cid, dtinv, ca, pa )));
+         break;
+
+      case InelasticCoulombContactByOrthogonalProjections:
+         setDeltaMax(std::max( getDeltaMax(), relaxInelasticCoulombContactsByOrthogonalProjections( cid, dtinv, false, ca, pa )));
+         break;
+
+      case InelasticGeneralizedMaximumDissipationContact:
+         setDeltaMax(std::max( getDeltaMax(), relaxInelasticGeneralizedMaximumDissipationContacts( cid, dtinv, ca, pa )));
+         break;
+
+      case InelasticProjectedGaussSeidel:
+         setDeltaMax(std::max( getDeltaMax(), relaxInelasticContactsByProjectedGaussSeidel( cid, dtinv, ca, pa )));
+         break;
+
+      default:
+         throw std::runtime_error( "Unsupported relaxation model." );
+}
+
+WALBERLA_LOG_DETAIL("Delta Max: " << getDeltaMax());
+
+}
+
+//*************************************************************************************************
+/*!\brief Relaxes The contact with ID cid once. The contact model is for inelastic unilateral contacts without friction.
+ *
+ * \param cid The index of the contact
+ * \param ca The contact accessor
+ * \param pa The particle accessor
+ * \return The largest variation of contact impulses in the L-infinity norm.
+ *
+ * This function is to be called from resolveContacts(). Separating contacts are preferred over
+ * persisting solutions if valid.
+ */
+template <typename CAccessor, typename PAccessor>
+inline real_t HCSITSRelaxationStep::relaxInelasticFrictionlessContacts(size_t cid, real_t dtinv, CAccessor &ca, PAccessor& pa)
+{
+   real_t delta_max( 0 );
+
+   // Remove velocity corrections of this contact's reaction.
+   size_t bId1 = ca.getId1(cid);
+   size_t bId2 = ca.getId2(cid);
+   pa.getDvRef(bId1) -= pa.getInvMass(bId1) * ca.getP(cid);
+   pa.getDwRef(bId1) -= pa.getInvInertia(bId1) * (ca.getR1(cid) % ca.getP(cid));
+   pa.getDvRef(bId2) += pa.getInvMass(bId2) * ca.getP(cid);
+   pa.getDwRef(bId2) += pa.getInvInertia(bId2) * (ca.getR2(cid) % ca.getP(cid));
+
+   // Calculate the relative contact VELOCITY in the global world frame (if no contact reaction is present at contact i)
+   Vec3 gdot    ( ( pa.getLinearVelocity(bId1)     + pa.getDv(bId1) ) -
+                  ( pa.getLinearVelocity(bId2)     + pa.getDv(bId2) ) +
+                  ( pa.getAngularVelocity(bId1)    + pa.getDw(bId1) ) % ca.getR1(cid) -
+                  ( pa.getAngularVelocity(bId2)    + pa.getDw(bId2) ) % ca.getR2(cid) /* + diag_[i] * p */ );
+
+
+   // Change from the global world frame to the contact frame
+   Mat3 contactframe( ca.getNormal(cid), ca.getT(cid), ca.getO(cid) );
+   Vec3 gdot_nto( contactframe.getTranspose() * gdot );
+
+   // The constraint in normal direction is actually a positional constraint but instead of g_n we use g_n/dt equivalently and call it gdot_n
+   gdot_nto[0] += ( /* + trans( contactCache.n_[i] ) * ( contactCache.body1_[i]->getPosition() + contactCache.r1_[i] ) - ( contactCache.body2_[i]->getPosition() + contactCache.r2_[i] ) */ + ca.getDistance(cid) ) * dtinv;
+
+   if( gdot_nto[0] >= 0 ) {
+      // Contact is separating if no contact reaction is present at contact i.
+
+      delta_max = std::max( delta_max, std::max( std::abs( ca.getP(cid)[0] ), std::max( std::abs( ca.getP(cid)[1] ), std::abs( ca.getP(cid)[2] ) ) ) );
+      ca.getPRef(cid) = Vec3();
+
+      // No need to apply zero impulse.
+   }
+   else {
+      // Contact is persisting.
+
+      // Calculate the impulse necessary for a static contact expressed as components in the contact frame.
+      Vec3 p_wf( ca.getNormal(cid) * ( -ca.getDiag_n_inv(cid) * gdot_nto[0] ) );
+      Vec3 dp( ca.getP(cid) - p_wf );
+      delta_max = std::max( delta_max, std::max( std::abs( dp[0] ), std::max( std::abs( dp[1] ), std::abs( dp[2] ) ) ) );
+
+      ca.getPRef(cid) = p_wf;
+
+      // Apply impulse right away.
+      pa.getDvRef(bId1) += pa.getInvMass(bId1) * ca.getP(cid);
+      pa.getDwRef(bId1) += pa.getInvInertia(bId1) * (ca.getR1(cid) % ca.getP(cid));
+      pa.getDvRef(bId2) -= pa.getInvMass(bId2) * ca.getP(cid);
+      pa.getDwRef(bId2) -= pa.getInvInertia(bId2) * (ca.getR2(cid) % ca.getP(cid));
+   }
+
+   return delta_max;
+}
+//*************************************************************************************************
+
+
+//*************************************************************************************************
+/*!\brief Relaxes all contacts once. The contact model is for inelastic unilateral contacts with approximate Coulomb friction.
+ *
+ * \return The largest variation of contact impulses in the L-infinity norm.
+ *
+ * This function is to be called from resolveContacts(). Separating contacts are preferred over
+ * other solutions if valid. Static solutions are preferred over dynamic solutions. Dynamic
+ * solutions are computed by decoupling the normal from the frictional components. That is
+ * for a dynamic contact the normal component is relaxed first followed by the frictional
+ * components. The determination of the frictional components does not perform any subiterations
+ * and guarantees that the friction partially opposes slip.
+ */
+template <typename CAccessor, typename PAccessor>
+inline real_t HCSITSRelaxationStep::relaxApproximateInelasticCoulombContactsByDecoupling(size_t cid, real_t dtinv, CAccessor &ca, PAccessor& pa )
+{
+   real_t delta_max( 0 );
+
+   // Remove velocity corrections of this contact's reaction.
+   size_t bId1 = ca.getId1(cid);
+   size_t bId2 = ca.getId2(cid);
+   pa.getDvRef(bId1) -= pa.getInvMass(bId1) * ca.getP(cid);
+   pa.getDwRef(bId1) -= pa.getInvInertia(bId1) * (ca.getR1(cid) % ca.getP(cid));
+   pa.getDvRef(bId2) += pa.getInvMass(bId2) * ca.getP(cid);
+   pa.getDwRef(bId2) += pa.getInvInertia(bId2) * (ca.getR2(cid) % ca.getP(cid));
+
+
+   // Calculate the relative contact VELOCITY in the global world frame (if no contact reaction is present at contact i)
+   Vec3 gdot    ( ( pa.getLinearVelocity(bId1)     + pa.getDv(bId1) ) -
+                  ( pa.getLinearVelocity(bId2)     + pa.getDv(bId2) ) +
+                  ( pa.getAngularVelocity(bId1)    + pa.getDw(bId1) ) % ca.getR1(cid) -
+                  ( pa.getAngularVelocity(bId2)    + pa.getDw(bId2) ) % ca.getR2(cid) /* + diag_[i] * p */ );
+
+   // Change from the global world frame to the contact frame
+   Mat3 contactframe( ca.getNormal(cid), ca.getT(cid), ca.getO(cid) );
+   Vec3 gdot_nto( contactframe.getTranspose() * gdot );
+
+   // The constraint in normal direction is actually a positional constraint but instead of g_n we use g_n/dt equivalently and call it gdot_n
+   gdot_nto[0] += ( /* + trans( contactCache.n_[i] ) * ( contactCache.body1_[i]->getPosition() + contactCache.r1_[i] ) - ( contactCache.body2_[i]->getPosition() + contactCache.r2_[i] ) */ + ca.getDistance(cid) ) * dtinv;
+
+
+   if( gdot_nto[0] >= 0 ) {
+      // Contact is separating if no contact reaction is present at contact i.
+      delta_max = std::max( delta_max, std::max( std::abs( ca.getP(cid)[0] ), std::max( std::abs( ca.getP(cid)[1] ), std::abs( ca.getP(cid)[2] ) ) ) );
+      ca.getPRef(cid) = Vec3();
+
+      // No need to apply zero impulse.
+   }
+   else {
+      // Contact is persisting (either static or dynamic).
+
+      // Calculate the impulse necessary for a static contact expressed as components in the contact frame.
+      //Vec3 p_cf( -( contactCache.diag_nto_inv_[i] * gdot_nto ) );
+      Vec3 p_cf( -( ca.getDiag_nto_inv(cid) * gdot_nto ) );
+
+      // Can p_cf[0] be negative even though -gdot_nto[0] > 0? Yes! Try:
+      // A = [0.5 -0.1 +0.1; -0.1 0.5 -0.1; +0.1 -0.1 1];
+      // b = [0.01 -1 -1]';
+      // A\b    \approx [-0.19 -2.28 -1.21]'
+      // eig(A) \approx [ 0.40  0.56  1.04]'
+
+      //real_t flimit( contactCache.mu_[i] * p_cf[0] );
+      real_t flimit( ca.getMu(cid) * p_cf[0] );
+      real_t fsq( p_cf[1] * p_cf[1] + p_cf[2] * p_cf[2] );
+      if( fsq > flimit * flimit || p_cf[0] < 0 ) {
+         // Contact cannot be static so it must be dynamic.
+         // => Complementarity condition on normal reaction now turns into an equation since we know that the normal reaction is definitely not zero.
+
+         // For simplicity we change to a simpler relaxation scheme here:
+         // 1. Relax normal reaction with the tangential components equal to the previous values
+         // 2. Relax tangential components with the newly relaxed normal reaction
+         // Note: The better approach would be to solve the true 3x3 block problem!
+         // Warning: Simply projecting the frictional components is wrong since then the normal action is no longer 0 and simulations break.
+
+         // Add the action of the frictional reactions from the last iteration to the relative contact velocity in normal direction so we can relax it separately.
+         // TODO This can be simplified:
+         //p_cf = trans( contactframe ) * contactCache.p_[i];
+         //p_cf[0] = 0;
+         //p_[i] = contactframe * p_cf;
+
+
+         //Vec3 p_tmp = ( contactCache.t_[i] * contactCache.p_[i] ) * contactCache.t_[i] + ( contactCache.o_[i] * contactCache.p_[i] ) * contactCache.o_[i];
+         Vec3 p_tmp = ( ca.getT(cid) * ca.getP(cid)  ) * ca.getT(cid)  + ( ca.getO(cid) * ca.getP(cid) ) * ca.getO(cid);
+
+
+         //real_t gdot_n = gdot_nto[0] + contactCache.n_[i] * ( ( contactCache.body1_[i]->getInvInertia() * ( contactCache.r1_[i] % p_tmp ) ) % contactCache.r1_[i] + ( contactCache.body2_[i]->getInvInertia() * ( contactCache.r2_[i] % p_tmp ) ) % contactCache.r2_[i] /* + diag_[i] * p */ );
+         real_t gdot_n = gdot_nto[0] + ca.getNormal(cid) * ( ( pa.getInvInertia(bId1) * ( ca.getR1(cid) % p_tmp ) ) % ca.getR1(cid) + ( pa.getInvInertia(bId2) * ( ca.getR2(cid) % p_tmp ) ) % ca.getR2(cid) /* + diag_[i] * p */ );
+
+         //p_cf[0] = -( contactCache.diag_n_inv_[i] * gdot_n );
+         p_cf[0] = -( ca.getDiag_n_inv(cid) * gdot_n );
+
+         // We cannot be sure that gdot_n <= 0 here and thus p_cf[0] >= 0 since we just modified it with the old values of the tangential reactions! => Project
+         p_cf[0] = std::max( real_c( 0 ), p_cf[0] );
+
+         // Now add the action of the normal reaction to the relative contact velocity in the tangential directions so we can relax the frictional components separately.
+         p_tmp = ca.getNormal(cid)  * p_cf[0];
+         Vec3 gdot2 = gdot + ( pa.getInvInertia(bId1) * ( ca.getR1(cid) % p_tmp ) ) % ca.getR1(cid) + ( pa.getInvInertia(bId2)* ( ca.getR2(cid) % p_tmp ) ) % ca.getR2(cid);
+         Vec2 gdot_to;
+         gdot_to[0] = ca.getT(cid) * gdot2;
+         gdot_to[1] = ca.getO(cid) * gdot2;
+
+         //Vec2 ret = -( contactCache.diag_to_inv_[i] * gdot_to );
+         Vec2 ret = -( ca.getDiag_to_inv(cid) * gdot_to );
+         p_cf[1] = ret[0];
+         p_cf[2] = ret[1];
+
+         flimit = ca.getMu(cid) * p_cf[0];
+         fsq = p_cf[1] * p_cf[1] + p_cf[2] * p_cf[2];
+         if( fsq > flimit * flimit ) {
+            const real_t f( flimit / std::sqrt( fsq ) );
+            p_cf[1] *= f;
+            p_cf[2] *= f;
+         }
+      }
+      else {
+         // Contact is static.
+      }
+      Vec3 p_wf( contactframe * p_cf );
+
+      Vec3 dp( ca.getP(cid) - p_wf );
+      delta_max = std::max( delta_max, std::max( std::abs( dp[0] ), std::max( std::abs( dp[1] ), std::abs( dp[2] ) ) ) );
+
+      ca.getPRef(cid) = p_wf;
+
+      // Apply impulse right away.
+      pa.getDvRef(bId1) += pa.getInvMass(bId1) * ca.getP(cid);
+      pa.getDwRef(bId1) += pa.getInvInertia(bId1) * (ca.getR1(cid) % ca.getP(cid));
+      pa.getDvRef(bId2) -= pa.getInvMass(bId2) * ca.getP(cid);
+      pa.getDwRef(bId2) -= pa.getInvInertia(bId2) * (ca.getR2(cid) % ca.getP(cid));
+   }
+   return delta_max;
+}
+//*************************************************************************************************
+
+
+//*************************************************************************************************
+
+/*!\brief Relaxes all contacts once. The contact model is for inelastic unilateral contacts with Coulomb friction.
+ *
+ * \return The largest variation of contact impulses in the L-infinity norm.
+ *
+ * This function is to be called from resolveContacts(). Separating contacts are preferred over
+ * other solutions if valid. Static solutions are preferred over dynamic solutions. Dynamic
+ * solutions are computed by decoupling the normal from the frictional components. That is
+ * for a dynamic contact the normal component is relaxed first followed by the frictional
+ * components. How much the frictional components directly oppose slip as required by the Coulomb
+ * friction model depends on the number of subiterations performed. If no subiterations are
+ * performed the friction is guaranteed to be at least partially dissipative.
+ */
+template <typename CAccessor, typename PAccessor>
+inline real_t HCSITSRelaxationStep::relaxInelasticCoulombContactsByDecoupling(size_t cid, real_t dtinv, CAccessor &ca, PAccessor& pa )
+{
+   real_t delta_max( 0 );
+
+   // Remove velocity corrections of this contact's reaction.
+   size_t bId1 = ca.getId1(cid);
+   size_t bId2 = ca.getId2(cid);
+   pa.getDvRef(bId1) -= pa.getInvMass(bId1) * ca.getP(cid);
+   pa.getDwRef(bId1) -= pa.getInvInertia(bId1) * (ca.getR1(cid) % ca.getP(cid));
+   pa.getDvRef(bId2) += pa.getInvMass(bId2) * ca.getP(cid);
+   pa.getDwRef(bId2) += pa.getInvInertia(bId2) * (ca.getR2(cid) % ca.getP(cid));
+
+
+   // Calculate the relative contact VELOCITY in the global world frame (if no contact reaction is present at contact i)
+   Vec3 gdot    ( ( pa.getLinearVelocity(bId1)     + pa.getDv(bId1) ) -
+                  ( pa.getLinearVelocity(bId2)     + pa.getDv(bId2) ) +
+                  ( pa.getAngularVelocity(bId1)    + pa.getDw(bId1) ) % ca.getR1(cid) -
+                  ( pa.getAngularVelocity(bId2)    + pa.getDw(bId2) ) % ca.getR2(cid) /* + diag_[i] * p */ );
+
+   // Change from the global world frame to the contact frame
+   Mat3 contactframe( ca.getNormal(cid), ca.getT(cid), ca.getO(cid) );
+   Vec3 gdot_nto( contactframe.getTranspose() * gdot );
+
+   // The constraint in normal direction is actually a positional constraint but instead of g_n we use g_n/dt equivalently and call it gdot_n
+   gdot_nto[0] += ( /* + trans( contactCache.n_[i] ) * ( contactCache.body1_[i]->getPosition() + contactCache.r1_[i] ) - ( contactCache.body2_[i]->getPosition() + contactCache.r2_[i] ) */ + ca.getDistance(cid) ) * dtinv;
+
+   //WALBERLA_LOG_WARNING( "Contact #" << i << " is\nA = \n" << contactCache.diag_nto_[i] << "\nb = \n" << gdot_nto << "\nmu = " << contactCache.mu_[i] );
+
+   if( gdot_nto[0] >= 0 ) {
+      // Contact is separating if no contact reaction is present at contact i.
+
+      delta_max = std::max( delta_max, std::max( std::abs( ca.getP(cid)[0] ), std::max( std::abs( ca.getP(cid)[1] ), std::abs( ca.getP(cid)[2] ) ) ) );
+      ca.getPRef(cid) = Vec3();
+      //WALBERLA_LOG_WARNING( "Contact #" << i << " is separating." );
+
+      // No need to apply zero impulse.
+   }
+   else {
+      // Contact is persisting (either static or dynamic).
+
+      // Calculate the impulse necessary for a static contact expressed as components in the contact frame.
+      Vec3 p_cf( -( ca.getDiag_nto_inv(cid) * gdot_nto ) );
+
+      // Can p_cf[0] be negative even though -gdot_nto[0] > 0? Yes! Try:
+      // A = [0.5 -0.1 +0.1; -0.1 0.5 -0.1; +0.1 -0.1 1];
+      // b = [0.01 -1 -1]';
+      // A\b    \approx [-0.19 -2.28 -1.21]'
+      // eig(A) \approx [ 0.40  0.56  1.04]'
+
+      real_t flimit( ca.getMu(cid) * p_cf[0] );
+      real_t fsq( p_cf[1] * p_cf[1] + p_cf[2] * p_cf[2] );
+      if( fsq > flimit * flimit || p_cf[0] < 0 ) {
+         // Contact cannot be static so it must be dynamic.
+         // => Complementarity condition on normal reaction now turns into an equation since we know that the normal reaction is definitely not zero.
+
+         for (int j = 0; j < 20; ++j) {
+            // For simplicity we change to a simpler relaxation scheme here:
+            // 1. Relax normal reaction with the tangential components equal to the previous values
+            // 2. Relax tangential components with the newly relaxed normal reaction
+            // Note: The better approach would be to solve the true 3x3 block problem!
+            // Warning: Simply projecting the frictional components is wrong since then the normal action is no longer 0 and simulations break.
+
+            Vec3 gdotCorrected;
+            real_t gdotCorrected_n;
+            Vec2 gdotCorrected_to;
+
+            // Calculate the relative contact velocity in the global world frame (if no normal contact reaction is present at contact i)
+            p_cf[0] = 0;
+            //                       |<- p_cf is orthogonal to the normal and drops out in next line ->|
+            gdotCorrected   = /* ( contactCache.body1_[i]->getInvMass() + contactCache.body2_[i]->getInvMass() ) * p_cf  */ gdot + ( pa.getInvInertia(bId1) * ( ca.getR1(cid) % ( ca.getT(cid) * p_cf[1] + ca.getO(cid) * p_cf[2] ) ) ) % ca.getR1(cid) + ( pa.getInvInertia(bId2) * ( ca.getR2(cid) % ( ca.getT(cid) * p_cf[1] + ca.getO(cid) * p_cf[2] ) ) ) % ca.getR2(cid);
+            gdotCorrected_n = ca.getNormal(cid) * gdotCorrected + ca.getDistance(cid) * dtinv;
+
+            // Relax normal component.
+            p_cf[0] = std::max( real_c( 0 ), -( ca.getDiag_n_inv(cid) * gdotCorrected_n ) );
+
+            // Calculate the relative contact velocity in the global world frame (if no frictional contact reaction is present at contact i)
+            p_cf[1] = p_cf[2] = real_c( 0 );
+            //                       |<- p_cf is orthogonal to the tangential plane and drops out   ->|
+            gdotCorrected   = /* ( contactCache.body1_[i]->getInvMass() + contactCache.body2_[i]->getInvMass() ) * p_cf */ gdot + ( pa.getInvInertia(bId1) * ( ca.getR1(cid) % ( ca.getNormal(cid) * p_cf[0] ) ) ) % ca.getR1(cid) + ( pa.getInvInertia(bId2) * ( ca.getR2(cid) % ( ca.getNormal(cid) * p_cf[0] ) ) ) % ca.getR2(cid);
+            gdotCorrected_to[0] = ca.getT(cid) * gdotCorrected;
+            gdotCorrected_to[1] = ca.getO(cid) * gdotCorrected;
+
+            // Relax frictional components.
+            Vec2 ret = -( ca.getDiag_to_inv(cid) * gdotCorrected_to );
+            p_cf[1] = ret[0];
+            p_cf[2] = ret[1];
+
+            flimit = ca.getMu(cid) * p_cf[0];
+            fsq = p_cf[1] * p_cf[1] + p_cf[2] * p_cf[2];
+            if( fsq > flimit * flimit ) {
+               // 3.2.1 Decoupling
+               // \tilde{x}^0 = p_cf[1..2]
+
+               // Determine \tilde{A}
+               Mat2 diag_to( ca.getDiag_nto(cid)(1, 1), ca.getDiag_nto(cid)(1, 2), ca.getDiag_nto(cid)(2, 1), ca.getDiag_nto(cid)(2, 2) );
+
+               const real_t f( flimit / std::sqrt( fsq ) );
+               //p_cf[1] *= f;
+               //p_cf[2] *= f;
+
+               // Determine search interval for Golden Section Search
+               const real_t phi( real_c(0.5) * ( real_c(1) + std::sqrt( real_c( 5 ) ) ) );
+               real_t shift( std::atan2( -p_cf[2], p_cf[1] ) );
+               real_t acos_f( std::acos( f ) );
+
+               //WALBERLA_LOG_WARNING( acos_f << " " << shift );
+
+               real_t alpha_left( -acos_f - shift );
+               //Vec2 x_left( flimit * std::cos( alpha_left ), flimit * std::sin( alpha_left ) );
+               //real_t f_left( 0.5 * trans( x_left ) * ( diag_to * x_left ) - trans( x_left ) * ( -gdot_to ) );
+
+               real_t alpha_right( acos_f - shift );
+               //Vec2 x_right( flimit * std::cos( alpha_right ), flimit * std::sin( alpha_right ) );
+               //real_t f_right( 0.5 * trans( x_right ) * ( diag_to * x_right ) - trans( x_right ) * ( -gdot_to ) );
+
+               real_t alpha_mid( ( alpha_right + alpha_left * phi ) / ( 1 + phi ) );
+               Vec2 x_mid( flimit * std::cos( alpha_mid ), flimit * std::sin( alpha_mid ) );
+               real_t f_mid( real_c(0.5) * x_mid * ( diag_to * x_mid ) - x_mid * ( -gdotCorrected_to ) );
+
+               bool leftlarger = false;
+               for( size_t k = 0; k < getMaxSubIterations(); ++k ) {
+                  real_t alpha_next( alpha_left + ( alpha_right - alpha_mid ) );
+                  Vec2 x_next( flimit * std::cos( alpha_next ), flimit * std::sin( alpha_next ) );
+                  real_t f_next( real_c(0.5) * x_next * ( diag_to * x_next ) - x_next * ( -gdotCorrected_to ) );
+                  //WALBERLA_LOG_WARNING( "[(" << alpha_left << ", ?); (" << alpha_mid << ", " << f_mid << "); (" << alpha_right << ", ?)] <- (" << alpha_next << ", " << f_next << ")" );
+                  //WALBERLA_LOG_WARNING( "left: " << alpha_mid - alpha_left << "  right: " << alpha_right - alpha_mid << "  ll: " << leftlarger );
+                  //WALBERLA_ASSERT(leftlarger ? (alpha_mid - alpha_left > alpha_right - alpha_mid) : (alpha_mid - alpha_left < alpha_right - alpha_mid), "ll inconsistent!" );
+
+                  if (leftlarger) {
+                     // left interval larger
+                     if( f_next < f_mid ) {
+                        alpha_right = alpha_mid;
+                        alpha_mid   = alpha_next;
+                        x_mid       = x_next;
+                        f_mid       = f_next;
+                        leftlarger = true;
+                     }
+                     else {
+                        alpha_left  = alpha_next;
+                        leftlarger = false;
+                     }
+                  }
+                  else {
+                     // right interval larger
+                     if( f_next < f_mid ) {
+                        alpha_left = alpha_mid;
+                        alpha_mid  = alpha_next;
+                        x_mid      = x_next;
+                        f_mid      = f_next;
+                        leftlarger = false;
+                     }
+                     else {
+                        alpha_right = alpha_next;
+                        leftlarger = true;
+                     }
+                  }
+               }
+               //WALBERLA_LOG_WARNING( "dalpha = " << alpha_right - alpha_left );
+
+               p_cf[1] = x_mid[0];
+               p_cf[2] = x_mid[1];
+            }
+         }
+         //WALBERLA_LOG_WARNING( "Contact #" << i << " is dynamic." );
+      }
+      else {
+         // Contact is static.
+         //WALBERLA_LOG_WARNING( "Contact #" << i << " is static." );
+      }
+
+      //WALBERLA_LOG_WARNING( "Contact reaction in contact frame: " << p_cf << "\n" << ca.getDiag_nto(cid)*p_cf + gdot_nto );
+      Vec3 p_wf( contactframe * p_cf );
+      Vec3 dp( ca.getP(cid) - p_wf );
+      delta_max = std::max( delta_max, std::max( std::abs( dp[0] ), std::max( std::abs( dp[1] ), std::abs( dp[2] ) ) ) );
+
+      ca.getPRef(cid) = p_wf;
+
+      // Apply impulse right away.
+      pa.getDvRef(bId1) += pa.getInvMass(bId1) * ca.getP(cid);
+      pa.getDwRef(bId1) += pa.getInvInertia(bId1) * (ca.getR1(cid) % ca.getP(cid));
+      pa.getDvRef(bId2) -= pa.getInvMass(bId2) * ca.getP(cid);
+      pa.getDwRef(bId2) -= pa.getInvInertia(bId2) * (ca.getR2(cid) % ca.getP(cid));
+   }
+
+   return delta_max;
+}
+//*************************************************************************************************
+
+
+//*************************************************************************************************
+/*!\brief Relaxes all contacts once. The contact model is for inelastic unilateral contacts with Coulomb friction.
+ *
+ * \param dtinv The inverse of the current time step.
+ * \param approximate Use the approximate model showing bouncing.
+ * \return The largest variation of contact impulses in the L-infinity norm.
+ *
+ * This function is to be called from resolveContacts(). The iterative method to solve the contact
+ * problem is e.g. described in the article "A matrix-free cone complementarity approach for
+ * solving large-scale, nonsmooth, rigid body dynamics" by A. Tasora and M. Anitescu in Computer
+ * Methods in Applied Mechanics and Engineering (Volume 200, Issues 5–8, 15 January 2011,
+ * Pages 439-453). The contact model is purely quadratic and convergence should be good but depends
+ * on a parameter. The one-contact problem has a unique solution. The frictional reactions
+ * for a dynamic contact converge to those that directly oppose slip. However, the contact is
+ * not perfectly inelastic for dynamic contacts but bounces. These vertical motions tend to
+ * go to zero for smaller time steps and can be interpreted as exaggerated vertical motions
+ * coming from micro asperities (see "Optimization-based simulation of nonsmooth rigid multibody
+ * dynamics" by M. Anitescu in Mathematical Programming (Volume 105, Issue 1, January 2006, Pages
+ * 113-143). These motions can be prevented by a small change in the iteration proposed in "The
+ * bipotential method: a constructive approach to design the complete contact law with friction and
+ * improved numerical algorithms" by G. De Saxce and Z-Q. Feng in Mathematical and Computer
+ * Modelling (Volume 28, Issue 4, 1998, Pages 225-245). Which iteration is used is controlled with
+ * the approximate parameter.
+ */
+template <typename CAccessor, typename PAccessor>
+inline real_t HCSITSRelaxationStep::relaxInelasticCoulombContactsByOrthogonalProjections(size_t cid, real_t dtinv, bool approximate, CAccessor &ca, PAccessor& pa )
+{
+   real_t delta_max( 0 );
+
+   // Remove velocity corrections of this contact's reaction.
+   size_t bId1 = ca.getId1(cid);
+   size_t bId2 = ca.getId2(cid);
+   pa.getDvRef(bId1) -= pa.getInvMass(bId1) * ca.getP(cid);
+   pa.getDwRef(bId1) -= pa.getInvInertia(bId1) * (ca.getR1(cid) % ca.getP(cid));
+   pa.getDvRef(bId2) += pa.getInvMass(bId2) * ca.getP(cid);
+   pa.getDwRef(bId2) += pa.getInvInertia(bId2) * (ca.getR2(cid) % ca.getP(cid));
+
+   // Calculate the relative contact VELOCITY in the global world frame (if no contact reaction is present at contact i)
+   Vec3 gdot    ( ( pa.getLinearVelocity(bId1)     + pa.getDv(bId1) ) -
+                  ( pa.getLinearVelocity(bId2)     + pa.getDv(bId2) ) +
+                  ( pa.getAngularVelocity(bId1)    + pa.getDw(bId1) ) % ca.getR1(cid) -
+                  ( pa.getAngularVelocity(bId2)    + pa.getDw(bId2) ) % ca.getR2(cid) /* + diag_[i] * p */ );
+
+   // Change from the global world frame to the contact frame
+   Mat3 contactframe( ca.getNormal(cid), ca.getT(cid), ca.getO(cid) );
+   Vec3 gdot_nto( contactframe.getTranspose() * gdot );
+
+   // The constraint in normal direction is actually a positional constraint but instead of g_n we use g_n/dt equivalently and call it gdot_n
+   gdot_nto[0] += ( /* + trans( contactCache.n_[i] ) * ( contactCache.body1_[i]->getPosition() + contactCache.r1_[i] ) - ( contactCache.body2_[i]->getPosition() + contactCache.r2_[i] ) */ + ca.getDistance(cid) ) * dtinv;
+
+
+   const real_t w( 1 ); // w > 0
+   Vec3 p_cf( contactframe.getTranspose() * ca.getP(cid) );
+   if( approximate ) {
+      // Calculate next iterate (Anitescu/Tasora).
+      p_cf = p_cf - w * ( ca.getDiag_nto(cid) * p_cf + gdot_nto );
+   }
+   else {
+      // Calculate next iterate (De Saxce/Feng).
+      Vec3 tmp( ca.getDiag_nto(cid) * p_cf + gdot_nto );
+      tmp[0] += std::sqrt( math::sq( tmp[1] ) + math::sq( tmp[2] ) ) * ca.getMu(cid);
+      p_cf = p_cf - w * tmp;
+   }
+
+   // Project.
+   real_t flimit( ca.getMu(cid) * p_cf[0] );
+   real_t fsq( p_cf[1] * p_cf[1] + p_cf[2] * p_cf[2] );
+   if( p_cf[0] > 0 && fsq < flimit * flimit ) {
+      // Unconstrained minimum is in cone leading to a static contact and no projection
+      // is necessary.
+   }
+   else if( p_cf[0] < 0 && fsq < math::sq( p_cf[0] )/ math::sq( ca.getMu(cid) ) ) {
+      // Unconstrained minimum is in dual cone leading to a separating contact where no contact
+      // reaction is present (the unconstrained minimum is projected to the tip of the cone).
+      p_cf = Vec3();
+   }
+   else {
+      // The contact is dynamic.
+      real_t f( std::sqrt( fsq ) );
+      p_cf[0] = ( f * ca.getMu(cid) + p_cf[0] ) / ( math::sq( ca.getMu(cid) ) + 1 );
+      real_t factor( ca.getMu(cid) * p_cf[0] / f );
+      p_cf[1] *= factor;
+      p_cf[2] *= factor;
+   }
+
+   Vec3 p_wf( contactframe * p_cf );
+   Vec3 dp( ca.getP(cid) - p_wf );
+   delta_max = std::max( delta_max, std::max( std::abs( dp[0] ), std::max( std::abs( dp[1] ), std::abs( dp[2] ) ) ) );
+
+   ca.getPRef(cid) = p_wf;
+
+   // Apply impulse right away.
+   pa.getDvRef(bId1) += pa.getInvMass(bId1) * ca.getP(cid);
+   pa.getDwRef(bId1) += pa.getInvInertia(bId1) * (ca.getR1(cid) % ca.getP(cid));
+   pa.getDvRef(bId2) -= pa.getInvMass(bId2) * ca.getP(cid);
+   pa.getDwRef(bId2) -= pa.getInvInertia(bId2) * (ca.getR2(cid) % ca.getP(cid));
+
+   return delta_max;
+}
+//*************************************************************************************************
+
+
+//*************************************************************************************************
+
+/*!\brief Relaxes all contacts once. The contact model is for inelastic unilateral contacts with the generalized maximum dissipation principle for friction.
+ *
+ * \return The largest variation of contact impulses in the L-infinity norm.
+ *
+ * This function is to be called from resolveContacts(). Dynamic solutions are computed by
+ * minimizing the kinetic energy along the intersection of the plane of maximum compression and
+ * the friction cone.
+ */
+template <typename CAccessor, typename PAccessor>
+inline real_t HCSITSRelaxationStep::relaxInelasticGeneralizedMaximumDissipationContacts(size_t cid, real_t dtinv, CAccessor &ca, PAccessor& pa )
+{
+   real_t delta_max( 0 );
+
+   // Remove velocity corrections of this contact's reaction.
+   size_t bId1 = ca.getId1(cid);
+   size_t bId2 = ca.getId2(cid);
+   pa.getDvRef(bId1) -= pa.getInvMass(bId1) * ca.getP(cid);
+   pa.getDwRef(bId1) -= pa.getInvInertia(bId1) * (ca.getR1(cid) % ca.getP(cid));
+   pa.getDvRef(bId2) += pa.getInvMass(bId2) * ca.getP(cid);
+   pa.getDwRef(bId2) += pa.getInvInertia(bId2) * (ca.getR2(cid) % ca.getP(cid));
+
+   // Calculate the relative contact VELOCITY in the global world frame (if no contact reaction is present at contact i)
+   Vec3 gdot    ( ( pa.getLinearVelocity(bId1)     + pa.getDv(bId1) ) -
+                  ( pa.getLinearVelocity(bId2)     + pa.getDv(bId2) ) +
+                  ( pa.getAngularVelocity(bId1)    + pa.getDw(bId1) ) % ca.getR1(cid) -
+                  ( pa.getAngularVelocity(bId2)    + pa.getDw(bId2) ) % ca.getR2(cid) /* + diag_[i] * p */ );
+
+   // Change from the global world frame to the contact frame
+   Mat3 contactframe( ca.getNormal(cid), ca.getT(cid), ca.getO(cid) );
+   Vec3 gdot_nto( contactframe.getTranspose() * gdot );
+
+   // The constraint in normal direction is actually a positional constraint but instead of g_n we use g_n/dt equivalently and call it gdot_n
+   gdot_nto[0] += ( /* + trans( contactCache.n_[i] ) * ( contactCache.body1_[i]->getPosition() + contactCache.r1_[i] ) - ( contactCache.body2_[i]->getPosition() + contactCache.r2_[i] ) */ + ca.getDistance(cid) ) * dtinv;
+
+
+   if( gdot_nto[0] >= 0 ) {
+      // Contact is separating if no contact reaction is present at contact i.
+      delta_max = std::max( delta_max, std::max( std::abs( ca.getP(cid)[0] ), std::max( std::abs( ca.getP(cid)[1] ), std::abs( ca.getP(cid)[2] ) ) ) );
+      ca.getPRef(cid) = Vec3();
+
+      // No need to apply zero impulse.
+   }
+   else {
+      // Contact is persisting (either static or dynamic).
+
+      // Calculate the impulse necessary for a static contact expressed as components in the contact frame.
+      Vec3 p_cf( -( ca.getDiag_nto_inv(cid) * gdot_nto ) );
+
+      // Can p_cf[0] be negative even though -gdot_nto[0] > 0? Yes! Try:
+      // A = [0.5 -0.1 +0.1; -0.1 0.5 -0.1; +0.1 -0.1 1];
+      // b = [0.01 -1 -1]';
+      // A\b    \approx [-0.19 -2.28 -1.21]'
+      // eig(A) \approx [ 0.40  0.56  1.04]'
+
+      real_t flimit( ca.getMu(cid) * p_cf[0] );
+      real_t fsq( p_cf[1] * p_cf[1] + p_cf[2] * p_cf[2] );
+      if( fsq > flimit * flimit || p_cf[0] < 0 ) {
+         // Contact cannot be static so it must be dynamic.
+         // => Complementarity condition on normal reaction now turns into an equation since we know that the normal reaction is definitely not zero.
+
+         // \breve{x}^0 = p_cf[1..2]
+
+         // Eliminate normal component from 3x3 system: ca.getDiag_nto(cid)*p_cf + gdot_nto => \breve{A} \breve{x} - \breve{b}
+         const real_t invA_nn( math::inv( ca.getDiag_nto(cid)(0, 0) ) );
+         const real_t offdiag( ca.getDiag_nto(cid)(1, 2) - invA_nn * ca.getDiag_nto(cid)(0, 1) * ca.getDiag_nto(cid)(0, 2) );
+         Mat2 A_breve( ca.getDiag_nto(cid)(1, 1) - invA_nn *math::sq( ca.getDiag_nto(cid)(0, 1) ), offdiag, offdiag, ca.getDiag_nto(cid)(2, 2) - invA_nn *math::sq( ca.getDiag_nto(cid)(0, 2) ) );
+         Vec2 b_breve( -gdot_nto[1] + invA_nn * ca.getDiag_nto(cid)(0, 1) * gdot_nto[0], -gdot_nto[2] + invA_nn * ca.getDiag_nto(cid)(0, 2) * gdot_nto[0] );
+
+         const real_t shiftI( std::atan2( -ca.getDiag_nto(cid)(0, 2), ca.getDiag_nto(cid)(0, 1) ) );
+         const real_t shiftJ( std::atan2( -p_cf[2], p_cf[1] ) );
+         const real_t a3( std::sqrt(math::sq( ca.getDiag_nto(cid)(0, 1) ) +math::sq( ca.getDiag_nto(cid)(0, 2) ) ) );
+         const real_t fractionI( -ca.getDiag_nto(cid)(0, 0) / ( ca.getMu(cid) * a3 ) );
+         const real_t fractionJ( std::min( invA_nn * ca.getMu(cid) * ( ( -gdot_nto[0] ) / std::sqrt( fsq ) - a3 * std::cos( shiftI - shiftJ ) ), real_c( 1 ) ) );
+
+         // Search interval determination.
+         real_t alpha_left, alpha_right;
+         if( fractionJ < -1 ) {
+            // J is complete
+            const real_t angleI( std::acos( fractionI ) );
+            alpha_left = -angleI - shiftI;
+            alpha_right = +angleI - shiftI;
+            if( alpha_left < 0 ) {
+               alpha_left += 2 * math::pi;
+               alpha_right += 2 * math::pi;
+            }
+         }
+         else if( ca.getDiag_nto(cid)(0, 0) > ca.getMu(cid) * a3 ) {
+            // I is complete
+            const real_t angleJ( std::acos( fractionJ ) );
+            alpha_left = -angleJ - shiftJ;
+            alpha_right = +angleJ - shiftJ;
+            if( alpha_left < 0 ) {
+               alpha_left += 2 * math::pi;
+               alpha_right += 2 * math::pi;
+            }
+         }
+         else {
+            // neither I nor J is complete
+            const real_t angleJ( std::acos( fractionJ ) );
+            real_t alpha1_left( -angleJ - shiftJ );
+            real_t alpha1_right( +angleJ - shiftJ );
+            if( alpha1_left < 0 ) {
+               alpha1_left += 2 * math::pi;
+               alpha1_right += 2 * math::pi;
+            }
+            const real_t angleI( std::acos( fractionI ) );
+            real_t alpha2_left( -angleI - shiftI );
+            real_t alpha2_right( +angleI - shiftI );
+            if( alpha2_left < 0 ) {
+               alpha2_left += 2 * math::pi;
+               alpha2_right += 2 * math::pi;
+            }
+
+            // Swap intervals if second interval does not start right of the first interval.
+            if( alpha1_left > alpha2_left ) {
+               std::swap( alpha1_left, alpha2_left );
+               std::swap( alpha1_right, alpha2_right );
+            }
+
+            if( alpha2_left > alpha1_right ) {
+               alpha2_right -= 2*math::pi;
+               if( alpha2_right > alpha1_right ) {
+                  // [alpha1_left; alpha1_right] \subset [alpha2_left; alpha2_right]
+               }
+               else {
+                  // [alpha2_left; alpha2_right] intersects the left end of [alpha1_left; alpha1_right]
+                  alpha1_right = alpha2_right;
+               }
+            }
+            else {
+               alpha1_left = alpha2_left;
+               if( alpha2_right > alpha1_right ) {
+                  // [alpha2_left; alpha2_right] intersects the right end of [alpha1_left; alpha1_right]
+               }
+               else {
+                  // [alpha2_left; alpha2_right] \subset [alpha1_left; alpha1_right]
+                  alpha1_right = alpha2_right;
+               }
+            }
+
+            alpha_left = alpha1_left;
+            alpha_right = alpha1_right;
+         }
+
+         const real_t phi( real_c(0.5) * ( real_c(1) + std::sqrt( real_c( 5 ) ) ) );
+         real_t alpha_mid( ( alpha_right + alpha_left * phi ) / ( 1 + phi ) );
+         Vec2 x_mid;
+         real_t f_mid;
+
+         {
+            real_t r_ub = ca.getMu(cid) * ( -gdot_nto[0] ) / ( ca.getDiag_nto(cid)(0, 0) + ca.getMu(cid) * a3 * std::cos( alpha_mid + shiftI ) );
+            if( r_ub < 0 )
+               r_ub = math::Limits<real_t>::inf();
+            x_mid = Vec2( r_ub * std::cos( alpha_mid ), r_ub * std::sin( alpha_mid ) );
+            f_mid = real_c(0.5) * x_mid * ( A_breve * x_mid ) - x_mid * b_breve;
+         }
+
+         bool leftlarger = false;
+         for( size_t k = 0; k < maxSubIterations_; ++k ) {
+            real_t alpha_next( alpha_left + ( alpha_right - alpha_mid ) );
+            real_t r_ub = ca.getMu(cid) * ( -gdot_nto[0] ) / ( ca.getDiag_nto(cid)(0, 0) + ca.getMu(cid) * a3 * std::cos( alpha_next + shiftI ) );
+            if( r_ub < 0 )
+               r_ub = math::Limits<real_t>::inf();
+            Vec2 x_next( r_ub * std::cos( alpha_next ), r_ub * std::sin( alpha_next ) );
+            real_t f_next( real_c(0.5) * x_next * ( A_breve * x_next ) - x_next * b_breve );
+
+            //WALBERLA_LOG_WARNING( "[(" << alpha_left << ", ?); (" << alpha_mid << ", " << f_mid << "); (" << alpha_right << ", ?)] <- (" << alpha_next << ", " << f_next << ")" );
+            //WALBERLA_LOG_WARNING( "left: " << alpha_mid - alpha_left << "  right: " << alpha_right - alpha_mid << "  ll: " << leftlarger );
+            //WALBERLA_ASSERT(leftlarger ? (alpha_mid - alpha_left > alpha_right - alpha_mid) : (alpha_mid - alpha_left < alpha_right - alpha_mid), "ll inconsistent!" );
+
+            if (leftlarger) {
+               // left interval larger
+               if( f_next < f_mid ) {
+                  alpha_right = alpha_mid;
+                  alpha_mid   = alpha_next;
+                  x_mid       = x_next;
+                  f_mid       = f_next;
+                  leftlarger = true;
+               }
+               else {
+                  alpha_left  = alpha_next;
+                  leftlarger = false;
+               }
+            }
+            else {
+               // right interval larger
+               if( f_next < f_mid ) {
+                  alpha_left = alpha_mid;
+                  alpha_mid  = alpha_next;
+                  x_mid      = x_next;
+                  f_mid      = f_next;
+                  leftlarger = false;
+               }
+               else {
+                  alpha_right = alpha_next;
+                  leftlarger = true;
+               }
+            }
+         }
+         //WALBERLA_LOG_DETAIL( "dalpha = " << alpha_right - alpha_left << "\n");
+         {
+            real_t alpha_init( std::atan2( p_cf[2], p_cf[1] ) );
+            real_t r_ub = ca.getMu(cid) * ( -gdot_nto[0] ) / ( ca.getDiag_nto(cid)(0, 0) + ca.getMu(cid) * a3 * std::cos( alpha_init + shiftI ) );
+            if( r_ub < 0 )
+               r_ub = math::Limits<real_t>::inf();
+            Vec2 x_init( r_ub * std::cos( alpha_init ), r_ub * std::sin( alpha_init ) );
+            real_t f_init( real_c(0.5) * x_init * ( A_breve * x_init ) - x_init * b_breve );
+
+            if( f_init < f_mid )
+            {
+               x_mid = x_init;
+               WALBERLA_LOG_DETAIL( "Replacing solution by primitive dissipative solution (" << f_init << " < " << f_mid << " at " << alpha_init << " vs. " << alpha_mid << ").\n");
+            }
+         }
+
+         p_cf[0] = invA_nn * ( -gdot_nto[0] - ca.getDiag_nto(cid)(0, 1) * x_mid[0] - ca.getDiag_nto(cid)(0, 2) * x_mid[1] );
+         p_cf[1] = x_mid[0];
+         p_cf[2] = x_mid[1];
+         //WALBERLA_LOG_DETAIL( "Contact #" << i << " is dynamic." );
+      }
+      else {
+         // Contact is static.
+         //WALBERLA_LOG_DETAIL( "Contact #" << i << " is static." );
+      }
+      Vec3 p_wf( contactframe * p_cf );
+      Vec3 dp( ca.getP(cid) - p_wf );
+      delta_max = std::max( delta_max, std::max( std::abs( dp[0] ), std::max( std::abs( dp[1] ), std::abs( dp[2] ) ) ) );
+      //WALBERLA_LOG_DETAIL( "Contact reaction in contact frame: " << p_cf << "\nContact action in contact frame: " << ca.getDiag_nto(cid)*p_cf + gdot_nto );
+
+      ca.getPRef(cid) = p_wf;
+
+      // Apply impulse right away.
+      pa.getDvRef(bId1) += pa.getInvMass(bId1) * ca.getP(cid);
+      pa.getDwRef(bId1) += pa.getInvInertia(bId1) * (ca.getR1(cid) % ca.getP(cid));
+      pa.getDvRef(bId2) -= pa.getInvMass(bId2) * ca.getP(cid);
+      pa.getDwRef(bId2) -= pa.getInvInertia(bId2) * (ca.getR2(cid) % ca.getP(cid));
+   }
+   return delta_max;
+}
+//*************************************************************************************************
+
+//*************************************************************************************************
+//*************************************************************************************************
+/*!\brief Relaxes all contacts once. The contact model is from the paper by Tschisgale et al.
+ * "A constraint-based collision model for Cosserat rods" and works with a coefficient of
+ * restitution cor with 0 < cor <= 1.
+ *
+ * \return The largest variation of contact impulses in the L-infinity norm.
+ *
+ */
+template <typename CAccessor, typename PAccessor>
+inline real_t HCSITSRelaxationStep::relaxInelasticContactsByProjectedGaussSeidel(size_t cid, real_t /*dtinv*/, CAccessor &ca, PAccessor& pa )
+{
+   real_t delta_max( 0 );
+   size_t bId1 = ca.getId1(cid);
+   size_t bId2 = ca.getId2(cid);
+   // Calculate the relative contact VELOCITY in the global world frame (if no contact reaction is present at contact i)
+   // This is the negative contact velocity as for the other methods
+   Vec3 gdot    ( ( pa.getLinearVelocity(bId2)     + pa.getDv(bId2) ) -
+                  ( pa.getLinearVelocity(bId1)     + pa.getDv(bId1) ) +
+                  ( pa.getAngularVelocity(bId2)    + pa.getDw(bId2) ) % ca.getR2(cid) -
+                  ( pa.getAngularVelocity(bId1)    + pa.getDw(bId1) ) % ca.getR1(cid) /* + diag_[i] * p */ );
+
+   // Use restitution hypothesis
+   gdot = gdot + getCor()*(gdot*ca.getNormal(cid))*ca.getNormal(cid);
+
+   Mat3 contactframe( ca.getNormal(cid), ca.getT(cid), ca.getO(cid) );
+
+   //
+   // Turn system matrix back to the world frame.
+   Mat3 K = contactframe * ca.getDiag_nto(cid) *  contactframe.getTranspose();
+   Mat3 Kinv = contactframe * ca.getDiag_nto_inv(cid) * contactframe.getTranspose();
+
+   // Compute impulse necessary in the world frame
+   Vec3 p_wf( - Kinv * gdot );
+
+
+
+   if( gdot * ca.getNormal(cid) <= 0 ) {
+      // Contact is separating if no contact reaction is present at contact i.
+      delta_max = std::max( delta_max, std::max( std::abs( ca.getP(cid)[0] ), std::max( std::abs( ca.getP(cid)[1] ), std::abs( ca.getP(cid)[2] ) ) ) );
+      ca.getPRef(cid) = Vec3();
+      // No need to apply zero impulse.
+   }
+   else {
+      // Dissect the impuls in a tangetial and normal directions
+      // Use the inverted contact frame with -n as in the publication
+      Mat3 reversedContactFrame( -ca.getNormal(cid), ca.getT(cid), ca.getO(cid) );
+      Vec3 p_rcf( reversedContactFrame.getTranspose() * p_wf );
+
+      // Check the frictional limit
+      real_t flimit( ca.getMu(cid) * p_rcf[0] );
+
+      // Square of tangential components of the impulse
+      real_t fsq( p_rcf[1] * p_rcf[1] + p_rcf[2] * p_rcf[2] );
+
+      if( fsq > flimit * flimit || p_rcf[0] < 0 ) {
+         // Contact cannot be static so it must be dynamic.
+         // Calculate corrected contact reaction by the method of Tschigale et al.
+         // Normal component is close to 0 or negative, and we cannot asses a tangential direction
+         // Treat this case with the 0 impulse
+         if (fsq < real_t(1e-8)) {
+            delta_max = std::max(delta_max, std::max(std::abs(ca.getP(cid)[0]),
+                                                     std::max(std::abs(ca.getP(cid)[1]), std::abs(ca.getP(cid)[2]))));
+            ca.getPRef(cid) = Vec3();
+         } else {
+            // tangential direction of sliding
+            Vec3 tan_dir = ((p_rcf[1] * ca.getT(cid)) + (p_rcf[2] * ca.getO(cid))).getNormalized();
+            // scalar magnitude of pv.
+            real_t abspv = ((K * p_wf) * ca.getNormal(cid)) /
+                           ((K * (-ca.getNormal(cid) + ca.getMu(cid) * tan_dir)) * ca.getNormal(cid));
+            p_wf = abspv * (-ca.getNormal(cid) + ca.getMu(cid) * tan_dir);
+
+         }
+      }
+      // Calculate variation
+      Vec3 dp(ca.getP(cid) - p_wf);
+      delta_max = std::max(delta_max, std::max(std::abs(dp[0]), std::max(std::abs(dp[1]), std::abs(dp[2]))));
+      ca.getPRef(cid) = p_wf;
+
+      // Apply impulse right away.
+      pa.getDvRef(bId1) -= pa.getInvMass(bId1) * ca.getP(cid);
+      pa.getDwRef(bId1) -= pa.getInvInertia(bId1) * (ca.getR1(cid) % ca.getP(cid));
+      pa.getDvRef(bId2) += pa.getInvMass(bId2) * ca.getP(cid);
+      pa.getDwRef(bId2) += pa.getInvInertia(bId2) * (ca.getR2(cid) % ca.getP(cid));
+   }
+   return delta_max;
+}
+//*************************************************************************************************
+
+
+} //namespace kernel
+} //namespace mesa_pd
+} //namespace walberla
\ No newline at end of file
diff --git a/src/mesa_pd/kernel/InitContactsForHCSITS.h b/src/mesa_pd/kernel/InitContactsForHCSITS.h
new file mode 100644
index 0000000000000000000000000000000000000000..e2d14795204d7372f0b61032f3437653acbbd154
--- /dev/null
+++ b/src/mesa_pd/kernel/InitContactsForHCSITS.h
@@ -0,0 +1,175 @@
+//======================================================================================================================
+//
+//  This file is part of waLBerla. waLBerla is free software: you can
+//  redistribute it and/or modify it under the terms of the GNU General Public
+//  License as published by the Free Software Foundation, either version 3 of
+//  the License, or (at your option) any later version.
+//
+//  waLBerla is distributed in the hope that it will be useful, but WITHOUT
+//  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+//  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+//  for more details.
+//
+//  You should have received a copy of the GNU General Public License along
+//  with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file InitContactsForHCSITS.h
+//! \author Tobias Leemann <tobias.leemann@fau.de>
+//
+//======================================================================================================================
+
+//======================================================================================================================
+//
+//  THIS FILE IS GENERATED - PLEASE CHANGE THE TEMPLATE !!!
+//
+//======================================================================================================================
+
+#pragma once
+
+#include <mesa_pd/common/ParticleFunctions.h>
+#include <mesa_pd/data/DataTypes.h>
+#include <mesa_pd/data/IAccessor.h>
+#include <mesa_pd/data/IContactAccessor.h>
+#include <mesa_pd/data/Flags.h>
+#include <core/logging/Logging.h>
+
+#include <vector>
+
+namespace walberla {
+namespace mesa_pd {
+namespace kernel {
+
+/**
+* Init the datastructures for a contact for later use of the HCSITS-Solver.
+* Call this kernel on all contacts that you want to treat with HCSITS before performing any relaxation timesteps.
+* Use setErp() to set the error reduction parameter, which defines the share of the overlap that is resolved in one step
+* (0 meaning after the relaxation the overlap is the same, 1 meaning the particles will have no overlap after relaxation).
+* Use setFriction(a,b, cof) to define the coefficient of friction cof between materials a and b. It is assumed to be
+ * symmetric w.r.t. the materials.
+* \ingroup mesa_pd_kernel
+*/
+class InitContactsForHCSITS{
+public:
+
+   // Default constructor sets the default values
+   explicit InitContactsForHCSITS(const uint_t numParticleTypes) :
+   numParticleTypes_ (numParticleTypes),
+   erp_( real_t(0.8) ),
+   maximumPenetration_( 0 )
+   {
+
+      
+      friction_.resize(numParticleTypes * numParticleTypes, real_t(0));
+   }
+
+   // Getter and Setter Functions
+   inline const real_t& getErp() const {return erp_;}
+   inline void setErp(real_t v) { erp_ = v;}
+   
+   inline const real_t& getMaximumPenetration() const {return maximumPenetration_;}
+   inline void setMaximumPenetration(real_t v) { maximumPenetration_ = v;}
+   
+
+   // Getter and Setter Functions for material parameter combinations (they are assumed symmetric).
+   
+   inline void setFriction(const size_t type1, const size_t type2, const real_t& val)
+   {
+      WALBERLA_ASSERT_LESS( type1, numParticleTypes_ );
+      WALBERLA_ASSERT_LESS( type2, numParticleTypes_ );
+      friction_[numParticleTypes_*type1 + type2] = val;
+      friction_[numParticleTypes_*type2 + type1] = val;
+   }
+
+   
+   inline real_t getFriction(const size_t type1, const size_t type2) const
+   {
+      WALBERLA_ASSERT_LESS( type1, numParticleTypes_ );
+      WALBERLA_ASSERT_LESS( type2, numParticleTypes_ );
+      WALBERLA_ASSERT_FLOAT_EQUAL( friction_[numParticleTypes_*type1 + type2],
+              friction_[numParticleTypes_*type2 + type1],
+              "parameter matrix for friction not symmetric!");
+      return friction_[numParticleTypes_*type1 + type2];
+   }
+
+   // List material parameters
+   
+   std::vector<real_t> friction_ {};
+
+   template<typename CAccessor, typename PAccessor>
+   void operator()(size_t c, CAccessor &ca, PAccessor &pa);
+
+private:
+   // List properties
+   const uint_t numParticleTypes_;
+
+   
+   real_t erp_;
+   real_t maximumPenetration_;
+
+   
+
+};
+
+
+template<typename CAccessor, typename PAccessor>
+inline void InitContactsForHCSITS::operator()(size_t c, CAccessor &ca, PAccessor &pa) {
+
+      static_assert(std::is_base_of<data::IContactAccessor, CAccessor>::value, "please provide a valid contact accessor");
+      static_assert(std::is_base_of<data::IAccessor, PAccessor>::value, "please provide a valid particle accessor");
+
+   size_t bId1 = ca.getId1(c);
+   size_t bId2 = ca.getId2(c);
+   ca.setR1(c, ca.getPosition(c) - pa.getPosition(bId1));
+   ca.setR2(c, ca.getPosition(c) - pa.getPosition(bId2));
+
+
+   // construct vector perpendicular to the normal (cross product with cardinal basis vector where the 1 component is where the other vector has its component of smallest magnitude)
+   if (std::fabs(ca.getNormalRef(c)[0]) < std::fabs(ca.getNormalRef(c)[1])) {
+      if (std::fabs(ca.getNormalRef(c)[0]) < std::fabs(ca.getNormalRef(c)[2]))
+         ca.setT(c, Vec3(0, ca.getNormalRef(c)[2], -ca.getNormalRef(c)[1]));   // = n x (1, 0, 0)^T
+      else
+         ca.setT(c, Vec3(ca.getNormalRef(c)[1], -ca.getNormalRef(c)[0], 0));   // = n x (0, 0, 1)^T
+   } else {
+      if (std::fabs(ca.getNormalRef(c)[1]) < std::fabs(ca.getNormalRef(c)[2]))
+         ca.setT(c, Vec3(-ca.getNormalRef(c)[2], 0, ca.getNormalRef(c)[0]));   // = n x (0, 1, 0)^T
+      else
+         ca.setT(c, Vec3(ca.getNormalRef(c)[1], -ca.getNormalRef(c)[0], 0));   // = n x (0, 0, 1)^T
+   }
+   normalize(ca.getTRef(c));
+   ca.setO(c, ca.getNormal(c) % ca.getT(c));
+
+   Mat3 contactframe(ca.getNormal(c), ca.getT(c), ca.getO(c));
+
+   // If the distance is negative then penetration is present. This is an error and should be corrected.
+   // Correcting the whole error is not recommended since due to the linearization the errors cannot
+   // completely fixed anyway and the error reduction will introduce artificial restitution.
+   // However, if the distance is positive then it is not about error correction but the distance that
+   // can still be overcome without penetration and thus no error correction parameter should be applied.
+   if (ca.getDistance(c) < real_t(0.0)) {
+      setMaximumPenetration(std::max(getMaximumPenetration(), -ca.getDistance(c)));
+      ca.getDistanceRef(c) *= erp_;
+   }
+
+   ca.getMuRef(c) = getFriction(pa.getType(bId1), pa.getType(bId2));
+
+   Mat3 diag = -(
+           math::skewSymCrossProduct(ca.getR1(c),
+                                     math::skewSymCrossProduct(pa.getInvInertia(bId1), ca.getR1(c)))
+           + math::skewSymCrossProduct(ca.getR2(c),
+                                       math::skewSymCrossProduct(pa.getInvInertia(bId2), ca.getR2(c))));
+   diag[0] += pa.getInvMass(bId1) + pa.getInvMass(bId2);
+   diag[4] += pa.getInvMass(bId1) + pa.getInvMass(bId2);
+   diag[8] += pa.getInvMass(bId1) + pa.getInvMass(bId2);
+
+   diag = contactframe.getTranspose() * diag * contactframe;
+
+   // Diagonal block is known to be positive-definite and thus an inverse always exists.
+   ca.getDiag_ntoRef(c) = diag;
+   ca.getDiag_nto_invRef(c) = diag.getInverse();
+   ca.getDiag_n_invRef(c) = math::inv(diag[0]);
+   ca.getDiag_to_invRef(c) = Mat2(diag[4], diag[5], diag[7], diag[8]).getInverse();
+}
+
+}
+}
+}
\ No newline at end of file
diff --git a/src/mesa_pd/kernel/InitParticlesForHCSITS.h b/src/mesa_pd/kernel/InitParticlesForHCSITS.h
new file mode 100644
index 0000000000000000000000000000000000000000..5a72e4fadaee5c914b88c654ae40cf41a6955d0d
--- /dev/null
+++ b/src/mesa_pd/kernel/InitParticlesForHCSITS.h
@@ -0,0 +1,119 @@
+//======================================================================================================================
+//
+//  This file is part of waLBerla. waLBerla is free software: you can
+//  redistribute it and/or modify it under the terms of the GNU General Public
+//  License as published by the Free Software Foundation, either version 3 of
+//  the License, or (at your option) any later version.
+//
+//  waLBerla is distributed in the hope that it will be useful, but WITHOUT
+//  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+//  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+//  for more details.
+//
+//  You should have received a copy of the GNU General Public License along
+//  with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file InitParticlesForHCSITS.h
+//! \author Tobias Leemann <tobias.leemann@fau.de>
+//
+//======================================================================================================================
+
+//======================================================================================================================
+//
+//  THIS FILE IS GENERATED - PLEASE CHANGE THE TEMPLATE !!!
+//
+//======================================================================================================================
+
+#pragma once
+
+#include <mesa_pd/common/ParticleFunctions.h>
+#include <mesa_pd/data/DataTypes.h>
+#include <mesa_pd/data/IAccessor.h>
+#include <mesa_pd/data/Flags.h>
+#include <core/logging/Logging.h>
+
+#include <vector>
+
+namespace walberla {
+namespace mesa_pd {
+namespace kernel {
+/**
+ * Init the datastructures for the particles for later use of the HCSITS-Solver.
+ * Call this kernel on all particles that will be treated with HCSITS before performing any relaxation timesteps.
+ * Use setGlobalAcceleration() to set an accelleration action uniformly across all particles (e.g. gravity)
+ * \ingroup mesa_pd_kernel
+ */
+class InitParticlesForHCSITS
+{
+public:
+   // Default constructor sets the default values
+   InitParticlesForHCSITS() :
+   globalAcceleration_( 0 )
+   {}
+
+   // Getter and Setter Functions for properties
+   inline const walberla::mesa_pd::Vec3& getGlobalAcceleration() const {return globalAcceleration_;}
+   inline void setGlobalAcceleration(walberla::mesa_pd::Vec3 v) { globalAcceleration_ = v;}
+   
+
+   template <typename Accessor>
+   void operator()(size_t j, Accessor& ac, real_t dt);
+
+   template <typename Accessor>
+   void initializeVelocityCorrections(Accessor& ac, size_t body, Vec3& dv, Vec3& dw, real_t dt ) const;
+
+private:
+   // List properties
+   
+   walberla::mesa_pd::Vec3 globalAcceleration_;
+
+};
+
+
+template <typename Accessor>
+inline void InitParticlesForHCSITS::operator()(size_t j, Accessor& ac, real_t dt)
+{
+   using namespace data::particle_flags;
+   static_assert(std::is_base_of<data::IAccessor, Accessor>::value, "please provide a valid accessor");
+   auto particle_flags = ac.getFlagsRef(j);
+   if (isSet(particle_flags, GLOBAL)){
+      WALBERLA_CHECK( isSet(particle_flags, FIXED), "Global bodies need to have infinite mass as they are not communicated!" );
+      initializeVelocityCorrections( ac, j, ac.getDvRef(j), ac.getDwRef(j), dt ); // use applied external forces to calculate starting velocity
+   }else{
+      initializeVelocityCorrections( ac, j, ac.getDvRef(j), ac.getDwRef(j), dt ); // use applied external forces to calculate starting velocity
+      if(!isSet(particle_flags, FIXED)){ // Update velocities with global acceleration and angular velocity with euler eqn
+         ac.getLinearVelocityRef(j) = ac.getLinearVelocity(j) + getGlobalAcceleration() * dt;
+         ac.getAngularVelocityRef(j) = ac.getAngularVelocity(j) + dt * ( ac.getInvInertia(j) * ( ( ac.getInertia(j) * ac.getAngularVelocity(j) ) % ac.getAngularVelocity(j) ) );
+      }
+   }
+}
+
+
+//*************************************************************************************************
+/*!\brief Calculates the initial velocity corrections of a given body.
+ * \param ac The particle accessor
+ * \param body The body whose velocities to time integrate
+ * \param dv On return the initial linear velocity correction.
+ * \param w On return the initial angular velocity correction.
+ * \param dt The time step size.
+ * \return void
+ *
+ * Calculates the velocity corrections effected by external forces and torques in an explicit Euler
+ * time integration of the velocities of the given body. For fixed objects the velocity corrections
+ * are set to zero. External forces and torques are reset if indicated by the settings.
+ */
+template <typename Accessor>
+inline void InitParticlesForHCSITS::initializeVelocityCorrections(Accessor& ac, size_t body, Vec3& dv, Vec3& dw, real_t dt ) const
+{
+   dv = ( ac.getInvMass(body) * dt ) * ac.getForce(body);
+   dw = dt * ( ac.getInvInertia(body) * ac.getTorque(body) );
+
+   ac.getForceRef(body) = Vec3();
+   ac.getTorqueRef(body) = Vec3();
+}
+//*************************************************************************************************
+
+
+} //namespace kernel
+} //namespace mesa_pd
+} //namespace walberla
\ No newline at end of file
diff --git a/src/mesa_pd/kernel/IntegrateParticlesHCSITS.h b/src/mesa_pd/kernel/IntegrateParticlesHCSITS.h
new file mode 100644
index 0000000000000000000000000000000000000000..7cc75be73f78cba51ba5d78b29e037624710ae42
--- /dev/null
+++ b/src/mesa_pd/kernel/IntegrateParticlesHCSITS.h
@@ -0,0 +1,158 @@
+//======================================================================================================================
+//
+//  This file is part of waLBerla. waLBerla is free software: you can
+//  redistribute it and/or modify it under the terms of the GNU General Public
+//  License as published by the Free Software Foundation, either version 3 of
+//  the License, or (at your option) any later version.
+//
+//  waLBerla is distributed in the hope that it will be useful, but WITHOUT
+//  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+//  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+//  for more details.
+//
+//  You should have received a copy of the GNU General Public License along
+//  with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file IntegrateParticlesHCSITS.h
+//! \author Sebastian Eibl <sebastian.eibl@fau.de>
+//! \author Tobias Leemann <tobias.leemann@fau.de>
+//
+//======================================================================================================================
+
+//======================================================================================================================
+//
+//  THIS FILE IS GENERATED - PLEASE CHANGE THE TEMPLATE !!!
+//
+//======================================================================================================================
+
+#pragma once
+
+#include <mesa_pd/common/ParticleFunctions.h>
+#include <mesa_pd/data/DataTypes.h>
+#include <mesa_pd/data/IAccessor.h>
+#include <mesa_pd/data/ContactStorage.h>
+#include <mesa_pd/data/Flags.h>
+#include <core/logging/Logging.h>
+#include <core/math/Constants.h>
+
+#include <vector>
+
+namespace walberla {
+namespace mesa_pd {
+namespace kernel {
+
+/**
+ * Kernel performing integration of the particles after the HCSITS iteration is done.
+ * Call this kernel on all particles j to integrate them by a timestep of size dt.
+ * The Speed Limiter limits the number of body radii, a particle can travel in one timestep.
+ * The speed limit factor defines a number of radii that are allowed in a timestep, e.g. a factor of 1 means, that
+ * a particle can only travel one time its radius in each timestep.
+ *
+ * \ingroup mesa_pd_kernel
+ */
+class IntegrateParticlesHCSITS
+{
+   public:
+   // Default constructor sets the default values
+   IntegrateParticlesHCSITS() :
+   speedLimiterActive_( false ),
+   speedLimitFactor_( real_t(1.0) )
+   {}
+
+   // Getter and Setter Functions
+   inline const bool& getSpeedLimiterActive() const {return speedLimiterActive_;}
+   inline void setSpeedLimiterActive(bool v) { speedLimiterActive_ = v;}
+   
+   inline const real_t& getSpeedLimitFactor() const {return speedLimitFactor_;}
+   inline void setSpeedLimitFactor(real_t v) { speedLimitFactor_ = v;}
+   
+
+   template <typename PAccessor>
+   void operator()(size_t j, PAccessor& ac, real_t dt);
+
+   template <typename PAccessor>
+   void integratePositions(PAccessor& ac, size_t body, Vec3 v, Vec3 w, real_t dt ) const;
+
+
+   private:
+   // List properties
+   
+   bool speedLimiterActive_;
+   real_t speedLimitFactor_;
+};
+
+
+template <typename PAccessor>
+inline void IntegrateParticlesHCSITS::operator()(size_t j, PAccessor& ac, real_t dt)
+{
+   using namespace data::particle_flags;
+   static_assert(std::is_base_of<data::IAccessor, PAccessor>::value, "please provide a valid accessor");
+
+   auto body_flags = ac.getFlagsRef(j);
+   if (isSet(body_flags, FIXED)){
+      integratePositions(ac, j, ac.getLinearVelocity(j), ac.getAngularVelocity(j), dt );
+   }else{
+      integratePositions(ac, j, ac.getLinearVelocity(j) + ac.getDv(j), ac.getAngularVelocity(j) + ac.getDw(j), dt );
+   }
+}
+
+
+
+
+//*************************************************************************************************
+/*!\brief Time integration of the position and orientation of a given body.
+ *
+ * \param body The body whose position and orientation to time integrate
+ * \param v The linear velocity to use for time integration of the position.
+ * \param w The angular velocity to use for time integration of the orientation.
+ * \param dt The time step size.
+ * \return void
+ *
+ * Performs an Euler time integration of the positions of the given body. Velocities are damped if
+ * indicated by the settings and stored back in the body properties. The bounding box is
+ * recalculated and it is redetermined whether the body is awake or not. Also the data
+ * structure tracking the contacts attached to the body are cleared and
+ */
+template <typename PAccessor>
+inline void IntegrateParticlesHCSITS::integratePositions(PAccessor& ac, size_t body, Vec3 v, Vec3 w, real_t dt ) const {
+   using namespace data::particle_flags;
+   auto body_flags = ac.getFlags(body);
+   if (isSet(body_flags, FIXED))
+      return;
+
+
+   if (getSpeedLimiterActive()) {
+      const auto speed = v.length();
+      const auto edge = ac.getInteractionRadius(body);
+      if (speed * dt > edge * getSpeedLimitFactor()) {
+         v = v * (edge * getSpeedLimitFactor() / dt / speed);
+      }
+
+      const real_t maxPhi = real_t(2) * math::pi * getSpeedLimitFactor();
+      const real_t phi = w.length() * dt;
+      if (phi > maxPhi) {
+         w = w / phi * maxPhi;
+      }
+   }
+
+   // Calculating the translational displacement
+   ac.getPositionRef(body) = (ac.getPosition(body) + v * dt);
+
+   // Calculating the rotation angle
+   const Vec3 phi(w * dt);
+
+   // Calculating the new orientation
+   WALBERLA_ASSERT(!math::isnan(phi), " phi: " << phi << " w: " << w << " dt: " << dt );
+   ac.getRotationRef(body).rotate(phi, phi.length());
+
+   // Storing the velocities back in the body properties
+   ac.getLinearVelocityRef(body) = v;
+   ac.getAngularVelocityRef(body) = w;
+}
+//*************************************************************************************************
+
+
+
+} //namespace kernel
+} //namespace mesa_pd
+} //namespace walberla
\ No newline at end of file
diff --git a/src/mesa_pd/mpi/notifications/VelocityCorrectionNotification.h b/src/mesa_pd/mpi/notifications/VelocityCorrectionNotification.h
new file mode 100644
index 0000000000000000000000000000000000000000..dd4ca2a89d89251f35cca0dfef8750e452cf1b34
--- /dev/null
+++ b/src/mesa_pd/mpi/notifications/VelocityCorrectionNotification.h
@@ -0,0 +1,120 @@
+//======================================================================================================================
+//
+//  This file is part of waLBerla. waLBerla is free software: you can
+//  redistribute it and/or modify it under the terms of the GNU General Public
+//  License as published by the Free Software Foundation, either version 3 of
+//  the License, or (at your option) any later version.
+//
+//  waLBerla is distributed in the hope that it will be useful, but WITHOUT
+//  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+//  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+//  for more details.
+//
+//  You should have received a copy of the GNU General Public License along
+//  with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file VelocityCorrectionNotification.h
+//! \author Sebastian Eibl <sebastian.eibl@fau.de>
+//
+//======================================================================================================================
+
+//======================================================================================================================
+//
+//  THIS FILE IS GENERATED - PLEASE CHANGE THE TEMPLATE !!!
+//
+//======================================================================================================================
+
+#pragma once
+
+#include <mesa_pd/data/DataTypes.h>
+#include <mesa_pd/data/ParticleStorage.h>
+#include <mesa_pd/mpi/notifications/NotificationType.h>
+#include <mesa_pd/mpi/notifications/reset.h>
+
+#include <core/mpi/Datatype.h>
+#include <core/mpi/RecvBuffer.h>
+#include <core/mpi/SendBuffer.h>
+
+namespace walberla {
+namespace mesa_pd {
+
+/**
+ * Transmits corrections of the linear and angular velocity (dv / dw) that were generated by the impulses acting on the
+ * ghost particles during application of the Hard-Contact-Solvers (HCSITS) to the main particle and adds them up.
+ * Use this Notification with ReduceProperty only.
+ */
+class VelocityCorrectionNotification
+{
+public:
+
+   struct Parameters
+   {
+      id_t uid_;
+      Vec3 dv_; /* Linear velocity correction */
+      Vec3 dw_; /* Angular velocity correction */
+   };
+
+   inline explicit VelocityCorrectionNotification( const data::Particle& p ) : p_(p)  {}
+
+   const data::Particle& p_;
+};
+
+
+// Reduce method for reduction (add up the velocity corrections)
+void reduce(data::Particle&& p, const VelocityCorrectionNotification::Parameters& objparam)
+{
+   p.getDvRef() += objparam.dv_;
+   p.getDwRef() += objparam.dw_;
+}
+
+template<>
+void reset<VelocityCorrectionNotification>(data::Particle& p )
+{
+   p.setDv( Vec3(real_t(0)) );
+   p.setDw( Vec3(real_t(0)) );
+}
+
+}  // namespace mesa_pd
+}  // namespace walberla
+
+//======================================================================================================================
+//
+//  Send/Recv Buffer Serialization Specialization
+//
+//======================================================================================================================
+
+namespace walberla {
+namespace mpi {
+
+template< typename T,    // Element type of SendBuffer
+          typename G>    // Growth policy of SendBuffer
+mpi::GenericSendBuffer<T,G>& operator<<( mpi::GenericSendBuffer<T,G> & buf, const mesa_pd::VelocityCorrectionNotification& obj )
+{
+   buf.addDebugMarker( "ft" );
+   buf << obj.p_.getUid();
+   buf << obj.p_.getDv();
+   buf << obj.p_.getDw();
+   return buf;
+}
+
+template< typename T>    // Element type  of RecvBuffer
+mpi::GenericRecvBuffer<T>& operator>>( mpi::GenericRecvBuffer<T> & buf, mesa_pd::VelocityCorrectionNotification::Parameters& objparam )
+{
+   buf.readDebugMarker( "ft" );
+   buf >> objparam.uid_;
+   buf >> objparam.dv_;
+   buf >> objparam.dw_;
+   return buf;
+}
+
+template< >
+struct BufferSizeTrait< mesa_pd::VelocityCorrectionNotification > {
+   static const bool constantSize = true;
+   static const uint_t size = BufferSizeTrait<id_t>::size +
+                              BufferSizeTrait<mesa_pd::Vec3>::size +
+                              BufferSizeTrait<mesa_pd::Vec3>::size +
+                              mpi::BUFFER_DEBUG_OVERHEAD;
+};
+
+} // mpi
+} // walberla
diff --git a/src/mesa_pd/mpi/notifications/VelocityUpdateNotification.h b/src/mesa_pd/mpi/notifications/VelocityUpdateNotification.h
new file mode 100644
index 0000000000000000000000000000000000000000..7f8c1e7c733df07629bbbc4fe3540c19c7dc97d4
--- /dev/null
+++ b/src/mesa_pd/mpi/notifications/VelocityUpdateNotification.h
@@ -0,0 +1,135 @@
+//======================================================================================================================
+//
+//  This file is part of waLBerla. waLBerla is free software: you can
+//  redistribute it and/or modify it under the terms of the GNU General Public
+//  License as published by the Free Software Foundation, either version 3 of
+//  the License, or (at your option) any later version.
+//
+//  waLBerla is distributed in the hope that it will be useful, but WITHOUT
+//  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+//  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+//  for more details.
+//
+//  You should have received a copy of the GNU General Public License along
+//  with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file VelocityCorrectionNotification.h
+//! \author Sebastian Eibl <sebastian.eibl@fau.de>
+//
+//======================================================================================================================
+
+//======================================================================================================================
+//
+//  THIS FILE IS GENERATED - PLEASE CHANGE THE TEMPLATE !!!
+//
+//======================================================================================================================
+
+#pragma once
+
+#include <mesa_pd/data/DataTypes.h>
+#include <mesa_pd/data/ParticleStorage.h>
+#include <mesa_pd/mpi/notifications/NotificationType.h>
+#include <mesa_pd/mpi/notifications/reset.h>
+#include <core/mpi/Datatype.h>
+#include <core/mpi/RecvBuffer.h>
+#include <core/mpi/SendBuffer.h>
+
+namespace walberla {
+namespace mesa_pd {
+
+/**
+ * Adds up LinearVelocity + Parameters::relaxationParam * velocity_correction in a particle and transmits the result to
+ * all its ghost particles.
+ * After adding up and sending the result, the velocity corrections of the main particle are reset to 0.
+ * After receiving new values, the velocity_corrections of the ghost_particles are reset to 0.
+ * This notification is used during relaxation with the HCSITS solver.
+ * Notification for use with BroadcastProperty only.
+ *
+ */
+class VelocityUpdateNotification
+{
+public:
+
+   struct Parameters
+   {
+      static real_t relaxationParam;
+      id_t uid_;
+      Vec3 v_; /* Linear velocity */
+      Vec3 w_; /* Angular velocity */
+   };
+
+   inline explicit VelocityUpdateNotification( data::Particle& p ) : p_(p)  {}
+
+   data::Particle& p_;
+};
+
+real_t VelocityUpdateNotification::Parameters::relaxationParam = real_t(0.8);
+
+// Update method for broadcast
+void update(data::Particle&& p, const VelocityUpdateNotification::Parameters& objparam) {
+   // Reset the velocity corrections dv/dw of ghost particle
+   p.getDvRef() = Vec3();
+   p.getDwRef() = Vec3();
+   p.getLinearVelocityRef() = objparam.v_;
+   p.getAngularVelocityRef() = objparam.w_;
+}
+
+template<>
+void reset<VelocityUpdateNotification>(data::Particle& p )
+{
+   p.setDv( Vec3(real_t(0)) );
+   p.setDw( Vec3(real_t(0)) );
+   p.setLinearVelocity( Vec3(real_t(0)) );
+   p.setAngularVelocity( Vec3(real_t(0)) );
+}
+
+}  // namespace mesa_pd
+}  // namespace walberla
+
+//======================================================================================================================
+//
+//  Send/Recv Buffer Serialization Specialization
+//
+//======================================================================================================================
+
+namespace walberla {
+namespace mpi {
+
+template< typename T,    // Element type of SendBuffer
+          typename G>    // Growth policy of SendBuffer
+mpi::GenericSendBuffer<T,G>& operator<<( mpi::GenericSendBuffer<T,G> & buf, const mesa_pd::VelocityUpdateNotification& obj )
+{
+   // Perform the addition
+   obj.p_.getLinearVelocityRef() = obj.p_.getLinearVelocity() + mesa_pd::VelocityUpdateNotification::Parameters::relaxationParam * obj.p_.getDv();
+   obj.p_.getAngularVelocityRef() = obj.p_.getAngularVelocity() + mesa_pd::VelocityUpdateNotification::Parameters::relaxationParam * obj.p_.getDw();
+   // Reset the velocity corrections dv/dw of main particle
+   obj.p_.getDvRef() = mesa_pd::Vec3();
+   obj.p_.getDwRef() = mesa_pd::Vec3();
+   buf.addDebugMarker( "ft" );
+   buf << obj.p_.getUid();
+   buf << obj.p_.getLinearVelocity();
+   buf << obj.p_.getAngularVelocity();
+   return buf;
+}
+
+template< typename T>    // Element type  of RecvBuffer
+mpi::GenericRecvBuffer<T>& operator>>( mpi::GenericRecvBuffer<T> & buf, mesa_pd::VelocityUpdateNotification::Parameters& objparam )
+{
+   buf.readDebugMarker( "ft" );
+   buf >> objparam.uid_;
+   buf >> objparam.v_;
+   buf >> objparam.w_;
+   return buf;
+}
+
+template< >
+struct BufferSizeTrait< mesa_pd::VelocityUpdateNotification > {
+   static const bool constantSize = true;
+   static const uint_t size = BufferSizeTrait<id_t>::size +
+                              BufferSizeTrait<mesa_pd::Vec3>::size +
+                              BufferSizeTrait<mesa_pd::Vec3>::size +
+                              mpi::BUFFER_DEBUG_OVERHEAD;
+};
+
+} // mpi
+} // walberla
diff --git a/src/mesa_pd/vtk/ParticleVtkOutput.cpp b/src/mesa_pd/vtk/ParticleVtkOutput.cpp
index b63295893ed9827127aabcbe3ae26eb44e48e539..018670be9dd72965049fd3c0006fbe41a3cecd0f 100644
--- a/src/mesa_pd/vtk/ParticleVtkOutput.cpp
+++ b/src/mesa_pd/vtk/ParticleVtkOutput.cpp
@@ -72,7 +72,7 @@ void ParticleVtkOutput::push( walberla::vtk::Base64Writer& b64, const uint_t dat
    selectors_[data].second->push(b64, (*ps_)[particleIndices_[point]], component);
 }
 
-void ParticleVtkOutput::addOutput(const std::string& name, std::shared_ptr<IOutputSelector> selector)
+void ParticleVtkOutput::addOutput(const std::string& name, const std::shared_ptr<IOutputSelector>& selector)
 {
    if ( std::find_if(selectors_.begin(), selectors_.end(), [&name](const auto& item){return item.first==name;} ) !=
         selectors_.end() )
diff --git a/src/mesa_pd/vtk/ParticleVtkOutput.h b/src/mesa_pd/vtk/ParticleVtkOutput.h
index 651403cea4cc750620486306a6debb4290dc8eb1..5cbe88a6d546009b550aac368d836c56aa79f68e 100644
--- a/src/mesa_pd/vtk/ParticleVtkOutput.h
+++ b/src/mesa_pd/vtk/ParticleVtkOutput.h
@@ -55,7 +55,7 @@ public:
    template <typename T>
    void addOutput(const std::string& name) { addOutput(name, std::make_shared<OutputSelector<T>>(T())); }
 
-   void addOutput(const std::string& name, std::shared_ptr<IOutputSelector> selector);
+   void addOutput(const std::string& name, const std::shared_ptr<IOutputSelector>& selector);
 
    ///sets a function which decides which particles should be written to file
    void setParticleSelector( const ParticleSelectorFunc& func) {particleSelector_ = func;}
diff --git a/src/pe/ccd/HashGrids.cpp b/src/pe/ccd/HashGrids.cpp
index b73a25548efae620d69f6310df736e3900d922e0..0f9d4908dc4ad4c2dea8dab6c95534ebbab13dc3 100644
--- a/src/pe/ccd/HashGrids.cpp
+++ b/src/pe/ccd/HashGrids.cpp
@@ -788,7 +788,7 @@ void HashGrids::update(WcTimingTree* tt)
 
    if (tt != nullptr) tt->start("AddNewBodies");
    // Finally add all bodies that were temporarily stored in 'bodiesToAdd_' to the data structure.
-   if( bodiesToAdd_.size() > 0 )
+   if( !bodiesToAdd_.empty() )
    {
       for( auto bodyIt = bodiesToAdd_.begin(); bodyIt < bodiesToAdd_.end(); ++bodyIt ) {
 
diff --git a/src/pe/collision/EPA.cpp b/src/pe/collision/EPA.cpp
index 85775e5a89893aa2638ac7ae0cb58d64c750d7a6..6e7eb97551070580c1686139876341868d5923d7 100644
--- a/src/pe/collision/EPA.cpp
+++ b/src/pe/collision/EPA.cpp
@@ -263,7 +263,7 @@ bool EPA::doEPA( GeomPrimitive &geom1, GeomPrimitive &geom2, const GJK& gjk, Vec
       }
    }
 
-   if(entryHeap.size() == 0) {
+   if(entryHeap.empty()) {
       //unrecoverable error.
       return false;
    }
@@ -461,7 +461,7 @@ bool EPA::doEPA( GeomPrimitive &geom1, GeomPrimitive &geom2, const GJK& gjk, Vec
 
          firstTriangle->link(2, lastTriangle, 1);
       }
-   } while (entryHeap.size() > 0 && entryHeap[0]->getSqrDist() <= upperBoundSqr);
+   } while (!entryHeap.empty() && entryHeap[0]->getSqrDist() <= upperBoundSqr);
 
    //Normal must be inverted
    retNormal   = -current->getClosest().getNormalized();
diff --git a/src/pe/collision/GJK.cpp b/src/pe/collision/GJK.cpp
index e25c62b5e5114fbde39d5e8ee127b12af18f21da..d2320f9ec63d8c9c68b919e149e8a21d360a695f 100644
--- a/src/pe/collision/GJK.cpp
+++ b/src/pe/collision/GJK.cpp
@@ -286,7 +286,7 @@ inline real_t GJK::calcDistance( Vec3& normal, Vec3& contactPoint )
    //its distance to the origin is the distance of the two objects
    real_t dist= 0.0;
 
-   real_t barCoords[3] = { 0.0, 0.0, 0.0};
+   std::array<real_t, 3> barCoords = {{ 0.0, 0.0, 0.0 }};
    real_t& u = barCoords[0];
    real_t& v = barCoords[1];
    real_t& w = barCoords[2];
diff --git a/src/pe/cr/HCSITS.h b/src/pe/cr/HCSITS.h
index 896f358080c9aed186ecf1d203b503f3285b297c..67056df71da2ccc3b15a3085517e0529c951d502 100644
--- a/src/pe/cr/HCSITS.h
+++ b/src/pe/cr/HCSITS.h
@@ -84,12 +84,12 @@ private:
    {
       void resize(const size_t n);
 
-      std::vector<Vec3>   r1_, r2_;
+      std::vector<Vec3>   r1_, r2_; // vector pointing from body1/body2 to the contact position
       std::vector<BodyID> body1_, body2_;
-      std::vector<Vec3>   n_, t_, o_;
-      std::vector<real_t> dist_;
-      std::vector<real_t> mu_;
-      std::vector<Mat3>   diag_nto_;
+      std::vector<Vec3>   n_, t_, o_; // contact normal and the two other directions perpendicular to the normal
+      std::vector<real_t> dist_; // overlap length, a contact is present if dist_ < 0
+      std::vector<real_t> mu_; // contact friction
+      std::vector<Mat3>   diag_nto_; 
       std::vector<Mat3>   diag_nto_inv_;
       std::vector<Mat2>   diag_to_inv_;
       std::vector<real_t> diag_n_inv_;
@@ -102,9 +102,9 @@ public:
    enum RelaxationModel {
       InelasticFrictionlessContact,
       ApproximateInelasticCoulombContactByDecoupling,
-//      ApproximateInelasticCoulombContactByOrthogonalProjections,
+      ApproximateInelasticCoulombContactByOrthogonalProjections,
       InelasticCoulombContactByDecoupling,
-//      InelasticCoulombContactByOrthogonalProjections,
+      InelasticCoulombContactByOrthogonalProjections,
       InelasticGeneralizedMaximumDissipationContact
    };
    //**********************************************************************************************
@@ -136,6 +136,7 @@ public:
    inline const std::map<IBlockID::IDType, ContactCache> getContactCache() const { return blockToContactCache_; }
    inline real_t                    getSpeedLimitFactor() const;
    inline size_t                    getMaxIterations() const { return maxIterations_; }
+   inline real_t                    getOverRelaxationParameter() const { return overRelaxationParam_; }
    inline real_t                    getRelaxationParameter() const { return relaxationParam_; }
    inline real_t                    getErrorReductionParameter() const { return erp_; }
    inline RelaxationModel           getRelaxationModel() const { return relaxationModel_; }
@@ -145,6 +146,7 @@ public:
    //**Set functions*******************************************************************************
    /*!\name Set functions */
    //@{
+   inline void            setOverRelaxationParameter( real_t omega );
    inline void            setRelaxationParameter( real_t f );
    inline void            setMaxIterations( size_t n );
    inline void            setRelaxationModel( RelaxationModel relaxationModel );
@@ -235,6 +237,7 @@ private:
    size_t maxSubIterations_;          //!< Maximum number of iterations of iterative solvers in the one-contact problem.
    real_t abortThreshold_;            //!< If L-infinity iterate difference drops below this threshold the iteration is aborted.
    RelaxationModel relaxationModel_;  //!< The method used to relax unilateral contacts
+   real_t overRelaxationParam_;       //!< Parameter specifying the convergence speed for othogonal projection models.
    real_t relaxationParam_;           //!< Parameter specifying underrelaxation of velocity corrections for boundary bodies.
    real_t maximumPenetration_;
    size_t numContacts_;
@@ -322,6 +325,28 @@ inline real_t HardContactSemiImplicitTimesteppingSolvers::getSpeedLimitFactor()
 //
 //=================================================================================================
 
+//*************************************************************************************************
+/*!\brief Sets the relaxation parameter for boundary bodies.
+ *
+ * \param f The overrelaxation parameter.
+ * \return void
+ *
+ * The overrelaxation parameter \omega is only used when the relaxation model is one of
+ * - ApproximateInelasticCoulombContactByOrthogonalProjections
+ * - InelasticCoulombContactByOrthogonalProjections
+ *
+ * It is used to control the convergence of the model. Large values show faster convergence,
+ * but they can also lead to divergence ("exploding" particles). The default values is 1.0.
+ */
+inline void HardContactSemiImplicitTimesteppingSolvers::setOverRelaxationParameter( real_t omega )
+{
+   WALBERLA_ASSERT_GREATER( omega, 0, "Overrelaxation parameter must be positive." );
+
+   overRelaxationParam_ = omega;
+}
+//*************************************************************************************************
+
+
 //*************************************************************************************************
 /*!\brief Sets the relaxation parameter for boundary bodies.
  *
diff --git a/src/pe/cr/HCSITS.impl.h b/src/pe/cr/HCSITS.impl.h
index ba8fd6aa29d0ec028448b838838406c9d49c50f2..7218b4580519cd623a74976c678a5786eba69184 100644
--- a/src/pe/cr/HCSITS.impl.h
+++ b/src/pe/cr/HCSITS.impl.h
@@ -97,6 +97,7 @@ inline HardContactSemiImplicitTimesteppingSolvers::HardContactSemiImplicitTimest
    , maxSubIterations_ ( 20 )
    , abortThreshold_   ( real_c(1e-7) )
    , relaxationModel_  ( InelasticFrictionlessContact )
+   , overRelaxationParam_( real_c(1.0) )
    , relaxationParam_  ( real_c(0.75) )
    , maximumPenetration_ ( real_c(0.0) )
    , numContacts_      ( 0 )
@@ -388,17 +389,17 @@ inline void HardContactSemiImplicitTimesteppingSolvers::timestep( const real_t d
             delta_max = relaxApproximateInelasticCoulombContactsByDecoupling( dtinv, contactCache, bodyCache );
             break;
 
-            //         case ApproximateInelasticCoulombContactByOrthogonalProjections:
-            //            delta_max = relaxInelasticCoulombContactsByOrthogonalProjections( dtinv, true, contactCache, bodyCache );
-            //            break;
+         case ApproximateInelasticCoulombContactByOrthogonalProjections:
+            delta_max = relaxInelasticCoulombContactsByOrthogonalProjections( dtinv, true, contactCache, bodyCache );
+            break;
 
          case InelasticCoulombContactByDecoupling:
             delta_max = relaxInelasticCoulombContactsByDecoupling( dtinv, contactCache, bodyCache );
             break;
 
-            //         case InelasticCoulombContactByOrthogonalProjections:
-            //            delta_max = relaxInelasticCoulombContactsByOrthogonalProjections( dtinv, false, contactCache, bodyCache );
-            //            break;
+         case InelasticCoulombContactByOrthogonalProjections:
+            delta_max = relaxInelasticCoulombContactsByOrthogonalProjections( dtinv, false, contactCache, bodyCache );
+            break;
 
          case InelasticGeneralizedMaximumDissipationContact:
             delta_max = relaxInelasticGeneralizedMaximumDissipationContacts( dtinv, contactCache, bodyCache );
@@ -1049,55 +1050,68 @@ inline real_t HardContactSemiImplicitTimesteppingSolvers::relaxInelasticCoulombC
       bodyCache.dv_[contactCache.body2_[i]->index_] += contactCache.body2_[i]->getInvMass() * contactCache.p_[i];
       bodyCache.dw_[contactCache.body2_[i]->index_] += contactCache.body2_[i]->getInvInertia() * ( contactCache.r2_[i] % contactCache.p_[i] );
 
-      // Calculate the relative contact velocity in the global world frame (if no contact reaction is present at contact i)
-      Vec3 gdot    ( ( bodyCache.v_[contactCache.body1_[i]->index_] + bodyCache.dv_[contactCache.body1_[i]->index_] ) - ( bodyCache.v_[contactCache.body2_[i]->index_] + bodyCache.dv_[contactCache.body2_[i]->index_] ) + ( bodyCache.w_[contactCache.body1_[i]->index_] + bodyCache.dw_[contactCache.body1_[i]->index_] ) % contactCache.r1_[i] - ( bodyCache.w_[contactCache.body2_[i]->index_] + bodyCache.dw_[contactCache.body2_[i]->index_] ) % contactCache.r2_[i] /* + diag_[i] * p */ );
+      // Calculate the relative contact velocity in the global world frame (as if no contact reaction was present at contact i)
+      Vec3 gdot(   ( bodyCache.v_[contactCache.body1_[i]->index_] + bodyCache.dv_[contactCache.body1_[i]->index_] )
+                 - ( bodyCache.v_[contactCache.body2_[i]->index_] + bodyCache.dv_[contactCache.body2_[i]->index_] )
+                 + ( bodyCache.w_[contactCache.body1_[i]->index_] + bodyCache.dw_[contactCache.body1_[i]->index_] ) % contactCache.r1_[i]
+                 - ( bodyCache.w_[contactCache.body2_[i]->index_] + bodyCache.dw_[contactCache.body2_[i]->index_] ) % contactCache.r2_[i] /* + diag_[i] * p */ );
 
       // Change from the global world frame to the contact frame
       Mat3 contactframe( contactCache.n_[i], contactCache.t_[i], contactCache.o_[i] );
       Vec3 gdot_nto( contactframe.getTranspose() * gdot );
 
-      //real_t gdot_n  ( trans( contactCache.n_[i] ) * gdot );  // The component of gdot along the contact normal n
-      //Vec3 gdot_t  ( gdot - gdot_n * contactCache.n_[i] );  // The components of gdot tangential to the contact normal n
-      //real_t g_n     ( gdot_n * dt /* + trans( contactCache.n_[i] ) * ( contactCache.body1_[i]->getPosition() + contactCache.r1_[i] ) - ( contactCache.body2_[i]->getPosition() + contactCache.r2_[i] ) */ + contactCache.dist_[i] );  // The gap in normal direction
+      //real_t gdot_n( trans( contactCache.n_[i] ) * gdot );  // The component of gdot along the contact normal n
+      //Vec3 gdot_t( gdot - gdot_n * contactCache.n_[i] );  // The components of gdot tangential to the contact normal n
+      //real_t g_n( gdot_n * dt /* + trans( contactCache.n_[i] ) * ( contactCache.body1_[i]->getPosition() + contactCache.r1_[i] ) - ( contactCache.body2_[i]->getPosition() + contactCache.r2_[i] ) */ + contactCache.dist_[i] );  // The gap in normal direction
 
       // The constraint in normal direction is actually a positional constraint but instead of g_n we use g_n/dt equivalently and call it gdot_n
-      gdot_nto[0] += ( /* + trans( contactCache.n_[i] ) * ( contactCache.body1_[i]->getPosition() + contactCache.r1_[i] ) - ( contactCache.body2_[i]->getPosition() + contactCache.r2_[i] ) */ + contactCache.dist_[i] ) * dtinv;
+      gdot_nto[0] += ( /* + trans( contactCache.n_[i] ) * ( contactCache.body1_[i]->getPosition() + contactCache.r1_[i] )
+                          - ( contactCache.body2_[i]->getPosition() + contactCache.r2_[i] ) */ + contactCache.dist_[i] ) * dtinv;
+
+      // Tasora et al., 2011 starts here
+      // -------------------------------------------------------------------------------------
 
-      const real_t w( 1 ); // w > 0
       Vec3 p_cf( contactframe.getTranspose() * contactCache.p_[i] );
       if( approximate ) {
-         // Calculate next iterate (Anitescu/Tasora).
-         p_cf = p_cf - w * ( contactCache.diag_nto_[i] * p_cf + gdot_nto );
+         // Calculate next iterate (Tasora et al., 2011).
+         p_cf = p_cf - overRelaxationParam_ * ( contactCache.diag_nto_[i] * p_cf + gdot_nto );
       }
       else {
          // Calculate next iterate (De Saxce/Feng).
          Vec3 tmp( contactCache.diag_nto_[i] * p_cf + gdot_nto );
          tmp[0] += std::sqrt( math::sq( tmp[1] ) + math::sq( tmp[2] ) ) * contactCache.mu_[i];
-         p_cf = p_cf - w * tmp;
+         p_cf = p_cf - overRelaxationParam_ * tmp;
       }
 
-      // Project.
+      // Project on friction cone (Tasora et al., 2011; Fig. 2; Eq. (46)).
       real_t flimit( contactCache.mu_[i] * p_cf[0] );
       real_t fsq( p_cf[1] * p_cf[1] + p_cf[2] * p_cf[2] );
+
       if( p_cf[0] > 0 && fsq < flimit * flimit ) {
-         // Unconstrained minimum is in cone leading to a static contact and no projection
-         // is necessary.
+         // Unconstrained minimum is INSIDE THE UPPER CONE,
+         // with slope n*mu
+         // leading to a static contact and no projection is necessary.
       }
-      else if( p_cf[0] < 0 && fsq < p_cf[0] / math::sq( contactCache.mu_[i] ) ) {
-         // Unconstrained minimum is in dual cone leading to a separating contact where no contact
-         // reaction is present (the unconstrained minimum is projected to the tip of the cone).
-
+      else if( p_cf[0] < 0 && fsq < math::sq( p_cf[0] / contactCache.mu_[i] ) ) {
+         // Unconstrained minimum is INSIDE THE LOWER CONE,
+         // with slope n/mu
+         // leading to a separating contact where no contact reaction is present,
+         // i.e. the unconstrained minimum is projected to the tip of the lower cone.
          p_cf = Vec3();
       }
       else {
-         // The contact is dynamic.
-         real_t f( std::sqrt( fsq ) );
-         p_cf[0] = ( f * contactCache.mu_[i] + p_cf[0] ) / ( math::sq( contactCache.mu_[i] ) + 1 );
+         // Unconstrained minimum is OUTSIDE THE CONE -> Project on cone surface, Eq. (45) in Tasora et al., 2011
+         real_t f( std::sqrt( fsq ) ); // gamma_r
+         p_cf[0] = ( f * contactCache.mu_[i] + p_cf[0] ) / ( math::sq( contactCache.mu_[i] ) + 1 ); // p_cf[0] = gamma_n
+         
          real_t factor( contactCache.mu_[i] * p_cf[0] / f );
          p_cf[1] *= factor;
          p_cf[2] *= factor;
       }
 
+      // Tasora et al., 2011 ends here
+      // -------------------------------------------------------------------------------------
+
       Vec3 p_wf( contactframe * p_cf );
       Vec3 dp( contactCache.p_[i] - p_wf );
       delta_max = std::max( delta_max, std::max( std::abs( dp[0] ), std::max( std::abs( dp[1] ), std::abs( dp[2] ) ) ) );
diff --git a/src/pe/rigidbody/RigidBody.cpp b/src/pe/rigidbody/RigidBody.cpp
index 78743f7969e7efbba1bff7d16ffb180cbd383df6..b58bcad567315b4a725ca65722e13df91f9912e4 100644
--- a/src/pe/rigidbody/RigidBody.cpp
+++ b/src/pe/rigidbody/RigidBody.cpp
@@ -196,7 +196,7 @@ bool RigidBody::checkInvariants()
  *
  * The function calculates the global velocity of a point relative to the body's center of mass.
  */
-const Vec3 RigidBody::velFromBF( real_t px, real_t py, real_t pz ) const
+Vec3 RigidBody::velFromBF( real_t px, real_t py, real_t pz ) const
 {
    return velFromBF( Vec3( px, py, pz ) );
 }
@@ -211,7 +211,7 @@ const Vec3 RigidBody::velFromBF( real_t px, real_t py, real_t pz ) const
  *
  * The function calculates the global velocity of a point relative to the body's center of mass.
  */
-const Vec3 RigidBody::velFromBF( const Vec3& rpos ) const
+Vec3 RigidBody::velFromBF( const Vec3& rpos ) const
 {
    if( !hasSuperBody() )
       return v_ + w_ % ( R_ * rpos );
@@ -230,7 +230,7 @@ const Vec3 RigidBody::velFromBF( const Vec3& rpos ) const
  *
  * The function calculates the global velocity of a point in global coordinates.
  */
-const Vec3 RigidBody::velFromWF( real_t px, real_t py, real_t pz ) const
+Vec3 RigidBody::velFromWF( real_t px, real_t py, real_t pz ) const
 {
    return velFromWF( Vec3( px, py, pz ) );
 }
@@ -245,7 +245,7 @@ const Vec3 RigidBody::velFromWF( real_t px, real_t py, real_t pz ) const
  *
  * The function calculates the global velocity of a point in global coordinates.
  */
-const Vec3 RigidBody::velFromWF( const Vec3& gpos ) const
+Vec3 RigidBody::velFromWF( const Vec3& gpos ) const
 {
    if( !hasSuperBody() )
       return v_ + w_ % ( gpos - gpos_ );
diff --git a/src/pe/rigidbody/RigidBody.h b/src/pe/rigidbody/RigidBody.h
index 1ac988c750b02d95ce5e552f048c941907e2dcd8..440abac642f2e9f018dcd59c519dd931bcc76f9a 100644
--- a/src/pe/rigidbody/RigidBody.h
+++ b/src/pe/rigidbody/RigidBody.h
@@ -125,14 +125,14 @@ public:
    inline const Vec3     vectorFromBFtoWF( const Vec3& v )             const;
    inline const Vec3     pointFromBFtoWF ( real_t px, real_t py, real_t pz ) const;
    inline const Vec3     pointFromBFtoWF ( const Vec3& rpos )          const;
-   virtual const Vec3    velFromBF       ( real_t px, real_t py, real_t pz ) const;
-   virtual const Vec3    velFromBF       ( const Vec3& rpos )          const;
+   virtual Vec3    velFromBF       ( real_t px, real_t py, real_t pz ) const;
+   virtual Vec3    velFromBF       ( const Vec3& rpos )          const;
    inline const Vec3     vectorFromWFtoBF( real_t vx, real_t vy, real_t vz ) const;
    inline const Vec3     vectorFromWFtoBF( const Vec3& v )             const;
    inline const Vec3     pointFromWFtoBF ( real_t px, real_t py, real_t pz ) const;
    inline const Vec3     pointFromWFtoBF ( const Vec3& gpos )          const;
-   virtual const Vec3    velFromWF       ( real_t px, real_t py, real_t pz ) const;
-   virtual const Vec3    velFromWF       ( const Vec3& gpos )          const;
+   virtual Vec3    velFromWF       ( real_t px, real_t py, real_t pz ) const;
+   virtual Vec3    velFromWF       ( const Vec3& gpos )          const;
    inline const Vec3     accFromWF       ( real_t px, real_t py, real_t pz ) const;
           const Vec3     accFromWF       ( const Vec3& gpos )          const;
 
diff --git a/src/pe/rigidbody/Squirmer.cpp b/src/pe/rigidbody/Squirmer.cpp
index e9d386c59140f8870a0862b195c6afaf5816748e..4a9f714b5108d37aab16ddef18463cb7445da380 100644
--- a/src/pe/rigidbody/Squirmer.cpp
+++ b/src/pe/rigidbody/Squirmer.cpp
@@ -89,7 +89,7 @@ Squirmer::~Squirmer()
  *
  * The function calculates the global velocity of a point relative to the body's center of mass.
  */
-const Vec3 Squirmer::velFromBF( real_t px, real_t py, real_t pz ) const
+Vec3 Squirmer::velFromBF( real_t px, real_t py, real_t pz ) const
 {
    return velFromBF( Vec3( px, py, pz ) );
 }
@@ -104,7 +104,7 @@ const Vec3 Squirmer::velFromBF( real_t px, real_t py, real_t pz ) const
  *
  * The function calculates the global velocity of a point relative to the body's center of mass.
  */
-const Vec3 Squirmer::velFromBF( const Vec3& rpos ) const
+Vec3 Squirmer::velFromBF( const Vec3& rpos ) const
 {
    return Sphere::velFromBF( rpos ) + getSquirmerVelocity( getRotation() * rpos );
 }
@@ -120,7 +120,7 @@ const Vec3 Squirmer::velFromBF( const Vec3& rpos ) const
  *
  * The function calculates the global velocity of a point in global coordinates.
  */
-const Vec3 Squirmer::velFromWF( real_t px, real_t py, real_t pz ) const
+Vec3 Squirmer::velFromWF( real_t px, real_t py, real_t pz ) const
 {
    return velFromWF( Vec3( px, py, pz ) );
 }
@@ -133,7 +133,7 @@ const Vec3 Squirmer::velFromWF( real_t px, real_t py, real_t pz ) const
  * \param rpos The relative global coordinate.
  * \return The local surface velocity of the squirmer.
  */
-const Vec3 Squirmer::getSquirmerVelocity( const Vec3& rpos ) const
+Vec3 Squirmer::getSquirmerVelocity( const Vec3& rpos ) const
 {
    const auto rs = rpos.getNormalized();
    const auto e = getQuaternion().rotate(Vec3(0.0,0.0,1.0)).getNormalized();
@@ -152,7 +152,7 @@ const Vec3 Squirmer::getSquirmerVelocity( const Vec3& rpos ) const
  *
  * The function calculates the global velocity of a point in global coordinates.
  */
-const Vec3 Squirmer::velFromWF( const Vec3& gpos ) const
+Vec3 Squirmer::velFromWF( const Vec3& gpos ) const
 {
    return Sphere::velFromWF( gpos ) + getSquirmerVelocity( gpos - getPosition() );
 }
diff --git a/src/pe/rigidbody/Squirmer.h b/src/pe/rigidbody/Squirmer.h
index 0d9514324a7f2f092af4e36a357fa44f5b6c3335..688894cff8d6f2a9622de3e00247b2f96f106e4b 100644
--- a/src/pe/rigidbody/Squirmer.h
+++ b/src/pe/rigidbody/Squirmer.h
@@ -53,10 +53,10 @@ public:
    inline real_t getSquirmerVelocity() const;
    inline real_t getSquirmerBeta()     const;
 
-   inline const Vec3     velFromBF       ( real_t px, real_t py, real_t pz ) const WALBERLA_OVERRIDE;
-   inline const Vec3     velFromBF       ( const Vec3& rpos )                const WALBERLA_OVERRIDE;
-   inline const Vec3     velFromWF       ( real_t px, real_t py, real_t pz ) const WALBERLA_OVERRIDE;
-   inline const Vec3     velFromWF       ( const Vec3& gpos )                const WALBERLA_OVERRIDE;
+   inline Vec3     velFromBF       ( real_t px, real_t py, real_t pz ) const WALBERLA_OVERRIDE;
+   inline Vec3     velFromBF       ( const Vec3& rpos )                const WALBERLA_OVERRIDE;
+   inline Vec3     velFromWF       ( real_t px, real_t py, real_t pz ) const WALBERLA_OVERRIDE;
+   inline Vec3     velFromWF       ( const Vec3& gpos )                const WALBERLA_OVERRIDE;
 
    static inline id_t getStaticTypeID() WALBERLA_OVERRIDE;
    //@}
@@ -67,7 +67,7 @@ protected:
    //**Get functions*******************************************************************************
    /*!\name Get functions */
    //@{
-   const Vec3 getSquirmerVelocity( const Vec3& rpos ) const;
+   Vec3 getSquirmerVelocity( const Vec3& rpos ) const;
    //@}
 
    //**Member variables****************************************************************************
diff --git a/src/postprocessing/all.h b/src/postprocessing/all.h
index 90a82d17a76a8288d30b1f4f9e8fd022cea4a44a..1783d5a2951428bedac75ca1d5ef6bd8e99b2c4c 100644
--- a/src/postprocessing/all.h
+++ b/src/postprocessing/all.h
@@ -22,6 +22,4 @@
 
 #pragma once
 
-#include "MarchingCubes.h"
-
-#include "sqlite/SQLite.h"
\ No newline at end of file
+#include "MarchingCubes.h"
\ No newline at end of file
diff --git a/src/sqlite/CMakeLists.txt b/src/sqlite/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..621760105711d5a82b476cdbef5870524e66b550
--- /dev/null
+++ b/src/sqlite/CMakeLists.txt
@@ -0,0 +1,9 @@
+###################################################################################################
+#
+# Module sqlite
+#
+###################################################################################################
+
+waLBerla_add_module( DEPENDS core )
+
+###################################################################################################
diff --git a/src/postprocessing/sqlite/SQLite.cpp b/src/sqlite/SQLite.cpp
similarity index 99%
rename from src/postprocessing/sqlite/SQLite.cpp
rename to src/sqlite/SQLite.cpp
index e6efa739fb073c771f440a8389cc83ae1c9fa208..e4729238e71434d4553e735ed6faabf4c7c240c2 100644
--- a/src/postprocessing/sqlite/SQLite.cpp
+++ b/src/sqlite/SQLite.cpp
@@ -30,7 +30,7 @@
 
 
 namespace walberla {
-namespace postprocessing {
+namespace sqlite {
 
 
 SQLiteDB::SQLiteDB( const string & dbFile, const int busyTimeout )
@@ -513,5 +513,5 @@ void storeTimingTreeInSqliteDB ( const string & dbFile, uint_t runId,
    db.storeTimingTree( runId, tt, timingTreeName );
 }
 
-} // namespace postprocessing
+} // namespace sqlite
 } // namespace walberla
diff --git a/src/postprocessing/sqlite/SQLite.h b/src/sqlite/SQLite.h
similarity index 99%
rename from src/postprocessing/sqlite/SQLite.h
rename to src/sqlite/SQLite.h
index 22e66daf8ef4475a479799e216f2d75843d3f802..84ba2746643d120f41fc8e363f3cdd32c4bde118 100644
--- a/src/postprocessing/sqlite/SQLite.h
+++ b/src/sqlite/SQLite.h
@@ -35,7 +35,7 @@
 struct sqlite3;
 
 namespace walberla {
-namespace postprocessing {
+namespace sqlite {
 
 using std::string;
 using std::map;
@@ -126,7 +126,7 @@ void storeTimingTreeInSqliteDB( const string & dbFile, uint_t runId, const WcTim
 
 
 
-} // namespace postprocessing
+} // namespace sqlite
 } // namespace walberla
 
 
diff --git a/src/postprocessing/sqlite/extern/sqlite3.c b/src/sqlite/extern/sqlite3.c
similarity index 100%
rename from src/postprocessing/sqlite/extern/sqlite3.c
rename to src/sqlite/extern/sqlite3.c
diff --git a/src/postprocessing/sqlite/extern/sqlite3.h b/src/sqlite/extern/sqlite3.h
similarity index 100%
rename from src/postprocessing/sqlite/extern/sqlite3.h
rename to src/sqlite/extern/sqlite3.h
diff --git a/src/timeloop/PerformanceMeter.cpp b/src/timeloop/PerformanceMeter.cpp
index 6efb92d969bb67da70230c1453a7c0a4cb62db9b..d7986320312cac1969331a2a8678821d09960873 100644
--- a/src/timeloop/PerformanceMeter.cpp
+++ b/src/timeloop/PerformanceMeter.cpp
@@ -82,7 +82,7 @@ namespace timeloop {
     * Behaves like addMeasurement() function above, with n= total number of cells
     *
     *******************************************************************************************************************/
-   void PerformanceMeter::addMeasurement ( const std::string & name, CountFunction countFunction,
+   void PerformanceMeter::addMeasurement ( const std::string & name, const CountFunction& countFunction,
                                            uint_t countFreq, real_t scaling  )
    {
       measurements_.emplace_back( countFunction, name, scaling, countFreq );
@@ -126,7 +126,7 @@ namespace timeloop {
     *******************************************************************************************************************/
    void PerformanceMeter::logResultOnRoot( )
    {
-      if( measurements_.size() == 0)
+      if( measurements_.empty())
          return;
 
       std::stringstream ss;
@@ -148,7 +148,7 @@ namespace timeloop {
     *******************************************************************************************************************/
    void PerformanceMeter::print( std::ostream & os, int targetRank )
    {
-      if( measurements_.size() == 0)
+      if( measurements_.empty())
          return;
 
       std::vector<real_t> totalNrCells;
@@ -294,7 +294,7 @@ namespace timeloop {
     *******************************************************************************************************************/
    void PerformanceMeter::reduce ( std::vector<real_t> & reduced, int targetRank )
    {
-      if ( measurements_.size() == 0 )
+      if ( measurements_.empty() )
          return;
 
       reduced.clear();
diff --git a/src/timeloop/PerformanceMeter.h b/src/timeloop/PerformanceMeter.h
index 731f968fe7046e95e03f7ac2e7953119fce48f57..0efac6514774670b2efae9f08274be25a3e4ebb0 100644
--- a/src/timeloop/PerformanceMeter.h
+++ b/src/timeloop/PerformanceMeter.h
@@ -95,7 +95,7 @@ namespace timeloop {
       //** Measurement Definitions *************************************************************************************
       /*! \name Measurement Definitions */
       //@{
-      void addMeasurement( const std::string & name, CountFunction countFunction,
+      void addMeasurement( const std::string & name, const CountFunction& countFunction,
                            uint_t countFreq = 0, real_t scaling = 1 );
 
       void addMeasurement( const std::string & name, real_t scaling = 1 );
diff --git a/tests/lbm/CMakeLists.txt b/tests/lbm/CMakeLists.txt
index 8f735fb94c96198cf6153050a56c8bb89cdaab53..7ffa9167b581853dbef5ffa4d203923f7e2069e1 100644
--- a/tests/lbm/CMakeLists.txt
+++ b/tests/lbm/CMakeLists.txt
@@ -77,3 +77,7 @@ waLBerla_python_file_generates(codegen/LbCodeGenerationExample.py
                               LbCodeGenerationExample_UBB.cpp )
 waLBerla_compile_test( FILES codegen/LbCodeGenerationExample.py
                              codegen/LbCodeGenerationExample.cpp)
+waLBerla_python_file_generates(codegen/FluctuatingMRT.py
+                              FluctuatingMRT_LatticeModel.cpp )
+waLBerla_compile_test( FILES codegen/FluctuatingMRT.py
+                             codegen/FluctuatingMRT.cpp)
\ No newline at end of file
diff --git a/tests/lbm/codegen/FluctuatingMRT.cpp b/tests/lbm/codegen/FluctuatingMRT.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2b9ccdba11237b4b8a3129e02eaae668e2c24e3c
--- /dev/null
+++ b/tests/lbm/codegen/FluctuatingMRT.cpp
@@ -0,0 +1,119 @@
+//======================================================================================================================
+//
+//  This file is part of waLBerla. waLBerla is free software: you can
+//  redistribute it and/or modify it under the terms of the GNU General Public
+//  License as published by the Free Software Foundation, either version 3 of
+//  the License, or (at your option) any later version.
+//
+//  waLBerla is distributed in the hope that it will be useful, but WITHOUT
+//  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+//  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+//  for more details.
+//
+//  You should have received a copy of the GNU General Public License along
+//  with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file SrtWithForceField.cpp
+//! \author Michael Kuron <mkuron@icp.uni-stuttgart.de>
+//
+//======================================================================================================================
+
+#include "blockforest/all.h"
+#include "core/all.h"
+#include "domain_decomposition/all.h"
+#include "field/all.h"
+#include "geometry/all.h"
+#include "gui/all.h"
+#include "timeloop/all.h"
+
+#include "lbm/field/PdfField.h"
+#include "lbm/field/AddToStorage.h"
+#include "lbm/communication/PdfFieldPackInfo.h"
+#include "lbm/gui/Connection.h"
+#include "lbm/vtk/VTKOutput.h"
+
+#include "FluctuatingMRT_LatticeModel.h"
+
+
+using namespace walberla;
+
+typedef lbm::FluctuatingMRT_LatticeModel          LatticeModel_T;
+typedef LatticeModel_T::Stencil                   Stencil_T;
+typedef LatticeModel_T::CommunicationStencil      CommunicationStencil_T;
+typedef lbm::PdfField< LatticeModel_T >           PdfField_T;
+
+typedef GhostLayerField< real_t, LatticeModel_T::Stencil::D > VectorField_T;
+typedef GhostLayerField< real_t, 1 > ScalarField_T;
+
+typedef walberla::uint8_t    flag_t;
+typedef FlagField< flag_t >  FlagField_T;
+
+
+
+int main( int argc, char ** argv )
+{
+   walberla::Environment walberlaEnv( argc, argv );
+
+   auto blocks = blockforest::createUniformBlockGridFromConfig( walberlaEnv.config() );
+
+   // read parameters
+   auto parameters = walberlaEnv.config()->getOneBlock( "Parameters" );
+
+   const real_t          omega           = parameters.getParameter< real_t >         ( "omega",           real_c( 1.4 ) );
+   const Vector3<real_t> initialVelocity = parameters.getParameter< Vector3<real_t> >( "initialVelocity", Vector3<real_t>() );
+   const uint_t          timesteps       = parameters.getParameter< uint_t >         ( "timesteps",       uint_c( 10 )  );
+   const real_t          temperature     = real_t(0.01);
+   const uint_t seed = uint_t(0);
+
+   const double remainingTimeLoggerFrequency = parameters.getParameter< double >( "remainingTimeLoggerFrequency", 3.0 ); // in seconds
+
+   // create fields
+   BlockDataID forceFieldId = field::addToStorage<VectorField_T>( blocks, "Force", real_t( 0.0 ));
+
+   LatticeModel_T latticeModel = LatticeModel_T( forceFieldId, omega, omega, seed, temperature, uint_t(0) );
+   BlockDataID pdfFieldId = lbm::addPdfFieldToStorage( blocks, "pdf field", latticeModel, initialVelocity, real_t(1) );
+   BlockDataID flagFieldId = field::addFlagFieldToStorage< FlagField_T >( blocks, "flag field" );
+
+   // create and initialize boundary handling
+   const FlagUID fluidFlagUID( "Fluid" );
+
+   // create time loop
+   SweepTimeloop timeloop( blocks->getBlockStorage(), timesteps );
+
+   // create communication for PdfField
+   blockforest::communication::UniformBufferedScheme< CommunicationStencil_T > communication( blocks );
+   communication.addPackInfo( make_shared< lbm::PdfFieldPackInfo< LatticeModel_T > >( pdfFieldId ) );
+
+   // add LBM sweep and communication to time loop
+   timeloop.add() << BeforeFunction( [&](){ latticeModel.time_step = uint32_c(timeloop.getCurrentTimeStep()); }, "set RNG counter" )
+                  << BeforeFunction( communication, "communication" )
+                  << Sweep( LatticeModel_T::Sweep( pdfFieldId ), "LB stream & collide" );
+
+   // LBM stability check
+   timeloop.addFuncAfterTimeStep( makeSharedFunctor( field::makeStabilityChecker< PdfField_T, FlagField_T >( walberlaEnv.config(), blocks, pdfFieldId,
+                                                                                                             flagFieldId, fluidFlagUID ) ),
+                                  "LBM stability check" );
+
+   // log remaining time
+   timeloop.addFuncAfterTimeStep( timing::RemainingTimeLogger( timeloop.getNrOfTimeSteps(), remainingTimeLoggerFrequency ), "remaining time logger" );
+
+   // add VTK output to time loop
+   lbm::VTKOutput< LatticeModel_T, FlagField_T >::addToTimeloop( timeloop, blocks, walberlaEnv.config(), pdfFieldId, flagFieldId, fluidFlagUID );
+
+   // create adaptors, so that the GUI also displays density and velocity
+   // adaptors are like fields with the difference that they do not store values
+   // but calculate the values based on other fields ( here the PdfField )
+   field::addFieldAdaptor<lbm::Adaptor<LatticeModel_T>::Density>       ( blocks, pdfFieldId, "DensityAdaptor" );
+   field::addFieldAdaptor<lbm::Adaptor<LatticeModel_T>::VelocityVector>( blocks, pdfFieldId, "VelocityAdaptor" );
+
+   if( parameters.getParameter<bool>( "useGui", false ) )
+   {
+      GUI gui ( timeloop, blocks, argc, argv );
+      lbm::connectToGui<LatticeModel_T> ( gui );
+      gui.run();
+   }
+   else
+      timeloop.run();
+
+   return EXIT_SUCCESS;
+}
diff --git a/tests/lbm/codegen/FluctuatingMRT.py b/tests/lbm/codegen/FluctuatingMRT.py
new file mode 100644
index 0000000000000000000000000000000000000000..b996fe43c53dbf3fff48452cc02b3b684eaedd15
--- /dev/null
+++ b/tests/lbm/codegen/FluctuatingMRT.py
@@ -0,0 +1,22 @@
+import sympy as sp
+import pystencils as ps
+from lbmpy.creationfunctions import create_lb_collision_rule
+from pystencils_walberla import CodeGeneration
+from lbmpy_walberla import generate_lattice_model
+
+with CodeGeneration() as ctx:
+    omega_shear, omega_bulk = sp.symbols("omega_shear, omega_bulk")
+    temperature = sp.symbols("temperature")
+    force_field, vel_field = ps.fields("force(3), velocity(3): [3D]", layout='fzyx')
+
+    collision_rule = create_lb_collision_rule(
+        stencil='D3Q19', compressible=True, fluctuating={
+            'temperature' : temperature,
+            'block_offsets' : 'walberla',
+        },
+        method='mrt3', relaxation_rates=[omega_shear, omega_bulk],
+        force_model='guo', force=force_field.center_vector,
+        optimization={'cse_global': True}
+    )
+
+    generate_lattice_model(ctx, 'FluctuatingMRT_LatticeModel', collision_rule)
diff --git a/tests/mesa_pd/CMakeLists.txt b/tests/mesa_pd/CMakeLists.txt
index cdaf984c4d6bd7cbdcbcc56e740566f9562aeaa1..5555ac9cfdae03f92baf272ed9c59564d6aed5d5 100644
--- a/tests/mesa_pd/CMakeLists.txt
+++ b/tests/mesa_pd/CMakeLists.txt
@@ -111,6 +111,9 @@ waLBerla_execute_test( NAME   MESA_PD_Kernel_GenerateAnalyticContacts PROCESSES
 waLBerla_compile_test( NAME   MESA_PD_Kernel_GenerateLinkedCells FILES kernel/GenerateLinkedCells.cpp DEPENDS core )
 waLBerla_execute_test( NAME   MESA_PD_Kernel_GenerateLinkedCells )
 
+waLBerla_compile_test( NAME   MESA_PD_Kernel_HCSITSKernels FILES kernel/HCSITSKernels.cpp DEPENDS core )
+waLBerla_execute_test( NAME   MESA_PD_Kernel_HCSITSKernels )
+
 waLBerla_compile_test( NAME   MESA_PD_Kernel_HeatConduction FILES kernel/HeatConduction.cpp DEPENDS core )
 waLBerla_execute_test( NAME   MESA_PD_Kernel_HeatConduction )
 
@@ -167,6 +170,9 @@ waLBerla_execute_test( NAME   MESA_PD_MPI_ReduceContactHistory PROCESSES 8 )
 waLBerla_compile_test( NAME   MESA_PD_MPI_ReduceProperty FILES mpi/ReduceProperty.cpp DEPENDS core )
 waLBerla_execute_test( NAME   MESA_PD_MPI_ReduceProperty PROCESSES 8 )
 
+waLBerla_compile_test( NAME   MESA_PD_MPI_VelocityCorrectionNotification FILES mpi/VelocityCorrectionNotification.cpp DEPENDS core )
+waLBerla_execute_test( NAME   MESA_PD_MPI_VelocityCorrectionNotification PROCESSES 8)
+
 waLBerla_compile_test( NAME   MESA_PD_Sorting FILES Sorting.cpp DEPENDS core )
 waLBerla_execute_test( NAME   MESA_PD_Sorting )
 
diff --git a/tests/mesa_pd/kernel/HCSITSKernels.cpp b/tests/mesa_pd/kernel/HCSITSKernels.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2977c398d114905ad0623fd4057b6ba069179837
--- /dev/null
+++ b/tests/mesa_pd/kernel/HCSITSKernels.cpp
@@ -0,0 +1,485 @@
+//======================================================================================================================
+//
+//  This file is part of waLBerla. waLBerla is free software: you can
+//  redistribute it and/or modify it under the terms of the GNU General Public
+//  License as published by the Free Software Foundation, either version 3 of
+//  the License, or (at your option) any later version.
+//
+//  waLBerla is distributed in the hope that it will be useful, but WITHOUT
+//  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+//  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+//  for more details.
+//
+//  You should have received a copy of the GNU General Public License along
+//  with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file   HCSITSKernels.cpp
+//! \author Tobias Leemann <tobias.leemann@fau.de>
+//
+//======================================================================================================================
+
+
+/** Test Collision Detection and Insertion of contacts into the contact storage */
+
+#include <mesa_pd/data/DataTypes.h>
+#include <mesa_pd/data/ContactStorage.h>
+#include <mesa_pd/data/ParticleStorage.h>
+#include <mesa_pd/data/ShapeStorage.h>
+#include <mesa_pd/kernel/DetectAndStoreContacts.h>
+#include <mesa_pd/domain/InfiniteDomain.h>
+#include <mesa_pd/data/ContactAccessor.h>
+#include <mesa_pd/kernel/ParticleSelector.h>
+//HCSITS Kernels
+
+#include "mesa_pd/kernel/InitContactsForHCSITS.h"
+#include "mesa_pd/kernel/InitParticlesForHCSITS.h"
+#include "mesa_pd/kernel/HCSITSRelaxationStep.h"
+#include "mesa_pd/kernel/IntegrateParticlesHCSITS.h"
+
+// Communication kernels
+#include "mesa_pd/mpi/ReduceProperty.h"
+#include "mesa_pd/mpi/BroadcastProperty.h"
+
+#include "mesa_pd/mpi/notifications/VelocityUpdateNotification.h"
+#include "mesa_pd/mpi/notifications/VelocityCorrectionNotification.h"
+
+#include <mesa_pd/data/ParticleAccessor.h>
+#include <core/Environment.h>
+#include <core/logging/Logging.h>
+
+#include <iostream>
+
+namespace walberla {
+
+using namespace walberla::mesa_pd;
+
+   class ParticleAccessorWithShape : public data::ParticleAccessor
+   {
+      public:
+      ParticleAccessorWithShape(std::shared_ptr<data::ParticleStorage>& ps, std::shared_ptr<data::ShapeStorage>& ss)
+              : ParticleAccessor(ps)
+              , ss_(ss)
+      {}
+
+      const real_t& getMass(const size_t p_idx) const {return ss_->shapes[ps_->getShapeIDRef(p_idx)]->getMass();}
+      const real_t& getInvMass(const size_t p_idx) const {return ss_->shapes[ps_->getShapeIDRef(p_idx)]->getInvMass();}
+
+      const Mat3& getInertia(const size_t p_idx) const {return ss_->shapes[ps_->getShapeIDRef(p_idx)]->getInertiaBF();}
+      const Mat3& getInvInertia(const size_t p_idx) const {return ss_->shapes[ps_->getShapeIDRef(p_idx)]->getInvInertiaBF();}
+
+      data::BaseShape* getShape(const size_t p_idx) const {return ss_->shapes[ps_->getShapeIDRef(p_idx)].get();}
+      private:
+      std::shared_ptr<data::ShapeStorage> ss_;
+   };
+
+   template<typename PStorage, typename CStorage, typename PAccessor, typename CAccessor>
+   class TestHCSITSKernel {
+      public:
+      TestHCSITSKernel(PStorage &ps_, CStorage &cs_, PAccessor &pa_, CAccessor &ca_) : ps(ps_), cs(cs_), pa(pa_), ca(ca_),
+            erp(real_t(1.0)), model(kernel::HCSITSRelaxationStep::RelaxationModel::InelasticFrictionlessContact), contactThreshold(0), globalAcc(0) {}
+
+      void operator()(real_t dt){
+         // Perform Collision detection (call kernel, that stores contacts into cs)
+         kernel::DetectAndStoreContacts detectAndStore(cs);
+         cs.clear();
+
+         domain::InfiniteDomain domain;
+         collision_detection::AnalyticContactDetection acd;
+         acd.getContactThreshold() = contactThreshold;
+         ps.forEachParticlePairHalf(false, kernel::ExcludeInfiniteInfinite(), pa, detectAndStore, pa, domain, acd);
+
+         // Create Kernels
+         kernel::InitContactsForHCSITS initContacts(1);
+         initContacts.setFriction(0,0,real_t(0.2));
+         initContacts.setErp(real_t(erp));
+
+         kernel::InitParticlesForHCSITS initParticles;
+         initParticles.setGlobalAcceleration(globalAcc);
+
+         kernel::HCSITSRelaxationStep relaxationStep;
+         relaxationStep.setRelaxationModel(model);
+         relaxationStep.setCor(real_t(0.6)); // Only effective for PGSM
+
+         kernel::IntegrateParticlesHCSITS integration;
+
+         mesa_pd::mpi::ReduceProperty reductionKernel;
+         mesa_pd::mpi::BroadcastProperty broadcastKernel;
+
+         // Run the HCSITS loop
+         cs.forEachContact(false, kernel::SelectAll(), ca, initContacts, ca, pa);
+         ps.forEachParticle(false, kernel::SelectAll(), pa, initParticles, pa, dt);
+
+         VelocityUpdateNotification::Parameters::relaxationParam = real_t(1.0);
+         reductionKernel.operator()<VelocityCorrectionNotification>(ps);
+         broadcastKernel.operator()<VelocityUpdateNotification>(ps);
+
+         VelocityUpdateNotification::Parameters::relaxationParam = real_t(0.8);
+         for(int i = 0; i < 10; i++){
+            cs.forEachContact(false, kernel::SelectAll(), ca, relaxationStep, ca, pa, dt);
+            reductionKernel.operator()<VelocityCorrectionNotification>(ps);
+            broadcastKernel.operator()<VelocityUpdateNotification>(ps);
+         }
+         ps.forEachParticle(false, kernel::SelectAll(), pa, integration, pa, dt);
+      }
+
+      private:
+         PStorage  &ps;
+         CStorage  &cs;
+         PAccessor &pa;
+         CAccessor &ca;
+
+      public:
+         real_t erp;
+         kernel::HCSITSRelaxationStep::RelaxationModel model;
+         real_t contactThreshold;
+         Vec3 globalAcc;
+   };
+
+
+void normalReactionTest(kernel::HCSITSRelaxationStep::RelaxationModel model)
+{
+   //init data structures
+   auto ps = std::make_shared<data::ParticleStorage>(100);
+   auto cs = std::make_shared<data::ContactStorage>(100);
+   auto ss = std::make_shared<data::ShapeStorage>();
+   ParticleAccessorWithShape paccessor(ps, ss);
+   data::ContactAccessor caccessor(cs);
+   auto density = real_t(7.874);
+   auto radius = real_t(1.1);
+
+   //Geometries for sphere and half space.
+   auto smallSphere = ss->create<data::Sphere>( radius );
+   auto halfSpace = ss->create<data::HalfSpace>(Vec3(0,0,1));
+
+   ss->shapes[halfSpace]->updateMassAndInertia( density );
+   ss->shapes[smallSphere]->updateMassAndInertia( density );
+
+   // Create four slightly overlapping spheres in a row (located at x=0,2)
+   auto p = ps->create();
+   p->getPositionRef()        = Vec3(real_t(0), real_t(0), real_t(0));
+   p->getShapeIDRef()         = smallSphere;
+   p->getOwnerRef()           = walberla::mpi::MPIManager::instance()->rank();
+   p->getLinearVelocityRef()  = Vec3(real_t(5), real_t(5), real_t(6));
+   p->getTypeRef()            = 0;
+   //WALBERLA_LOG_INFO(paccessor.ParticleAccessorWithShape::getInvMass(0));
+
+
+   auto p2 = ps->create();
+   p2->getPositionRef()          = Vec3(real_t(5), real_t(5), real_t(5));
+   p2->getShapeIDRef()           = halfSpace;
+   p2->getOwnerRef()             = walberla::mpi::MPIManager::instance()->rank();
+   p2->getTypeRef()               = 0;
+   data::particle_flags::set(p2->getFlagsRef(), data::particle_flags::FIXED);
+   data::particle_flags::set(p2->getFlagsRef(), data::particle_flags::GLOBAL);
+
+   TestHCSITSKernel<data::ParticleStorage, data::ContactStorage, ParticleAccessorWithShape, data::ContactAccessor> testHCSITS(*ps, *cs, paccessor, caccessor);
+   testHCSITS.model = model;
+
+   WALBERLA_LOG_INFO(paccessor.getInvMass(0))
+   WALBERLA_LOG_INFO(paccessor.getInvMass(1))
+
+   // plane at 5,5,5
+   // radius 1.1
+   p->setPosition(  Vec3(5,5,6) );
+   p->setLinearVelocity( Vec3(0,0,0) );
+   testHCSITS( real_c( real_t(1.0) ) );
+   WALBERLA_CHECK_FLOAT_EQUAL( p->getPosition() , Vec3(5,5,real_t(6.1)) );
+   WALBERLA_CHECK_FLOAT_EQUAL( p->getLinearVelocity(), Vec3(0,0,real_t(0.1)) );
+   WALBERLA_LOG_INFO(p->getPosition());
+   WALBERLA_LOG_INFO(p->getLinearVelocity());
+
+   p->setPosition(  Vec3(5,5,6) );
+   p->setLinearVelocity( Vec3(0,0,0) );
+   testHCSITS.erp = real_t(0.5) ;
+   testHCSITS( real_t(1.0) );
+   WALBERLA_CHECK_FLOAT_EQUAL( p->getPosition() , Vec3(5,5,real_t(6.05)) );
+   WALBERLA_CHECK_FLOAT_EQUAL( p->getLinearVelocity(), Vec3(0,0,real_t(0.05)) );
+   WALBERLA_LOG_INFO(p->getPosition());
+   WALBERLA_LOG_INFO(p->getLinearVelocity());
+
+   p->setPosition(  Vec3(5,5,6) );
+   p->setLinearVelocity( Vec3(0,0,0) );
+   testHCSITS.erp = real_t(0.0) ;
+   testHCSITS( real_t(1.0) );
+   WALBERLA_CHECK_FLOAT_EQUAL( p->getPosition() , Vec3(5,5,6) );
+   WALBERLA_CHECK_FLOAT_EQUAL( p->getLinearVelocity(), Vec3(0,0,0) );
+   WALBERLA_LOG_INFO(p->getPosition());
+   WALBERLA_LOG_INFO(p->getLinearVelocity());
+
+   p->setPosition(  Vec3(5,5,6) );
+   p->setLinearVelocity( Vec3(0,0,-1) );
+   testHCSITS.erp = real_t(1.0) ;
+   testHCSITS( real_t(1.0) );
+   WALBERLA_CHECK_FLOAT_EQUAL( p->getPosition() , Vec3(5,5,real_t(6.1)) );
+   WALBERLA_CHECK_FLOAT_EQUAL( p->getLinearVelocity(), Vec3(0,0,real_t(0.1)) );
+   WALBERLA_LOG_INFO(p->getPosition());
+   WALBERLA_LOG_INFO(p->getLinearVelocity());
+
+   p->setPosition(  Vec3(5,5,6) );
+   p->setLinearVelocity( Vec3(0,0,-1) );
+   testHCSITS.erp = real_t(0.5) ;
+   testHCSITS( real_t(1.0) );
+   WALBERLA_CHECK_FLOAT_EQUAL( p->getPosition() , Vec3(5,5,real_t(6.05)) );
+   WALBERLA_CHECK_FLOAT_EQUAL( p->getLinearVelocity(), Vec3(0,0,real_t(0.05)) );
+   WALBERLA_LOG_INFO(p->getPosition());
+   WALBERLA_LOG_INFO(p->getLinearVelocity());
+
+   p->setPosition(  Vec3(5,5,6) );
+   p->setLinearVelocity( Vec3(0,0,-1) );
+   testHCSITS.erp = real_t(0.0) ;
+   testHCSITS( real_t(1.0) );
+   WALBERLA_CHECK_FLOAT_EQUAL( p->getPosition() , Vec3(5,5,6) );
+   WALBERLA_CHECK_FLOAT_EQUAL( p->getLinearVelocity(), Vec3(0,0,0) );
+   WALBERLA_LOG_INFO(p->getPosition());
+   WALBERLA_LOG_INFO(p->getLinearVelocity());
+
+   // No collision
+   p->setPosition(  Vec3(5,5,real_t(6.2)) );
+   p->setLinearVelocity( Vec3(0,0,real_t(-0.2)) );
+   testHCSITS.erp = real_t(1.0) ;
+   testHCSITS( real_t(1.0) );
+   WALBERLA_CHECK_FLOAT_EQUAL( p->getPosition() , Vec3(5,5,real_t(6.0)) );
+   WALBERLA_CHECK_FLOAT_EQUAL( p->getLinearVelocity(), Vec3(0,0,real_t(-0.2)) );
+
+   testHCSITS.contactThreshold = real_t(1.0);
+   p->setPosition(  Vec3(5,5,real_t(6.2)) );
+   p->setLinearVelocity( Vec3(0,0,real_t(-0.2)) );
+   testHCSITS.erp = real_t(1.0) ;
+   testHCSITS( real_t(1.0) );
+   WALBERLA_CHECK_FLOAT_EQUAL( p->getPosition() , Vec3(5,5,real_t(6.1)) );
+   WALBERLA_CHECK_FLOAT_EQUAL( p->getLinearVelocity(), Vec3(0,0,real_t(-0.1)) );
+
+   p->setPosition(  Vec3(5,5,real_t(6.1)) );
+   p->setLinearVelocity( Vec3(0,0,real_t(-0.1)) );
+   testHCSITS.erp = real_t(1.0) ;
+   testHCSITS( real_t(1.0) );
+   WALBERLA_CHECK_FLOAT_EQUAL( p->getPosition() , Vec3(5,5,real_t(6.1)) );
+   WALBERLA_CHECK_FLOAT_EQUAL( p->getLinearVelocity(), Vec3(0,0,real_t(0)) );
+   WALBERLA_LOG_INFO(p->getPosition());
+   WALBERLA_LOG_INFO(p->getLinearVelocity());
+}
+
+
+/**Check hard contact constraints on two overlapping, colliding spheres
+ * Works only for the solvers that really archieve seperation after a single
+ * timestep. Use SphereSeperationTest to check for seperation after multiple
+ * timesteps.
+ * @param model The collision model to use.
+ * */
+void SphereSphereTest(kernel::HCSITSRelaxationStep::RelaxationModel model){
+
+      //init data structures
+      auto ps = std::make_shared<data::ParticleStorage>(100);
+      auto cs = std::make_shared<data::ContactStorage>(100);
+      auto ss = std::make_shared<data::ShapeStorage>();
+      ParticleAccessorWithShape paccessor(ps, ss);
+      data::ContactAccessor caccessor(cs);
+      auto density = real_t(7.874);
+      auto radius = real_t(1.1);
+
+      auto smallSphere = ss->create<data::Sphere>( radius );
+      ss->shapes[smallSphere]->updateMassAndInertia( density );
+
+      auto dt = real_t(1);
+
+      // Create two slightly overlapping spheres in a row (located at x=0,2)
+      auto p = ps->create();
+      p->getPositionRef()          = Vec3(real_t(0), real_t(0), real_t(0));
+      p->getShapeIDRef()           = smallSphere;
+      p->getOwnerRef()             = walberla::mpi::MPIManager::instance()->rank();
+      p->getLinearVelocityRef()    = Vec3(real_t(1), real_t(0), real_t(0));
+      p->getTypeRef()              = 0;
+      auto p2 = ps->create();
+      p2->getPositionRef()          = Vec3(real_t(2), real_t(0), real_t(0));
+      p2->getShapeIDRef()           = smallSphere;
+      p2->getOwnerRef()             = walberla::mpi::MPIManager::instance()->rank();
+      p2->getLinearVelocityRef() = Vec3(real_t(-1), real_t(0), real_t(0));
+      p2->getTypeRef()              = 0;
+      TestHCSITSKernel<data::ParticleStorage, data::ContactStorage, ParticleAccessorWithShape, data::ContactAccessor> testHCSITS(*ps, *cs, paccessor, caccessor);
+      testHCSITS.model = model;
+      testHCSITS(dt);
+
+      WALBERLA_CHECK_FLOAT_EQUAL(p->getPosition(), Vec3(real_t(-0.1),0,0));
+      WALBERLA_CHECK_FLOAT_EQUAL(p->getLinearVelocity(), Vec3(real_t(-0.1),0,0));
+      WALBERLA_CHECK_FLOAT_EQUAL(p->getAngularVelocity(), Vec3(0,0,0));
+      WALBERLA_CHECK_FLOAT_EQUAL(p2->getPosition(), Vec3(real_t(2.1),0,0));
+      WALBERLA_CHECK_FLOAT_EQUAL(p2->getLinearVelocity(), Vec3(real_t(0.1),0,0))
+      WALBERLA_CHECK_FLOAT_EQUAL(p2->getAngularVelocity(), Vec3(0,0,0));
+
+      WALBERLA_LOG_INFO(p->getPosition());
+      WALBERLA_LOG_INFO(p->getLinearVelocity());
+      WALBERLA_LOG_INFO(p2->getPosition());
+      WALBERLA_LOG_INFO(p2->getLinearVelocity());
+}
+
+/**
+ * Create two overlapping spheres with opposing velocities, that are in contact.
+ * Assert that the collision is resolved after a certain (10) number of timesteps.
+ * @param model The collision model to use.
+ */
+void SphereSeperationTest(kernel::HCSITSRelaxationStep::RelaxationModel model){
+
+   //init data structures
+   auto ps = std::make_shared<data::ParticleStorage>(100);
+   auto cs = std::make_shared<data::ContactStorage>(100);
+   auto ss = std::make_shared<data::ShapeStorage>();
+   ParticleAccessorWithShape paccessor(ps, ss);
+   data::ContactAccessor caccessor(cs);
+   auto density = real_t(7.874);
+   auto radius = real_t(1.1);
+
+   auto smallSphere = ss->create<data::Sphere>( radius );
+
+   ss->shapes[smallSphere]->updateMassAndInertia( density );
+   auto dt = real_t(0.2);
+
+   // Create two slightly overlapping spheres in a row (located at x=0,2)
+   auto p = ps->create();
+   p->getPositionRef()          = Vec3(real_t(0), real_t(0), real_t(0));
+   p->getShapeIDRef()           = smallSphere;
+   p->getOwnerRef()             = walberla::mpi::MPIManager::instance()->rank();
+   p->getLinearVelocityRef()    = Vec3(real_t(1), real_t(0), real_t(0));
+   p->getTypeRef()              = 0;
+   auto p2 = ps->create();
+   p2->getPositionRef()          = Vec3(real_t(2.0), real_t(0), real_t(0));
+   p2->getShapeIDRef()           = smallSphere;
+   p2->getOwnerRef()             = walberla::mpi::MPIManager::instance()->rank();
+   p2->getLinearVelocityRef()    = Vec3(real_t(-1), real_t(0), real_t(0));
+   p2->getTypeRef()              = 0;
+   TestHCSITSKernel<data::ParticleStorage, data::ContactStorage, ParticleAccessorWithShape, data::ContactAccessor> testHCSITS(*ps, *cs, paccessor, caccessor);
+
+   int solveCount = 0;
+   testHCSITS.model = model;
+
+   // Number of allowed iterations
+   int maxIter = 10;
+   while(p2->getPosition()[0]-p->getPosition()[0] < 2.2){
+      testHCSITS(dt);
+      WALBERLA_LOG_INFO(p->getPosition());
+      WALBERLA_LOG_INFO(p->getLinearVelocity());
+      WALBERLA_LOG_INFO(p2->getPosition());
+      WALBERLA_LOG_INFO(p2->getLinearVelocity());
+      solveCount ++;
+      if(solveCount==maxIter){
+         WALBERLA_CHECK(false, "Seperation did not occur after " << maxIter << " Iterations performed.");
+      }
+   }
+   WALBERLA_LOG_INFO("Seperation achieved after " << solveCount << " iterations.");
+}
+
+/**
+ * Create a sphere that slides on a plane with only linear velocity. It is
+ * put into a spin by the frictional reactions, until it rolls with no slip.
+ * Assert that the sphere rolls with all slip resolved and at the physically correct
+ * speed after a certain number of timesteps. Use only with solvers that obey the coulomb friction law.
+ * @param model The collision model to use.
+ */
+void SlidingSphereFrictionalReactionTest(kernel::HCSITSRelaxationStep::RelaxationModel model){
+
+   //init data structures
+   auto ps = std::make_shared<data::ParticleStorage>(100);
+   auto cs = std::make_shared<data::ContactStorage>(100);
+   auto ss = std::make_shared<data::ShapeStorage>();
+   ParticleAccessorWithShape paccessor(ps, ss);
+   data::ContactAccessor caccessor(cs);
+   auto density = real_t(1);
+   auto radius = real_t(1);
+
+   auto smallSphere = ss->create<data::Sphere>( radius );
+   auto halfSpace = ss->create<data::HalfSpace>(Vec3(0,0,1));
+   ss->shapes[smallSphere]->updateMassAndInertia( density );
+   ss->shapes[halfSpace]->updateMassAndInertia( density );
+   auto dt = real_t(0.002);
+
+   // Create a spheres (located at x=0, height = 1)
+   auto p = ps->create();
+   p->getPositionRef()          = Vec3(real_t(0), real_t(0), real_t(1));
+   p->getShapeIDRef()           = smallSphere;
+   p->getOwnerRef()             = walberla::mpi::MPIManager::instance()->rank();
+   p->getLinearVelocityRef()    = Vec3(real_t(5), real_t(0), real_t(0));
+   p->getTypeRef()              = 0;
+
+   auto p2 = ps->create();
+   p2->getPositionRef()          = Vec3(real_t(0), real_t(0), real_t(0));
+   p2->getShapeIDRef()           = halfSpace;
+   p2->getOwnerRef()             = walberla::mpi::MPIManager::instance()->rank();
+   p2->getTypeRef()               = 0;
+   data::particle_flags::set(p2->getFlagsRef(), data::particle_flags::FIXED);
+   data::particle_flags::set(p2->getFlagsRef(), data::particle_flags::GLOBAL);
+
+   TestHCSITSKernel<data::ParticleStorage, data::ContactStorage, ParticleAccessorWithShape, data::ContactAccessor> testHCSITS(*ps, *cs, paccessor, caccessor);
+   testHCSITS.model = model;
+   testHCSITS.globalAcc = Vec3(0,0,-10);
+   int solveCount = 0;
+
+
+   // Number of allowed iterations
+   int maxIter = 500;
+   while(!walberla::floatIsEqual(p->getAngularVelocity()[1],p->getLinearVelocity()[0], real_t(0.002))){
+      testHCSITS(dt);
+      if(solveCount % 50 == 0){
+         WALBERLA_LOG_INFO(p->getAngularVelocity());
+         WALBERLA_LOG_INFO(p->getLinearVelocity());
+      }
+      solveCount ++;
+      if(solveCount==maxIter){
+         WALBERLA_CHECK(false, "End of slip did not occur after " << maxIter << " Iterations performed.");
+      }
+   }
+   WALBERLA_LOG_INFO("Rolling with no slip achieved after " << solveCount << " iterations.");
+
+   // Check if the value obtained values equal the physically correct values
+   // (which can be determined by newtons equation to be 25/7).
+   WALBERLA_CHECK_FLOAT_EQUAL_EPSILON(real_t(25.0/7.0), p->getAngularVelocity()[1], real_t(0.01), "Angular velocity is not physically correct");
+   WALBERLA_CHECK_FLOAT_EQUAL_EPSILON(real_t(25.0/7.0), p->getLinearVelocity()[0], real_t(0.01), "Linear velocity is not physically correct");
+}
+
+int main( int argc, char ** argv )
+{
+   Environment env(argc, argv);
+   WALBERLA_UNUSED(env);
+
+   walberla::mpi::MPIManager::instance()->useWorldComm();
+
+   WALBERLA_LOG_INFO_ON_ROOT("*** SETUP - START ***");
+
+
+   WALBERLA_LOG_INFO_ON_ROOT("InelasticFrictionlessContact");
+   normalReactionTest(kernel::HCSITSRelaxationStep::RelaxationModel::InelasticFrictionlessContact);
+   SphereSphereTest(kernel::HCSITSRelaxationStep::RelaxationModel::InelasticFrictionlessContact);
+
+   WALBERLA_LOG_INFO_ON_ROOT("ApproximateInelasticCoulombContactByDecoupling");
+   normalReactionTest(kernel::HCSITSRelaxationStep::RelaxationModel::ApproximateInelasticCoulombContactByDecoupling);
+   SphereSphereTest(kernel::HCSITSRelaxationStep::RelaxationModel::ApproximateInelasticCoulombContactByDecoupling);
+   SlidingSphereFrictionalReactionTest(kernel::HCSITSRelaxationStep::RelaxationModel::ApproximateInelasticCoulombContactByDecoupling);
+
+   WALBERLA_LOG_INFO_ON_ROOT("InelasticCoulombContactByDecoupling");
+   normalReactionTest(kernel::HCSITSRelaxationStep::RelaxationModel::InelasticCoulombContactByDecoupling);
+   SphereSphereTest(kernel::HCSITSRelaxationStep::RelaxationModel::InelasticCoulombContactByDecoupling);
+   SlidingSphereFrictionalReactionTest(kernel::HCSITSRelaxationStep::RelaxationModel::InelasticCoulombContactByDecoupling);
+
+   WALBERLA_LOG_INFO_ON_ROOT("InelasticGeneralizedMaximumDissipationContact");
+   normalReactionTest(kernel::HCSITSRelaxationStep::RelaxationModel::InelasticGeneralizedMaximumDissipationContact);
+   SphereSphereTest(kernel::HCSITSRelaxationStep::RelaxationModel::InelasticGeneralizedMaximumDissipationContact);
+   SlidingSphereFrictionalReactionTest(kernel::HCSITSRelaxationStep::RelaxationModel::InelasticGeneralizedMaximumDissipationContact);
+
+   WALBERLA_LOG_INFO_ON_ROOT("InelasticCoulombContactByOrthogonalProjections");
+   SphereSeperationTest(kernel::HCSITSRelaxationStep::RelaxationModel::InelasticCoulombContactByOrthogonalProjections);
+   SlidingSphereFrictionalReactionTest(kernel::HCSITSRelaxationStep::RelaxationModel::InelasticCoulombContactByOrthogonalProjections);
+
+   WALBERLA_LOG_INFO_ON_ROOT("ApproximateInelasticCoulombContactByOrthogonalProjections");
+   SphereSeperationTest(kernel::HCSITSRelaxationStep::RelaxationModel::ApproximateInelasticCoulombContactByOrthogonalProjections);
+   SlidingSphereFrictionalReactionTest(kernel::HCSITSRelaxationStep::RelaxationModel::ApproximateInelasticCoulombContactByOrthogonalProjections);
+
+   WALBERLA_LOG_INFO_ON_ROOT("InelasticProjectedGaussSeidel");
+   SphereSeperationTest(kernel::HCSITSRelaxationStep::RelaxationModel::InelasticProjectedGaussSeidel);
+   SlidingSphereFrictionalReactionTest(kernel::HCSITSRelaxationStep::RelaxationModel::InelasticProjectedGaussSeidel);
+   return EXIT_SUCCESS;
+}
+
+} //namespace walberla
+
+int main( int argc, char ** argv )
+{
+   return walberla::main(argc, argv);
+}
diff --git a/tests/mesa_pd/mpi/VelocityCorrectionNotification.cpp b/tests/mesa_pd/mpi/VelocityCorrectionNotification.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..79cd6351519295c35e4ab62dd7106537fdc3752e
--- /dev/null
+++ b/tests/mesa_pd/mpi/VelocityCorrectionNotification.cpp
@@ -0,0 +1,135 @@
+//======================================================================================================================
+//
+//  This file is part of waLBerla. waLBerla is free software: you can
+//  redistribute it and/or modify it under the terms of the GNU General Public
+//  License as published by the Free Software Foundation, either version 3 of
+//  the License, or (at your option) any later version.
+//
+//  waLBerla is distributed in the hope that it will be useful, but WITHOUT
+//  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+//  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+//  for more details.
+//
+//  You should have received a copy of the GNU General Public License along
+//  with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file   VelocityCorrectionNotification.cpp
+//! \author Sebastian Eibl <sebastian.eibl@fau.de>
+//
+//======================================================================================================================
+
+
+#include <blockforest/BlockForest.h>
+#include <blockforest/Initialization.h>
+#include <core/Environment.h>
+#include <core/logging/Logging.h>
+
+#include <mesa_pd/domain/BlockForestDomain.h>
+
+#include <mesa_pd/data/ParticleStorage.h>
+#include <mesa_pd/data/ShapeStorage.h>
+
+#include <mesa_pd/mpi/SyncNextNeighbors.h>
+#include <mesa_pd/mpi/BroadcastProperty.h>
+#include <mesa_pd/mpi/ReduceProperty.h>
+
+#include <mesa_pd/mpi/notifications/VelocityCorrectionNotification.h>
+#include <mesa_pd/mpi/notifications/VelocityUpdateNotification.h>
+
+#include <iostream>
+
+namespace walberla {
+
+int main( int argc, char ** argv )
+{
+
+   using namespace mesa_pd;
+
+   Environment env(argc, argv);
+   WALBERLA_UNUSED(env);
+   int np = walberla::mpi::MPIManager::instance()->numProcesses();
+
+   // create blocks
+   shared_ptr< blockforest::BlockForest > forest = blockforest::createBlockForest(
+           math::AABB(-10,-10,-10, 10, 10, 10),
+           Vector3<uint_t>(2,2,2),
+           Vector3<bool>(false, false, false));
+
+   domain::BlockForestDomain domain(forest);
+
+   //init data structures
+   data::ParticleStorage ps(10);
+
+   //initialize particle
+   const auto linVel = Vec3(1,2,3);
+   const auto angVel = Vec3(-1,-2,-3);
+
+   Vec3 pt(real_t(0.1), real_t(0.1),real_t(0.1));
+
+   for (auto& iBlk : *forest)
+   {
+      if(iBlk.getAABB().contains(pt)) {
+         auto p                       = ps.create();
+         p->getPositionRef()          = pt;
+         p->getInteractionRadiusRef() = real_t(1.0);
+         p->getOwnerRef()             = walberla::mpi::MPIManager::instance()->rank();
+         p->getTypeRef()              = 0;
+         p->getLinearVelocityRef()    = linVel;
+         p->getAngularVelocityRef()    = angVel;
+         WALBERLA_LOG_INFO("Particle created.");
+      }
+   }
+
+   // Sync (create ghost particles on the other processes)
+   mesa_pd::mpi::SyncNextNeighbors snn;
+   snn(ps, domain);
+
+   auto relax_param = real_t(0.8);
+   VelocityUpdateNotification::Parameters::relaxationParam = relax_param;
+   mesa_pd::mpi::ReduceProperty reductionKernel;
+   mesa_pd::mpi::BroadcastProperty broadcastKernel;
+
+   WALBERLA_LOG_INFO("Particle-Storage size: " << ps.size());
+
+   // Reduce dv
+   // dv per process
+   auto dvprocess = Vec3(real_t(0.1),real_t(0.1),real_t(0.1));
+   auto dwprocess = Vec3(real_t(0.05),real_t(0.1),real_t(0.15));
+   ps.setDv(0, dvprocess);
+   ps.setDw(0, dwprocess);
+   reductionKernel.operator()<VelocityCorrectionNotification>(ps);
+
+   for (auto& iBlk : *forest)
+   {
+      if(iBlk.getAABB().contains(pt)) {
+         WALBERLA_CHECK_FLOAT_EQUAL(ps.getLinearVelocity(0), linVel);
+         WALBERLA_CHECK_FLOAT_EQUAL(ps.getAngularVelocity(0), angVel);
+         WALBERLA_CHECK_FLOAT_EQUAL(ps.getDv(0), real_t(np) * dvprocess);
+         WALBERLA_CHECK_FLOAT_EQUAL(ps.getDw(0), real_t(np) * dwprocess);
+      }
+   }
+
+   broadcastKernel.operator()<VelocityUpdateNotification>(ps);
+
+
+   // Broadcast v
+   reductionKernel.operator()<VelocityCorrectionNotification>(ps);
+   if(np > 1){
+      WALBERLA_CHECK_FLOAT_EQUAL(ps.getLinearVelocity(0), linVel + relax_param * real_t(np) * dvprocess);
+      WALBERLA_CHECK_FLOAT_EQUAL(ps.getAngularVelocity(0), angVel + relax_param * real_t(np) * dwprocess);
+      WALBERLA_CHECK_FLOAT_EQUAL(ps.getDv(0), Vec3());
+      WALBERLA_CHECK_FLOAT_EQUAL(ps.getDw(0), Vec3());
+   }else{
+      WALBERLA_CHECK_FLOAT_EQUAL(ps.getLinearVelocity(0) + ps.getDv(0), linVel + real_t(np) * dvprocess);
+      WALBERLA_CHECK_FLOAT_EQUAL(ps.getAngularVelocity(0) + ps.getDw(0), angVel + real_t(np) * dwprocess);
+   }
+
+   return EXIT_SUCCESS;
+}
+
+} //namespace walberla
+
+int main( int argc, char ** argv )
+{
+   return walberla::main(argc, argv);
+}
diff --git a/tests/mesh/PeVTKMeshWriterTest.cpp b/tests/mesh/PeVTKMeshWriterTest.cpp
index 589f46642b6ca902f52cc4e379b2f32200dbc245..7e7b26e13360f9917b15701bd6b55e1ae8709fb3 100644
--- a/tests/mesh/PeVTKMeshWriterTest.cpp
+++ b/tests/mesh/PeVTKMeshWriterTest.cpp
@@ -41,7 +41,6 @@
 #include <core/waLBerlaBuildInfo.h>
 #include <core/math/Random.h>
 #include <core/math/Utility.h>
-#include <postprocessing/sqlite/SQLite.h>
 #include <vtk/VTKOutput.h>
 
 #include <functional>
diff --git a/tests/postprocessing/CMakeLists.txt b/tests/postprocessing/CMakeLists.txt
index 549bea2f00f57755e81dfaf4fc8d787296aa575e..ffe99cd52776ffa370638541c3a22625b834a7fc 100644
--- a/tests/postprocessing/CMakeLists.txt
+++ b/tests/postprocessing/CMakeLists.txt
@@ -6,7 +6,4 @@
 
 
 waLBerla_compile_test( FILES SphereTriangulate.cpp )
-waLBerla_execute_test( NAME SphereTriangulate )
-
-waLBerla_compile_test( FILES SQLiteTest.cpp )
-waLBerla_execute_test( NAME SQLiteTest )
+waLBerla_execute_test( NAME SphereTriangulate )
\ No newline at end of file
diff --git a/tests/sqlite/CMakeLists.txt b/tests/sqlite/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..21513d96b056a643907df3eb4738d50c815796ff
--- /dev/null
+++ b/tests/sqlite/CMakeLists.txt
@@ -0,0 +1,8 @@
+###################################################################################################
+#
+# Tests for sqlite module
+#
+###################################################################################################
+
+waLBerla_compile_test( FILES SQLiteTest.cpp )
+waLBerla_execute_test( NAME SQLiteTest )
\ No newline at end of file
diff --git a/tests/postprocessing/SQLiteTest.cpp b/tests/sqlite/SQLiteTest.cpp
similarity index 88%
rename from tests/postprocessing/SQLiteTest.cpp
rename to tests/sqlite/SQLiteTest.cpp
index 547bd12e9b2c3a07548a68ca7001c508fb5f8885..b65ad060362d9cc9d33880c88ea2466195bdaf0a 100644
--- a/tests/postprocessing/SQLiteTest.cpp
+++ b/tests/sqlite/SQLiteTest.cpp
@@ -22,7 +22,7 @@
 #include "core/debug/TestSubsystem.h"
 #include "core/mpi/Environment.h"
 
-#include "postprocessing/sqlite/SQLite.h"
+#include "sqlite/SQLite.h"
 
 
 int main( int argc, char ** argv )
@@ -40,7 +40,7 @@ int main( int argc, char ** argv )
       strColumns["property2"] = "value2";
       strColumns["property3"] = "value3";
       intColumns["i"] = int(i);
-      walberla::postprocessing::storeRunInSqliteDB( "dbFile.sqlite", intColumns, strColumns );
+      walberla::sqlite::storeRunInSqliteDB( "dbFile.sqlite", intColumns, strColumns );
    }
 
    for( int i=0; i< 100; ++i )
@@ -49,7 +49,7 @@ int main( int argc, char ** argv )
       strColumns["property2"] = "value2";
       strColumns["property3"] = "value3";
       largeColumns["i"] = 4294967297 + i;
-      walberla::postprocessing::storeRunInSqliteDB( "dbFile.sqlite", largeColumns, strColumns );
+      walberla::sqlite::storeRunInSqliteDB( "dbFile.sqlite", largeColumns, strColumns );
    }
 
    return 0;
diff --git a/utilities/conda/walberla/meta.yaml b/utilities/conda/walberla/meta.yaml
index 869f578214879f354d01732d7eca7c86cefd0524..2148479bbb815ac49d584f8a4d79995adaed5a94 100644
--- a/utilities/conda/walberla/meta.yaml
+++ b/utilities/conda/walberla/meta.yaml
@@ -15,13 +15,13 @@ requirements:
   host:
   - python
   - boost
-  - mpich2 [linux]
+  - mpich [linux]
   - openmesh
   run:
   - python
   - boost
   - numpy
-  - mpich2 [linux]
+  - mpich [linux]
   - openmesh
 source:
   path: ../../..
diff --git a/utilities/filterCompileCommands.py b/utilities/filterCompileCommands.py
index 3b0a08e7f932c224ce36d3845425937fadc08057..cb4813231736c7e40eb6c0f7eb2f664e0ebba522 100755
--- a/utilities/filterCompileCommands.py
+++ b/utilities/filterCompileCommands.py
@@ -6,6 +6,13 @@ import sys
 def compileCommandSelector(x):
    return not (("extern" in x["file"]) or ("tests" in x["file"]))
 
+def removePrecompiler(x):
+   pos = x.find("clang++")
+   if (pos != -1):
+      return x[pos:]
+   else:
+      return x
+
 if __name__ == "__main__":
    if (len(sys.argv) != 2):
       print("usage: ./filterCompileCommands.py compile_commands.json")
@@ -21,6 +28,8 @@ if __name__ == "__main__":
    print("compile commands read: {}".format(len(cc)))
 
    cc_filtered = list( filter(compileCommandSelector, cc) )
+   for x in cc_filtered:
+      x["command"] = removePrecompiler(x["command"])
 
    print("compile commands filtered: {}".format(len(cc_filtered)))