diff --git a/apps/benchmarks/PoiseuilleChannel/CMakeLists.txt b/apps/benchmarks/PoiseuilleChannel/CMakeLists.txt
index 4c7d676557603a20b00da98c4976fd307ee84e02..cb056fdb66bab0ae8bebde1be250ebbed409e06a 100644
--- a/apps/benchmarks/PoiseuilleChannel/CMakeLists.txt
+++ b/apps/benchmarks/PoiseuilleChannel/CMakeLists.txt
@@ -2,25 +2,41 @@
 waLBerla_link_files_to_builddir( "*.dat" )                 
 waLBerla_link_files_to_builddir( "*.prm" )
 
-waLBerla_add_executable( NAME PoiseuilleChannel
-                         FILES PoiseuilleChannel.cpp
-                         DEPENDS blockforest boundary core field lbm postprocessing stencil timeloop vtk sqlite )
 
-waLBerla_add_executable( NAME PoiseuilleChannelForceTesting
-                         FILES PoiseuilleChannelForceTesting.cpp
-                         DEPENDS blockforest core field lbm geometry timeloop )
+if( WALBERLA_BUILD_WITH_CODEGEN )
 
-##############
-# Some tests #
-##############
+    waLBerla_generate_target_from_python(NAME PoiseuilleChannelForceGeneratedLBM FILE GeneratedLBM.py
+            OUT_FILES GeneratedLBM.cpp GeneratedLBM.h )
+
+    waLBerla_add_executable( NAME PoiseuilleChannelForceTesting
+            FILES PoiseuilleChannelForceTesting.cpp
+            DEPENDS blockforest core field lbm geometry timeloop PoiseuilleChannelForceGeneratedLBM )
+
+else()
+
+    waLBerla_add_executable( NAME PoiseuilleChannel
+                             FILES PoiseuilleChannel.cpp
+                             DEPENDS blockforest boundary core field lbm postprocessing stencil timeloop vtk sqlite )
+
+    waLBerla_add_executable( NAME PoiseuilleChannelForceTesting
+                             FILES PoiseuilleChannelForceTesting.cpp
+                             DEPENDS blockforest core field lbm geometry timeloop )
+
+    ##############
+    # Some tests #
+    ##############
+    waLBerla_execute_test( NO_MODULE_LABEL NAME PoiseuilleChannelTestParallelPlatesNoCheckRelease COMMAND $<TARGET_FILE:PoiseuilleChannel> ${CMAKE_CURRENT_SOURCE_DIR}/TestParallelPlatesNoCheck.dat --trt --linear-exp PROCESSES 4 CONFIGURATIONS Release RelWithDbgInfo DEPENDS_ON_TARGETS PoiseuilleChannel )
+    waLBerla_execute_test( NO_MODULE_LABEL NAME PoiseuilleChannelTestPipeNoCheckRelease           COMMAND $<TARGET_FILE:PoiseuilleChannel> ${CMAKE_CURRENT_SOURCE_DIR}/TestPipeNoCheck.dat           --trt --linear-exp PROCESSES 4 CONFIGURATIONS Release RelWithDbgInfo DEPENDS_ON_TARGETS PoiseuilleChannel )
+
+    waLBerla_execute_test( NO_MODULE_LABEL NAME PoiseuilleChannelTestParallelPlatesNoCheckDebug COMMAND $<TARGET_FILE:PoiseuilleChannel> ${CMAKE_CURRENT_SOURCE_DIR}/TestParallelPlatesNoCheck.dat --trt --linear-exp PROCESSES 4 LABELS longrun CONFIGURATIONS Debug DebugOptimized DEPENDS_ON_TARGETS PoiseuilleChannel )
+    waLBerla_execute_test( NO_MODULE_LABEL NAME PoiseuilleChannelTestPipeNoCheckDebug           COMMAND $<TARGET_FILE:PoiseuilleChannel> ${CMAKE_CURRENT_SOURCE_DIR}/TestPipeNoCheck.dat           --trt --linear-exp PROCESSES 4 LABELS longrun CONFIGURATIONS Debug DebugOptimized DEPENDS_ON_TARGETS PoiseuilleChannel )
+
+    waLBerla_execute_test( NO_MODULE_LABEL NAME PoiseuilleChannelTestParallelPlates0 COMMAND $<TARGET_FILE:PoiseuilleChannel> ${CMAKE_CURRENT_SOURCE_DIR}/TestParallelPlates0.dat --trt --linear-exp LABELS longrun                         CONFIGURATIONS Release RelWithDbgInfo DEPENDS_ON_TARGETS PoiseuilleChannel )
+    waLBerla_execute_test( NO_MODULE_LABEL NAME PoiseuilleChannelTestParallelPlates2 COMMAND $<TARGET_FILE:PoiseuilleChannel> ${CMAKE_CURRENT_SOURCE_DIR}/TestParallelPlates2.dat --trt --linear-exp LABELS longrun verylongrun PROCESSES 4 CONFIGURATIONS Release RelWithDbgInfo DEPENDS_ON_TARGETS PoiseuilleChannel )
+    waLBerla_execute_test( NO_MODULE_LABEL NAME PoiseuilleChannelTestPipe0           COMMAND $<TARGET_FILE:PoiseuilleChannel> ${CMAKE_CURRENT_SOURCE_DIR}/TestPipe0.dat --trt --linear-exp           LABELS longrun                         CONFIGURATIONS Release RelWithDbgInfo DEPENDS_ON_TARGETS PoiseuilleChannel )
+    waLBerla_execute_test( NO_MODULE_LABEL NAME PoiseuilleChannelTestPipe2           COMMAND $<TARGET_FILE:PoiseuilleChannel> ${CMAKE_CURRENT_SOURCE_DIR}/TestPipe2.dat --trt --linear-exp           LABELS longrun verylongrun PROCESSES 4 CONFIGURATIONS Release RelWithDbgInfo DEPENDS_ON_TARGETS PoiseuilleChannel )
+
+endif()
 
-waLBerla_execute_test( NO_MODULE_LABEL NAME PoiseuilleChannelTestParallelPlatesNoCheckRelease COMMAND $<TARGET_FILE:PoiseuilleChannel> ${CMAKE_CURRENT_SOURCE_DIR}/TestParallelPlatesNoCheck.dat --trt --linear-exp PROCESSES 4 CONFIGURATIONS Release RelWithDbgInfo DEPENDS_ON_TARGETS PoiseuilleChannel )
-waLBerla_execute_test( NO_MODULE_LABEL NAME PoiseuilleChannelTestPipeNoCheckRelease           COMMAND $<TARGET_FILE:PoiseuilleChannel> ${CMAKE_CURRENT_SOURCE_DIR}/TestPipeNoCheck.dat           --trt --linear-exp PROCESSES 4 CONFIGURATIONS Release RelWithDbgInfo DEPENDS_ON_TARGETS PoiseuilleChannel )
 
-waLBerla_execute_test( NO_MODULE_LABEL NAME PoiseuilleChannelTestParallelPlatesNoCheckDebug COMMAND $<TARGET_FILE:PoiseuilleChannel> ${CMAKE_CURRENT_SOURCE_DIR}/TestParallelPlatesNoCheck.dat --trt --linear-exp PROCESSES 4 LABELS longrun CONFIGURATIONS Debug DebugOptimized DEPENDS_ON_TARGETS PoiseuilleChannel )
-waLBerla_execute_test( NO_MODULE_LABEL NAME PoiseuilleChannelTestPipeNoCheckDebug           COMMAND $<TARGET_FILE:PoiseuilleChannel> ${CMAKE_CURRENT_SOURCE_DIR}/TestPipeNoCheck.dat           --trt --linear-exp PROCESSES 4 LABELS longrun CONFIGURATIONS Debug DebugOptimized DEPENDS_ON_TARGETS PoiseuilleChannel )
 
-waLBerla_execute_test( NO_MODULE_LABEL NAME PoiseuilleChannelTestParallelPlates0 COMMAND $<TARGET_FILE:PoiseuilleChannel> ${CMAKE_CURRENT_SOURCE_DIR}/TestParallelPlates0.dat --trt --linear-exp LABELS longrun                         CONFIGURATIONS Release RelWithDbgInfo DEPENDS_ON_TARGETS PoiseuilleChannel )
-waLBerla_execute_test( NO_MODULE_LABEL NAME PoiseuilleChannelTestParallelPlates2 COMMAND $<TARGET_FILE:PoiseuilleChannel> ${CMAKE_CURRENT_SOURCE_DIR}/TestParallelPlates2.dat --trt --linear-exp LABELS longrun verylongrun PROCESSES 4 CONFIGURATIONS Release RelWithDbgInfo DEPENDS_ON_TARGETS PoiseuilleChannel )
-waLBerla_execute_test( NO_MODULE_LABEL NAME PoiseuilleChannelTestPipe0           COMMAND $<TARGET_FILE:PoiseuilleChannel> ${CMAKE_CURRENT_SOURCE_DIR}/TestPipe0.dat --trt --linear-exp           LABELS longrun                         CONFIGURATIONS Release RelWithDbgInfo DEPENDS_ON_TARGETS PoiseuilleChannel )
-waLBerla_execute_test( NO_MODULE_LABEL NAME PoiseuilleChannelTestPipe2           COMMAND $<TARGET_FILE:PoiseuilleChannel> ${CMAKE_CURRENT_SOURCE_DIR}/TestPipe2.dat --trt --linear-exp           LABELS longrun verylongrun PROCESSES 4 CONFIGURATIONS Release RelWithDbgInfo DEPENDS_ON_TARGETS PoiseuilleChannel )
diff --git a/apps/benchmarks/PoiseuilleChannel/GeneratedLBM.py b/apps/benchmarks/PoiseuilleChannel/GeneratedLBM.py
new file mode 100644
index 0000000000000000000000000000000000000000..8acc9a28573efd63972773dd72ceffdd96769ce8
--- /dev/null
+++ b/apps/benchmarks/PoiseuilleChannel/GeneratedLBM.py
@@ -0,0 +1,49 @@
+import sympy as sp
+
+from lbmpy.creationfunctions import LBMConfig, LBMOptimisation, create_lb_collision_rule
+from lbmpy.enums import ForceModel, Method, Stencil
+from lbmpy.stencils import LBStencil
+
+from pystencils_walberla import CodeGeneration
+from lbmpy_walberla import generate_lattice_model
+
+generatedMethod = 'TRT'
+
+# general parameters
+stencil = LBStencil(Stencil.D2Q9)
+force = sp.symbols('force_:2')
+layout = 'fzyx'  #'zyxf'
+
+if generatedMethod == 'SRT':
+    omega = sp.Symbol('omega')
+    # method definition
+    lbm_config = LBMConfig(stencil=stencil,
+                           method=Method.SRT,
+                           relaxation_rate=omega,
+                           compressible=True,
+                           force=force,
+                           force_model=ForceModel.GUO,
+                           zero_centered=False,
+                           streaming_pattern='pull')  # free surface implementation only works with pull pattern
+elif generatedMethod == 'TRT':
+    omega_e = sp.Symbol('omega_e')
+    omega_o = sp.Symbol('omega_o')
+    # method definition
+    lbm_config = LBMConfig(stencil=stencil,
+                           method=Method.TRT,
+                           relaxation_rates=[omega_e, omega_o],
+                           compressible=True,
+                           force=force,
+                           force_model=ForceModel.GUO,
+                           zero_centered=False,
+                           streaming_pattern='pull')  # free surface implementation only works with pull pattern
+
+# optimizations to be used by the code generator
+lbm_opt = LBMOptimisation(cse_global=True,
+                          field_layout=layout)
+
+collision_rule = create_lb_collision_rule(lbm_config=lbm_config,
+                                          lbm_optimisation=lbm_opt)
+
+with CodeGeneration() as ctx:
+    generate_lattice_model(ctx, "GeneratedLBM", collision_rule, field_layout=layout)
diff --git a/apps/benchmarks/PoiseuilleChannel/PoiseuilleChannelForceTesting.cpp b/apps/benchmarks/PoiseuilleChannel/PoiseuilleChannelForceTesting.cpp
index ae0ef75821028d4e55daa4497a906a56d63091cb..12849995613e62b2d7ace957b65235e1f7d5580d 100644
--- a/apps/benchmarks/PoiseuilleChannel/PoiseuilleChannelForceTesting.cpp
+++ b/apps/benchmarks/PoiseuilleChannel/PoiseuilleChannelForceTesting.cpp
@@ -29,11 +29,15 @@
 #include "lbm/all.h"
 #include "timeloop/all.h"
 
+#ifdef WALBERLA_BUILD_WITH_CODEGEN
+   #include "GeneratedLBM.h"
+#endif
 
 
 namespace walberla {
 
 //const uint_t FieldGhostLayers( 1 );
+#define CODEGEN
 
 //#define USE_SRT
 #define USE_TRT
@@ -42,19 +46,25 @@ namespace walberla {
 //#define USE_SimpleConstant
 //#define USE_GuoField
 
-#if defined(USE_GuoConstant)
-   using ForceModel_T = lbm::force_model::GuoConstant;
-#elif defined(USE_SimpleConstant)
-   using ForceModel_T = lbm::force_model::SimpleConstant;
+#ifdef CODEGEN
+#else
+   #if defined(USE_GuoConstant)
+      using ForceModel_T = lbm::force_model::GuoConstant;
+   #elif defined(USE_SimpleConstant)
+      using ForceModel_T = lbm::force_model::SimpleConstant;
+   #endif
 #endif
 
 //using Vec3Field_T = field::GhostLayerField<Vector3<real_t>, 1>;
 //using ForceModel_T = lbm::force_model::GuoField<Vec3Field_T>;
-#if defined(USE_SRT)
-   using CollisionModel_T = lbm::collision_model::SRT;
-   using LatticeModel_T = lbm::D2Q9<CollisionModel_T , true, ForceModel_T>;
-#elif defined(USE_TRT)
-   using CollisionModel_T = lbm::collision_model::TRT;
+#ifdef CODEGEN
+   using LatticeModel_T = lbm::GeneratedLBM;
+#else
+   #ifdef USE_SRT
+      using CollisionModel_T = lbm::collision_model::SRT;
+   #elif defined(USE_TRT)
+      using CollisionModel_T = lbm::collision_model::TRT;
+   #endif
    using LatticeModel_T = lbm::D2Q9<CollisionModel_T , true, ForceModel_T>;
 #endif
 
@@ -67,7 +77,6 @@ using flag_t = walberla::uint8_t;
 using FlagField_T = FlagField<flag_t>;
 
 
-
 int main( int argc, char ** argv )
 {
    walberla::Environment walberlaEnv( argc, argv );
@@ -82,27 +91,38 @@ int main( int argc, char ** argv )
    const uint_t          timesteps       = parameters.getParameter< uint_t >         ( "timesteps",       uint_c( 10 )  );
 
    const double remainingTimeLoggerFrequency = parameters.getParameter< double >( "remainingTimeLoggerFrequency", 3.0 ); // in seconds
-   const Vector3<real_t> bodyForce(real_t(1e-6), real_t(0), real_t(0));
+   const Vector3<real_t> bodyForce(real_t(1e-5), real_t(0), real_t(0));
 
    // create fields
    //> BlockDataID forceFieldID = field::addToStorage< Vec3Field_T >( blocks, "force field", Vector3<real_t>(real_t(0)), field::zyxf, FieldGhostLayers );
-
-#if defined(USE_SRT)
-   LatticeModel_T latticeModel = LatticeModel_T(CollisionModel_T(omega),ForceModel_T(bodyForce));
-#elif defined(USE_TRT)
-   real_t lambda_e = lbm::collision_model::TRT::lambda_e( omega );
-   real_t lambda_d = lbm::collision_model::TRT::lambda_d( omega, lbm::collision_model::TRT::threeSixteenth );
-   std::cout << "   lambda_e = " << lambda_e << " | lambda_d = " << lambda_d << std::endl;
-   LatticeModel_T latticeModel =
-      LatticeModel_T(CollisionModel_T(lambda_e, lambda_d), ForceModel_T(bodyForce));
-   auto viscosity = lbm::collision_model::viscosityFromOmega(omega);
-   std::cout << "   omega = " << omega << " | viscosity = " << viscosity << std::endl;
-#elif defined(USE_MRT)
-   LatticeModel_T latticeModel = LatticeModel_T(CollisionModel_T(omega, omega, omega, omega, omega, omega),
-                                                ForceModel_T(bodyForce));
+#ifdef CODEGEN
+   #ifdef USE_SRT
+      LatticeModel_T  latticeModel = LatticeModel_T (bodyForce[0], bodyForce[1], omega);
+   #elif defined(USE_TRT)
+      real_t lambda_e = lbm::collision_model::TRT::lambda_e( omega );
+      real_t lambda_d = lbm::collision_model::TRT::lambda_d( omega, lbm::collision_model::TRT::threeSixteenth );
+      std::cout << "   lambda_e = " << lambda_e << " | lambda_d = " << lambda_d << std::endl;
+      LatticeModel_T  latticeModel = LatticeModel_T (bodyForce[0], bodyForce[1], lambda_e, lambda_d);
+   #endif
+#else
+   #if defined(USE_SRT)
+      LatticeModel_T latticeModel = LatticeModel_T(CollisionModel_T(omega),ForceModel_T(bodyForce));
+   #elif defined(USE_TRT)
+      real_t lambda_e = lbm::collision_model::TRT::lambda_e( omega );
+      real_t lambda_d = lbm::collision_model::TRT::lambda_d( omega, lbm::collision_model::TRT::threeSixteenth );
+      std::cout << "   lambda_e = " << lambda_e << " | lambda_d = " << lambda_d << std::endl;
+      LatticeModel_T latticeModel =
+         LatticeModel_T(CollisionModel_T(lambda_e, lambda_d), ForceModel_T(bodyForce));
+      auto viscosity = lbm::collision_model::viscosityFromOmega(omega);
+      std::cout << "   omega = " << omega << " | viscosity = " << viscosity << std::endl;
+   #elif defined(USE_MRT)
+      LatticeModel_T latticeModel = LatticeModel_T(CollisionModel_T(omega, omega, omega, omega, omega, omega),
+                                                   ForceModel_T(bodyForce));
+   #endif
 #endif
+
    //> LatticeModel_T latticeModel = LatticeModel_T( lbm::collision_model::SRT( omega ), ForceModel_T( forceFieldID ));
-   BlockDataID pdfFieldId = lbm::addPdfFieldToStorage( blocks, "pdf field", latticeModel, initialVelocity, real_t(1) );
+   BlockDataID pdfFieldId = lbm::addPdfFieldToStorage( blocks, "pdf field", latticeModel, initialVelocity, real_t(1), field::fzyx );
    //> BlockDataID pdfFieldId = lbm::addPdfFieldToStorage( blocks, "pdf field (zyxf)", latticeModel, initialVelocity, real_t(1), FieldGhostLayers, field::zyxf );
    BlockDataID flagFieldId = field::addFlagFieldToStorage< FlagField_T >( blocks, "flag field" );
 
@@ -132,7 +152,13 @@ int main( int argc, char ** argv )
    // add LBM sweep and communication to time loop
    timeloop.add() << BeforeFunction( communication, "communication" )
                   << Sweep( BHFactory::BoundaryHandling::getBlockSweep( boundaryHandlingId ), "boundary handling" );
-   timeloop.add() << Sweep( makeSharedSweep( lbm::makeCellwiseSweep< LatticeModel_T, FlagField_T >( pdfFieldId, flagFieldId, fluidFlagUID ) ), "LB stream & collide" );
+#ifdef CODEGEN
+   auto lbmSweep = LatticeModel_T::Sweep(pdfFieldId);
+   timeloop.add() << Sweep( lbmSweep, "LB Sweep" );
+#else
+   auto lbmSweep = lbm::makeCellwiseSweep< LatticeModel_T, FlagField_T >( pdfFieldId, flagFieldId, fluidFlagUID );
+   timeloop.add() << Sweep( makeSharedSweep( lbmSweep ), "LB stream & collide" );
+#endif
 
    // LBM stability check
    timeloop.addFuncAfterTimeStep( makeSharedFunctor( field::makeStabilityChecker< PdfField_T, FlagField_T >( walberlaEnv.config(), blocks, pdfFieldId,
diff --git a/apps/benchmarks/PoiseuilleChannel/PoiseuilleChannelForceTesting.prm b/apps/benchmarks/PoiseuilleChannel/PoiseuilleChannelForceTesting.prm
index 4e1813907e1652e3ed77ff596a16c7c76e4cec2b..18c2dec95cb0ea96df60e5fec294b194c07daa0a 100644
--- a/apps/benchmarks/PoiseuilleChannel/PoiseuilleChannelForceTesting.prm
+++ b/apps/benchmarks/PoiseuilleChannel/PoiseuilleChannelForceTesting.prm
@@ -3,8 +3,8 @@ Parameters
 {
 	omega           1.8;
 	initialVelocity < 0.0, 0, 0 >;
-	//timesteps       10000;
-	timesteps       1;
+	timesteps       10000;
+	//timesteps       1;
 
 	remainingTimeLoggerFrequency 3; // in seconds
 }
@@ -12,10 +12,10 @@ Parameters
 DomainSetup
 {
    blocks        <  1,    1, 1 >;
-   //cellsPerBlock <  300, 80, 1 >;
-   //periodic      <  1,    0, 1 >;
-   cellsPerBlock <  2,    2, 1 >;
-   periodic      <  1,    1, 1 >;
+   cellsPerBlock <  300, 80, 1 >;
+   periodic      <  1,    0, 1 >;
+   //cellsPerBlock <  2,    2, 1 >;
+   //periodic      <  1,    1, 1 >;
 }
 
 StabilityChecker
@@ -27,7 +27,7 @@ StabilityChecker
 
 Boundaries
 {
-//	Border { direction S,N;  walldistance -1;  NoSlip    {} }
+	Border { direction S,N;  walldistance -1;  NoSlip    {} }
 }