diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index b40d9bf9ad662363df9a216e5889d75ba2505a13..cbf8ca71d4e31974774b8199f1adf4020b36f224 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -29,24 +29,35 @@ typecheck:
 # -------------------- C++ Test Suite ---------------------------------------------------------------------
 
 
-testsuite-clang18:
+.testsuite-base:
   image: i10git.cs.fau.de:5005/walberla/buildenvs/clang-18:latest
-  tags:
-    - docker
   stage: "Test"
   needs: []
-  variables:
-    CXX: clang++
-    CC: clang
   before_script:
     - cd tests
-    - cmake -G Ninja -S . -B build
-    - cd build
+    - cmake --preset ${cmakePresetName}
+    - cd build/${cmakePresetName}
     - cmake --build . --target SfgTests
     - cmake --build . --target UserManualExamples
   script:
     - ctest
 
+testsuite-clang18-cpu:
+  extends: .testsuite-base
+  tags:
+    - docker
+    - avx2
+  variables:
+    cmakePresetName: testsuite-dbg-cpu
+
+testsuite-clang18-cuda:
+  extends: .testsuite-base
+  tags:
+    - docker
+    - cuda11
+  variables:
+    cmakePresetName: testsuite-dbg-cuda
+
 # -------------------- User Manual ---------------------------------------------------------------------
 
 build-user-manual:
diff --git a/lib/walberla/experimental/memory/MemoryTags.hpp b/lib/walberla/experimental/memory/MemoryTags.hpp
index 01c80e240cf2144eb51b02e16adfade7aefa6d64..f6c1f70ba7be55c43c1fdc8a6f54484b3675f194 100644
--- a/lib/walberla/experimental/memory/MemoryTags.hpp
+++ b/lib/walberla/experimental/memory/MemoryTags.hpp
@@ -1,10 +1,10 @@
 #pragma once
 
+#include "waLBerlaDefinitions.h"
+
 #include <concepts>
 #include <memory>
 
-#include "./UnifiedMemoryAllocator.hpp"
-
 namespace walberla::experimental::memory
 {
 
@@ -48,12 +48,32 @@ struct SelectStandardAllocator< memtag::host >
    using allocator = std::allocator< T >;
 };
 
+#if defined(WALBERLA_BUILD_WITH_CUDA) || defined(WALBERLA_BUILD_WITH_HIP)
+
+/* If CUDA or HIP are active, use the managed memory allocator for unified memory */
+
+#include "./UnifiedMemoryAllocator.hpp"
+
 template<>
 struct SelectStandardAllocator< memtag::unified >
 {
    template< typename T >
    using allocator = UnifiedMemoryAllocator< T >;
 };
+
+#else
+
+/* If no GPU support is active, use std::allocator */
+
+template<>
+struct SelectStandardAllocator< memtag::unified >
+{
+   template< typename T >
+   using allocator = std::allocator< T >;
+};
+
+#endif
+
 } // namespace detail
 
 /**
diff --git a/user_manual/examples/ForceDrivenChannel/LbmAlgorithms.py b/user_manual/examples/ForceDrivenChannel/LbmAlgorithms.py
index 6289568aa40c49b1f56560db34676c12eb9abe5b..2a1292f53a9b1536df69d9820e59deaefaaa107c 100644
--- a/user_manual/examples/ForceDrivenChannel/LbmAlgorithms.py
+++ b/user_manual/examples/ForceDrivenChannel/LbmAlgorithms.py
@@ -2,7 +2,7 @@ import sympy as sp
 import pystencils as ps
 
 from pystencilssfg import SourceFileGenerator
-from walberla.codegen import Sweep
+from walberla.codegen import Sweep, get_build_config
 from walberla.codegen.boundaries import GenericHBB
 
 from lbmpy import (
@@ -47,21 +47,19 @@ with SourceFileGenerator() as sfg:
 
     lbm_opt = LBMOptimisation(symbolic_field=f, symbolic_temporary_field=f_tmp)
 
-    target = ps.Target.GenericCPU
-
-    gen_config = ps.CreateKernelConfig(target=target)
-    gen_config.cpu.openmp.enable = True
+    wlb_config = get_build_config(sfg)
+    wlb_config.override.target = ps.Target.GenericCPU
 
     lb_update = create_lb_update_rule(lbm_config=lbm_config, lbm_optimisation=lbm_opt)
-    lb_update_sweep = Sweep("LbStreamCollide", lb_update, gen_config)
+    lb_update_sweep = Sweep("LbStreamCollide", lb_update)
     lb_update_sweep.swap_fields(f, f_tmp)
     sfg.generate(lb_update_sweep)
 
     lb_init = macroscopic_values_setter(
         lb_update.method, density=rho, velocity=u, pdfs=f, set_pre_collision_pdfs=True
     )
-    lb_init_sweep = Sweep("LbInit", lb_init, gen_config)
+    lb_init_sweep = Sweep("LbInit", lb_init)
     sfg.generate(lb_init_sweep)
 
     #   No-Slip Wall
-    sfg.generate(GenericHBB(NoSlip(), lb_method, f, target=target))
+    sfg.generate(GenericHBB(NoSlip(), lb_method, f))
diff --git a/user_manual/examples/FreeSlipBubble/LbmAlgorithms.py b/user_manual/examples/FreeSlipBubble/LbmAlgorithms.py
index 693fd68c40adaddba491218cbc2b225c0d8d2148..150144f14a785e74ceb8bf359515e87fd6afc59b 100644
--- a/user_manual/examples/FreeSlipBubble/LbmAlgorithms.py
+++ b/user_manual/examples/FreeSlipBubble/LbmAlgorithms.py
@@ -6,7 +6,7 @@ from lbmpy import LBStencil, Stencil, LBMConfig, LBMOptimisation, create_lb_upda
 from lbmpy.macroscopic_value_kernels import macroscopic_values_setter
 
 
-from walberla.codegen import Sweep
+from walberla.codegen import Sweep, get_build_config
 
 with SourceFileGenerator() as sfg:
     sfg.namespace("FreeSlipBubble::gen")
@@ -28,14 +28,14 @@ with SourceFileGenerator() as sfg:
         symbolic_temporary_field=pdfs_tmp,
     )
 
-    target = Target.GenericCPU
-    cfg = CreateKernelConfig(target=target)
+    wlb_config = get_build_config(sfg)
+    wlb_config.override.target = Target.GenericCPU
 
     lb_update = create_lb_update_rule(lbm_config=lbm_config, lbm_optimisation=lbm_opt)
     lb_method = lb_update.method
     assert lb_update is not None
 
-    lb_update_sweep = Sweep("LbStreamCollide", lb_update, cfg)
+    lb_update_sweep = Sweep("LbStreamCollide", lb_update)
     lb_update_sweep.swap_fields(pdfs, pdfs_tmp)
     sfg.generate(lb_update_sweep)
 
@@ -45,7 +45,7 @@ with SourceFileGenerator() as sfg:
         velocity=sp.symbols(f"velocity_:{d}"),
         pdfs=pdfs,
     )
-    lb_init_sweep = Sweep("LbInit", lb_init, cfg)
+    lb_init_sweep = Sweep("LbInit", lb_init)
     sfg.generate(lb_init_sweep)
 
     #   begin irregular-freeslip
@@ -56,7 +56,6 @@ with SourceFileGenerator() as sfg:
         lb_method,
         pdfs,
         wall_orientation=FreeSlip.IRREGULAR,
-        target=target
     )
 
     sfg.generate(freeslip)