diff --git a/CMake/VirtualFluidsMacros.cmake b/CMake/VirtualFluidsMacros.cmake
index 4fd163b2cc1b53fe461ef482d906f4cb1255a76c..2bf2a979e6bbed32fc229e99739c79b601b007f2 100644
--- a/CMake/VirtualFluidsMacros.cmake
+++ b/CMake/VirtualFluidsMacros.cmake
@@ -246,8 +246,8 @@ function(vf_add_library)
     target_include_directories(${library_name} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
     target_include_directories(${library_name} PRIVATE ${CMAKE_BINARY_DIR})
     target_include_directories(${library_name} PRIVATE ${VF_SRC_DIR})
-    target_include_directories(${library_name} PRIVATE ${VF_SRC_DIR}/gpu)
-    target_include_directories(${library_name} PRIVATE ${VF_SRC_DIR}/cpu)
+    target_include_directories(${library_name} PUBLIC ${VF_SRC_DIR}/gpu)
+    target_include_directories(${library_name} PUBLIC ${VF_SRC_DIR}/cpu)
 
     if(BUILD_VF_GPU)
         target_include_directories(${library_name} PRIVATE "${VF_THIRD_DIR}/cuda_samples/")
diff --git a/pythonbindings/src/cpu/submodules/boundaryconditions.cpp b/pythonbindings/src/cpu/submodules/boundaryconditions.cpp
index d7cd0b578a52c369923db0e31b01200f0389c9eb..8ab64a7a5037d134563eaac4e836f72e89c4ec77 100644
--- a/pythonbindings/src/cpu/submodules/boundaryconditions.cpp
+++ b/pythonbindings/src/cpu/submodules/boundaryconditions.cpp
@@ -30,16 +30,17 @@
 //! \ingroup submodules
 //! \author Sven Marcus, Henry Korb
 //=======================================================================================
+#include "BCStrategy.h"
 #include <pybind11/pybind11.h>
 #include <pybind11/stl.h>
-#include <BoundaryConditions/DensityBCAdapter.h>
-#include <BoundaryConditions/NonReflectingOutflowBCAlgorithm.h>
-#include <BoundaryConditions/BCAdapter.h>
-#include <BoundaryConditions/NoSlipBCAdapter.h>
-#include <BoundaryConditions/VelocityBCAdapter.h>
-#include <BoundaryConditions/NoSlipBCAlgorithm.h>
-#include <BoundaryConditions/VelocityBCAlgorithm.h>
-#include <BoundaryConditions/HighViscosityNoSlipBCAlgorithm.h>
+#include <BoundaryConditions/DensityBC.h>
+#include <BoundaryConditions/NonReflectingOutflowBCStrategy.h>
+#include <BoundaryConditions/BC.h>
+#include <BoundaryConditions/NoSlipBC.h>
+#include <BoundaryConditions/VelocityBC.h>
+#include <BoundaryConditions/NoSlipBCStrategy.h>
+#include <BoundaryConditions/VelocityBCStrategy.h>
+#include <BoundaryConditions/HighViscosityNoSlipBCStrategy.h>
 
 namespace boundaryconditions
 {
@@ -47,35 +48,35 @@ namespace boundaryconditions
     using namespace py::literals;
 
     template<class adapter, class algorithm,
-            class = std::enable_if_t<std::is_base_of<BCAdapter, adapter>::value>,
-            class = std::enable_if_t<std::is_base_of<BCAlgorithm, algorithm>::value>>
+            class = std::enable_if_t<std::is_base_of<BC, adapter>::value>,
+            class = std::enable_if_t<std::is_base_of<BCStrategy, algorithm>::value>>
     class PyBoundaryCondition : public adapter
     {
     public:
         template<typename ...Args>
         PyBoundaryCondition(Args &&... args) : adapter(std::forward<Args>(args)...)
         {
-            this->setBcAlgorithm(std::make_shared<algorithm>());
+            this->setBCStrategy(std::make_shared<algorithm>());
         }
     };
 
     template<class adapter, class algorithm>
-    using bc_class = py::class_<PyBoundaryCondition<adapter, algorithm>, BCAdapter,
+    using bc_class = py::class_<PyBoundaryCondition<adapter, algorithm>, BC,
             std::shared_ptr<PyBoundaryCondition<adapter, algorithm>>>;
 
     void makeModule(py::module_ &parentModule)
     {
         py::module_ bcModule = parentModule.def_submodule("boundaryconditions");
 
-        auto _ = py::class_<BCAdapter, std::shared_ptr<BCAdapter>>(bcModule, "BCAdapter");
+        auto _ = py::class_<BC, std::shared_ptr<BC>>(bcModule, "BC");
 
-        bc_class<NoSlipBCAdapter, NoSlipBCAlgorithm>(bcModule, "NoSlipBoundaryCondition")
+        bc_class<NoSlipBC, NoSlipBCStrategy>(bcModule, "NoSlipBoundaryCondition")
                 .def(py::init());
 
-        bc_class<NoSlipBCAdapter, HighViscosityNoSlipBCAlgorithm>(bcModule, "HighViscosityNoSlipBoundaryCondition")
+        bc_class<NoSlipBC, HighViscosityNoSlipBCStrategy>(bcModule, "HighViscosityNoSlipBoundaryCondition")
                 .def(py::init());
 
-        bc_class<VelocityBCAdapter, VelocityBCAlgorithm>(bcModule, "VelocityBoundaryCondition")
+        bc_class<VelocityBC, VelocityBCStrategy>(bcModule, "VelocityBoundaryCondition")
                 .def(py::init())
                 .def(py::init<bool &, bool &, bool &, mu::Parser &, real &, real &>(),
                      "vx1"_a, "vx2"_a, "vx3"_a,
@@ -89,7 +90,7 @@ namespace boundaryconditions
                      "vx2"_a, "vx2_start_time"_a, "vx2_end_time"_a,
                      "vx3"_a, "vx3_start_time"_a, "vx3_end_time"_a);
 
-        bc_class<DensityBCAdapter, NonReflectingOutflowBCAlgorithm>(bcModule, "NonReflectingOutflow")
+        bc_class<DensityBC, NonReflectingOutflowBCStrategy>(bcModule, "NonReflectingOutflow")
                 .def(py::init());
     }
 
diff --git a/pythonbindings/src/cpu/submodules/simulationconfig.cpp b/pythonbindings/src/cpu/submodules/simulationconfig.cpp
index 09d91f44e85f03c6150c56ce5762e7629212fba0..282b51fbfc986d20a27ee57c6f8e3b716ad34a06 100644
--- a/pythonbindings/src/cpu/submodules/simulationconfig.cpp
+++ b/pythonbindings/src/cpu/submodules/simulationconfig.cpp
@@ -39,16 +39,16 @@ namespace simulation
 
     void makeModule(py::module_ &parentModule)
     {
-        py::class_<Simulation, std::shared_ptr<Simulation>>(parentModule, "Simulation")
+        py::class_<CPUSimulation, std::shared_ptr<CPUSimulation>>(parentModule, "Simulation")
                 .def(py::init())
-                .def("set_writer", &Simulation::setWriterConfiguration)
-                .def("set_grid_parameters", &Simulation::setGridParameters)
-                .def("set_physical_parameters", &Simulation::setPhysicalParameters)
-                .def("set_runtime_parameters", &Simulation::setRuntimeParameters)
-                .def("set_kernel_config", &Simulation::setKernelConfiguration)
-                .def("add_object", &Simulation::addObject)
-                .def("add_bc_adapter", &Simulation::addBCAdapter)
-                .def("run_simulation", &Simulation::run);
+                .def("set_writer", &CPUSimulation::setWriterConfiguration)
+                .def("set_grid_parameters", &CPUSimulation::setGridParameters)
+                .def("set_physical_parameters", &CPUSimulation::setPhysicalParameters)
+                .def("set_runtime_parameters", &CPUSimulation::setRuntimeParameters)
+                .def("set_kernel_config", &CPUSimulation::setKernelConfiguration)
+                .def("add_object", &CPUSimulation::addObject)
+                .def("add_bc_adapter", &CPUSimulation::addBCAdapter)
+                .def("run_simulation", &CPUSimulation::run);
     }
 
 }
\ No newline at end of file
diff --git a/src/cpu/VirtualFluidsCore/Interactors/D3Q27TriFaceMeshInteractor.cpp b/src/cpu/VirtualFluidsCore/Interactors/D3Q27TriFaceMeshInteractor.cpp
index 237097ed5fd48f29b0b2e236cc497bd42110e681..e8746ffda6e2b44d004b0d33136779be405b5a28 100644
--- a/src/cpu/VirtualFluidsCore/Interactors/D3Q27TriFaceMeshInteractor.cpp
+++ b/src/cpu/VirtualFluidsCore/Interactors/D3Q27TriFaceMeshInteractor.cpp
@@ -186,11 +186,11 @@ void D3Q27TriFaceMeshInteractor::setQs(const real &timeStep)
     assert(UbMath::equal(cblockDeltaX1 / (double)blocknx1, cblockDeltaX3 / (double)blocknx3));
 
     for (int level = coarsestInitLevel; level <= finestInitLevel; level++) {
-        double nodeDeltaX1 = cblockDeltaX1 / (double)(blocknx1 * (1 << (level - coarsestInitLevel)));
-        double nodeDeltaX2 = cblockDeltaX2 / (double)(blocknx2 * (1 << (level - coarsestInitLevel)));
-        double nodeDeltaX3 = cblockDeltaX3 / (double)(blocknx3 * (1 << (level - coarsestInitLevel)));
+        real nodeDeltaX1 = cblockDeltaX1 / (double)(blocknx1 * (1 << (level - coarsestInitLevel)));
+        real nodeDeltaX2 = cblockDeltaX2 / (double)(blocknx2 * (1 << (level - coarsestInitLevel)));
+        real nodeDeltaX3 = cblockDeltaX3 / (double)(blocknx3 * (1 << (level - coarsestInitLevel)));
 
-        std::vector<double> distNeigh(D3Q27System::FENDDIR + 1, 0.0);
+        std::vector<real> distNeigh(D3Q27System::FENDDIR + 1, 0.0);
         D3Q27System::calcDistanceToNeighbors(distNeigh, nodeDeltaX1, nodeDeltaX2, nodeDeltaX3);
         // D3Q27System::calcDistanceToNeighbors(distNeigh, nodeDeltaX1);
 
@@ -666,9 +666,9 @@ void D3Q27TriFaceMeshInteractor::initInteractor2(const real &timeStep)
     assert(UbMath::equal(cblockDeltaX1 / (double)blocknx1, cblockDeltaX3 / (double)blocknx3));
 
     for (int level = coarsestInitLevel; level <= finestInitLevel; level++) {
-        double nodeDelta = cblockDeltaX1 / (double)(blocknx1 * (1 << (level - coarsestInitLevel)));
+        real nodeDelta = cblockDeltaX1 / (double)(blocknx1 * (1 << (level - coarsestInitLevel)));
 
-        std::vector<double> distNeigh(D3Q27System::FENDDIR + 1, 0.0);
+        std::vector<real> distNeigh(D3Q27System::FENDDIR + 1, 0.0);
         D3Q27System::calcDistanceToNeighbors(distNeigh, nodeDelta);
 
         nodeDeltaToNeigh[level].resize(D3Q27System::ENDDIR + 1, 0.0);
@@ -1313,7 +1313,7 @@ void D3Q27TriFaceMeshInteractor::initInteractor2(const real &timeStep)
     //}
 }
 //////////////////////////////////////////////////////////////////////////
-void D3Q27TriFaceMeshInteractor::refineBlockGridToLevel(int level, double startDistance, double stopDistance)
+void D3Q27TriFaceMeshInteractor::refineBlockGridToLevel(int level, real startDistance, real stopDistance)
 {
     UBLOG(logDEBUG1, "D3Q27TriFaceMeshInteractor::refineBlockGridToLevel - start");
 
diff --git a/src/cpu/simulationconfig/include/simulationconfig/AbstractLBMSystem.h b/src/cpu/simulationconfig/AbstractLBMSystem.h
similarity index 79%
rename from src/cpu/simulationconfig/include/simulationconfig/AbstractLBMSystem.h
rename to src/cpu/simulationconfig/AbstractLBMSystem.h
index 156649c6fd3c060117e8247efab2765f56f7c77b..77ab8798da189b4eedc64eb736b2d92e2b4be1cc 100644
--- a/src/cpu/simulationconfig/include/simulationconfig/AbstractLBMSystem.h
+++ b/src/cpu/simulationconfig/AbstractLBMSystem.h
@@ -2,7 +2,7 @@
 #define VIRTUALFLUIDSPYTHONBINDINGS_ABSTRACTLBMSYSTEM_H
 
 #include <Interactors/Interactor3D.h>
-#include <BoundaryConditions/BCAdapter.h>
+#include <BoundaryConditions/BC.h>
 #include <memory>
 
 class AbstractLBMSystem {
@@ -19,11 +19,11 @@ public:
 
     virtual std::shared_ptr<Interactor3D>
     makeInteractor(std::shared_ptr<GbObject3D> object, std::shared_ptr<Grid3D> grid,
-                   std::shared_ptr<BCAdapter> bcAdapter, int type) = 0;
+                   std::shared_ptr<BC> bcAdapter, int type) = 0;
 
     virtual std::shared_ptr<Interactor3D>
     makeInteractor(std::shared_ptr<GbObject3D> object, std::shared_ptr<Grid3D> grid,
-                   std::shared_ptr<BCAdapter> bcAdapter, int type, Interactor3D::Accuracy accuracy) = 0;
+                   std::shared_ptr<BC> bcAdapter, int type, Interactor3D::Accuracy accuracy) = 0;
 
 };
 
diff --git a/src/cpu/simulationconfig/CMakeLists.txt b/src/cpu/simulationconfig/CMakeLists.txt
index f0659f67a2af8d40a20991be42b4b49e1cab8ff1..255c83dfc2bff125e15f67e98080a76017abe6e9 100644
--- a/src/cpu/simulationconfig/CMakeLists.txt
+++ b/src/cpu/simulationconfig/CMakeLists.txt
@@ -1,8 +1,6 @@
-project(simulationconfig)
 
-
-vf_add_library(NAME simulationconfig PUBLIC_LINK VirtualFluidsCore basics muparser lbm)
+vf_add_library(PUBLIC_LINK VirtualFluidsCore basics muparser lbm)
 
 set_target_properties(simulationconfig PROPERTIES POSITION_INDEPENDENT_CODE ON)
 
-target_include_directories(simulationconfig PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
+target_include_directories(simulationconfig PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
\ No newline at end of file
diff --git a/src/cpu/simulationconfig/src/D3Q27LBMSystem.cpp b/src/cpu/simulationconfig/D3Q27LBMSystem.cpp
similarity index 84%
rename from src/cpu/simulationconfig/src/D3Q27LBMSystem.cpp
rename to src/cpu/simulationconfig/D3Q27LBMSystem.cpp
index b1a01ca7b05fedcbc7a66a0de3cdcfa33f3b0722..1e34e91c7a79d755b8670ff6e241e6b764548917 100644
--- a/src/cpu/simulationconfig/src/D3Q27LBMSystem.cpp
+++ b/src/cpu/simulationconfig/D3Q27LBMSystem.cpp
@@ -20,14 +20,14 @@ D3Q27LBMSystem::makeInteractor(std::shared_ptr<GbObject3D> object, std::shared_p
 
 std::shared_ptr<Interactor3D>
 D3Q27LBMSystem::makeInteractor(std::shared_ptr<GbObject3D> object, std::shared_ptr<Grid3D> grid,
-                               std::shared_ptr<BCAdapter> bcAdapter, int type)
+                               std::shared_ptr<BC> bcAdapter, int type)
 {
     return std::shared_ptr<Interactor3D>(new D3Q27Interactor(object, grid, bcAdapter, type));
 }
 
 std::shared_ptr<Interactor3D>
 D3Q27LBMSystem::makeInteractor(std::shared_ptr<GbObject3D> object, std::shared_ptr<Grid3D> grid,
-                               std::shared_ptr<BCAdapter> bcAdapter, int type, Interactor3D::Accuracy accuracy)
+                               std::shared_ptr<BC> bcAdapter, int type, Interactor3D::Accuracy accuracy)
 {
     return std::shared_ptr<Interactor3D>(new D3Q27Interactor(object, grid, bcAdapter, type, accuracy));
 }
diff --git a/src/cpu/simulationconfig/include/simulationconfig/D3Q27LBMSystem.h b/src/cpu/simulationconfig/D3Q27LBMSystem.h
similarity index 89%
rename from src/cpu/simulationconfig/include/simulationconfig/D3Q27LBMSystem.h
rename to src/cpu/simulationconfig/D3Q27LBMSystem.h
index c9883a61a27aa3d44af61be11d5b809aaf7068ce..581d8049b7ca5717ed44e746d55766b82ad57e0e 100644
--- a/src/cpu/simulationconfig/include/simulationconfig/D3Q27LBMSystem.h
+++ b/src/cpu/simulationconfig/D3Q27LBMSystem.h
@@ -6,8 +6,6 @@
 
 class D3Q27LBMSystem : public AbstractLBMSystem {
 public:
-    D3Q27LBMSystem() = default;
-
     int getNumberOfDirections() override;
 
     std::shared_ptr<Interactor3D> makeInteractor() override;
@@ -16,10 +14,10 @@ public:
     makeInteractor(std::shared_ptr<GbObject3D> object, std::shared_ptr<Grid3D> grid, int type) override;
 
     std::shared_ptr<Interactor3D> makeInteractor(std::shared_ptr<GbObject3D> object, std::shared_ptr<Grid3D> grid,
-                                                 std::shared_ptr<BCAdapter> bcAdapter, int type) override;
+                                                 std::shared_ptr<BC> bcAdapter, int type) override;
 
     std::shared_ptr<Interactor3D> makeInteractor(std::shared_ptr<GbObject3D> object, std::shared_ptr<Grid3D> grid,
-                                                 std::shared_ptr<BCAdapter> bcAdapter, int type,
+                                                 std::shared_ptr<BC> bcAdapter, int type,
                                                  Interactor3D::Accuracy accuracy) override;
 };
 
diff --git a/src/cpu/simulationconfig/include/simulationconfig/KernelConfigStructs.h b/src/cpu/simulationconfig/KernelConfigStructs.h
similarity index 59%
rename from src/cpu/simulationconfig/include/simulationconfig/KernelConfigStructs.h
rename to src/cpu/simulationconfig/KernelConfigStructs.h
index 53ea667c9da3a9c57d5aeeac67588cab0afbff3f..c7e46854933e7a8e64abc7b8ab961fc0f6e5eeb3 100644
--- a/src/cpu/simulationconfig/include/simulationconfig/KernelConfigStructs.h
+++ b/src/cpu/simulationconfig/KernelConfigStructs.h
@@ -4,14 +4,16 @@
 #include <string>
 #include <basics/DataTypes.h>
 
+#include "KernelFactory.h"
+
 struct LBMKernelConfiguration {
     KernelFactory::KernelType kernelType;
-    bool useForcing = false;
-    real forcingX1{};
-    real forcingX2{};
-    real forcingX3{};
+    bool useForcing {false};
+    real forcingX1 {};
+    real forcingX2 {};
+    real forcingX3 {};
 
-    explicit LBMKernelConfiguration(KernelFactory::KernelType kernelType) : kernelType(kernelType)
+    LBMKernelConfiguration(KernelFactory::KernelType kernelType) : kernelType(kernelType)
     {
     }
 };
diff --git a/src/cpu/simulationconfig/src/KernelFactory.cpp b/src/cpu/simulationconfig/KernelFactory.cpp
similarity index 100%
rename from src/cpu/simulationconfig/src/KernelFactory.cpp
rename to src/cpu/simulationconfig/KernelFactory.cpp
diff --git a/src/cpu/simulationconfig/include/simulationconfig/KernelFactory.h b/src/cpu/simulationconfig/KernelFactory.h
similarity index 100%
rename from src/cpu/simulationconfig/include/simulationconfig/KernelFactory.h
rename to src/cpu/simulationconfig/KernelFactory.h
diff --git a/src/cpu/simulationconfig/src/Simulation.cpp b/src/cpu/simulationconfig/Simulation.cpp
similarity index 56%
rename from src/cpu/simulationconfig/src/Simulation.cpp
rename to src/cpu/simulationconfig/Simulation.cpp
index 098f913d61a87b0dd2692faad07de691ca7e04a1..ec8773515ce49bdb8c0680152924605203ba9405 100644
--- a/src/cpu/simulationconfig/src/Simulation.cpp
+++ b/src/cpu/simulationconfig/Simulation.cpp
@@ -1,24 +1,30 @@
+#include <simulationconfig/Simulation.h>
+
 #include <memory>
 #include <string>
 #include <set>
 #include <utility>
 #include <cmath>
+
+#ifdef _OPENMP
 #include <omp.h>
+#endif
+
 #include <mpi.h>
 
 #include <basics/utilities/UbScheduler.h>
 #include <geometry3d/GbCuboid3D.h>
 #include <geometry3d/GbSystem3D.h>
 
-#include <BoundaryConditions/BCProcessor.h>
-#include <CoProcessors/CoProcessor.h>
-#include <CoProcessors/NUPSCounterCoProcessor.h>
-#include <CoProcessors/WriteBlocksCoProcessor.h>
-#include <CoProcessors/WriteBoundaryConditionsCoProcessor.h>
-#include <CoProcessors/WriteMacroscopicQuantitiesCoProcessor.h>
-#include <Grid/BasicCalculator.h>
-#include <Grid/Calculator.h>
-#include <Grid/Grid3D.h>
+#include <BoundaryConditions/BCStrategy.h>
+#include <BoundaryConditions/BCSet.h>
+#include <SimulationObservers/NUPSCounterSimulationObserver.h>
+#include <SimulationObservers/WriteBlocksSimulationObserver.h>
+#include <SimulationObservers/WriteBoundaryConditionsSimulationObserver.h>
+#include <SimulationObservers/WriteMacroscopicQuantitiesSimulationObserver.h>
+
+#include <Simulation/Simulation.h>
+#include <Simulation/Grid3D.h>
 #include <Interactors/InteractorsHelper.h>
 #include <LBM/CompressibleOffsetMomentsInterpolationProcessor.h>
 #include <LBM/LBMKernel.h>
@@ -31,38 +37,34 @@
 #include <Visitors/SetKernelBlockVisitor.h>
 
 #include <simulationconfig/SimulationParameters.h>
-#include <simulationconfig/Simulation.h>
 
 #include <lbm/constants/D3Q27.h>
 
+#include <logger/Logger.h>
 
-Simulation::Simulation()
+
+CPUSimulation::CPUSimulation()
 {
     this->communicator = vf::mpi::MPICommunicator::getInstance();
-    this->grid = std::shared_ptr<Grid3D>(new Grid3D(communicator));
-    this->interactors = std::vector<std::shared_ptr<Interactor3D>>();
-    this->bcVisitor = BoundaryConditionsBlockVisitor();
-    this->registeredAdapters = std::set<std::shared_ptr<BCAdapter>>();
+    this->grid = std::make_shared<Grid3D>(communicator);
 }
 
-void Simulation::setGridParameters(std::shared_ptr<GridParameters> parameters)
+void CPUSimulation::setGridParameters(std::shared_ptr<GridParameters> parameters)
 {
     this->gridParameters = std::move(parameters);
 }
 
-void Simulation::setPhysicalParameters(std::shared_ptr<PhysicalParameters> parameters)
+void CPUSimulation::setPhysicalParameters(std::shared_ptr<PhysicalParameters> parameters)
 {
     this->physicalParameters = std::move(parameters);
 }
 
-void Simulation::setRuntimeParameters(std::shared_ptr<RuntimeParameters> parameters)
+void CPUSimulation::setRuntimeParameters(std::shared_ptr<RuntimeParameters> parameters)
 {
     this->simulationParameters = std::move(parameters);
 }
 
-void
-Simulation::addObject(const std::shared_ptr<GbObject3D> &object, const std::shared_ptr<BCAdapter> &bcAdapter, int state,
-                      const std::string &folderPath)
+void CPUSimulation::addObject(const std::shared_ptr<GbObject3D> &object, const std::shared_ptr<BC> &bcAdapter, int state, const std::string &folderPath)
 {
     const bool is_in = registeredAdapters.find(bcAdapter) != registeredAdapters.end();
     if (!is_in) addBCAdapter(bcAdapter);
@@ -72,38 +74,32 @@ Simulation::addObject(const std::shared_ptr<GbObject3D> &object, const std::shar
     GbSystem3D::writeGeoObject(object, writerConfig.outputPath + folderPath, writerConfig.getWriter());
 }
 
-void Simulation::addBCAdapter(const std::shared_ptr<BCAdapter> &bcAdapter)
+void CPUSimulation::addBCAdapter(const std::shared_ptr<BC> &bcAdapter)
 {
     registeredAdapters.insert(bcAdapter);
     this->bcVisitor.addBC(bcAdapter);
 }
 
-void Simulation::setKernelConfiguration(const std::shared_ptr<LBMKernelConfiguration> &kernel)
+void CPUSimulation::setKernelConfiguration(const std::shared_ptr<LBMKernelConfiguration> &kernel)
 {
     this->kernelConfig = kernel;
     this->lbmKernel = kernelFactory.makeKernel(kernel->kernelType);
     this->lbmSystem = kernelFactory.makeLBMSystem(kernel->kernelType);
 }
 
-void Simulation::setWriterConfiguration(const WriterConfiguration &config)
+void CPUSimulation::setWriterConfiguration(WriterConfiguration config)
 {
     this->writerConfig = config;
 }
 
-WriterConfiguration &Simulation::getWriterConfig()
-{
-    return writerConfig;
-}
-
-void Simulation::run()
+void CPUSimulation::run()
 {
-    UBLOG(logINFO, "Beginning simulation setup for MPI rank " << communicator->getProcessID())
+    VF_LOG_INFO("Beginning simulation setup for MPI rank {}", communicator->getProcessID());
     grid->setDeltaX(gridParameters->nodeDistance);
     grid->setPeriodicX1(gridParameters->periodicBoundaryInX1);
     grid->setPeriodicX2(gridParameters->periodicBoundaryInX2);
     grid->setPeriodicX3(gridParameters->periodicBoundaryInX3);
 
-    //int &numberOfNodesInReferenceDirection = gridParameters->numberOfNodesPerDirection[gridParameters->referenceDirectionIndex];
     std::shared_ptr<LBMUnitConverter> converter = makeLBMUnitConverter();
 
     int &nodesInX1 = gridParameters->numberOfNodesPerDirection[0];
@@ -146,7 +142,7 @@ void Simulation::run()
 #ifdef _OPENMP
     omp_set_num_threads(simulationParameters->numberOfThreads);
     if (isMainProcess())
-        UBLOG(logINFO, "OpenMP is set to run with " << simulationParameters->numberOfThreads << " threads")
+        VF_LOG_INFO("OpenMP is set to run with {} threads", simulationParameters->numberOfThreads);
 #endif
 
     auto visualizationScheduler = std::make_shared<UbScheduler>(simulationParameters->timeStepLogInterval);
@@ -155,23 +151,22 @@ void Simulation::run()
 
     auto nupsCoProcessor = makeNupsCoProcessor();
 
-    auto calculator = std::make_shared<BasicCalculator>(grid, visualizationScheduler,
+    auto simulation = std::make_shared<Simulation>(grid, visualizationScheduler,
                                                         simulationParameters->numberOfTimeSteps);
-    calculator->addCoProcessor(nupsCoProcessor);
-    calculator->addCoProcessor(mqCoProcessor);
+    simulation->addSimulationObserver(nupsCoProcessor);
+    simulation->addSimulationObserver(mqCoProcessor);
 
-    if (isMainProcess()) UBLOG(logINFO, "Simulation-start")
-    calculator->calculate();
-    if (isMainProcess()) UBLOG(logINFO, "Simulation-end")
+    if (isMainProcess()) VF_LOG_TRACE("Simulation start");
+    simulation->run();
+    if (isMainProcess()) VF_LOG_TRACE("Simulation end");
 }
 
-bool Simulation::isMainProcess()
+bool CPUSimulation::isMainProcess()
 {
     return communicator->getProcessID() == 0;
 }
 
-void
-Simulation::setKernelForcing(const std::shared_ptr<LBMKernel> &kernel,
+void CPUSimulation::setKernelForcing(const std::shared_ptr<LBMKernel> &kernel,
                              std::shared_ptr<LBMUnitConverter> &converter) const
 {
     kernel->setWithForcing(kernelConfig->useForcing);
@@ -180,79 +175,74 @@ Simulation::setKernelForcing(const std::shared_ptr<LBMKernel> &kernel,
     kernel->setForcingX3(kernelConfig->forcingX3 * converter->getFactorForceWToLb());
 }
 
-void Simulation::logSimulationData(const int &nodesInX1, const int &nodesInX2, const int &nodesInX3) const
+void CPUSimulation::logSimulationData(const int &nodesInX1, const int &nodesInX2, const int &nodesInX3) const
 {
-    UBLOG(logINFO, "Domain size = " << nodesInX1 << " x " << nodesInX2 << " x " << nodesInX3)
-    UBLOG(logINFO, "dx          = " << gridParameters->nodeDistance << " m")
-    UBLOG(logINFO, "latticeViscosity    = " << physicalParameters->latticeViscosity)
+    VF_LOG_INFO("Domain size = {} x {} x {}", nodesInX1, nodesInX2, nodesInX3);
+    VF_LOG_INFO("dx          = {} m", gridParameters->nodeDistance);
+    VF_LOG_INFO("latticeViscosity    = {}", physicalParameters->latticeViscosity);
 }
 
-void Simulation::generateBlockGrid(const std::shared_ptr<GbObject3D> &gridCube) const
+void CPUSimulation::generateBlockGrid(const std::shared_ptr<GbObject3D> &gridCube) const
 {
-    UBLOG(logINFO, "Generate block grid")
+    VF_LOG_TRACE("Generate block grid");
     GenBlocksGridVisitor genBlocks(gridCube);
     grid->accept(genBlocks);
 }
 
-void Simulation::setBoundaryConditionProcessor(const std::shared_ptr<LBMKernel> &kernel)
+void CPUSimulation::setBoundaryConditionProcessor(const std::shared_ptr<LBMKernel> &kernel)
 {
-    UBLOG(logINFO, "Create boundary conditions processor")
-    auto bcProc = std::make_shared<BCProcessor>();
-    kernel->setBCProcessor(bcProc);
+    VF_LOG_TRACE("Create boundary conditions processor");
+    auto bcProc = std::make_shared<BCSet>();
+    kernel->setBCSet(bcProc);
 }
 
-void Simulation::setBlockSize(const int &nodesInX1, const int &nodesInX2, const int &nodesInX3) const
+void CPUSimulation::setBlockSize(const int &nodesInX1, const int &nodesInX2, const int &nodesInX3) const
 {
     int blockSizeX1 = nodesInX1 / gridParameters->blocksPerDirection[0];
     int blockSizeX2 = nodesInX2 / gridParameters->blocksPerDirection[1];
     int blockSizeX3 = nodesInX3 / gridParameters->blocksPerDirection[2];
-    UBLOG(logINFO, "Block size  = " << blockSizeX1 << " x " << blockSizeX2 << " x " << blockSizeX3)
+    VF_LOG_INFO("Block size  = {} x {} x {}", blockSizeX1, blockSizeX2, blockSizeX3);
     grid->setBlockNX(blockSizeX1,
                      blockSizeX2,
                      blockSizeX3);
 }
 
 std::shared_ptr<LBMUnitConverter>
-Simulation::makeLBMUnitConverter()
+CPUSimulation::makeLBMUnitConverter()
 {
     return std::make_shared<LBMUnitConverter>();
 }
 
 
 
-void Simulation::writeBoundaryConditions() const
+void CPUSimulation::writeBoundaryConditions() const
 {
     auto geoSch = std::make_shared<UbScheduler>(1);
-    WriteBoundaryConditionsCoProcessor ppgeo(grid, geoSch, writerConfig.outputPath, writerConfig.getWriter(),
+    WriteBoundaryConditionsSimulationObserver ppgeo(grid, geoSch, writerConfig.outputPath, writerConfig.getWriter(),
                                              communicator);
-    ppgeo.process(0);
+    ppgeo.update(0);
 }
 
-void Simulation::writeBlocksToFile() const
+void CPUSimulation::writeBlocksToFile() const
 {
-    UBLOG(logINFO, "Write block grid to VTK-file")
+    VF_LOG_TRACE("Write block grid to VTK-file");
     auto scheduler = std::make_shared<UbScheduler>(1);
-    auto ppblocks = std::make_shared<WriteBlocksCoProcessor>(grid,
+    auto ppblocks = std::make_shared<WriteBlocksSimulationObserver>(grid,
                                                              scheduler,
                                                              writerConfig.outputPath,
                                                              writerConfig.getWriter(),
                                                              communicator);
-    ppblocks->process(0);
+    ppblocks->update(0);
     ppblocks.reset();
 }
 
-std::shared_ptr<GbObject3D>
-Simulation::makeSimulationBoundingBox()
+std::shared_ptr<GbObject3D> CPUSimulation::makeSimulationBoundingBox()
 {
     auto box = gridParameters->boundingBox();
-    auto gridCube = std::make_shared<GbCuboid3D>(box->minX1, box->minX2, box->minX3, box->maxX1, box->maxX2,
-                                                 box->maxX3);
+    auto gridCube = std::make_shared<GbCuboid3D>(box->minX1, box->minX2, box->minX3, box->maxX1, box->maxX2, box->maxX3);
 
-    if (isMainProcess())
-    {
-        UBLOG(logINFO, "Bounding box dimensions = [("
-                << box->minX1 << ", " << box->minX2 << ", " << box->minX3 << "); ("
-                << box->maxX1 << ", " << box->maxX2 << ", " << box->maxX3 << ")]")
+    if (isMainProcess()) {
+        VF_LOG_INFO("Bounding box dimensions = [({}},{}},{}}); ({}}, {}}, {}})]", box->minX1, box->minX2, box->minX3, box->maxX1, box->maxX2, box->maxX3);
 
         GbSystem3D::writeGeoObject(gridCube.get(), writerConfig.outputPath + "/geo/gridCube", writerConfig.getWriter());
     }
@@ -260,38 +250,29 @@ Simulation::makeSimulationBoundingBox()
     return gridCube;
 }
 
-void Simulation::setConnectors()
+void CPUSimulation::setConnectors()
 {
     OneDistributionSetConnectorsBlockVisitor setConnsVisitor(communicator);
     grid->accept(setConnsVisitor);
 }
 
-void Simulation::initializeDistributions()
+void CPUSimulation::initializeDistributions()
 {
     InitDistributionsBlockVisitor initVisitor;
     grid->accept(initVisitor);
 }
 
-std::shared_ptr<CoProcessor>
-Simulation::makeMacroscopicQuantitiesCoProcessor(const std::shared_ptr<LBMUnitConverter> &converter,
-                                                 const std::shared_ptr<UbScheduler> &visualizationScheduler) const
+std::shared_ptr<SimulationObserver> CPUSimulation::makeMacroscopicQuantitiesCoProcessor(const std::shared_ptr<LBMUnitConverter> &converter, const std::shared_ptr<UbScheduler> &visualizationScheduler) const
 {
-    auto mqCoProcessor = std::make_shared<WriteMacroscopicQuantitiesCoProcessor>(grid, visualizationScheduler,
-                                                                                 writerConfig.outputPath,
-                                                                                 writerConfig.getWriter(),
-                                                                                 converter,
-                                                                                 communicator);
-    mqCoProcessor->process(0);
+    auto mqCoProcessor = std::make_shared<WriteMacroscopicQuantitiesSimulationObserver>(grid, visualizationScheduler, writerConfig.outputPath, writerConfig.getWriter(), converter, communicator);
+    mqCoProcessor->update(0);
     return mqCoProcessor;
 }
 
-std::shared_ptr<CoProcessor> Simulation::makeNupsCoProcessor() const
+std::shared_ptr<SimulationObserver> CPUSimulation::makeNupsCoProcessor() const
 {
     auto scheduler = std::make_shared<UbScheduler>(100, 100);
-    return std::make_shared<NUPSCounterCoProcessor>(grid, scheduler,
+    return std::make_shared<NUPSCounterSimulationObserver>(grid, scheduler,
                                                     simulationParameters->numberOfThreads,
                                                     communicator);
 }
-
-
-Simulation::~Simulation() = default;
diff --git a/src/cpu/simulationconfig/include/simulationconfig/Simulation.h b/src/cpu/simulationconfig/Simulation.h
similarity index 76%
rename from src/cpu/simulationconfig/include/simulationconfig/Simulation.h
rename to src/cpu/simulationconfig/Simulation.h
index 63298db81741864b40c4b320fbe4bd72f688715c..ee8fc911c684b55d0f624ab8db960d225e24790b 100644
--- a/src/cpu/simulationconfig/include/simulationconfig/Simulation.h
+++ b/src/cpu/simulationconfig/Simulation.h
@@ -9,9 +9,9 @@
 
 #include <geometry3d/GbPoint3D.h>
 #include <Interactors/Interactor3D.h>
-#include <BoundaryConditions/BCAdapter.h>
+#include <BoundaryConditions/BC.h>
 #include <Visitors/BoundaryConditionsBlockVisitor.h>
-#include <CoProcessors/CoProcessor.h>
+#include <SimulationObservers/SimulationObserver.h>
 #include <LBM/LBMUnitConverter.h>
 #include "KernelFactory.h"
 #include "AbstractLBMSystem.h"
@@ -20,34 +20,13 @@
 #include "WriterConfiguration.h"
 
 
-class Simulation {
-private:
-    KernelFactory kernelFactory = KernelFactory();
-
-    std::shared_ptr<LBMKernel> lbmKernel;
-    std::shared_ptr<AbstractLBMSystem> lbmSystem;
-    std::shared_ptr<vf::mpi::Communicator> communicator;
-
-    std::shared_ptr<Grid3D> grid;
-    std::vector<std::shared_ptr<Interactor3D>> interactors;
-    BoundaryConditionsBlockVisitor bcVisitor;
-    std::set<std::shared_ptr<BCAdapter>> registeredAdapters;
-
-    std::shared_ptr<LBMKernelConfiguration> kernelConfig;
-    std::shared_ptr<RuntimeParameters> simulationParameters;
-    std::shared_ptr<GridParameters> gridParameters;
-    std::shared_ptr<PhysicalParameters> physicalParameters;
-
-    WriterConfiguration &writerConfig = *(new WriterConfiguration());
 
+class CPUSimulation
+{
 public:
-    explicit Simulation();
-
-    ~Simulation();
+    CPUSimulation();
 
-    WriterConfiguration &getWriterConfig();
-
-    void setWriterConfiguration(const WriterConfiguration &config);
+    void setWriterConfiguration(WriterConfiguration config);
 
     void setGridParameters(std::shared_ptr<GridParameters> parameters);
 
@@ -57,10 +36,10 @@ public:
 
     void setKernelConfiguration(const std::shared_ptr<LBMKernelConfiguration> &kernel);
 
-    void addObject(const std::shared_ptr<GbObject3D> &object, const std::shared_ptr<BCAdapter> &bcAdapter, int state,
+    void addObject(const std::shared_ptr<GbObject3D> &object, const std::shared_ptr<BC> &bcAdapter, int state,
                    const std::string &folderPath);
 
-    void addBCAdapter(const std::shared_ptr<BCAdapter> &bcAdapter);
+    void addBCAdapter(const std::shared_ptr<BC> &bcAdapter);
 
     void run();
 
@@ -73,7 +52,7 @@ private:
 
     void writeBoundaryConditions() const;
 
-    std::shared_ptr<CoProcessor> makeMacroscopicQuantitiesCoProcessor(const std::shared_ptr<LBMUnitConverter> &converter,
+    std::shared_ptr<SimulationObserver> makeMacroscopicQuantitiesCoProcessor(const std::shared_ptr<LBMUnitConverter> &converter,
                                                            const std::shared_ptr<UbScheduler> &visualizationScheduler) const;
 
     static std::shared_ptr<LBMUnitConverter> makeLBMUnitConverter();
@@ -86,14 +65,33 @@ private:
 
     void logSimulationData(const int &nodesInX1, const int &nodesInX2, const int &nodesInX3) const;
 
-
     void setKernelForcing(const std::shared_ptr<LBMKernel> &kernel, std::shared_ptr<LBMUnitConverter> &converter) const;
 
     void setConnectors();
 
     void initializeDistributions();
 
-    std::shared_ptr<CoProcessor> makeNupsCoProcessor() const;
+    std::shared_ptr<SimulationObserver> makeNupsCoProcessor() const;
+
+private:
+    KernelFactory kernelFactory = KernelFactory();
+
+    std::shared_ptr<LBMKernel> lbmKernel;
+    std::shared_ptr<AbstractLBMSystem> lbmSystem;
+    std::shared_ptr<vf::mpi::Communicator> communicator;
+
+    std::shared_ptr<Grid3D> grid;
+    std::vector<std::shared_ptr<Interactor3D>> interactors;
+    BoundaryConditionsBlockVisitor bcVisitor {};
+    std::set<std::shared_ptr<BC>> registeredAdapters;
+
+    std::shared_ptr<LBMKernelConfiguration> kernelConfig;
+    std::shared_ptr<RuntimeParameters> simulationParameters;
+    std::shared_ptr<GridParameters> gridParameters;
+    std::shared_ptr<PhysicalParameters> physicalParameters;
+
+    WriterConfiguration writerConfig;
 };
 
+
 #endif
\ No newline at end of file
diff --git a/src/cpu/simulationconfig/include/simulationconfig/SimulationParameters.h b/src/cpu/simulationconfig/SimulationParameters.h
similarity index 100%
rename from src/cpu/simulationconfig/include/simulationconfig/SimulationParameters.h
rename to src/cpu/simulationconfig/SimulationParameters.h
diff --git a/src/cpu/simulationconfig/include/simulationconfig/WriterConfiguration.h b/src/cpu/simulationconfig/WriterConfiguration.h
similarity index 95%
rename from src/cpu/simulationconfig/include/simulationconfig/WriterConfiguration.h
rename to src/cpu/simulationconfig/WriterConfiguration.h
index a487917ff3c8a9a7b7f3847e5b04de1801a0fce0..7f7e5fc25d0042317ea7c7ca7f3cef808f09aa96 100644
--- a/src/cpu/simulationconfig/include/simulationconfig/WriterConfiguration.h
+++ b/src/cpu/simulationconfig/WriterConfiguration.h
@@ -14,7 +14,7 @@ struct WriterConfiguration {
     OutputFormat outputFormat{};
     std::string outputPath{"./output"};
 
-    WbWriter *getWriter()
+    WbWriter *getWriter() const 
     {
         if (outputFormat == ASCII) return WbWriterVtkXmlASCII::getInstance();
         if (outputFormat == BINARY) return WbWriterVtkXmlBinary::getInstance();