diff --git a/apps/showcases/CMakeLists.txt b/apps/showcases/CMakeLists.txt
index 6330a83bdde5027a2d0fd8e030862b7bf521dcd4..64becac3b5b95193aa8ada372255ad92e9915b0b 100644
--- a/apps/showcases/CMakeLists.txt
+++ b/apps/showcases/CMakeLists.txt
@@ -8,6 +8,7 @@ add_subdirectory( ParticlePacking )
 add_subdirectory( PegIntoSphereBed )
 if ( WALBERLA_BUILD_WITH_CODEGEN AND WALBERLA_BUILD_WITH_PYTHON )
 add_subdirectory( PhaseFieldAllenCahn )
+add_subdirectory( LDC )
 endif()
 if ( WALBERLA_BUILD_WITH_CODEGEN AND NOT WALBERLA_BUILD_WITH_OPENMP)
    add_subdirectory( PorousMedia )
diff --git a/apps/showcases/LDC/CMakeLists.txt b/apps/showcases/LDC/CMakeLists.txt
index 339f648197b4d716c9357f19b5f03ad4fdb43ffd..c254106e37d2cec1c65e08b332219ea2fbed1ca7 100644
--- a/apps/showcases/LDC/CMakeLists.txt
+++ b/apps/showcases/LDC/CMakeLists.txt
@@ -1,51 +1,17 @@
 # Code Generation Tutorials
-
+waLBerla_link_files_to_builddir(*.prm)
 if( WALBERLA_BUILD_WITH_CODEGEN )
 
-    #   Tutorial 1: Heat Equation with pystencils
-    walberla_generate_target_from_python( NAME CodegenHeatEquationKernel
-        FILE HeatEquationKernel.py
-        OUT_FILES HeatEquationKernel.cpp HeatEquationKernel.h )
-    
-    walberla_add_executable ( NAME 01_CodegenHeatEquation 
-                              FILES 01_CodegenHeatEquation.cpp
-                              DEPENDS blockforest core field stencil timeloop vtk pde CodegenHeatEquationKernel )
-
-    #   Tutorial 2: lbmpy Lattice Model Generation
-    waLBerla_link_files_to_builddir( *.prm )
-    
-    walberla_generate_target_from_python( NAME 02_LBMLatticeModelGenerationPython
-        FILE 02_LBMLatticeModelGeneration.py
-        OUT_FILES   SRTLatticeModel.cpp SRTLatticeModel.h 
-                    SRTPackInfo.cpp SRTPackInfo.h )
-
-    walberla_add_executable ( NAME 02_LBMLatticeModelGenerationApp 
-                    FILES 02_LBMLatticeModelGeneration.cpp
-                    DEPENDS blockforest core domain_decomposition field geometry timeloop lbm stencil vtk 02_LBMLatticeModelGenerationPython )
-
-    #   Tutorial 3: Advanced lbmpy Code Generation
-    if(WALBERLA_BUILD_WITH_CUDA)
-        walberla_generate_target_from_python( NAME 03_AdvancedLBMCodegenPython
-            FILE 03_AdvancedLBMCodegen.py
-            OUT_FILES   CumulantMRTSweep.cu CumulantMRTSweep.h
-                        CumulantMRTPackInfo.cu CumulantMRTPackInfo.h
-                        InitialPDFsSetter.cu InitialPDFsSetter.h
-                        CumulantMRTNoSlip.cu CumulantMRTNoSlip.h)
-
-        walberla_add_executable ( NAME 03_AdvancedLBMCodegenApp
-                        FILES 03_AdvancedLBMCodegen.cpp
-                        DEPENDS blockforest cuda core domain_decomposition field geometry timeloop lbm stencil vtk 03_AdvancedLBMCodegenPython )
-    else()
-        walberla_generate_target_from_python( NAME 03_AdvancedLBMCodegenPython
-                FILE 03_AdvancedLBMCodegen.py
-                OUT_FILES   CumulantMRTSweep.cpp CumulantMRTSweep.h
-                CumulantMRTPackInfo.cpp CumulantMRTPackInfo.h
-                InitialPDFsSetter.cpp InitialPDFsSetter.h
-                CumulantMRTNoSlip.cpp CumulantMRTNoSlip.h)
-
-        walberla_add_executable ( NAME 03_AdvancedLBMCodegenApp
-                FILES 03_AdvancedLBMCodegen.cpp
-                DEPENDS blockforest core domain_decomposition field geometry timeloop lbm stencil vtk 03_AdvancedLBMCodegenPython )
-    endif()
+    walberla_generate_target_from_python( NAME LDCCodegen
+            FILE LDC.py
+            OUT_FILES   LDCSweep.cpp LDCSweep.h
+            LDCPackInfo.cpp LDCPackInfo.h
+            LDCSetter.cpp LDCSetter.h
+            LDCNoSlip.cpp LDCNoSlip.h
+            LDCUBB.cpp LDCUBB.h)
+
+    walberla_add_executable ( NAME LDC
+            FILES LDC.cpp
+            DEPENDS blockforest core domain_decomposition field geometry timeloop lbm stencil vtk LDCCodegen )
 
 endif()
\ No newline at end of file
diff --git a/apps/showcases/LDC/LDC.cpp b/apps/showcases/LDC/LDC.cpp
index 492d40b8bf07458e2b8b847d36dff28e9356d72a..c76ea38518371cd2b112af51b0a565014839f539 100644
--- a/apps/showcases/LDC/LDC.cpp
+++ b/apps/showcases/LDC/LDC.cpp
@@ -19,34 +19,20 @@
 //======================================================================================================================
 
 #include "blockforest/all.h"
-
 #include "core/all.h"
-
-#if defined(WALBERLA_BUILD_WITH_CUDA)
-#   include "cuda/AddGPUFieldToStorage.h"
-#   include "cuda/DeviceSelectMPI.h"
-#   include "cuda/HostFieldAllocator.h"
-#   include "cuda/ParallelStreams.h"
-#   include "cuda/communication/GPUPackInfo.h"
-#   include "cuda/communication/UniformGPUScheme.h"
-#endif
-
 #include "domain_decomposition/all.h"
-
 #include "field/all.h"
 #include "field/vtk/VTKWriter.h"
-
 #include "geometry/all.h"
-
-#include "stencil/D2Q9.h"
-
+#include "stencil/D3Q19.h"
 #include "timeloop/all.h"
 
 //    Codegen Includes
-#include "CumulantMRTNoSlip.h"
-#include "CumulantMRTPackInfo.h"
-#include "CumulantMRTSweep.h"
-#include "InitialPDFsSetter.h"
+#include "LDCSweep.h"
+#include "LDCPackInfo.h"
+#include "LDCSetter.h"
+#include "LDCNoSlip.h"
+#include "LDCUBB.h"
 
 namespace walberla
 {
@@ -55,57 +41,23 @@ namespace walberla
 ///////////////////////
 
 // Communication Pack Info
-typedef pystencils::CumulantMRTPackInfo PackInfo_T;
+typedef pystencils::LDCPackInfo PackInfo_T;
 
 // LB Method Stencil
-typedef stencil::D2Q9 Stencil_T;
+typedef stencil::D3Q19 Stencil_T;
 
 // PDF field type
 typedef field::GhostLayerField< real_t, Stencil_T::Size > PdfField_T;
 
 // Velocity Field Type
 typedef field::GhostLayerField< real_t, Stencil_T::D > VectorField_T;
+typedef field::GhostLayerField< real_t, 1 > ScalarField_T;
 
 // Boundary Handling
 typedef walberla::uint8_t flag_t;
 typedef FlagField< flag_t > FlagField_T;
-typedef lbm::CumulantMRTNoSlip NoSlip_T;
-
-#if defined(WALBERLA_BUILD_WITH_CUDA)
-typedef cuda::GPUField< real_t > GPUField;
-#endif
-
-//////////////////////////////////////////
-/// Shear Flow Velocity Initialization ///
-//////////////////////////////////////////
-
-void initShearFlowVelocityField(const shared_ptr< StructuredBlockForest >& blocks, const BlockDataID& velocityFieldId,
-                                const Config::BlockHandle& config)
-{
-   math::RealRandom< real_t > rng(config.getParameter< std::mt19937::result_type >("noiseSeed", 42));
-
-   real_t velocityMagnitude = config.getParameter< real_t >("velocityMagnitude", real_c(0.08));
-   real_t noiseMagnitude    = config.getParameter< real_t >("noiseMagnitude", real_c(0.1) * velocityMagnitude);
-
-   real_t n_y = real_c(blocks->getNumberOfYCells());
-
-   for (auto blockIt = blocks->begin(); blockIt != blocks->end(); ++blockIt)
-   {
-      auto u = (*blockIt).getData< VectorField_T >(velocityFieldId);
-
-      for (auto cellIt = u->beginWithGhostLayerXYZ(); cellIt != u->end(); ++cellIt)
-      {
-         Cell globalCell(cellIt.cell());
-         blocks->transformBlockLocalToGlobalCell(globalCell, *blockIt);
-
-         real_t relative_y = real_c(globalCell.y()) / n_y;
-
-         u->get(cellIt.cell(), 0) = relative_y < 0.3 || relative_y > 0.7 ? velocityMagnitude : -velocityMagnitude;
-
-         u->get(cellIt.cell(), 1) = noiseMagnitude * rng();
-      }
-   }
-}
+typedef lbm::LDCNoSlip NoSlip_T;
+typedef lbm::LDCUBB UBB_T;
 
 /////////////////////
 /// Main Function ///
@@ -115,7 +67,7 @@ int main(int argc, char** argv)
 {
    walberla::Environment walberlaEnv(argc, argv);
 
-   if (!walberlaEnv.config()) { WALBERLA_ABORT("No configuration file specified!"); }
+   if (!walberlaEnv.config()) { WALBERLA_ABORT("No configuration file specified!") }
 
    ///////////////////////////////////////////////////////
    /// Block Storage Creation and Simulation Parameter ///
@@ -137,35 +89,45 @@ int main(int argc, char** argv)
    ////////////////////////////////////
 
    // Common Fields
+   BlockDataID densityFieldId = field::addToStorage< ScalarField_T >(blocks, "density", real_c(1.0), field::fzyx);
    BlockDataID velocityFieldId = field::addToStorage< VectorField_T >(blocks, "velocity", real_c(0.0), field::fzyx);
    BlockDataID flagFieldId     = field::addFlagFieldToStorage< FlagField_T >(blocks, "flag field");
 
-#if defined(WALBERLA_BUILD_WITH_CUDA)
-   // GPU Field for PDFs
-   BlockDataID pdfFieldId = cuda::addGPUFieldToStorage< cuda::GPUField< real_t > >(
-      blocks, "pdf field on GPU", Stencil_T::Size, field::fzyx, uint_t(1));
+   for (auto blockIt = blocks->begin(); blockIt != blocks->end(); ++blockIt) {
+      auto densityField = blockIt->getData<ScalarField_T>(densityFieldId);
+      std::ifstream infile("density.txt");
+
+      WALBERLA_FOR_ALL_CELLS_XYZ(densityField,
+                                 real_t dens;
+                                 infile >> dens;
+                                 densityField->get(x, y, z) = dens;
+      )
+      infile.close();
+   }
+
+   for (auto blockIt = blocks->begin(); blockIt != blocks->end(); ++blockIt) {
+      auto velocityField = blockIt->getData<VectorField_T>(velocityFieldId);
+      std::ifstream infile("velocity.txt");
+
+      WALBERLA_FOR_ALL_CELLS_XYZ(velocityField,
+                                 for (uint_t i = 0; i < 3; ++i)
+         {
+            real_t velo;
+            infile >> velo;
+            velocityField->get(x, y, z, i) = velo;
+         }
+      )
+      infile.close();
+   }
+
+   WALBERLA_LOG_INFO_ON_ROOT("Finished parameter reading")
 
-   // GPU Velocity Field
-   BlockDataID velocityFieldIdGPU =
-      cuda::addGPUFieldToStorage< VectorField_T >(blocks, velocityFieldId, "velocity on GPU", true);
-#else
    // CPU Field for PDFs
    BlockDataID pdfFieldId = field::addToStorage< PdfField_T >(blocks, "pdf field", real_c(0.0), field::fzyx);
-#endif
-
-   // Velocity field setup
-   auto shearFlowSetup = walberlaEnv.config()->getOneBlock("ShearFlowSetup");
-   initShearFlowVelocityField(blocks, velocityFieldId, shearFlowSetup);
 
-   real_t rho = shearFlowSetup.getParameter("rho", real_c(1.0));
 
    // pdfs setup
-#if defined(WALBERLA_BUILD_WITH_CUDA)
-   cuda::fieldCpy< GPUField, VectorField_T >(blocks, velocityFieldIdGPU, velocityFieldId);
-   pystencils::InitialPDFsSetter pdfSetter(pdfFieldId, velocityFieldIdGPU, rho);
-#else
-   pystencils::InitialPDFsSetter pdfSetter(pdfFieldId, velocityFieldId, rho);
-#endif
+   pystencils::LDCSetter pdfSetter(densityFieldId, pdfFieldId, velocityFieldId);
 
    for (auto blockIt = blocks->begin(); blockIt != blocks->end(); ++blockIt)
    {
@@ -176,11 +138,7 @@ int main(int argc, char** argv)
    /// Sweep ///
    /////////////
 
-#if defined(WALBERLA_BUILD_WITH_CUDA)
-   pystencils::CumulantMRTSweep CumulantMRTSweep(pdfFieldId, velocityFieldIdGPU, omega);
-#else
-   pystencils::CumulantMRTSweep CumulantMRTSweep(pdfFieldId, velocityFieldId, omega);
-#endif
+   pystencils::LDCSweep LBMKernel(densityFieldId, pdfFieldId, velocityFieldId, omega);
 
    /////////////////////////
    /// Boundary Handling ///
@@ -191,10 +149,12 @@ int main(int argc, char** argv)
    auto boundariesConfig = walberlaEnv.config()->getOneBlock("Boundaries");
 
    NoSlip_T noSlip(blocks, pdfFieldId);
+   UBB_T ubb(blocks, pdfFieldId);
 
    geometry::initBoundaryHandling< FlagField_T >(*blocks, flagFieldId, boundariesConfig);
    geometry::setNonBoundaryCellsToDomain< FlagField_T >(*blocks, flagFieldId, fluidFlagUID);
 
+   ubb.fillFromFlagField< FlagField_T >(blocks, flagFieldId, FlagUID("UBB"), fluidFlagUID);
    noSlip.fillFromFlagField< FlagField_T >(blocks, flagFieldId, FlagUID("NoSlip"), fluidFlagUID);
 
    /////////////////
@@ -204,18 +164,13 @@ int main(int argc, char** argv)
    SweepTimeloop timeloop(blocks->getBlockStorage(), timesteps);
 
    // Communication
-#if defined(WALBERLA_BUILD_WITH_CUDA)
-   cuda::communication::UniformGPUScheme< Stencil_T > com(blocks, 0);
-   com.addPackInfo(make_shared< PackInfo_T >(pdfFieldId));
-   auto communication = std::function< void() >([&]() { com.communicate(nullptr); });
-#else
    blockforest::communication::UniformBufferedScheme< Stencil_T > communication(blocks);
    communication.addPackInfo(make_shared< PackInfo_T >(pdfFieldId));
-#endif
 
    // Timeloop
    timeloop.add() << BeforeFunction(communication, "communication") << Sweep(noSlip);
-   timeloop.add() << Sweep(CumulantMRTSweep);
+   timeloop.add() << Sweep(ubb);
+   timeloop.add() << Sweep(LBMKernel);
 
    // Time logger
    timeloop.addFuncAfterTimeStep(timing::RemainingTimeLogger(timeloop.getNrOfTimeSteps(), remainingTimeLoggerFrequency),
@@ -223,16 +178,12 @@ int main(int argc, char** argv)
 
    if (VTKwriteFrequency > 0)
    {
-      const std::string path = "vtk_out/tut03";
-      auto vtkOutput = vtk::createVTKOutput_BlockData(*blocks, "cumulant_mrt_velocity_field", VTKwriteFrequency, 0,
+      const std::string path = "vtk_out";
+      auto vtkOutput = vtk::createVTKOutput_BlockData(*blocks, "LDC", VTKwriteFrequency, 0,
                                                       false, path, "simulation_step", false, true, true, false, 0);
 
-#if defined(WALBERLA_BUILD_WITH_CUDA)
-      // Copy velocity data to CPU before output
-      vtkOutput->addBeforeFunction(
-         [&]() { cuda::fieldCpy< VectorField_T, GPUField >(blocks, velocityFieldId, velocityFieldIdGPU); });
-#endif
-
+      auto densWriter = make_shared< field::VTKWriter< ScalarField_T > >(densityFieldId, "Density");
+      vtkOutput->addCellDataWriter(densWriter);
       auto velWriter = make_shared< field::VTKWriter< VectorField_T > >(velocityFieldId, "Velocity");
       vtkOutput->addCellDataWriter(velWriter);
 
@@ -246,4 +197,7 @@ int main(int argc, char** argv)
 
 } // namespace walberla
 
-int main(int argc, char** argv) { return walberla::main(argc, argv); }
+int main(int argc, char** argv)
+{
+   return walberla::main(argc, argv);
+}
diff --git a/apps/showcases/LDC/LDC.prm b/apps/showcases/LDC/LDC.prm
index d292c02d13450a5ae947f3284ded79baf2348538..46debbcba77c76c0d5597ebc4ee461ed9ce254df 100644
--- a/apps/showcases/LDC/LDC.prm
+++ b/apps/showcases/LDC/LDC.prm
@@ -1,28 +1,18 @@
 
 Parameters 
 {
-	omega           1.8;
-	timesteps       10001;
+	omega           1.81818;
+	timesteps       201;
 
 	remainingTimeLoggerFrequency 3; // in seconds
-	VTKwriteFrequency 1000;
-}
-
-ShearFlowSetup
-{
-   rho   1.0;
-   
-   velocityMagnitude   0.08;
-   noiseMagnitude     0.005;
-
-   noiseSeed            42;
+	VTKwriteFrequency 100;
 }
 
 DomainSetup
 {
    blocks        <  1,    1, 1 >;
-   cellsPerBlock <  300, 80, 1 >;
-   periodic      <  1,    0, 1 >;  
+   cellsPerBlock <  128, 128, 128 >;
+   periodic      <  0,    0, 0 >;
 }
 
 StabilityChecker
@@ -33,6 +23,12 @@ StabilityChecker
 }
 
 Boundaries 
-{   
-	Border { direction S,N; walldistance -1; flag NoSlip; }		
+{
+
+    Border { direction E; walldistance -1; flag NoSlip; }
+    Border { direction W; walldistance -1; flag NoSlip; }
+    Border { direction S; walldistance -1; flag NoSlip; }
+    Border { direction T; walldistance -1; flag UBB; }
+    Border { direction N; walldistance -1; flag NoSlip; }
+    Border { direction B; walldistance -1; flag NoSlip; }
 }
diff --git a/apps/showcases/LDC/LDC.py b/apps/showcases/LDC/LDC.py
index c94eb81bab1f584ccfaf2ec4b9ebf2545c4434f9..e7b99a3035f56a06f56fd0055c68c25fc4d353af 100644
--- a/apps/showcases/LDC/LDC.py
+++ b/apps/showcases/LDC/LDC.py
@@ -5,7 +5,7 @@ from lbmpy import LBMConfig, LBMOptimisation, LBStencil, Method, Stencil
 
 from lbmpy.creationfunctions import create_lb_update_rule
 from lbmpy.macroscopic_value_kernels import macroscopic_values_setter
-from lbmpy.boundaries import NoSlip
+from lbmpy.boundaries import NoSlip, UBB
 
 from pystencils_walberla import CodeGeneration, generate_sweep, generate_pack_info_from_kernel
 from lbmpy_walberla import generate_boundary
@@ -15,16 +15,17 @@ from lbmpy_walberla import generate_boundary
 #      General Parameters
 #   ========================
 
-stencil = LBStencil(Stencil.D2Q9)
+stencil = LBStencil(Stencil.D3Q19)
 omega = sp.Symbol('omega')
 layout = 'fzyx'
 
 #   PDF Fields
-pdfs, pdfs_tmp = ps.fields(f'pdfs({stencil.Q}), pdfs_tmp({stencil.Q}): [2D]', layout=layout)
+pdfs, pdfs_tmp = ps.fields(f'pdfs({stencil.Q}), pdfs_tmp({stencil.Q}): [{stencil.D}D]', layout=layout)
 
 #   Velocity Output Field
-velocity = ps.fields(f"velocity({stencil.D}): [2D]", layout=layout)
-output = {'velocity': velocity}
+velocity = ps.fields(f"velocity({stencil.D}): [{stencil.D}D]", layout=layout)
+density = ps.fields(f"density: [{stencil.D}D]", layout=layout)
+output = {'density': density, 'velocity': velocity}
 
 # LBM Optimisation
 lbm_opt = LBMOptimisation(cse_global=True,
@@ -38,9 +39,9 @@ lbm_opt = LBMOptimisation(cse_global=True,
 #   ==================
 
 lbm_config = LBMConfig(stencil=stencil,
-                       method=Method.CUMULANT,
+                       method=Method.TRT,
                        relaxation_rate=omega,
-                       compressible=True,
+                       compressible=False,
                        output=output)
 
 lbm_update_rule = create_lb_update_rule(lbm_config=lbm_config, lbm_optimisation=lbm_opt)
@@ -51,10 +52,8 @@ lbm_method = lbm_update_rule.method
 #      PDF Initialization
 #   ========================
 
-initial_rho = sp.Symbol('rho_0')
-
 pdfs_setter = macroscopic_values_setter(lbm_method,
-                                        initial_rho,
+                                        density,
                                         velocity.center_vector,
                                         pdfs.center_vector)
 
@@ -63,19 +62,17 @@ pdfs_setter = macroscopic_values_setter(lbm_method,
 #   =====================
 
 with CodeGeneration() as ctx:
-    if ctx.cuda:
-        target = ps.Target.GPU
-    else:
-        target = ps.Target.CPU
+    target = ps.Target.CPU
 
     #   LBM Sweep
-    generate_sweep(ctx, "CumulantMRTSweep", lbm_update_rule, field_swaps=[(pdfs, pdfs_tmp)], target=target)
+    generate_sweep(ctx, "LDCSweep", lbm_update_rule, field_swaps=[(pdfs, pdfs_tmp)], target=target)
 
     #   Pack Info
-    generate_pack_info_from_kernel(ctx, "CumulantMRTPackInfo", lbm_update_rule, target=target)
+    generate_pack_info_from_kernel(ctx, "LDCPackInfo", lbm_update_rule, target=target)
 
     #   Macroscopic Values Setter
-    generate_sweep(ctx, "InitialPDFsSetter", pdfs_setter, target=target)
+    generate_sweep(ctx, "LDCSetter", pdfs_setter, target=target)
 
     #   NoSlip Boundary
-    generate_boundary(ctx, "CumulantMRTNoSlip", NoSlip(), lbm_method, target=target)
+    generate_boundary(ctx, "LDCNoSlip", NoSlip(), lbm_method, target=target)
+    generate_boundary(ctx, "LDCUBB", UBB((0.00014587, 0, 0)), lbm_method, target=target)