From fa05055b844c0260c5e3b4af144085331f3733e3 Mon Sep 17 00:00:00 2001 From: Sven Marcus <s.marcus@outlook.de> Date: Fri, 11 Dec 2020 19:45:22 +0100 Subject: [PATCH] Experimenting with bounding box --- Python/norms.py | 39 ++++++- Python/poiseuille/analytical.py | 9 ++ Python/poiseuille/simulation.py | 2 +- Python/poiseuille/test_poiseuille_l2.py | 106 ++++++++++++++++---- src/cpu/simulationconfig/src/Simulation.cpp | 10 +- 5 files changed, 136 insertions(+), 30 deletions(-) diff --git a/Python/norms.py b/Python/norms.py index 40018ac01..cd4666ed8 100644 --- a/Python/norms.py +++ b/Python/norms.py @@ -1,14 +1,43 @@ import math -def l2_norm(real_values, numerical_values): +def get_sum_of_squared_distances(real_values, numerical_values): + combined_values = zip(real_values, numerical_values) + sum_of_squared_distances = sum((numerical_value - real_value) ** 2 + for real_value, numerical_value + in combined_values) + return sum_of_squared_distances + + +def root_mean_squared_error(real_values, numerical_values): + num_values = len(real_values) + if num_values != len(numerical_values): + raise ValueError("Real and numerical value lists must be same length") + + sum_of_squared_distances = get_sum_of_squared_distances(real_values, numerical_values) + sum_of_squared_real_values = sum(real_value ** 2 for real_value in real_values) + + return math.sqrt(sum_of_squared_distances / num_values) + + +def mean_absolute_error(real_values, numerical_values): num_values = len(real_values) if num_values != len(numerical_values): raise ValueError("Real and numerical value lists must be same length") combined_values = zip(real_values, numerical_values) - sum_of_squared_distances = sum((real_value - numerical_value) ** 2 - for real_value, numerical_value - in combined_values) + sum_of_absolute_distances = sum(abs(numerical_value - real_value) + for real_value, numerical_value + in combined_values) + + return sum_of_absolute_distances / num_values + + +def mean_squared_error(real_values, numerical_values): + num_values = len(real_values) + if num_values != len(numerical_values): + raise ValueError("Real and numerical value lists must be same length") + + sum_of_squared_distances = get_sum_of_squared_distances(real_values, numerical_values) - return math.sqrt(1 / num_values * sum_of_squared_distances) + return sum_of_squared_distances / num_values diff --git a/Python/poiseuille/analytical.py b/Python/poiseuille/analytical.py index 4ee428a4a..fb5ea9ad0 100644 --- a/Python/poiseuille/analytical.py +++ b/Python/poiseuille/analytical.py @@ -24,3 +24,12 @@ def poiseuille_at_z(settings: PoiseuilleSettings, z: float): def poiseuille_at_heights(settings: PoiseuilleSettings, heights): return [poiseuille_at_z(settings, z) for z in heights] + + +if __name__ == '__main__': + h1 = [1, 2, 3, 4, 5, 6, 7, 8, 9] + h2 = [0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5, 6, 6.5, 7, 7.5, 8, 8.5, 9, 9.5] + settings = PoiseuilleSettings() + settings.force = 1e-6 + print(max(poiseuille_at_heights(settings, h1))) + print(max(poiseuille_at_heights(settings, h2))) diff --git a/Python/poiseuille/simulation.py b/Python/poiseuille/simulation.py index 40c40698a..13966fc9e 100644 --- a/Python/poiseuille/simulation.py +++ b/Python/poiseuille/simulation.py @@ -7,7 +7,7 @@ from pyfluids.writer import Writer, OutputFormat grid_params = GridParameters() grid_params.node_distance = 1 -grid_params.number_of_nodes_per_direction = [2, 2, 10] +grid_params.number_of_nodes_per_direction = [1, 1, 10] grid_params.blocks_per_direction = [1, 1, 1] grid_params.periodic_boundary_in_x1 = True grid_params.periodic_boundary_in_x2 = True diff --git a/Python/poiseuille/test_poiseuille_l2.py b/Python/poiseuille/test_poiseuille_l2.py index e9391f0c3..852d458f4 100644 --- a/Python/poiseuille/test_poiseuille_l2.py +++ b/Python/poiseuille/test_poiseuille_l2.py @@ -1,11 +1,16 @@ import unittest +import shutil +import math import pyvista as pv -from norms import l2_norm +from norms import root_mean_squared_error, mean_squared_error, mean_absolute_error +from pyfluids.parameters import GridParameters, PhysicalParameters, RuntimeParameters from poiseuille.analytical import poiseuille_at_heights, PoiseuilleSettings -from poiseuille.simulation import run_simulation, grid_params, physical_params, runtime_params +from poiseuille.simulation import run_simulation from vtk_utilities import vertical_column_from_mesh, get_values_from_indices +from matplotlib.pyplot import plot, show, legend + class TestPoiseuilleFlow(unittest.TestCase): @@ -14,39 +19,100 @@ class TestPoiseuilleFlow(unittest.TestCase): WHEN comparing the simulation results to the analytical solution THEN the L2-Norm should be less than 1e-4 """ - run_simulation() - file_name_of_last_timestep = get_output_file_name(runtime_params) - mesh_of_last_timestep = pv.read(file_name_of_last_timestep) - column_indices = vertical_column_from_mesh(mesh_of_last_timestep) - numerical_results_from_single_column = get_values_from_indices(mesh_of_last_timestep.get_array("Vx"), column_indices) + physical_params = PhysicalParameters() + physical_params.lattice_viscosity = 0.0005 + + runtime_params = RuntimeParameters() + runtime_params.number_of_threads = 4 + runtime_params.timestep_log_interval = 1000 + + runtime_params.number_of_timesteps = 10000 + grid_params = create_grid_params_with_nodes_in_column(nodes_in_column=5, height=10) + l2_norm_result_100 = get_l2_norm_for_simulation(grid_params, physical_params, runtime_params, 11) + + runtime_params.number_of_timesteps = 20000 + grid_params = create_grid_params_with_nodes_in_column(nodes_in_column=10, height=10) + l2_norm_result_200 = get_l2_norm_for_simulation(grid_params, physical_params, runtime_params, 11) + + # runtime_params.number_of_timesteps = 40000 + # grid_params = create_grid_params_with_nodes_in_column(nodes_in_column=20, height=10) + # l2_norm_result_400 = get_l2_norm_for_simulation(grid_params, physical_params, runtime_params, 11) + + # nodes = [5, 10, 20] + # l2_norms = [l2_norm_result_100, l2_norm_result_200, l2_norm_result_400] + # plot(nodes, l2_norms) + # show() + # + # self.assertTrue(l2_norm_result_200 <= l2_norm_result_100) + # self.assertTrue(l2_norm_result_400 <= l2_norm_result_200) + + +def get_l2_norm_for_simulation(grid_params, physical_params, runtime_params, total_height): + output_folder = "./output" + remove_existing_output_directory(output_folder) + run_simulation(physical_params, grid_params, runtime_params) + mesh_of_last_timestep = get_mesh_for_last_timestep(output_folder, runtime_params) + column_indices = vertical_column_from_mesh(mesh_of_last_timestep) + velocities_in_x_direction = mesh_of_last_timestep.get_array("Vx") + numerical_results = get_values_from_indices(velocities_in_x_direction, column_indices) + heights = get_heights_from_indices(mesh_of_last_timestep, column_indices) + analytical_results = get_analytical_results(physical_params, total_height, heights) - heights = get_heights_from_indices(mesh_of_last_timestep, column_indices) - settings = get_analytical_poiseuille_settings(grid_params, physical_params) - analytical_results = poiseuille_at_heights(settings, heights) + print("") + # print(f"Numerical results: {numerical_results}") + # print(f"Analytical results: {analytical_results}") + print(f"Heights: {(min(heights), max(heights))}") + plot(heights, numerical_results) + plot(heights, analytical_results) + legend(["numerical", "analytical"]) + show() - l2_norm_result = l2_norm(analytical_results, numerical_results_from_single_column) + return root_mean_squared_error(analytical_results, numerical_results) - max_acceptable_error = 1e-4 - self.assertLessEqual(l2_norm_result, max_acceptable_error) - print(f"The L2-Norm is: {l2_norm_result}") +def get_analytical_results(physical_params, total_height, height_values): + settings = get_analytical_poiseuille_settings(total_height, physical_params) + analytical_results = poiseuille_at_heights(settings, height_values) + return analytical_results -def get_analytical_poiseuille_settings(grid_params, physical_params): + +def get_mesh_for_last_timestep(output_folder, runtime_params): + file_name_of_last_timestep = get_output_file_name(output_folder, runtime_params) + mesh_of_last_timestep = pv.read(file_name_of_last_timestep) + return mesh_of_last_timestep + + +def remove_existing_output_directory(output_dir): + shutil.rmtree(output_dir, ignore_errors=True) + + +def get_analytical_poiseuille_settings(height, 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.height = height settings.viscosity = physical_params.lattice_viscosity settings.density = 1 settings.force = 1e-6 + + print(f"Poiseuille height {settings.height}") return settings -def get_output_file_name(rumtime_params): - timesteps = rumtime_params.number_of_timesteps - file_name = f"output/mq/mq{timesteps}/mq0_{timesteps}.bin.vtu" +def get_output_file_name(output_folder, runtime_params): + timesteps = runtime_params.number_of_timesteps + file_name = f"{output_folder}/mq/mq{timesteps}/mq0_{timesteps}.bin.vtu" return file_name def get_heights_from_indices(mesh, indices): return [mesh.points[index][2] for index in indices] + +def create_grid_params_with_nodes_in_column(nodes_in_column, height): + grid_params = GridParameters() + grid_params.node_distance = height / (nodes_in_column - 1) + grid_params.number_of_nodes_per_direction = [nodes_in_column, nodes_in_column, nodes_in_column] + 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 diff --git a/src/cpu/simulationconfig/src/Simulation.cpp b/src/cpu/simulationconfig/src/Simulation.cpp index 558f6d3c2..a3574fedc 100644 --- a/src/cpu/simulationconfig/src/Simulation.cpp +++ b/src/cpu/simulationconfig/src/Simulation.cpp @@ -258,10 +258,12 @@ std::shared_ptr<GbObject3D> Simulation::makeSimulationBoundingBox(const int &nodesInX1, const int &nodesInX2, const int &nodesInX3) const { - double minX1 = 0, minX2 = 0, minX3 = 0; - const double maxX1 = minX1 + gridParameters->nodeDistance * nodesInX1; - const double maxX2 = minX2 + gridParameters->nodeDistance * nodesInX2; - const double maxX3 = minX3 + gridParameters->nodeDistance * nodesInX3; + + double halfDx = -gridParameters->nodeDistance / 2.0; + double minX1 = halfDx, minX2 = halfDx, minX3 = halfDx; + const double maxX1 = minX1 + gridParameters->nodeDistance * (nodesInX1 - 1) + halfDx; + const double maxX2 = minX2 + gridParameters->nodeDistance * (nodesInX2 - 1) + halfDx; + const double maxX3 = minX3 + gridParameters->nodeDistance * (nodesInX3 - 1) + halfDx; UBLOG(logINFO, "Bounding box dimensions = [(" << minX1 << ", " << minX2 << ", " << minX3 << "); (" << maxX1 << ", " << maxX2 << ", " << maxX3 << ")]") -- GitLab