From 72629981306992b18f21d9354b0e70a8a3eaa407 Mon Sep 17 00:00:00 2001 From: loferga Date: Mon, 25 Aug 2025 10:46:39 +0200 Subject: [PATCH 1/4] Adds configuration tests implement tests for configuration --- .../dassflow2d_py/input/configuration_test.py | 105 ++++++++++++++++++ src/test/resources/input/test_config.yml | 11 ++ 2 files changed, 116 insertions(+) create mode 100644 src/test/py/fr/dasshydro/dassflow2d_py/input/configuration_test.py create mode 100644 src/test/resources/input/test_config.yml diff --git a/src/test/py/fr/dasshydro/dassflow2d_py/input/configuration_test.py b/src/test/py/fr/dasshydro/dassflow2d_py/input/configuration_test.py new file mode 100644 index 0000000..df6d275 --- /dev/null +++ b/src/test/py/fr/dasshydro/dassflow2d_py/input/configuration_test.py @@ -0,0 +1,105 @@ +import unittest +import os +from fr.dasshydro.dassflow2d_py.input.Configuration import Configuration, load_from_file +from fr.dasshydro.dassflow2d_py.resolution.ResolutionMethod import TemporalScheme, SpatialScheme + +class TestConfiguration(unittest.TestCase): + + def setUp(self): + self.config = Configuration() + + def testNamespacesValidity(self): + # Set of configuration tested + temporal_scheme = TemporalScheme.EULER + spatial_scheme = SpatialScheme.MUSCL + mesh_file = 'mesh.geo' + initial_state_file = 'dof_init.txt' + bathymetry_file = 'bathymetry.txt' + manning_file = 'manning.txt' + result_path = 'output/' + simulation_time = 42000 + delta_to_write = 100 + is_delta_adaptative = True + default_delta = 0.0001 + + # Apply these parameters + self.config.updateValues({ + 'temporal-scheme': temporal_scheme.value, + 'spatial-scheme': spatial_scheme.value, + 'mesh-file': mesh_file, + 'initial-state-file': initial_state_file, + 'bathymetry-file': bathymetry_file, + 'manning-file': manning_file, + 'result-path': result_path, + 'simulation-time': str(simulation_time), + 'delta-to-write': str(delta_to_write), + 'is-delta-adaptative': str(is_delta_adaptative), + 'default-delta': str(default_delta) + }) + + # Test if all have correctly been updated + self.assertEqual(self.config.getTemporalScheme(), temporal_scheme, "Temporal scheme is not stored correctly") + self.assertEqual(self.config.getSpatialScheme(), spatial_scheme, "Spatial scheme is not stored correctly") + self.assertEqual(self.config.getMeshFile(), mesh_file, "mesh file is not stored correctly") + self.assertEqual(self.config.getInitialStateFile(), initial_state_file, "initial state file is not stored correctly") + self.assertEqual(self.config.getBathymetryFile(), bathymetry_file, "bathymetry file is not stored correctly") + self.assertEqual(self.config.getManningFile(), manning_file, "manning file is not stored correctly") + self.assertEqual(self.config.getResultFilePath(), result_path, "result path is not stored correctly") + self.assertEqual(self.config.getSimulationTime(), simulation_time, "simulation time is not stored correctly") + self.assertEqual(self.config.getDeltaToWrite(), delta_to_write, "delta to write is not stored correctly") + self.assertEqual(self.config.isDeltaAdaptative(), is_delta_adaptative, "whether or not the delta is adaptative is not stored correctly") + self.assertEqual(self.config.getDefaultDelta(), default_delta, "default delta is not stored correctly") + + def testUpdateValues(self): + # Initial state + current_value = float(self.config.DEFAULT['default-delta']) + self.assertEqual(self.config.getDefaultDelta(), current_value) + previous_value = current_value + + # First update + current_value = 0.0001 + if current_value == previous_value: + current_value += 0.1 # Ensure previous and current values are not the same + self.config.updateValues({'default-delta': current_value}) + self.assertEqual(self.config.getDefaultDelta(), current_value) + previous_value = current_value + + # Second update + current_value = 0.0578 + # current and previous are already distinct here + self.config.updateValues({'default-delta': current_value}) + self.assertEqual(self.config.getDefaultDelta(), current_value) + + def testLoadFromFile(self): + test_config_path = os.path.join('src', 'test', 'resources', 'input', 'test_config.yml') + self.config = load_from_file(test_config_path) + + # expected values from the YAML file + expected_temporal_scheme = TemporalScheme.EULER + expected_spatial_scheme = SpatialScheme.MUSCL + expected_mesh_file = 'mesh_from_file.geo' + expected_initial_state_file = 'dof_init_from_file.txt' + expected_bathymetry_file = 'bathymetry_from_file.txt' + expected_manning_file = 'manning_from_file.txt' + expected_result_path = 'output_from_file/' + expected_simulation_time = 86400 + expected_delta_to_write = 500 + expected_is_delta_adaptative = False + expected_default_delta = 0.001 + + # assert that the loaded configuration matches the expected values + self.assertEqual(self.config.getTemporalScheme(), expected_temporal_scheme, "Temporal scheme from file is not loaded correctly") + self.assertEqual(self.config.getSpatialScheme(), expected_spatial_scheme, "Spatial scheme from file is not loaded correctly") + self.assertEqual(self.config.getMeshFile(), expected_mesh_file, "Mesh file from file is not loaded correctly") + self.assertEqual(self.config.getInitialStateFile(), expected_initial_state_file, "Initial state file from file is not loaded correctly") + self.assertEqual(self.config.getBathymetryFile(), expected_bathymetry_file, "Bathymetry file from file is not loaded correctly") + self.assertEqual(self.config.getManningFile(), expected_manning_file, "Manning file from file is not loaded correctly") + self.assertEqual(self.config.getResultFilePath(), expected_result_path, "Result path from file is not loaded correctly") + self.assertEqual(self.config.getSimulationTime(), expected_simulation_time, "Simulation time from file is not loaded correctly") + self.assertEqual(self.config.getDeltaToWrite(), expected_delta_to_write, "Delta to write from file is not loaded correctly") + self.assertEqual(self.config.isDeltaAdaptative(), expected_is_delta_adaptative, "Delta adaptative flag from file is not loaded correctly") + self.assertEqual(self.config.getDefaultDelta(), expected_default_delta, "Default delta from file is not loaded correctly") + + +if __name__ == '__main__': + unittest.main() diff --git a/src/test/resources/input/test_config.yml b/src/test/resources/input/test_config.yml new file mode 100644 index 0000000..fe0c96b --- /dev/null +++ b/src/test/resources/input/test_config.yml @@ -0,0 +1,11 @@ +temporal-scheme: euler +spatial-scheme: muscl +mesh-file: mesh_from_file.geo +initial-state-file: dof_init_from_file.txt +bathymetry-file: bathymetry_from_file.txt +manning-file: manning_from_file.txt +result-path: output_from_file/ +simulation-time: 86400 +delta-to-write: 500 +is-delta-adaptative: false +default-delta: 0.001 From da169d79a1f8fd7dfea0052fc2f6af4d5bdacbd4 Mon Sep 17 00:00:00 2001 From: loferga Date: Mon, 25 Aug 2025 11:20:04 +0200 Subject: [PATCH 2/4] Implementation of configuration configuration implementation using yaml parser --- requirements.txt | 1 + .../dassflow2d_py/input/Configuration.py | 79 +++++++++++++++---- 2 files changed, 64 insertions(+), 16 deletions(-) diff --git a/requirements.txt b/requirements.txt index e69de29..55c64f4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -0,0 +1 @@ +PyYAML>=6.0.2 diff --git a/src/main/py/fr/dasshydro/dassflow2d_py/input/Configuration.py b/src/main/py/fr/dasshydro/dassflow2d_py/input/Configuration.py index 1c73285..ff54b72 100644 --- a/src/main/py/fr/dasshydro/dassflow2d_py/input/Configuration.py +++ b/src/main/py/fr/dasshydro/dassflow2d_py/input/Configuration.py @@ -1,4 +1,5 @@ from fr.dasshydro.dassflow2d_py.resolution.ResolutionMethod import TemporalScheme, SpatialScheme +import sys class Configuration: """ @@ -16,51 +17,97 @@ class Configuration: 'bathymetry-file': 'bathymetry.txt', 'manning-file': 'manning.txt', 'result-path': 'output/', - 'simulation-time': '10000', - 'delta-to-write': '100', + 'simulation-time': '10000.0', + 'delta-to-write': '100.0', 'is-delta-adaptative': 'False', 'default-delta': '0.01' } def __init__(self): - raise NotImplementedError("Not yet implemented.") + self.updateValues(self.DEFAULT) def getTemporalScheme(self) -> TemporalScheme: - raise NotImplementedError("Not yet implemented.") + return self.temporal_scheme def getSpatialScheme(self) -> SpatialScheme: - raise NotImplementedError("Not yet implemented.") + return self.spatial_scheme def getMeshFile(self) -> str: - raise NotImplementedError("Not yet implemented.") + return self.mesh_file def getInitialStateFile(self) -> str: - raise NotImplementedError("Not yet implemented.") + return self.initial_state_file def getBathymetryFile(self) -> str: - raise NotImplementedError("Not yet implemented.") + return self.bathymetry_file def getManningFile(self) -> str: - raise NotImplementedError("Not yet implemented.") + return self.manning_file def getResultFilePath(self) -> str: - raise NotImplementedError("Not yet implemented.") + return self.result_path def getSimulationTime(self) -> float: - raise NotImplementedError("Not yet implemented.") + return self.simulation_time def getDeltaToWrite(self) -> float: - raise NotImplementedError("Not yet implemented.") + return self.delta_to_write def isDeltaAdaptative(self) -> bool: - raise NotImplementedError("Not yet implemented.") + return self.is_delta_adaptative def getDefaultDelta(self) -> float: - raise NotImplementedError("Not yet implemented.") + return self.default_delta def updateValues(self, values: dict[str, str]): - raise NotImplementedError("Not yet implemented.") + if 'temporal-scheme' in values: + self.temporal_scheme = TemporalScheme(values['temporal-scheme']) + if 'spatial-scheme' in values: + self.spatial_scheme = SpatialScheme(values['spatial-scheme']) + + if 'mesh-file' in values: + self.mesh_file = values['mesh-file'] + + if 'initial-state-file' in values: + self.initial_state_file = values['initial-state-file'] + + if 'bathymetry-file' in values: + self.bathymetry_file = values['bathymetry-file'] + + if 'manning-file' in values: + self.manning_file = values['manning-file'] + + if 'result-path' in values: + self.result_path = values['result-path'] + + if 'simulation-time' in values: + self.simulation_time = float(values['simulation-time']) + + if 'delta-to-write' in values: + self.delta_to_write = float(values['delta-to-write']) + + if 'is-delta-adaptative' in values: + self.is_delta_adaptative = bool(values['is-delta-adaptative']) + + if 'default-delta' in values: + self.default_delta = float(values['default-delta']) + + +import yaml def load_from_file(file_path: str) -> Configuration: - raise NotImplementedError("Not yet implemented.") + """ + Load configuration values from a YAML file and return a Configuration object. + :param str file_path: configuration yaml file path + :return: An instance of Configuration with values updated to match configuration yaml file content + :rtype: Configuration + """ + config = Configuration() + + with open(file_path, 'r') as file: + yaml_data = yaml.safe_load(file) + + config.updateValues(yaml_data) + + return config From 49fbdf2e7cc3eeb097d1df7318453867485a1ea2 Mon Sep 17 00:00:00 2001 From: Laforge <90221120+loferga@users.noreply.github.com> Date: Mon, 25 Aug 2025 11:28:09 +0200 Subject: [PATCH 3/4] Adds mypy imports for type checking add the necessary installation for optional type stub packages, only needed for mypy to run properly and type check --- .github/workflows/python-app.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml index 01b8ed9..b02ffc5 100644 --- a/.github/workflows/python-app.yml +++ b/.github/workflows/python-app.yml @@ -29,6 +29,7 @@ jobs: python -m pip install --upgrade pip pip install flake8 pytest mypy if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + mypy --install-types --non-interactive . - name: Lint with flake8 run: | @@ -43,4 +44,4 @@ jobs: - name: Test with pytest run: | - pytest \ No newline at end of file + pytest From 9f22b66306f2e9224aaaab1196c8e1bf02943b7e Mon Sep 17 00:00:00 2001 From: loferga Date: Fri, 12 Sep 2025 11:40:04 +0200 Subject: [PATCH 4/4] Fix import and outdated info adds missing import (OutputMode) and update the value of 'spatial-scheme' in the DEFAULT dictionary from 'first' to 'hllc' --- src/main/py/fr/dasshydro/dassflow2d_py/input/Configuration.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/py/fr/dasshydro/dassflow2d_py/input/Configuration.py b/src/main/py/fr/dasshydro/dassflow2d_py/input/Configuration.py index 41b36e0..479f204 100644 --- a/src/main/py/fr/dasshydro/dassflow2d_py/input/Configuration.py +++ b/src/main/py/fr/dasshydro/dassflow2d_py/input/Configuration.py @@ -1,5 +1,5 @@ from fr.dasshydro.dassflow2d_py.resolution.ResolutionMethod import TemporalScheme, SpatialScheme -import sys +from fr.dasshydro.dassflow2d_py.output.ResultWriter import OutputMode class Configuration: """ @@ -11,7 +11,7 @@ class Configuration: # Define default values and valid namespaces at the same time DEFAULT = { 'temporal-scheme': 'euler', - 'spatial-scheme': 'first', + 'spatial-scheme': 'hllc', 'mesh-file': 'mesh.geo', 'initial-state-file': 'dof_init.txt', 'bathymetry-file': 'bathymetry.txt',