From e9af5db825871e9c5da0b0956add2132507793a8 Mon Sep 17 00:00:00 2001
From: Sven Marcus <s.marcus@outlook.de>
Date: Tue, 6 Oct 2020 18:15:02 +0200
Subject: [PATCH] Begin restructuring Python folder. Implement some unit tests.

---
 .gitlab-ci.yml                                |   6 +-
 Python/cubeflow/__init__.py                   |   0
 Python/cubeflow/simulation.py                 | 101 ++++++++++++++++++
 Python/liddrivencavity/__init__.py            |   0
 Python/liddrivencavity/simulation.py          |  62 +++++++++++
 Python/poiseuille/__init__.py                 |   0
 .../analytical.py}                            |   0
 .../simulation.py}                            |   2 +-
 Python/poiseuille/test_poiseuille_l2.py       |  73 +++++++++++++
 Python/pyproject.toml                         |   2 -
 Python/test_boundaryconditions.py             |   2 +-
 Python/test_cubeflow.py                       |  96 -----------------
 Python/test_geometry.py                       |  46 ++++++--
 Python/test_kernel.py                         |  58 ++++++++--
 Python/test_lid_driven_cavity.py              |  62 -----------
 Python/test_poiseuille_l2.py                  |  47 --------
 Python/test_virtualfluids_help.py             |   2 -
 pyproject.toml                                |   2 +
 18 files changed, 329 insertions(+), 232 deletions(-)
 create mode 100644 Python/cubeflow/__init__.py
 create mode 100644 Python/cubeflow/simulation.py
 create mode 100644 Python/liddrivencavity/__init__.py
 create mode 100644 Python/liddrivencavity/simulation.py
 create mode 100644 Python/poiseuille/__init__.py
 rename Python/{poiseuille_analytical.py => poiseuille/analytical.py} (100%)
 rename Python/{poiseuille_flow.py => poiseuille/simulation.py} (96%)
 create mode 100644 Python/poiseuille/test_poiseuille_l2.py
 delete mode 100644 Python/pyproject.toml
 delete mode 100644 Python/test_cubeflow.py
 delete mode 100644 Python/test_lid_driven_cavity.py
 delete mode 100644 Python/test_poiseuille_l2.py
 delete mode 100644 Python/test_virtualfluids_help.py
 create mode 100644 pyproject.toml

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 26159a6e1..c27357efb 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -48,8 +48,4 @@ test_python_bindings:
     - source Python/venv/bin/activate
 
   script:
-    - python3 Python/test_geometry.py
-    - python3 Python/test_boundaryconditions.py
-    - python3 Python/test_kernel.py
-    - python3 Python/test_muparser.py
-    - python3 -m unittest Python/test_poiseuille_l2.py
\ No newline at end of file
+    - python3 -m unittest discover -s Python -v
\ No newline at end of file
diff --git a/Python/cubeflow/__init__.py b/Python/cubeflow/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/Python/cubeflow/simulation.py b/Python/cubeflow/simulation.py
new file mode 100644
index 000000000..309583e23
--- /dev/null
+++ b/Python/cubeflow/simulation.py
@@ -0,0 +1,101 @@
+from pyfluids import Simulation
+from pyfluids.boundaryconditions import NoSlipBCAlgorithm, NoSlipBCAdapter, VelocityBCAdapter, DensityBCAdapter, \
+    VelocityBCAlgorithm, NonReflectingOutflowBCAlgorithm
+from pyfluids.geometry import GbCuboid3D
+from pyfluids.kernel import LBMKernel, KernelType
+from pyfluids.parameters import PhysicalParameters, SimulationParameters, GridParameters
+from pyfluids.writer import Writer, WriterType
+from pymuparser import Parser
+
+
+def get_max_length(number_of_nodes_per_direction, delta_x):
+    return (number_of_nodes_per_direction[0] * delta_x,
+            number_of_nodes_per_direction[1] * delta_x,
+            number_of_nodes_per_direction[2] * delta_x)
+
+
+physical_params = PhysicalParameters()
+physical_params.lattice_viscosity = 0.005
+
+grid_params = GridParameters()
+grid_params.number_of_nodes_per_direction = [200, 120, 120]
+grid_params.blocks_per_direction = [2, 2, 2]
+grid_params.delta_x = 0.125
+grid_params.periodic_boundary_in_x1 = False
+grid_params.periodic_boundary_in_x2 = True
+grid_params.periodic_boundary_in_x3 = True
+
+sim_params = SimulationParameters()
+sim_params.timestep_log_interval = 1000
+sim_params.number_of_timesteps = 1000
+sim_params.number_of_threads = 4
+
+
+def run_simulation(physical_parameters=physical_params, grid_parameters=grid_params,
+                   sim_parameters=sim_params):
+    wall_thickness = 3 * grid_parameters.delta_x
+
+    min_x, min_y, min_z = 0, 0, 0
+    max_x, max_y, max_z = get_max_length(grid_parameters.number_of_nodes_per_direction, grid_parameters.delta_x)
+
+    bottom_wall = GbCuboid3D(min_x - wall_thickness, min_y - wall_thickness, min_z, max_x + wall_thickness,
+                             max_y + wall_thickness, min_z - wall_thickness)
+
+    top_wall = GbCuboid3D(min_x - wall_thickness, min_y - wall_thickness, max_z, max_x + wall_thickness,
+                          max_y + wall_thickness,
+                          max_z + wall_thickness)
+
+    left_wall = GbCuboid3D(min_x - wall_thickness, min_y, min_z - wall_thickness, max_x + wall_thickness,
+                           min_y - wall_thickness,
+                           max_z + wall_thickness)
+
+    right_wall = GbCuboid3D(min_x - wall_thickness, max_y, min_z - wall_thickness, max_x + wall_thickness,
+                            max_y + wall_thickness, max_z + wall_thickness)
+
+    obstacle = GbCuboid3D(7, 7, 7, 8, 8, 8)
+
+    velocity_boundary = GbCuboid3D(min_x - wall_thickness, min_y - wall_thickness, min_z - wall_thickness, min_x,
+                                   max_y + wall_thickness, max_z + wall_thickness)
+
+    outflow_boundary = GbCuboid3D(max_x, min_y - wall_thickness, min_z - wall_thickness, max_x + wall_thickness,
+                                  max_y + wall_thickness, max_z + wall_thickness)
+
+    no_slip_bc = NoSlipBCAdapter()
+    no_slip_bc.algorithm = NoSlipBCAlgorithm()
+
+    outflow_bc = DensityBCAdapter()
+    outflow_bc.algorithm = NonReflectingOutflowBCAlgorithm()
+
+    velocity_function = Parser()
+    velocity_function.define_constant("u", 0.07)
+    velocity_function.expression = "u"
+    velocity_bc = VelocityBCAdapter(True, False, False, velocity_function, 0, -10)
+    velocity_bc.algorithm = VelocityBCAlgorithm()
+
+    kernel = LBMKernel(KernelType.CompressibleCumulantFourthOrderViscosity)
+    # kernel.use_forcing = True
+    # kernel.forcing_in_x1 = 3e-6
+
+    writer = Writer()
+    writer.output_path = "./output"
+    writer.type = WriterType.BINARY
+
+    builder = Simulation()
+    builder.set_writer(writer)
+
+    builder.set_physical_parameters(physical_parameters)
+    builder.set_grid_parameters(grid_parameters)
+    builder.set_simulation_parameters(sim_parameters)
+    builder.set_kernel_config(kernel)
+
+    # builder.add_object(bottom_wall, no_slip_bc, 1, "/geo/bottomWall")
+    # builder.add_object(top_wall, no_slip_bc, 1, "/geo/topWall")
+    # builder.add_object(left_wall, no_slip_bc, 1, "/geo/leftWall")
+    # builder.add_object(right_wall, no_slip_bc, 1, "/geo/rightWall")
+
+    builder.add_object(obstacle, no_slip_bc, 1, "/geo/obstacle")
+
+    builder.add_object(outflow_boundary, outflow_bc, 1, "/geo/outflow")
+    builder.add_object(velocity_boundary, velocity_bc, 1, "/geo/velocityBoundary")
+
+    builder.run_simulation()
diff --git a/Python/liddrivencavity/__init__.py b/Python/liddrivencavity/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/Python/liddrivencavity/simulation.py b/Python/liddrivencavity/simulation.py
new file mode 100644
index 000000000..367bd5554
--- /dev/null
+++ b/Python/liddrivencavity/simulation.py
@@ -0,0 +1,62 @@
+from pyfluids import Simulation
+from pyfluids.boundaryconditions import NoSlipBCAdapter, NoSlipBCAlgorithm, VelocityBCAdapter, VelocityBCAlgorithm
+from pyfluids.geometry import GbCuboid3D
+from pyfluids.kernel import LBMKernel, KernelType
+from pyfluids.parameters import GridParameters, PhysicalParameters, SimulationParameters
+from pymuparser import Parser
+
+sim_params = SimulationParameters()
+sim_params.number_of_threads = 4
+sim_params.number_of_timesteps = 10000
+sim_params.timestep_log_interval = 1000
+
+physical_params = PhysicalParameters()
+physical_params.lattice_viscosity = 0.005
+
+grid_params = GridParameters()
+grid_params.number_of_nodes_per_direction = [64, 64, 64]
+grid_params.blocks_per_direction = [2, 2, 2]
+grid_params.delta_x = 1 / 10
+
+
+def run_simulation(physical_params=physical_params, grid_params=grid_params, sim_params=sim_params):
+    simulation = Simulation()
+    kernel = LBMKernel(KernelType.CompressibleCumulantFourthOrderViscosity)
+
+    simulation.output_path = "./output"
+    simulation.set_grid_parameters(grid_params)
+    simulation.set_physical_parameters(physical_params)
+    simulation.set_simulation_parameters(sim_params)
+    simulation.set_kernel_config(kernel)
+
+    no_slip_bc_adapter = NoSlipBCAdapter()
+    no_slip_bc_adapter.algorithm = NoSlipBCAlgorithm()
+
+    fct = Parser()
+    fct.expression = "u"
+    fct.define_constant("u", 0.005)
+    velocity_bc_adapter = VelocityBCAdapter(True, True, False, fct, 0, -10.0)
+    velocity_bc_adapter.algorithm = VelocityBCAlgorithm()
+
+    g_min_x1, g_min_x2, g_min_x3 = 0, 0, 0
+    g_max_x1 = grid_params.number_of_nodes_per_direction[0] * grid_params.delta_x
+    g_max_x2 = grid_params.number_of_nodes_per_direction[1] * grid_params.delta_x
+    g_max_x3 = grid_params.number_of_nodes_per_direction[2] * grid_params.delta_x
+
+    dx = grid_params.delta_x
+
+    wall_x_min = GbCuboid3D(g_min_x1 - dx, g_min_x2 - dx, g_min_x3 - dx, g_min_x1, g_max_x2 + dx, g_max_x3)
+    wall_x_max = GbCuboid3D(g_max_x1, g_min_x2 - dx, g_min_x3 - dx, g_max_x1 + dx, g_max_x2 + dx, g_max_x3)
+    wall_y_min = GbCuboid3D(g_min_x1 - dx, g_min_x2 - dx, g_min_x3 - dx, g_max_x1 + dx, g_min_x2, g_max_x3)
+    wall_y_max = GbCuboid3D(g_min_x1 - dx, g_max_x2, g_min_x3 - dx, g_max_x1 + dx, g_max_x2 + dx, g_max_x3)
+    wall_z_min = GbCuboid3D(g_min_x1 - dx, g_min_x2 - dx, g_min_x3 - dx, g_max_x1 + dx, g_max_x2 + dx, g_min_x3)
+    wall_z_max = GbCuboid3D(g_min_x1 - dx, g_min_x2 - dx, g_max_x3, g_max_x1 + dx, g_max_x2 + dx, g_max_x3 + dx)
+
+    simulation.add_object(wall_x_min, no_slip_bc_adapter, 1, "/geo/wallXmin")
+    simulation.add_object(wall_x_max, no_slip_bc_adapter, 1, "/geo/wallXmax")
+    simulation.add_object(wall_y_min, no_slip_bc_adapter, 1, "/geo/wallYmin")
+    simulation.add_object(wall_y_max, no_slip_bc_adapter, 1, "/geo/wallYmax")
+    simulation.add_object(wall_z_min, no_slip_bc_adapter, 1, "/geo/wallZmin")
+    simulation.add_object(wall_z_max, velocity_bc_adapter, 1, "/geo/wallZmax")
+
+    simulation.run_simulation()
diff --git a/Python/poiseuille/__init__.py b/Python/poiseuille/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/Python/poiseuille_analytical.py b/Python/poiseuille/analytical.py
similarity index 100%
rename from Python/poiseuille_analytical.py
rename to Python/poiseuille/analytical.py
diff --git a/Python/poiseuille_flow.py b/Python/poiseuille/simulation.py
similarity index 96%
rename from Python/poiseuille_flow.py
rename to Python/poiseuille/simulation.py
index 3f0fc86f2..7b7808615 100644
--- a/Python/poiseuille_flow.py
+++ b/Python/poiseuille/simulation.py
@@ -5,7 +5,7 @@ from pyfluids.kernel import LBMKernel, KernelType
 from pyfluids.writer import Writer, WriterType
 
 
-def simulate_poiseuille_flow(physical_params, grid_params, sim_params):
+def run_simulation(physical_params, grid_params, sim_params):
     simulation = Simulation()
 
     kernel = LBMKernel(KernelType.CompressibleCumulantFourthOrderViscosity)
diff --git a/Python/poiseuille/test_poiseuille_l2.py b/Python/poiseuille/test_poiseuille_l2.py
new file mode 100644
index 000000000..62be3371c
--- /dev/null
+++ b/Python/poiseuille/test_poiseuille_l2.py
@@ -0,0 +1,73 @@
+import unittest
+
+import pyvista as pv
+from norms import l2_norm
+from poiseuille.analytical import poiseuille_at_heights, PoiseuilleSettings
+from poiseuille.simulation import run_simulation
+from pyfluids.parameters import PhysicalParameters, GridParameters, SimulationParameters
+from vtk_utilities import vertical_column_from_mesh, get_values_from_indices
+
+
+class TestPoiseuilleFlow(unittest.TestCase):
+
+    def test_poiseuille_flow(self):
+        physical_params = _create_physical_params()
+        grid_params = _create_grid_params()
+        sim_params = _create_simulation_params()
+
+        run_simulation(physical_params, grid_params, sim_params)
+        file_name = _get_output_file_name(sim_params)
+        mesh = pv.read(file_name)
+        indices = vertical_column_from_mesh(mesh)
+        numerical_results = get_values_from_indices(mesh.get_array("Vx"), indices)
+        heights = _get_heights_from_indices(mesh, indices)
+
+        settings = _get_analytical_poiseuille_settings(grid_params, physical_params)
+        analytical_results = poiseuille_at_heights(settings, heights)
+
+        norm = l2_norm(analytical_results, numerical_results)
+        print(f"L2 norm value: {norm}")
+        self.assertLessEqual(norm, 1e-4)
+
+
+def _get_analytical_poiseuille_settings(grid_params, physical_params):
+    settings = PoiseuilleSettings()
+    settings.length = grid_params.number_of_nodes_per_direction[0]
+    settings.height = grid_params.number_of_nodes_per_direction[2]
+    settings.viscosity = physical_params.lattice_viscosity
+    settings.density = 1
+    settings.force = 1e-6
+    return settings
+
+
+def _get_output_file_name(sim_params):
+    file_name = f"output/mq/mq{sim_params.number_of_timesteps}/mq0_{sim_params.number_of_timesteps}.bin.vtu"
+    return file_name
+
+
+def _get_heights_from_indices(mesh, indices):
+    return [mesh.points[index][2] for index in indices]
+
+
+def _create_simulation_params():
+    sim_params = SimulationParameters()
+    sim_params.number_of_threads = 4
+    sim_params.number_of_timesteps = 10000
+    sim_params.timestep_log_interval = 1000
+    return sim_params
+
+
+def _create_grid_params():
+    grid_params = GridParameters()
+    grid_params.delta_x = 1
+    grid_params.number_of_nodes_per_direction = [2, 2, 10]
+    grid_params.blocks_per_direction = [1, 1, 1]
+    grid_params.periodic_boundary_in_x1 = True
+    grid_params.periodic_boundary_in_x2 = True
+    return grid_params
+
+
+def _create_physical_params():
+    physical_params = PhysicalParameters()
+    physical_params.lattice_viscosity = 0.005
+    return physical_params
diff --git a/Python/pyproject.toml b/Python/pyproject.toml
deleted file mode 100644
index a3d83b14b..000000000
--- a/Python/pyproject.toml
+++ /dev/null
@@ -1,2 +0,0 @@
-[build-system]
-requires = ["setuptools", "wheel", "scikit-build", "cmake", "ninja", "pybind11"]
\ No newline at end of file
diff --git a/Python/test_boundaryconditions.py b/Python/test_boundaryconditions.py
index 3a59cbbe3..437a26953 100644
--- a/Python/test_boundaryconditions.py
+++ b/Python/test_boundaryconditions.py
@@ -2,4 +2,4 @@ from pyfluids.boundaryconditions import *
 
 no_slip_algo = NoSlipBCAlgorithm()
 no_slip_bc_adapter = NoSlipBCAdapter()
-no_slip_bc_adapter.algorithm = no_slip_algo
\ No newline at end of file
+no_slip_bc_adapter.algorithm = no_slip_algo
diff --git a/Python/test_cubeflow.py b/Python/test_cubeflow.py
deleted file mode 100644
index 89c2d93fc..000000000
--- a/Python/test_cubeflow.py
+++ /dev/null
@@ -1,96 +0,0 @@
-from virtualfluids.geometry import GbCuboid3D
-from virtualfluids.boundaryconditions import NoSlipBCAlgorithm, NoSlipBCAdapter, VelocityBCAdapter, DensityBCAdapter, \
-    VelocityBCAlgorithm, NonReflectingOutflowBCAlgorithm
-from virtualfluids.parameters import PhysicalParameters, SimulationParameters, GridParameters
-from virtualfluids.kernel import LBMKernel, KernelType
-from virtualfluids.simulation import Simulation
-from virtualfluids.writer import Writer, WriterType
-from pymuparser import Parser
-
-
-def get_max_length(number_of_nodes_per_direction, delta_x):
-    return (number_of_nodes_per_direction[0] * delta_x,
-            number_of_nodes_per_direction[1] * delta_x,
-            number_of_nodes_per_direction[2] * delta_x)
-
-
-physical_parameters = PhysicalParameters()
-physical_parameters.lattice_viscosity = 0.005
-
-grid_parameters = GridParameters()
-grid_parameters.number_of_nodes_per_direction = [200, 120, 120]
-grid_parameters.blocks_per_direction = [2, 2, 2]
-grid_parameters.delta_x = 0.125
-grid_parameters.periodic_boundary_in_x1 = False
-grid_parameters.periodic_boundary_in_x2 = True
-grid_parameters.periodic_boundary_in_x3 = True
-
-sim_parameters = SimulationParameters()
-sim_parameters.timestep_log_interval = 1000
-sim_parameters.number_of_timesteps = 1000
-sim_parameters.number_of_threads = 4
-
-wall_thickness = 3 * grid_parameters.delta_x
-
-minX, minY, minZ = 0, 0, 0
-maxX, maxY, maxZ = get_max_length(grid_parameters.number_of_nodes_per_direction, grid_parameters.delta_x)
-
-bottom_wall = GbCuboid3D(minX - wall_thickness, minY - wall_thickness, minZ, maxX + wall_thickness,
-                         maxY + wall_thickness, minZ - wall_thickness)
-
-top_wall = GbCuboid3D(minX - wall_thickness, minY - wall_thickness, maxZ, maxX + wall_thickness, maxY + wall_thickness,
-                      maxZ + wall_thickness)
-
-left_wall = GbCuboid3D(minX - wall_thickness, minY, minZ - wall_thickness, maxX + wall_thickness, minY - wall_thickness,
-                       maxZ + wall_thickness)
-
-right_wall = GbCuboid3D(minX - wall_thickness, maxY, minZ - wall_thickness, maxX + wall_thickness,
-                        maxY + wall_thickness, maxZ + wall_thickness)
-
-obstacle = GbCuboid3D(7, 7, 7, 8, 8, 8)
-
-velocity_boundary = GbCuboid3D(minX - wall_thickness, minY - wall_thickness, minZ - wall_thickness, minX,
-                               maxY + wall_thickness, maxZ + wall_thickness)
-
-outflow_boundary = GbCuboid3D(maxX, minY - wall_thickness, minZ - wall_thickness, maxX + wall_thickness,
-                              maxY + wall_thickness, maxZ + wall_thickness)
-
-no_slip_bc = NoSlipBCAdapter()
-no_slip_bc.algorithm = NoSlipBCAlgorithm()
-
-outflow_bc = DensityBCAdapter()
-outflow_bc.algorithm = NonReflectingOutflowBCAlgorithm()
-
-velocity_function = Parser()
-velocity_function.define_constant("u", 0.07)
-velocity_function.expression = "u"
-velocity_bc = VelocityBCAdapter(True, False, False, velocity_function, 0, -10)
-velocity_bc.algorithm = VelocityBCAlgorithm()
-
-kernel = LBMKernel(KernelType.CompressibleCumulantFourthOrderViscosity)
-# kernel.use_forcing = True
-# kernel.forcing_in_x1 = 3e-6
-
-writer = Writer()
-writer.output_path = "./output"
-writer.type = WriterType.BINARY
-
-builder = Simulation()
-builder.set_writer(writer)
-
-builder.set_physical_parameters(physical_parameters)
-builder.set_grid_parameters(grid_parameters)
-builder.set_simulation_parameters(sim_parameters)
-builder.set_kernel_config(kernel)
-
-# builder.add_object(bottom_wall, no_slip_bc, 1, "/geo/bottomWall")
-# builder.add_object(top_wall, no_slip_bc, 1, "/geo/topWall")
-# builder.add_object(left_wall, no_slip_bc, 1, "/geo/leftWall")
-# builder.add_object(right_wall, no_slip_bc, 1, "/geo/rightWall")
-
-builder.add_object(obstacle, no_slip_bc, 1, "/geo/obstacle")
-
-builder.add_object(outflow_boundary, outflow_bc, 1, "/geo/outflow")
-builder.add_object(velocity_boundary, velocity_bc, 1, "/geo/velocityBoundary")
-
-builder.run_simulation()
diff --git a/Python/test_geometry.py b/Python/test_geometry.py
index 301542c3f..c2558cb1c 100644
--- a/Python/test_geometry.py
+++ b/Python/test_geometry.py
@@ -1,13 +1,41 @@
+import unittest
+
 from pyfluids.geometry import *
 
-point1 = GbPoint3D(1, 2, 3)
-point2 = GbPoint3D(4, 5, 6)
-line = GbLine3D()
-cube: GbCuboid3D = GbCuboid3D()
 
-line.point1 = point1
-line.point2 = point2
+class TestGeometry(unittest.TestCase):
+
+    def test_when_setting_point_coordinates_in_constructor__point_should_have_coordinates(self):
+        """
+        WHEN setting point coordinates in constructor THEN point should have coordinates
+        """
+        sut = GbPoint3D(4, 8, 3)
+
+        self.assertEqual(sut.x1, 4)
+        self.assertEqual(sut.x2, 8)
+        self.assertEqual(sut.x3, 3)
+
+    def test_when_setting_point_coordinates__point_should_have_coordinates(self):
+        """
+        WHEN setting point coordinates THEN point should have coordinates
+        """
+        sut = GbPoint3D()
+
+        sut.x1 = 4
+        sut.x2 = 8
+        sut.x3 = 3
+
+        self.assertEqual(sut.x1, 4)
+        self.assertEqual(sut.x2, 8)
+        self.assertEqual(sut.x3, 3)
+
+    def test_when_setting_line_points__line_should_have_points(self):
+        sut = GbLine3D()
+
+        point1 = GbPoint3D()
+        point2 = GbPoint3D()
+        sut.point1 = point1
+        sut.point2 = point2
 
-print(point1)
-print(line)
-print("Distance", point1.get_distance(point2))
+        self.assertEqual(sut.point1, point1)
+        self.assertEqual(sut.point2, point2)
diff --git a/Python/test_kernel.py b/Python/test_kernel.py
index 0497eb351..5e5487903 100644
--- a/Python/test_kernel.py
+++ b/Python/test_kernel.py
@@ -1,9 +1,53 @@
+import unittest
+
 from pyfluids.kernel import LBMKernel, KernelType
 
-kernel = LBMKernel(KernelType.BGK)
-kernel.use_forcing = True
-kernel.forcing_in_x1 = 1
-kernel.forcing_in_x2 = 1
-kernel.forcing_in_x3 = 1
-kernel.set_forcing(1, 2, 3)
-print(kernel)
+
+class TestLBMKernel(unittest.TestCase):
+
+    def setUp(self) -> None:
+        self.sut = LBMKernel(KernelType.BGK)
+
+    def test_lbm_kernel__when_use_forcing_set_to_true__use_forcing_should_be_true(self) -> None:
+        """
+        WHEN use_forcing is set to true THEN use_forcing should be true
+        """
+        self.sut.use_forcing = True
+
+        self.assertTrue(self.sut.use_forcing)
+
+    def test_lbm_kernel__when_forcing_in_x1_set_to_five__forcing_in_x1_should_be_five(self) -> None:
+        """
+        WHEN forcing_in_x1 is set to 5 THEN forcing_in_x1 should be 5
+        """
+        self.sut.forcing_in_x1 = 5
+
+        self.assertEqual(self.sut.forcing_in_x1, 5)
+
+    def test_lbm_kernel__when_forcing_in_x2_set_to_five__forcing_in_x2_should_be_five(self) -> None:
+        """
+        WHEN forcing_in_x2 is set to 5 THEN forcing_in_x2 should be 5
+        """
+        self.sut.forcing_in_x2 = 5
+
+        self.assertEqual(self.sut.forcing_in_x2, 5)
+
+    def test_lbm_kernel__when_forcing_in_x3_set_to_five__forcing_in_x3_should_be_five(self) -> None:
+        """
+        WHEN forcing_in_x3 is set to 5 THEN forcing_in_x3 should be 5
+        """
+        self.sut.forcing_in_x3 = 5
+
+        self.assertEqual(self.sut.forcing_in_x3, 5)
+
+    def test_lbm_kernel__when_setting_forcing_in_all_directions__forcing_should_equal_set_values(self) -> None:
+        """
+        WHEN setting forcing in all directions THEN forcing should equal set values
+        """
+
+        self.sut.set_forcing(3, 8, 5)
+
+        self.assertEqual(self.sut.forcing_in_x1, 3)
+        self.assertEqual(self.sut.forcing_in_x2, 8)
+        self.assertEqual(self.sut.forcing_in_x3, 5)
+
diff --git a/Python/test_lid_driven_cavity.py b/Python/test_lid_driven_cavity.py
deleted file mode 100644
index d06487e82..000000000
--- a/Python/test_lid_driven_cavity.py
+++ /dev/null
@@ -1,62 +0,0 @@
-from pyfluids import Simulation
-from pyfluids.boundaryconditions import NoSlipBCAdapter, NoSlipBCAlgorithm, VelocityBCAdapter, VelocityBCAlgorithm
-from pyfluids.geometry import GbCuboid3D
-from pyfluids.kernel import LBMKernel, KernelType
-from pyfluids.parameters import GridParameters, PhysicalParameters, SimulationParameters
-from pymuparser import Parser
-
-builder = Simulation()
-kernel = LBMKernel(KernelType.CompressibleCumulantFourthOrderViscosity)
-
-sim_parameters = SimulationParameters()
-sim_parameters.number_of_threads = 4
-sim_parameters.number_of_timesteps = 10000
-sim_parameters.timestep_log_interval = 1000
-
-physical_parameters = PhysicalParameters()
-physical_parameters.lattice_viscosity = 0.005
-
-grid_parameters = GridParameters()
-grid_parameters.number_of_nodes_per_direction = [64, 64, 64]
-grid_parameters.blocks_per_direction = [2, 2, 2]
-grid_parameters.delta_x = 1 / 10
-
-builder.output_path = "./output"
-builder.set_grid_parameters(grid_parameters)
-builder.set_physical_parameters(physical_parameters)
-builder.set_simulation_parameters(sim_parameters)
-builder.set_kernel_config(kernel)
-
-no_slip_bc_adapter = NoSlipBCAdapter()
-no_slip_bc_adapter.algorithm = NoSlipBCAlgorithm()
-
-fct = Parser()
-fct.expression = "u"
-fct.define_constant("u", 0.005)
-velocity_bc_adapter = VelocityBCAdapter(True, True, False, fct, 0, -10.0)
-velocity_bc_adapter.algorithm = VelocityBCAlgorithm()
-
-g_minX1 = 0
-g_minX2 = 0
-g_minX3 = 0
-g_maxX1 = grid_parameters.number_of_nodes_per_direction[0] * grid_parameters.delta_x
-g_maxX2 = grid_parameters.number_of_nodes_per_direction[1] * grid_parameters.delta_x
-g_maxX3 = grid_parameters.number_of_nodes_per_direction[2] * grid_parameters.delta_x
-
-dx = grid_parameters.delta_x
-
-wall_x_min = GbCuboid3D(g_minX1 - dx, g_minX2 - dx, g_minX3 - dx, g_minX1, g_maxX2 + dx, g_maxX3)
-wall_x_max = GbCuboid3D(g_maxX1, g_minX2 - dx, g_minX3 - dx, g_maxX1 + dx, g_maxX2 + dx, g_maxX3)
-wall_y_min = GbCuboid3D(g_minX1 - dx, g_minX2 - dx, g_minX3 - dx, g_maxX1 + dx, g_minX2, g_maxX3)
-wall_y_max = GbCuboid3D(g_minX1 - dx, g_maxX2, g_minX3 - dx, g_maxX1 + dx, g_maxX2 + dx, g_maxX3)
-wall_z_min = GbCuboid3D(g_minX1 - dx, g_minX2 - dx, g_minX3 - dx, g_maxX1 + dx, g_maxX2 + dx, g_minX3)
-wall_z_max = GbCuboid3D(g_minX1 - dx, g_minX2 - dx, g_maxX3, g_maxX1 + dx, g_maxX2 + dx, g_maxX3 + dx)
-
-builder.add_object(wall_x_min, no_slip_bc_adapter, 1, "/geo/wallXmin")
-builder.add_object(wall_x_max, no_slip_bc_adapter, 1, "/geo/wallXmax")
-builder.add_object(wall_y_min, no_slip_bc_adapter, 1, "/geo/wallYmin")
-builder.add_object(wall_y_max, no_slip_bc_adapter, 1, "/geo/wallYmax")
-builder.add_object(wall_z_min, no_slip_bc_adapter, 1, "/geo/wallZmin")
-builder.add_object(wall_z_max, velocity_bc_adapter, 1, "/geo/wallZmax")
-
-builder.run_simulation()
diff --git a/Python/test_poiseuille_l2.py b/Python/test_poiseuille_l2.py
deleted file mode 100644
index 91c100a3b..000000000
--- a/Python/test_poiseuille_l2.py
+++ /dev/null
@@ -1,47 +0,0 @@
-import unittest
-
-import pyvista as pv
-from norms import l2_norm
-from poiseuille_analytical import poiseuille_at_heights, PoiseuilleSettings
-from poiseuille_flow import simulate_poiseuille_flow
-from pyfluids.parameters import PhysicalParameters, GridParameters, SimulationParameters
-from vtk_utilities import vertical_column_from_mesh, get_values_from_indices
-
-
-class TestPoiseuilleFlow(unittest.TestCase):
-
-    def test_poiseuille_flow(self):
-        physical_params = PhysicalParameters()
-        physical_params.lattice_viscosity = 0.005
-
-        grid_params = GridParameters()
-        grid_params.delta_x = 1
-        grid_params.number_of_nodes_per_direction = [2, 2, 10]
-        grid_params.blocks_per_direction = [1, 1, 1]
-        grid_params.periodic_boundary_in_x1 = True
-        grid_params.periodic_boundary_in_x2 = True
-
-        sim_params = SimulationParameters()
-        sim_params.number_of_threads = 4
-        sim_params.number_of_timesteps = 10000
-        sim_params.timestep_log_interval = 1000
-
-        simulate_poiseuille_flow(physical_params, grid_params, sim_params)
-        file_name = f"output/mq/mq{sim_params.number_of_timesteps}/mq0_{sim_params.number_of_timesteps}.bin.vtu"
-        mesh = pv.read(file_name)
-        indices = vertical_column_from_mesh(mesh)
-        numerical_results = get_values_from_indices(mesh.get_array("Vx"), indices)
-        heights = [mesh.points[index][2] for index in indices]
-
-        settings = PoiseuilleSettings()
-        settings.length = grid_params.number_of_nodes_per_direction[0]
-        settings.height = grid_params.number_of_nodes_per_direction[2]
-        settings.viscosity = physical_params.lattice_viscosity
-        settings.density = 1
-        settings.force = 1e-6
-
-        analytical_results = poiseuille_at_heights(settings, heights)
-
-        norm = l2_norm(analytical_results, numerical_results)
-        print(f"L2 norm value: {norm}")
-        self.assertLessEqual(norm, 1e-4)
diff --git a/Python/test_virtualfluids_help.py b/Python/test_virtualfluids_help.py
deleted file mode 100644
index 8375dce8a..000000000
--- a/Python/test_virtualfluids_help.py
+++ /dev/null
@@ -1,2 +0,0 @@
-import pyfluids
-help(pyfluids)
\ No newline at end of file
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 000000000..8fcb79261
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,2 @@
+[build-system]
+requires = ["setuptools", "wheel", "scikit-build"]
\ No newline at end of file
-- 
GitLab