diff --git a/cmake/PrepareSFG.cmake b/cmake/PrepareSFG.cmake
index 54ee564d846f00a668ecf0524907e517aac62379..9c042b24d82e0c8291c0a6745588e38dba862f34 100644
--- a/cmake/PrepareSFG.cmake
+++ b/cmake/PrepareSFG.cmake
@@ -28,7 +28,7 @@ if( WALBERLA_CODEGEN_USE_PRIVATE_VENV )
         )
 
         execute_process(
-            COMMAND ${_venv_python_exe} -m pip install ${sfg_walberla_SOURCE_DIR}
+            COMMAND ${_venv_python_exe} -m pip install -e ${sfg_walberla_SOURCE_DIR}
             OUTPUT_QUIET
         )
 
diff --git a/cmake/venv-reqs.txt b/cmake/venv-reqs.txt
index f82e5aae7f4ca722991030c572bb2391d70096bc..97f53bbb590d9fd5e0fede0c74ca92b59014b804 100644
--- a/cmake/venv-reqs.txt
+++ b/cmake/venv-reqs.txt
@@ -4,5 +4,5 @@ git+https://i10git.cs.fau.de/pycodegen/pystencils.git@v2.0-dev
 # lbmpy: feature branch for pystencils-2.0 compatibility
 git+https://i10git.cs.fau.de/pycodegen/lbmpy.git@fhennig/pystencils2.0-compat
 
-# pystencils-sfg: (development branch with updated CMake modules)
-git+https://i10git.cs.fau.de/pycodegen/pystencils-sfg.git@fhennig/cmake-custom-python
+# pystencils-sfg: (development branch with updated CMake modules and cpptypes)
+git+https://i10git.cs.fau.de/pycodegen/pystencils-sfg.git@fhennig/devel
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index 2325a59a150872cd039792735b23a8df59c7a71e..59c36c295de0103a5eb5657faee2ff1dfadc1fb4 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -14,4 +14,4 @@ FetchContent_MakeAvailable(walberla)
 add_subdirectory(${CMAKE_SOURCE_DIR}/.. ${CMAKE_BINARY_DIR}/sfg-walberla)
 
 add_subdirectory( GeneratorScriptBasics )
-add_subdirectory( FullyPeriodicAde )
+add_subdirectory( ForceDrivenChannel )
diff --git a/examples/ForceDrivenChannel/Channel.prm b/examples/ForceDrivenChannel/Channel.prm
new file mode 100644
index 0000000000000000000000000000000000000000..36aa90daf3229784037bd6b99d89412df5a7f9f8
--- /dev/null
+++ b/examples/ForceDrivenChannel/Channel.prm
@@ -0,0 +1,23 @@
+DomainSetup
+{
+    blocks < 1, 1, 1 >;
+    cellsPerBlock < 4, 4, 32 >;
+    periodic < 1, 1, 0 >;
+}
+
+Parameters
+{
+    omega       1.0;
+    force       < 6.25e-5, 0, 0 >;
+    timesteps   5000;
+}
+
+Boundaries {
+    Border { direction T; walldistance -1; flag NoSlip;  }
+    Border { direction B; walldistance -1; flag NoSlip; }
+}
+
+Output
+{
+    vtkWriteFrequency   100;
+}
\ No newline at end of file
diff --git a/examples/ForceDrivenChannel/ForceDrivenChannel.cpp b/examples/ForceDrivenChannel/ForceDrivenChannel.cpp
index 9b6bdc2ec2f03e639bbb4a5124ae710e2467741b..52238a70a2ebcb079d0f61257174e7aef82102bf 100644
--- a/examples/ForceDrivenChannel/ForceDrivenChannel.cpp
+++ b/examples/ForceDrivenChannel/ForceDrivenChannel.cpp
@@ -1,3 +1,145 @@
-int main(void) {
-    return 0;
+#include "blockforest/all.h"
+#include "blockforest/communication/UniformBufferedScheme.h"
+
+#include "core/all.h"
+
+#include "domain_decomposition/SharedSweep.h"
+
+#include "field/all.h"
+#include "field/communication/PackInfo.h"
+#include "field/communication/StencilRestrictedPackInfo.h"
+
+#include "geometry/InitBoundaryHandling.h"
+
+#include "stencil/all.h"
+
+#include "timeloop/all.h"
+
+#include "vtk/all.h"
+
+#include "gen/Ex_ForceDrivenChannel/LbmAlgorithms.hpp"
+
+namespace Ex_ForceDrivenChannel
+{
+    using namespace walberla;
+    using namespace blockforest;
+
+    using std::make_unique;
+    using std::shared_ptr;
+
+    using ScalarField_T = field::GhostLayerField<real_t, 1>;
+    using VectorField_T = field::GhostLayerField<real_t, 3>;
+
+    using LbStencil = stencil::D3Q19;
+    using PdfField_T = field::GhostLayerField<real_t, LbStencil::Q>;
+
+    using CommScheme = blockforest::communication::UniformBufferedScheme<LbStencil>;
+    using PdfsPackInfo = field::communication::StencilRestrictedPackInfo<PdfField_T, LbStencil>;
+
+    using FlagField_T = FlagField<uint8_t>;
+
+    void run(const shared_ptr<Config> &config)
+    {
+        auto blocks = createUniformBlockGridFromConfig(config);
+
+        Config::BlockHandle simParams = config->getBlock("Parameters");
+        const real_t omega{simParams.getParameter<real_t>("omega")};
+
+        const Vector3<real_t> force = simParams.getParameter<Vector3<real_t>>("force");
+
+        BlockDataID pdfsId = field::addToStorage<PdfField_T>(blocks, "pdfs", real_c(0.0), field::fzyx, 1);
+        BlockDataID rhoId = field::addToStorage<ScalarField_T>(blocks, "rho", real_c(1.0), field::fzyx, 0);
+        BlockDataID uId = field::addToStorage<VectorField_T>(blocks, "u", real_c(0.0), field::fzyx, 0);
+
+        gen::LbInit lbInit{pdfsId, rhoId, uId, force};
+
+        for (auto &block : *blocks)
+        {
+            lbInit(&block);
+        }
+
+        //  Stream-Collide
+
+        auto streamCollide = make_shared<gen::LbStreamCollide>(pdfsId, rhoId, uId, force, omega);
+
+        //  Communication Setup
+
+        CommScheme comm{blocks};
+        auto pdfsPackInfo = std::make_shared<PdfsPackInfo>(pdfsId);
+        comm.addPackInfo(pdfsPackInfo);
+
+        //  Boundary Conditions
+
+        const BlockDataID flagFieldId = field::addFlagFieldToStorage<FlagField_T>(blocks, "flagField");
+        const FlagUID fluidFlagUid{"Fluid"};
+        const FlagUID noSlipFlagUid{"NoSlip"};
+
+        auto boundariesConfig = config->getBlock("Boundaries");
+        if (boundariesConfig)
+        {
+            WALBERLA_LOG_INFO_ON_ROOT("Setting boundary conditions")
+            geometry::initBoundaryHandling<FlagField_T>(*blocks, flagFieldId, boundariesConfig);
+        }
+
+        geometry::setNonBoundaryCellsToDomain<FlagField_T>(*blocks, flagFieldId, fluidFlagUid);
+
+        auto flagFieldOutput = field::createVTKOutput<FlagField_T>(flagFieldId, *blocks, "flagField", 1, 0);
+        flagFieldOutput();
+
+        auto noSlip = make_unique<gen::NoSlip>(blocks, pdfsId);
+        noSlip->fillFromFlagField<FlagField_T>(*blocks, flagFieldId, noSlipFlagUid, fluidFlagUid);
+
+        auto boundarySweep = [&](IBlock *block)
+        {
+            (*noSlip)(block);
+        };
+
+        //  Timeloop
+        const uint_t numTimesteps{simParams.getParameter<uint_t>("timesteps")};
+        SweepTimeloop loop{blocks->getBlockStorage(), numTimesteps};
+
+        loop.add() << Sweep(makeSharedSweep(streamCollide));
+        loop.add() << Sweep(boundarySweep) << AfterFunction(comm);
+
+        RemainingTimeLogger logger{numTimesteps};
+        loop.addFuncAfterTimeStep(logger);
+
+        //  VTK Output
+
+        Config::BlockHandle outputParams = config->getBlock("Output");
+
+        const uint_t vtkWriteFrequency = outputParams.getParameter<uint_t>("vtkWriteFrequency", 0);
+        if (vtkWriteFrequency > 0)
+        {
+            auto vtkOutput = vtk::createVTKOutput_BlockData(*blocks, "vtk", vtkWriteFrequency, 0, false, "vtk_out",
+                                                            "simulation_step", false, true, true, false, 0);
+
+            auto densityWriter = make_shared<field::VTKWriter<ScalarField_T, float32>>(rhoId, "density");
+            vtkOutput->addCellDataWriter(densityWriter);
+
+            auto velWriter = make_shared<field::VTKWriter<VectorField_T, float32>>(uId, "velocity");
+            vtkOutput->addCellDataWriter(velWriter);
+
+            const cell_idx_t xCells = cell_idx_c(blocks->getNumberOfXCells());
+            const cell_idx_t yCells = cell_idx_c(blocks->getNumberOfYCells());
+            const cell_idx_t zCells = cell_idx_c(blocks->getNumberOfZCells());
+
+            loop.addFuncAfterTimeStep(vtk::writeFiles(vtkOutput), "VTK Output");
+        }
+
+        //  Run the Simulation
+
+        WALBERLA_LOG_INFO_ON_ROOT("Commencing simulation with " << numTimesteps << " timesteps")
+
+        loop.run();
+    }
+}
+
+int main(int argc, char **argv)
+{
+    walberla::Environment env{argc, argv};
+
+    Ex_ForceDrivenChannel::run(env.config());
+
+    return EXIT_SUCCESS;
 }
diff --git a/examples/ForceDrivenChannel/LbmAlgorithms.py b/examples/ForceDrivenChannel/LbmAlgorithms.py
index c27d3ee7d8e490de863ba5fff77d581b6b8f33e2..fe9b7c1c314090e88db71ee82afe01311e6983c4 100644
--- a/examples/ForceDrivenChannel/LbmAlgorithms.py
+++ b/examples/ForceDrivenChannel/LbmAlgorithms.py
@@ -2,8 +2,10 @@ import sympy as sp
 
 from pystencilssfg import SourceFileGenerator
 from sfg_walberla import Sweep
+from sfg_walberla.boundaries import SimpleHbbBoundary
+
 from pystencils import Target, fields
-import pystencils.config as cfg
+import pystencils.codegen.config as cfg
 from lbmpy import (
     LBStencil,
     Stencil,
@@ -14,6 +16,7 @@ from lbmpy import (
     create_lb_update_rule,
 )
 
+from lbmpy.boundaries import NoSlip
 from lbmpy.macroscopic_value_kernels import macroscopic_values_setter
 
 stencil = LBStencil(Stencil.D3Q19)
@@ -37,7 +40,7 @@ lbm_config = LBMConfig(
 lb_method = create_lb_method(lbm_config)
 
 with SourceFileGenerator() as sfg:
-    sfg.namespace("ForceDrivenChannel::gen")
+    sfg.namespace("Ex_ForceDrivenChannel::gen")
 
     sfg.include(f"stencil/{stencil.name}.h")
     sfg.code(f"using LbStencil = walberla::stencil::{stencil.name};")
@@ -59,3 +62,5 @@ with SourceFileGenerator() as sfg:
     lb_init_sweep = Sweep("LbInit", lb_init, gen_config)
     sfg.generate(lb_init_sweep)
 
+    #   No-Slip Wall
+    sfg.generate(SimpleHbbBoundary(NoSlip(), lb_method, f))
diff --git a/src/sfg_walberla/boundaries/hbb.py b/src/sfg_walberla/boundaries/hbb.py
index 2a79cb70a0f6d4ed6d6f3fe8e38d87726a225132..2da0f1765def3493ae0c806c5a65d47f2c6f5ec2 100644
--- a/src/sfg_walberla/boundaries/hbb.py
+++ b/src/sfg_walberla/boundaries/hbb.py
@@ -211,7 +211,7 @@ def _create_lb_boundary_kernel(
     inv_dir = indexing.inverse_dir_symbol
 
     boundary_assignments = boundary_functor(
-        f_out, f_in, dir_symbol, inv_dir, lb_method, index_field
+        f_out, f_in, dir_symbol, inv_dir, lb_method, index_field, None  # TODO: Fix force vector
     )
     boundary_assignments = indexing.substitute_proxies(boundary_assignments)