diff --git a/apps/showcases/Thermocapillary/InitializerFunctions.cpp b/apps/showcases/Thermocapillary/InitializerFunctions.cpp
index 47b147497d73ee8cdfb327068fe0c67fc2df6c14..464e56d1939a37f2524c61455e8799e8271985cd 100644
--- a/apps/showcases/Thermocapillary/InitializerFunctions.cpp
+++ b/apps/showcases/Thermocapillary/InitializerFunctions.cpp
@@ -47,15 +47,17 @@ void initPhaseFieldDroplet(const shared_ptr< StructuredBlockStorage >& blocks, B
 void initMicroChannel(const shared_ptr< StructuredBlockStorage >& blocks, BlockDataID phaseFieldID, BlockDataID temperatureFieldID,
                            const real_t Th, const real_t T0, const real_t Tc, const real_t W)
 {
-   auto halfX          = real_c(blocks->getDomainCellBB().xMax()) / real_c(2.0);
-   auto halfY          = real_c((blocks->getDomainCellBB().yMax())) / real_c(2.0);
+   auto domain = blocks->getDomain();
+   auto halfX = real_c(domain.xMax()) / real_c(2.0);
+   auto halfY = real_c(domain.yMax()) / real_c(2.0);
    for (auto& block : *blocks)
    {
       auto phaseField = block.getData< ScalarField_T >(phaseFieldID);
       // clang-format off
       WALBERLA_FOR_ALL_CELLS_INCLUDING_GHOST_LAYER_XYZ(phaseField, Cell globalCell;
          blocks->transformBlockLocalToGlobalCell(globalCell, block, Cell(x, y, z));
-         phaseField->get(x, y, z)     = real_c(0.5) + real_c(0.5) * real_c(tanh(   (real_c(globalCell[1]) - halfY) / (W / real_c(2.0))   ));
+         auto globalCellCenter = blocks->getCellCenter(globalCell);
+         phaseField->get(x, y, z)     = real_c(0.5) + real_c(0.5) * real_c(tanh(   (real_c(globalCellCenter[1]) - halfY) / (W / real_c(2.0))   ));
       )
       // clang-format on
 
@@ -65,8 +67,8 @@ void initMicroChannel(const shared_ptr< StructuredBlockStorage >& blocks, BlockD
          blocks->transformBlockLocalToGlobalCell(globalCell, block, Cell(x, y, z));
          if(globalCell[1] == -1)
          {
-            auto X = (globalCell[0] < 0) ? 0.0 : globalCell[0];
-            temperatureField->get(x, y, z)     = Th + T0 * cos( (math::pi / halfX) * (X - halfX) );
+            auto globalCellCenter = blocks->getCellCenter(globalCell);
+            temperatureField->get(x, y, z)     = Th + T0 * cos( (math::pi / halfX) * (globalCellCenter[0] - halfX) );
          }
          else
          {
diff --git a/apps/showcases/Thermocapillary/microchannel2D.py b/apps/showcases/Thermocapillary/microchannel2D.py
index 9b183ace47dee2573461b24eb79f177dd3874769..a710eb7d4cf80dcf98f6c2192c77f47fcb99c65c 100755
--- a/apps/showcases/Thermocapillary/microchannel2D.py
+++ b/apps/showcases/Thermocapillary/microchannel2D.py
@@ -14,11 +14,11 @@ from waLBerla.tools.sqlitedb import sequenceValuesToScalars
 
 class Scenario:
     def __init__(self, heat_solver_rk_or_lbm, case):
-        self.reference_length = 256
+        self.reference_length = 80
 
         # simulation parameters
-        self.timesteps = 1
-        self.pre_thermal_timesteps = 1
+        self.timesteps = 400000
+        self.pre_thermal_timesteps = 100000
         self.vtkWriteFrequency = 0
         self.dbWriteFrequency = 10000
 
@@ -28,7 +28,7 @@ class Scenario:
         self.periodic = (1, 0, 0)
 
         self.heat_solver_rk_or_lbm = heat_solver_rk_or_lbm
-        self.order_rk_solver = 4
+        self.order_rk_solver = 2
 
         self.case = case
 
@@ -81,7 +81,8 @@ class Scenario:
         self.u_y = u_y
         self.t_a = t_a
         l0 = self.reference_length
-        self.XX, self.YY = np.meshgrid(np.arange(self.domain_size[0]) - l0, np.arange(self.domain_size[1]) - l0 // 2)
+        self.XX, self.YY = np.meshgrid(np.arange(self.domain_size[0]) - (l0-0.5),
+                                       np.arange(self.domain_size[1]) - (l0 // 2 - 0.5))
 
         self.config_dict = self.config()
 
@@ -197,8 +198,8 @@ class Scenario:
             contour_2 = plt.contour(self.XX, self.YY, temperature_field.T, levels=levels, colors=['k'])
             clabels = ax.clabel(contour_2, inline=1, fontsize=10, fmt='%2.0lf')
             [txt.set_bbox(dict(facecolor='white', edgecolor='none', pad=0)) for txt in clabels]
-            plt.ylim((-128, 128))
-            plt.xlim((-256, 256))
+            plt.ylim((-self.reference_length//2, self.reference_length//2))
+            plt.xlim((-self.reference_length, self.reference_length))
             plt.savefig(f'{path}/temperature_{t}.png', dpi=300)
             plt.close('all')
 
@@ -214,8 +215,8 @@ class Scenario:
                       velocity_field[::n, ::n, 0].T, velocity_field[::n, ::n, 1].T,
                       angles='xy', scale_units='xy', scale=0.00001, color='b')
             plt.grid()
-            plt.ylim((-128, 128))
-            plt.xlim((-256, 256))
+            plt.ylim((-self.reference_length, self.reference_length))
+            plt.xlim((-2*self.reference_length, 2*self.reference_length))
             plt.savefig(f'{path}/velocity_{t}.png', dpi=300)
             plt.close('all')
 
@@ -249,4 +250,4 @@ scenarios = wlb.ScenarioManager()
 # scenarios.add(Scenario(heat_solver_rk_or_lbm=False, case=1))
 scenarios.add(Scenario(heat_solver_rk_or_lbm=True, case=1))
 # scenarios.add(Scenario(heat_solver_rk_or_lbm=False, case=2))
-scenarios.add(Scenario(heat_solver_rk_or_lbm=True, case=2))
+# scenarios.add(Scenario(heat_solver_rk_or_lbm=True, case=2))
diff --git a/apps/showcases/Thermocapillary/microchannel3D.py b/apps/showcases/Thermocapillary/microchannel3D.py
index 0726d7114ed6cb60c759ba090e694dabff1edba8..e6b53f4b814b1d6fb46bc23692f37405ff265d56 100755
--- a/apps/showcases/Thermocapillary/microchannel3D.py
+++ b/apps/showcases/Thermocapillary/microchannel3D.py
@@ -14,7 +14,7 @@ from waLBerla.tools.sqlitedb import sequenceValuesToScalars
 
 class Scenario:
     def __init__(self, heat_solver_rk_or_lbm, case):
-        self.reference_length = 256
+        self.reference_length = 80
 
         # simulation parameters
         self.timesteps = 400001
@@ -22,7 +22,7 @@ class Scenario:
         self.vtkWriteFrequency = 0
         self.dbWriteFrequency = 10000
 
-        self.cells = (self.reference_length, self.reference_length, 10)
+        self.cells = (self.reference_length, self.reference_length, 3)
         self.blocks = (2, 1, 1)
         self.domain_size = tuple([c * b for c, b in zip(self.cells, self.blocks)])
         self.periodic = (1, 0, 1)
@@ -46,7 +46,7 @@ class Scenario:
             self.temperature_h = 20
             self.temperature_l = 4
 
-            self.interface_thickness = 5
+            self.interface_thickness = 4
             self.mobility = 0.05
             self.velocity_wall = 0
         else:
@@ -64,7 +64,7 @@ class Scenario:
             self.temperature_h = 20
             self.temperature_l = 4
 
-            self.interface_thickness = 5
+            self.interface_thickness = 4
             self.mobility = 0.05
             self.velocity_wall = 0
 
@@ -80,7 +80,8 @@ class Scenario:
         self.u_y = u_y
         self.t_a = t_a
         l0 = self.reference_length
-        self.XX, self.YY = np.meshgrid(np.arange(self.domain_size[0]) - l0, np.arange(self.domain_size[1]) - l0 // 2)
+        self.XX, self.YY = np.meshgrid(np.arange(self.domain_size[0]) - (l0-0.5),
+                                       np.arange(self.domain_size[1]) - (l0 // 2 - 0.5))
 
         self.config_dict = self.config()
 
@@ -195,8 +196,8 @@ class Scenario:
             contour_2 = plt.contour(self.XX, self.YY, temperature_field.T, levels=levels, colors=['k'])
             clabels = ax.clabel(contour_2, inline=1, fontsize=10, fmt='%2.0lf')
             [txt.set_bbox(dict(facecolor='white', edgecolor='none', pad=0)) for txt in clabels]
-            plt.ylim((-128, 128))
-            plt.xlim((-256, 256))
+            plt.ylim((-self.reference_length//2, self.reference_length//2))
+            plt.xlim((-self.reference_length, self.reference_length))
             plt.savefig(f'{path}/temperature_{t}.png', dpi=300)
             plt.close('all')
 
@@ -214,8 +215,8 @@ class Scenario:
                        angles='xy', scale_units='xy', scale=0.00001)
             ax1.set_title("lattice Boltzmann")
             plt.grid()
-            plt.ylim((-128, 128))
-            plt.xlim((-256, 256))
+            plt.ylim((-self.reference_length, self.reference_length))
+            plt.xlim((-2*self.reference_length, 2*self.reference_length))
             plt.savefig(f'{path}/velocity_{t}.png', dpi=300)
             plt.close('all')
 
diff --git a/apps/showcases/Thermocapillary/thermocapillary.cpp b/apps/showcases/Thermocapillary/thermocapillary.cpp
index fd8b5d155b9043e0d0df492d3820ab1a3a0aa4ea..3a6611f98e3b133609682d97cf6a66e22b887881 100644
--- a/apps/showcases/Thermocapillary/thermocapillary.cpp
+++ b/apps/showcases/Thermocapillary/thermocapillary.cpp
@@ -68,11 +68,13 @@ using FlagField_T = FlagField< flag_t >;
 auto DiffusionCallback = [](const Cell& pos, const shared_ptr< StructuredBlockForest >& blocks, IBlock& block,
                             const real_t Th, const real_t T0) {
 
-      auto x_half = real_c(blocks->getDomainCellBB().xMax()) / real_c(2.0);
-      Cell global_cell;
-      blocks->transformBlockLocalToGlobalCell(global_cell, block, pos);
+      auto domain = blocks->getDomain();
+      auto halfX = real_c(domain.xMax()) / real_c(2.0);
+      Cell globalCell;
+      blocks->transformBlockLocalToGlobalCell(globalCell, block, pos);
+      auto globalCellCenter = blocks->getCellCenter(globalCell);
 
-      return Th + T0 * cos( (math::pi / x_half) * (real_c(global_cell[0]) - x_half) );
+      return Th + T0 * cos( (math::pi / halfX) * (real_c(globalCellCenter[0]) - halfX) );
 };
 
 int main(int argc, char** argv)
@@ -549,9 +551,9 @@ int main(int argc, char** argv)
          DiffusionInitialisation = std::bind(DiffusionCallback, _1, _2, _3, t_h, t_0);
 
 #if defined(WALBERLA_BUILD_WITH_GPU_SUPPORT)
-      lbm::thermal_LB_DiffusionDirichlet_static thermal_LB_DiffusionStatic(blocks, temperature_PDFs_ID, vel_field_gpu, temperature_ref);
+      lbm::thermal_LB_DiffusionDirichlet_static thermal_LB_DiffusionStatic(blocks, temperature_PDFs_ID, temperature_ref);
       thermal_LB_DiffusionStatic.fillFromFlagField< FlagField_T >(blocks, flag_field_thermal_LB_ID, diffusionStaticFlagUID, fluidFlagUID);
-      lbm::thermal_LB_DiffusionDirichlet_dynamic thermal_LB_DiffusionDynamic(blocks, temperature_PDFs_ID, vel_field_gpu, DiffusionInitialisation);
+      lbm::thermal_LB_DiffusionDirichlet_dynamic thermal_LB_DiffusionDynamic(blocks, temperature_PDFs_ID, DiffusionInitialisation);
       thermal_LB_DiffusionDynamic.fillFromFlagField< FlagField_T >(blocks, flag_field_thermal_LB_ID, diffusionDynamicFlagUID, fluidFlagUID);
       lbm::thermal_LB_NeumannByCopy thermal_LB_Neumann(blocks, temperature_PDFs_ID);
       thermal_LB_Neumann.fillFromFlagField< FlagField_T >(blocks, flag_field_thermal_LB_ID, neumannFlagUID, fluidFlagUID);
@@ -559,10 +561,9 @@ int main(int argc, char** argv)
       pystencils::ContactAngle contact_angle(blocks, phase_field_gpu, interface_thickness, angle);
       contact_angle.fillFromFlagField< FlagField_T >(blocks, flag_field_allen_cahn_LB_ID, wallFlagUID, fluidFlagUID);
 #else
-      lbm::thermal_LB_DiffusionDirichlet_static thermal_LB_DiffusionStatic(blocks, temperature_PDFs_ID,
-                                                                           velocity_field_ID, temperature_ref);
+      lbm::thermal_LB_DiffusionDirichlet_static thermal_LB_DiffusionStatic(blocks, temperature_PDFs_ID, temperature_ref);
       thermal_LB_DiffusionStatic.fillFromFlagField< FlagField_T >(blocks, flag_field_thermal_LB_ID, diffusionStaticFlagUID, fluidFlagUID);
-      lbm::thermal_LB_DiffusionDirichlet_dynamic thermal_LB_DiffusionDynamic(blocks, temperature_PDFs_ID, velocity_field_ID, DiffusionInitialisation);
+      lbm::thermal_LB_DiffusionDirichlet_dynamic thermal_LB_DiffusionDynamic(blocks, temperature_PDFs_ID, DiffusionInitialisation);
       thermal_LB_DiffusionDynamic.fillFromFlagField< FlagField_T >(blocks, flag_field_thermal_LB_ID, diffusionDynamicFlagUID, fluidFlagUID);
       lbm::thermal_LB_NeumannByCopy thermal_LB_Neumann(blocks, temperature_PDFs_ID);
       thermal_LB_Neumann.fillFromFlagField< FlagField_T >(blocks, flag_field_thermal_LB_ID, neumannFlagUID, fluidFlagUID);
diff --git a/apps/showcases/Thermocapillary/thermocapillary_codegen.py b/apps/showcases/Thermocapillary/thermocapillary_codegen.py
index 1930f0019a19c139c8432a34794553e389799a4f..58c3c9f37a51a3cfbbfc52f91c3f67aef226acef 100644
--- a/apps/showcases/Thermocapillary/thermocapillary_codegen.py
+++ b/apps/showcases/Thermocapillary/thermocapillary_codegen.py
@@ -11,7 +11,7 @@ from pystencils.simp import (add_subexpressions_for_field_reads, sympy_cse, inse
 
 from lbmpy import LBMConfig, LBMOptimisation, LBStencil, Method, Stencil, create_lb_update_rule
 from lbmpy.creationfunctions import create_lb_method
-from lbmpy.boundaries import DiffusionDirichlet, NeumannByCopy, NoSlip, UBB
+from lbmpy.boundaries import FixedDensity, NeumannByCopy, NoSlip, UBB
 from lbmpy.macroscopic_value_kernels import pdf_initialization_assignments
 
 from lbmpy.phasefield_allen_cahn.contact_angle import ContactAngle
@@ -23,7 +23,6 @@ from lbmpy.phasefield_allen_cahn.parameter_calculation import ThermocapillaryPar
 
 import pystencils_walberla
 from pystencils_walberla import CodeGeneration, generate_sweep, generate_pack_info_for_field, generate_info_header
-from lbmpy_walberla.additional_data_handler import DiffusionDirichletAdditionalDataHandler
 from lbmpy_walberla import generate_boundary, generate_lb_pack_info
 
 # to disable type conversion warnings
@@ -44,9 +43,9 @@ with CodeGeneration() as ctx:
     contact_angle_in_degrees = sp.Symbol("alpha")
     generate_with_heat_source = False
 
-    stencil_phase = LBStencil(Stencil.D3Q19)
-    stencil_hydro = LBStencil(Stencil.D3Q19)
-    stencil_thermal = LBStencil(Stencil.D3Q7)
+    stencil_phase = LBStencil(Stencil.D2Q9)
+    stencil_hydro = LBStencil(Stencil.D2Q9)
+    stencil_thermal = LBStencil(Stencil.D2Q9)
     assert (stencil_phase.D == stencil_hydro.D == stencil_thermal.D)
     full_stencil = LBStencil(Stencil.D2Q9) if stencil_phase.D == 2 else LBStencil(Stencil.D3Q27)
 
@@ -374,14 +373,12 @@ const bool GeneratedHeatSource = false;
                    varying_parameters=vp, gpu_indexing_params=sweep_params,
                    cpu_openmp=openmp, cpu_vectorize_info=cpu_vec)
 
-    dirichlet_bc_static = DiffusionDirichlet(TypedSymbol('T_c', dtype=field_type), u, data_type=field_type)
+    dirichlet_bc_static = FixedDensity(TypedSymbol('T_c', dtype=field_type), u, data_type=field_type)
     generate_boundary(ctx, 'thermal_LB_DiffusionDirichlet_static', dirichlet_bc_static, method_thermal,
                       target=target, streaming_pattern='pull', cpu_openmp=openmp, data_type=field_type_pdfs)
 
-    dirichlet_bc_dynamic = DiffusionDirichlet(lambda *args: None, u, data_type=field_type)
-    diffusion_data_handler = DiffusionDirichletAdditionalDataHandler(stencil_thermal, dirichlet_bc_dynamic)
+    dirichlet_bc_dynamic = FixedDensity(lambda *args: None, u, data_type=field_type)
     generate_boundary(ctx, 'thermal_LB_DiffusionDirichlet_dynamic', dirichlet_bc_dynamic, method_thermal,
-                      additional_data_handler=diffusion_data_handler,
                       target=target, streaming_pattern='pull', cpu_openmp=openmp, data_type=field_type_pdfs)
 
     generate_boundary(ctx, 'thermal_LB_NeumannByCopy', NeumannByCopy(), method_thermal,
diff --git a/python/lbmpy_walberla/additional_data_handler.py b/python/lbmpy_walberla/additional_data_handler.py
index daaab32fd40aff5f2150495bf4782ef61a282dae..08208e39aba25a2813473bad49777c5b1e3c8e1e 100644
--- a/python/lbmpy_walberla/additional_data_handler.py
+++ b/python/lbmpy_walberla/additional_data_handler.py
@@ -9,7 +9,7 @@ try:
 except ImportError:
     from lbmpy.custom_code_nodes import MirroredStencilDirections
 from lbmpy.boundaries.boundaryconditions import LbBoundary
-from lbmpy.boundaries import (ExtrapolationOutflow, FreeSlip, UBB, DiffusionDirichlet,
+from lbmpy.boundaries import (ExtrapolationOutflow, FreeSlip, UBB, DiffusionDirichlet, FixedDensity,
                               NoSlipLinearBouzidi, QuadraticBounceBack)
 
 from pystencils_walberla.additional_data_handler import AdditionalDataHandler
@@ -41,6 +41,8 @@ def default_additional_data_handler(boundary_obj: LbBoundary, lb_method, field_n
         return NoSlipLinearBouzidiAdditionalDataHandler(lb_method.stencil, boundary_obj)
     elif isinstance(boundary_obj, QuadraticBounceBack):
         return QuadraticBounceBackAdditionalDataHandler(lb_method.stencil, boundary_obj)
+    elif isinstance(boundary_obj, FixedDensity):
+        return FixedDensityAdditionalDataHandler(lb_method.stencil, boundary_obj)
     else:
         raise ValueError(f"No default AdditionalDataHandler available for boundary of type {boundary_obj.__class__}")
 
@@ -374,3 +376,38 @@ class DiffusionDirichletAdditionalDataHandler(AdditionalDataHandler):
     def additional_member_variable(self):
         return "std::function<real_t(const Cell &, const shared_ptr<StructuredBlockForest>&, IBlock&)> " \
                "elementInitaliser; "
+
+
+class FixedDensityAdditionalDataHandler(AdditionalDataHandler):
+    def __init__(self, stencil, boundary_object):
+        assert isinstance(boundary_object, FixedDensity)
+        self._boundary_object = boundary_object
+        super(FixedDensityAdditionalDataHandler, self).__init__(stencil=stencil)
+
+    @property
+    def constructor_arguments(self):
+        return ", std::function<real_t(const Cell &, const shared_ptr<StructuredBlockForest>&, IBlock&)>& " \
+               "densityCallback "
+
+    @property
+    def initialiser_list(self):
+        return "elementInitaliser(densityCallback),"
+
+    @property
+    def additional_arguments_for_fill_function(self):
+        return "blocks, "
+
+    @property
+    def additional_parameters_for_fill_function(self):
+        return " const shared_ptr<StructuredBlockForest> &blocks, "
+
+    def data_initialisation(self, *_):
+        init_list = ["real_t InitialisatonAdditionalData = elementInitaliser(Cell(it.x(), it.y(), it.z()), "
+                     "blocks, *block);", "element.rho = InitialisatonAdditionalData;"]
+
+        return "\n".join(init_list)
+
+    @property
+    def additional_member_variable(self):
+        return "std::function<real_t(const Cell &, const shared_ptr<StructuredBlockForest>&, IBlock&)> " \
+               "elementInitaliser; "