From a86b47714b51bb243c7b3a287ebad5eda0d5c964 Mon Sep 17 00:00:00 2001 From: bretth Date: Thu, 4 Dec 2025 09:31:38 +0100 Subject: [PATCH 1/4] Figuring out the input limtis of the simulation --- .../deterministic_doublet.py | 8 +++- src/pythermogis/thermogis_classes/doublet.py | 23 ++++----- tests/test_define_calculation_limits.py | 48 +++++++++++++++++++ 3 files changed, 63 insertions(+), 16 deletions(-) create mode 100644 tests/test_define_calculation_limits.py diff --git a/src/pythermogis/doublet_simulation/deterministic_doublet.py b/src/pythermogis/doublet_simulation/deterministic_doublet.py index 02c75b5..98282eb 100644 --- a/src/pythermogis/doublet_simulation/deterministic_doublet.py +++ b/src/pythermogis/doublet_simulation/deterministic_doublet.py @@ -6,8 +6,12 @@ import xarray as xr from pythermogis import simulate_doublet from pythermogis.dask_utils.auto_chunk import auto_chunk_dataset -from pythermogis.physics.temperature_grid_calculation import calculate_temperature_from_gradient -from pythermogis.thermogis_classes.utc_properties import instantiate_utc_properties_builder +from pythermogis.physics.temperature_grid_calculation import ( + calculate_temperature_from_gradient, +) +from pythermogis.thermogis_classes.utc_properties import ( + instantiate_utc_properties_builder, +) def calculate_doublet_performance(reservoir_properties: xr.Dataset, utc_properties = None, rng_seed: int = None, chunk_size: int = None, print_execution_duration: bool = False, mask_value: float = np.nan) -> xr.Dataset: diff --git a/src/pythermogis/thermogis_classes/doublet.py b/src/pythermogis/thermogis_classes/doublet.py index c82e3fe..f9ca1b7 100644 --- a/src/pythermogis/thermogis_classes/doublet.py +++ b/src/pythermogis/thermogis_classes/doublet.py @@ -119,13 +119,13 @@ def calculate_performance_of_single_location(mask: float, depth: float, thicknes ) # The Java routine which calculates DoubletPerformance, for more detail on the simulation inspect the Java source code - results = doublet.calculateDoubletPerformance(input) - - # If calculation was not successful, return mask value - if results is None: + try: + results = doublet.calculateDoubletPerformance(input) + except: return (mask_value,) * 14 - if results.utc() == -9999.0: + # If calculation was not successful, return mask value + if results is None or results.utc() == -9999.0: return (mask_value,) * 14 # calculate net-present-value using the utc-cutoffs @@ -167,15 +167,10 @@ def validate_input(depth: float, transmissivity: float, transmissivity_with_ntg: float, ) -> bool: - if np.any(np.isnan([depth, - ntg, - porosity, - temperature, - thickness, - transmissivity, - transmissivity_with_ntg])): - return False - return True + """ + Check that none of the input is nan + """ + return not np.any(np.isnan([depth, ntg, porosity, temperature, thickness, transmissivity, transmissivity_with_ntg])) def instantiate_thermogis_doublet(utc_properties, rng_seed: int = None) -> JClass: """ diff --git a/tests/test_define_calculation_limits.py b/tests/test_define_calculation_limits.py new file mode 100644 index 0000000..b07029f --- /dev/null +++ b/tests/test_define_calculation_limits.py @@ -0,0 +1,48 @@ +from pathlib import Path + +import numpy as np +import xarray as xr + +from pythermogis import calculate_doublet_performance + +test_files_path = Path(__file__).parent / "resources" + +def print_min_max(variable: xr.DataArray): + print(f"{variable.name}, {np.min(variable):.2f}, {np.max(variable):.2f}") + +def test_define_calculation_limits(): + recalculate_results = True + if recalculate_results: + # generate simulation samples across desired reservoir properties + Nsamples = 1000 + thickness_samples = np.random.uniform(low=1, high=10e3, size=Nsamples) + porosity_samples = np.random.uniform(low=0.01, high=0.99, size=Nsamples) + ntg_samples = np.random.uniform(low=0.01, high=0.99, size=Nsamples) + depth_samples = np.random.uniform(low=1, high=10e3, size=Nsamples) + permeability_samples = np.random.uniform(low=1, high=10e3, size=Nsamples) + reservoir_properties = xr.Dataset( + { + "thickness": (["sample"], thickness_samples), + "porosity": (["sample"], porosity_samples), + "ntg": (["sample"], ntg_samples), + "depth": (["sample"], depth_samples), + "permeability": (["sample"], permeability_samples), + }, + coords={"sample": np.arange(Nsamples)}, + ) + + results = calculate_doublet_performance( + reservoir_properties, + chunk_size=100, + print_execution_duration=True + ) + results.to_netcdf(test_files_path / "calculation_limits_result.nc") + else: + results = xr.load_dataset(test_files_path / "calculation_limits_result.nc") + + # drop the values which returned nan: + results = results.dropna(dim="sample", subset=["power"]) + + # print the min and max values of all the inputs + for var in results: + print_min_max(results[var]) \ No newline at end of file -- GitLab From a2d37704150879eaf3f419e83a9ca126f7491d2b Mon Sep 17 00:00:00 2001 From: bretth Date: Thu, 4 Dec 2025 10:02:50 +0100 Subject: [PATCH 2/4] Adding a test that prints out the minimum and maximum successful model runs --- tests/test_define_calculation_limits.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_define_calculation_limits.py b/tests/test_define_calculation_limits.py index b07029f..0295f3e 100644 --- a/tests/test_define_calculation_limits.py +++ b/tests/test_define_calculation_limits.py @@ -11,7 +11,7 @@ def print_min_max(variable: xr.DataArray): print(f"{variable.name}, {np.min(variable):.2f}, {np.max(variable):.2f}") def test_define_calculation_limits(): - recalculate_results = True + recalculate_results = False if recalculate_results: # generate simulation samples across desired reservoir properties Nsamples = 1000 @@ -44,5 +44,5 @@ def test_define_calculation_limits(): results = results.dropna(dim="sample", subset=["power"]) # print the min and max values of all the inputs - for var in results: + for var in ["thickness", "porosity", "ntg", "depth", "permeability", "temperature"]: print_min_max(results[var]) \ No newline at end of file -- GitLab From 386c466864e61f0c08203bc0d914c6f1a15b559f Mon Sep 17 00:00:00 2001 From: bretth Date: Thu, 4 Dec 2025 10:03:44 +0100 Subject: [PATCH 3/4] Adding a test that prints out the minimum and maximum successful model runs --- tests/test_define_calculation_limits.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_define_calculation_limits.py b/tests/test_define_calculation_limits.py index 0295f3e..00dce08 100644 --- a/tests/test_define_calculation_limits.py +++ b/tests/test_define_calculation_limits.py @@ -4,12 +4,14 @@ import numpy as np import xarray as xr from pythermogis import calculate_doublet_performance +import pytest test_files_path = Path(__file__).parent / "resources" def print_min_max(variable: xr.DataArray): print(f"{variable.name}, {np.min(variable):.2f}, {np.max(variable):.2f}") +@pytest.mark.skip("Useful for understanding the range of possible input values, not for pipeline testing") def test_define_calculation_limits(): recalculate_results = False if recalculate_results: -- GitLab From 4c3151d9892bf48479f2fcbaf4c32814a74ffcb2 Mon Sep 17 00:00:00 2001 From: bretth Date: Thu, 4 Dec 2025 10:13:20 +0100 Subject: [PATCH 4/4] Reorganising the tests --- .../test_define_calculation_limits.py | 2 +- .../{ => documentation}/test_doc_examples.py | 13 ++++++------ .../test_mkdown_utctable.py | 21 +++++++++---------- .../test_ThermoGISDoublet_Benchmark.py | 0 tests/{ => java}/test_java_installation.py | 0 tests/{ => java}/test_utc_properties.py | 3 +-- .../test_dask_parralelization.py | 2 +- tests/{ => performance}/test_doublet_speed.py | 6 +++--- .../test_transmissivity_calculation.py | 3 +-- .../test_deterministic_doublet.py | 0 .../test_pythermogis_doublet_benchmark.py | 0 .../test_thermogis_scenarios.py | 14 +++++++------ 12 files changed, 31 insertions(+), 33 deletions(-) rename tests/{ => documentation}/test_define_calculation_limits.py (97%) rename tests/{ => documentation}/test_doc_examples.py (96%) rename tests/{ => documentation}/test_mkdown_utctable.py (58%) rename tests/{ => java}/test_ThermoGISDoublet_Benchmark.py (100%) rename tests/{ => java}/test_java_installation.py (100%) rename tests/{ => java}/test_utc_properties.py (94%) rename tests/{ => performance}/test_dask_parralelization.py (93%) rename tests/{ => performance}/test_doublet_speed.py (91%) rename tests/{ => physics}/test_transmissivity_calculation.py (98%) rename tests/{ => simulation}/test_deterministic_doublet.py (100%) rename tests/{ => simulation}/test_pythermogis_doublet_benchmark.py (100%) rename tests/{ => simulation}/test_thermogis_scenarios.py (92%) diff --git a/tests/test_define_calculation_limits.py b/tests/documentation/test_define_calculation_limits.py similarity index 97% rename from tests/test_define_calculation_limits.py rename to tests/documentation/test_define_calculation_limits.py index 00dce08..1a9effd 100644 --- a/tests/test_define_calculation_limits.py +++ b/tests/documentation/test_define_calculation_limits.py @@ -6,7 +6,7 @@ import xarray as xr from pythermogis import calculate_doublet_performance import pytest -test_files_path = Path(__file__).parent / "resources" +test_files_path = Path(__file__).parent.parent / "resources" def print_min_max(variable: xr.DataArray): print(f"{variable.name}, {np.min(variable):.2f}, {np.max(variable):.2f}") diff --git a/tests/test_doc_examples.py b/tests/documentation/test_doc_examples.py similarity index 96% rename from tests/test_doc_examples.py rename to tests/documentation/test_doc_examples.py index faa28fd..b8e9425 100644 --- a/tests/test_doc_examples.py +++ b/tests/documentation/test_doc_examples.py @@ -68,7 +68,7 @@ def test_example_5(): from matplotlib import pyplot as plt from pathlib import Path from os import path - output_data_path = Path(path.dirname(__file__), "resources") / "test_output" / "example_data" + output_data_path = Path(__file__).parent.parent / "resources" / "test_output" / "example_data" output_data_path.mkdir(parents=True, exist_ok=True) input_data = xr.Dataset({ @@ -108,10 +108,10 @@ def test_example_6(): from os import path # the location of the input data: the data can be found in the resources/example_data directory of the repo - input_data_path = Path(path.dirname(__file__), "resources") / "test_input" / "example_data" + input_data_path = Path(__file__).parent.parent / "resources" / "test_input" / "example_data" # create a directory to write the output files to - output_data_path = Path(path.dirname(__file__), "resources") / "test_output" / "example_data" + output_data_path = Path(__file__).parent.parent / "resources" / "test_output" / "example_data" output_data_path.mkdir(parents=True, exist_ok=True) # if set to True then simulation is always run, otherwise pre-calculated results are read (if available) @@ -176,10 +176,9 @@ def test_example_7(): import numpy as np import xarray as xr from pathlib import Path - from os import path - input_data_path = Path(path.dirname(__file__), "resources") / "test_input" / "example_data" - output_data_path = Path(path.dirname(__file__), "resources") / "test_output" / "example_data" + input_data_path = Path(__file__).parent.parent / "resources" / "test_input" / "example_data" + output_data_path = Path(__file__).parent.parent / "resources" / "test_output" / "example_data" output_data_path.mkdir(parents=True, exist_ok=True) # read in reservoir property maps @@ -276,7 +275,7 @@ def test_example8(): # output directory to write output to - output_data_path = Path(path.dirname(__file__), "resources") / "test_output" / "exceedance_example" + output_data_path = Path(__file__).parent.parent / "resources" / "test_output" / "exceedance_example" output_data_path.mkdir(parents=True, exist_ok=True) # generate simulation samples across desired reservoir properties diff --git a/tests/test_mkdown_utctable.py b/tests/documentation/test_mkdown_utctable.py similarity index 58% rename from tests/test_mkdown_utctable.py rename to tests/documentation/test_mkdown_utctable.py index 3cbdac1..07d91f7 100644 --- a/tests/test_mkdown_utctable.py +++ b/tests/documentation/test_mkdown_utctable.py @@ -1,13 +1,12 @@ -from os import path from pythermogis import * # Create the Markdown table -scenarios_file_path = Path(path.dirname(__file__), "resources") / "test_input" / "scenarios" +scenarios_file_path = Path(__file__).parent.parent / "resources" / "test_input" / "scenarios" def test_markdown_table(): # create correspondence table with xml names scenario_files = { - "TG basecase": path.join(scenarios_file_path, "doublet_techno-econ_basecase.xml") + "TG basecase": scenarios_file_path / "doublet_techno-econ_basecase.xml" } scenarios_data = {name: xml_to_dict(file) for name, file in scenario_files.items()} comparison_table = create_comparison_table(scenarios_data, skipparametername=False) @@ -17,10 +16,10 @@ def test_markdown_table(): def test_markdown_table_TG(): scenario_files = { - "TG basecase": path.join(scenarios_file_path , "doublet_techno-econ_basecase.xml"), - "TG HP": path.join(scenarios_file_path ,"doublet_techno-econ_HP.xml"), - "TG STIM": path.join(scenarios_file_path , "doublet_techno-econ_STIM.xml"), - "TG STIM HP": path.join(scenarios_file_path , "doublet_techno-econ_STIM_HP.xml"), + "TG basecase": scenarios_file_path / "doublet_techno-econ_basecase.xml", + "TG HP": scenarios_file_path / "doublet_techno-econ_HP.xml", + "TG STIM": scenarios_file_path / "doublet_techno-econ_STIM.xml", + "TG STIM HP": scenarios_file_path / "doublet_techno-econ_STIM_HP.xml", } scenarios_data = {name: xml_to_dict(file) for name, file in scenario_files.items()} # Create the comparison table @@ -32,10 +31,10 @@ def test_markdown_table_TG(): def test_markdown_table_GA4A(): scenario_files = { - "Direct Heat": path.join(scenarios_file_path, "ga4a_directheat_new_config.xml"), - "Direct Heat HP": path.join(scenarios_file_path, "ga4a_directheatHP_new_config.xml"), - "Chill": path.join(scenarios_file_path, "ga4a_chiller_new_config.xml"), - "ORC": path.join(scenarios_file_path, "ga4a_ORC_new_config.xml") + "Direct Heat": scenarios_file_path / "ga4a_directheat_new_config.xml", + "Direct Heat HP": scenarios_file_path / "ga4a_directheatHP_new_config.xml", + "Chill": scenarios_file_path / "ga4a_chiller_new_config.xml", + "ORC": scenarios_file_path / "ga4a_ORC_new_config.xml" } scenarios_data = {name: xml_to_dict(file) for name, file in scenario_files.items()}; # Create the comparison table diff --git a/tests/test_ThermoGISDoublet_Benchmark.py b/tests/java/test_ThermoGISDoublet_Benchmark.py similarity index 100% rename from tests/test_ThermoGISDoublet_Benchmark.py rename to tests/java/test_ThermoGISDoublet_Benchmark.py diff --git a/tests/test_java_installation.py b/tests/java/test_java_installation.py similarity index 100% rename from tests/test_java_installation.py rename to tests/java/test_java_installation.py diff --git a/tests/test_utc_properties.py b/tests/java/test_utc_properties.py similarity index 94% rename from tests/test_utc_properties.py rename to tests/java/test_utc_properties.py index b8757c8..3a227eb 100644 --- a/tests/test_utc_properties.py +++ b/tests/java/test_utc_properties.py @@ -1,10 +1,9 @@ -from os import path from unittest import TestCase from pythermogis import * class UTCBuilder(TestCase): - scenarios_file_path = Path(path.dirname(__file__), "resources") / "test_input" / "scenarios" + scenarios_file_path = Path(__file__).parent.parent / "resources" / "test_input" / "scenarios" def test_tg_scenario_xmls_parse_and_run(self): # These are the current 2.4 scenario settings, for BaseCase, HP, Stim and HP&Stim diff --git a/tests/test_dask_parralelization.py b/tests/performance/test_dask_parralelization.py similarity index 93% rename from tests/test_dask_parralelization.py rename to tests/performance/test_dask_parralelization.py index 9573cf8..362474a 100644 --- a/tests/test_dask_parralelization.py +++ b/tests/performance/test_dask_parralelization.py @@ -7,7 +7,7 @@ import xarray as xr from pythermogis import auto_chunk_dataset, assess_optimal_chunk_size def test_dask_parralelization(): - output_data_path = Path(path.dirname(__file__), "resources") / "test_output" / "parallelization" + output_data_path = Path(__file__).parent.parent / "resources" / "test_output" / "parallelization" output_data_path.mkdir(parents=True, exist_ok=True) assess_optimal_chunk_size(n_simulations = 100, chunk_step_size=50, plot_outfile = output_data_path / "parallelization.png") diff --git a/tests/test_doublet_speed.py b/tests/performance/test_doublet_speed.py similarity index 91% rename from tests/test_doublet_speed.py rename to tests/performance/test_doublet_speed.py index b9da7a4..1a9051e 100644 --- a/tests/test_doublet_speed.py +++ b/tests/performance/test_doublet_speed.py @@ -8,8 +8,8 @@ from pythermogis import * class PyThermoGIS(TestCase): - test_files_path = Path(path.dirname(__file__), "resources") / "test_input" / "example_data" - test_files_out_path = Path(path.dirname(__file__), "resources") / "test_output" / "example_data" + test_files_path = Path(__file__).parent.parent / "resources" / "test_input" / "example_data" + test_files_out_path = Path(__file__).parent.parent / "resources" / "test_output" / "example_data" def setUp(self): if self.test_files_out_path.exists(): @@ -21,7 +21,7 @@ class PyThermoGIS(TestCase): def test_doublet_speed(self): input_grids = self.read_input_grids() - p_values = [99] + p_values = [50] data = input_grids["thickness_mean"].data.flatten() non_nan_data = data[~np.isnan(data)] diff --git a/tests/test_transmissivity_calculation.py b/tests/physics/test_transmissivity_calculation.py similarity index 98% rename from tests/test_transmissivity_calculation.py rename to tests/physics/test_transmissivity_calculation.py index ac4e08c..101c521 100644 --- a/tests/test_transmissivity_calculation.py +++ b/tests/physics/test_transmissivity_calculation.py @@ -7,8 +7,7 @@ import matplotlib.pyplot as plt from pythermogis import * class PyThermoGIS(TestCase): - test_files_out_path = Path(path.dirname(path.dirname(__file__)), "tests", "resources") / "test_output" - + test_files_out_path = Path(__file__).parent.parent / "resources" / "test_output" def test_transmissivity_calculation(self): """ diff --git a/tests/test_deterministic_doublet.py b/tests/simulation/test_deterministic_doublet.py similarity index 100% rename from tests/test_deterministic_doublet.py rename to tests/simulation/test_deterministic_doublet.py diff --git a/tests/test_pythermogis_doublet_benchmark.py b/tests/simulation/test_pythermogis_doublet_benchmark.py similarity index 100% rename from tests/test_pythermogis_doublet_benchmark.py rename to tests/simulation/test_pythermogis_doublet_benchmark.py diff --git a/tests/test_thermogis_scenarios.py b/tests/simulation/test_thermogis_scenarios.py similarity index 92% rename from tests/test_thermogis_scenarios.py rename to tests/simulation/test_thermogis_scenarios.py index d5f9f21..ae63b42 100644 --- a/tests/test_thermogis_scenarios.py +++ b/tests/simulation/test_thermogis_scenarios.py @@ -6,12 +6,14 @@ from pygridsio import read_grid from pythermogis import * class PyThermoGIS(TestCase): - test_files_path = Path(path.dirname(__file__), "resources") / "test_input" - test_files_out_path = Path(path.dirname(__file__), "resources") / "test_output" / "doublet" - test_benchmark_output_basecase = Path(path.dirname(__file__), "resources") / "test_benchmark_output" / "doublet" / "basecase" - test_benchmark_output_HP = Path(path.dirname(__file__), "resources") / "test_benchmark_output" / "doublet" / "HP" - test_benchmark_output_STIM = Path(path.dirname(__file__), "resources") / "test_benchmark_output" / "doublet" / "STIM" - test_benchmark_output_HP_STIM = Path(path.dirname(__file__), "resources") / "test_benchmark_output" / "doublet" / "HP_STIM" + resources_path = Path(__file__).parent.parent / "resources" + + test_files_path = resources_path / "test_input" + test_files_out_path = resources_path / "test_output" / "doublet" + test_benchmark_output_basecase = resources_path / "test_benchmark_output" / "doublet" / "basecase" + test_benchmark_output_HP = resources_path / "test_benchmark_output" / "doublet" / "HP" + test_benchmark_output_STIM = resources_path / "test_benchmark_output" / "doublet" / "STIM" + test_benchmark_output_HP_STIM = resources_path / "test_benchmark_output" / "doublet" / "HP_STIM" def setUp(self): if self.test_files_out_path.exists(): -- GitLab