Loading pythermogis/thermogis_classes/doublet.py +47 −44 Original line number Diff line number Diff line Loading @@ -44,8 +44,7 @@ def calculate_performance_of_single_location(mask: float, depth: float, thicknes if not np.isnan(mask): return 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 set_doublet_parameters(doublet, transmissivity_with_ntg, depth, porosity, ntg, temperature, input_params["use_stimulation"], input_params["stimKhMax"], input_params["surface_temperature"], input_params["return_temperature"], input_params["use_heat_pump"], input_params["max_cooling_temperature_range"], input_params["hp_minimum_injection_temperature"]) set_doublet_parameters(doublet, transmissivity_with_ntg, depth, porosity, ntg, temperature, input_params) # The Java routine which calculates DoubletPerformance, for more detail on the simulation inspect the Java source code doublet.calculateDoubletPerformance(-9999.0, thickness, transmissivity) Loading Loading @@ -110,38 +109,14 @@ def calculate_doublet_performance_across_dimensions(input_data: xr.Dataset, """ # Check that all essential variables are provided missing_variables = [] for variable in ["thickness_mean", "thickness_sd", "porosity", "ntg", "depth", "ln_permeability_mean", "ln_permeability_sd"]: if variable not in input_data: missing_variables.append(variable) if len(missing_variables) > 0: raise ValueError(f"provided input Dataset does not contain the following required variables: {missing_variables}") validate_input_data(input_data) # If no p_values provided, calculate only the P50 if p_values is None: p_values = [50.0] # Input parameters input_params_basecase = {"hp_minimum_injection_temperature": 15, "return_temperature": 30, "surface_temperature": 10, "degrees_per_km": 31, "max_cooling_temperature_range": 100, "stimKhMax": 20, "use_stimulation": False, "use_heat_pump": False, "calculate_cop": True, "hp_application_mode": False, "hp_direct_heat_input_temp": 70.0, "utc_cutoff_shallow": 5.1, "utc_cutoff_deep": 6.5, "utc_cutoff_depth": 4000.0, "rng_seed": np.random.randint(low=0, high=10000)} if input_params is None: # If no input_params provided, use the basecase input_params = input_params_basecase else: input_params = {key: input_params.get(key, input_params_basecase[key]) for key in input_params_basecase} # Apply provided input_params; or return the base case input_params = implement_input_params(input_params) # Generate temperature values from gradient if no temperature provided if "temperature" not in input_data: Loading @@ -151,15 +126,9 @@ def calculate_doublet_performance_across_dimensions(input_data: xr.Dataset, if "mask" not in input_data: input_data["mask"] = np.nan # if (props.useHeatPump() & & props.calculateCop() & & !props.hpApplicationMode() ) { # doublet.doubletCalc1DData.setInjectionTemp(doublet.calculateInjectionTempWithHeatPump(temperature, props.hpDirectHeatInputTemp())); # } # Instantiate ThermoGIS doublet doublet = instantiate_thermogis_doublet(input_params) # set injectionTemp differently for heat_pump # Setup output_data dataset output_data = input_data.thickness_mean.copy().to_dataset(name="thickness") output_data = output_data.expand_dims({"p_value": p_values}) Loading Loading @@ -248,6 +217,39 @@ def calculate_doublet_performance_across_dimensions(input_data: xr.Dataset, return output_data def validate_input_data(input_data): missing_variables = [] for variable in ["thickness_mean", "thickness_sd", "porosity", "ntg", "depth", "ln_permeability_mean", "ln_permeability_sd"]: if variable not in input_data: missing_variables.append(variable) if len(missing_variables) > 0: raise ValueError(f"provided input Dataset does not contain the following required variables: {missing_variables}") def implement_input_params(input_params): # Input parameters input_params_basecase = {"hp_minimum_injection_temperature": 15, "return_temperature": 30, "surface_temperature": 10, "degrees_per_km": 31, "max_cooling_temperature_range": 100, "stimKhMax": 20, "use_stimulation": False, "use_heat_pump": False, "calculate_cop": True, "hp_application_mode": False, "hp_direct_heat_input_temp": 70.0, "utc_cutoff_shallow": 5.1, "utc_cutoff_deep": 6.5, "utc_cutoff_depth": 4000.0, "rng_seed": np.random.randint(low=0, high=10000)} if input_params is None: # If no input_params provided, use the basecase input_params = input_params_basecase else: input_params = {key: input_params.get(key, input_params_basecase[key]) for key in input_params_basecase} return input_params def instantiate_thermogis_doublet(input_params): """ Instantiate a ThermoGIS Doublet class, with a set random seed if provided Loading Loading @@ -282,8 +284,7 @@ def instantiate_thermogis_doublet(input_params): return doublet def set_doublet_parameters(doublet, transmissivity_with_ntg, depth, porosity, ntg, temperature, useStimulation, stimKhMax, surface_temperature, return_temperature, use_heat_pump, max_cooling_temperature_range, hp_minimum_injection_temperature): def set_doublet_parameters(doublet, transmissivity_with_ntg, depth, porosity, ntg, temperature, input_params): """ For a single location sets the necessary data on the doublet class, to then run a doublet simulation :param doublet: Loading @@ -301,20 +302,22 @@ def set_doublet_parameters(doublet, transmissivity_with_ntg, depth, porosity, nt :param hp_minimum_injection_temperature: :return: """ if not useStimulation or transmissivity_with_ntg > stimKhMax: if not input_params["use_stimulation"] or transmissivity_with_ntg > input_params["stimKhMax"]: doublet.setNoStimulation() doublet.doubletCalc1DData.setDepth(depth) doublet.doubletCalc1DData.setPorosity(porosity) doublet.doubletCalc1DData.setNtg(ntg) doublet.doubletCalc1DData.setSurfaceTemperature(surface_temperature) doublet.doubletCalc1DData.setSurfaceTemperature(input_params["surface_temperature"]) doublet.doubletCalc1DData.setReservoirTemp(temperature) doublet.doubletCalc1DData.setUseHeatPump(use_heat_pump) doublet.doubletCalc1DData.setUseHeatPump(input_params["use_heat_pump"]) if use_heat_pump: injectionTemp = np.max([temperature - max_cooling_temperature_range, hp_minimum_injection_temperature]) if not ["use_heat_pump"]: injectionTemp = np.max([temperature - input_params["max_cooling_temperature_range"], input_params["return_temperature"]]) elif input_params["use_heat_pump"] and input_params["calculate_cop"] and not input_params["hp_application_mode"]: injectionTemp = doublet.calculateInjectionTempWithHeatPump(temperature, input_params["hp_direct_heat_input_temp"]) else: injectionTemp = np.max([temperature - max_cooling_temperature_range, return_temperature]) injectionTemp = np.max([temperature - input_params["max_cooling_temperature_range"], input_params["hp_minimum_injection_temperature"]]) doublet.doubletCalc1DData.setInjectionTemp(injectionTemp) doublet.doubletCalc1DData.setDhReturnTemp(return_temperature) doublet.doubletCalc1DData.setDhReturnTemp(input_params["return_temperature"]) tests/tests/test_doublet.py +1 −1 Original line number Diff line number Diff line Loading @@ -126,7 +126,7 @@ class PyThermoGIS(TestCase): xr.testing.assert_allclose(output_grids.hprod, read_grid(benchmark_path / f"simplified__hprod_P{p_value}{scenario}.nc"), atol=30000) xr.testing.assert_allclose(output_grids.cop, read_grid(benchmark_path / f"simplified__cop_P{p_value}{scenario}.nc"), atol=1.0) xr.testing.assert_allclose(output_grids.pres, read_grid(benchmark_path / f"simplified__pres_P{p_value}{scenario}.nc"), atol=1.0) xr.testing.assert_allclose(output_grids.flow_rate, read_grid(benchmark_path / f"simplified__flowr_P{p_value}{scenario}.nc"), atol=3.0) xr.testing.assert_allclose(output_grids.flow_rate, read_grid(benchmark_path / f"simplified__flowr_P{p_value}{scenario}.nc"), atol=3.5) xr.testing.assert_allclose(output_grids.welld, read_grid(benchmark_path / f"simplified__welld_P{p_value}{scenario}.nc"), atol=20) def read_input_grids(self): Loading Loading
pythermogis/thermogis_classes/doublet.py +47 −44 Original line number Diff line number Diff line Loading @@ -44,8 +44,7 @@ def calculate_performance_of_single_location(mask: float, depth: float, thicknes if not np.isnan(mask): return 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 set_doublet_parameters(doublet, transmissivity_with_ntg, depth, porosity, ntg, temperature, input_params["use_stimulation"], input_params["stimKhMax"], input_params["surface_temperature"], input_params["return_temperature"], input_params["use_heat_pump"], input_params["max_cooling_temperature_range"], input_params["hp_minimum_injection_temperature"]) set_doublet_parameters(doublet, transmissivity_with_ntg, depth, porosity, ntg, temperature, input_params) # The Java routine which calculates DoubletPerformance, for more detail on the simulation inspect the Java source code doublet.calculateDoubletPerformance(-9999.0, thickness, transmissivity) Loading Loading @@ -110,38 +109,14 @@ def calculate_doublet_performance_across_dimensions(input_data: xr.Dataset, """ # Check that all essential variables are provided missing_variables = [] for variable in ["thickness_mean", "thickness_sd", "porosity", "ntg", "depth", "ln_permeability_mean", "ln_permeability_sd"]: if variable not in input_data: missing_variables.append(variable) if len(missing_variables) > 0: raise ValueError(f"provided input Dataset does not contain the following required variables: {missing_variables}") validate_input_data(input_data) # If no p_values provided, calculate only the P50 if p_values is None: p_values = [50.0] # Input parameters input_params_basecase = {"hp_minimum_injection_temperature": 15, "return_temperature": 30, "surface_temperature": 10, "degrees_per_km": 31, "max_cooling_temperature_range": 100, "stimKhMax": 20, "use_stimulation": False, "use_heat_pump": False, "calculate_cop": True, "hp_application_mode": False, "hp_direct_heat_input_temp": 70.0, "utc_cutoff_shallow": 5.1, "utc_cutoff_deep": 6.5, "utc_cutoff_depth": 4000.0, "rng_seed": np.random.randint(low=0, high=10000)} if input_params is None: # If no input_params provided, use the basecase input_params = input_params_basecase else: input_params = {key: input_params.get(key, input_params_basecase[key]) for key in input_params_basecase} # Apply provided input_params; or return the base case input_params = implement_input_params(input_params) # Generate temperature values from gradient if no temperature provided if "temperature" not in input_data: Loading @@ -151,15 +126,9 @@ def calculate_doublet_performance_across_dimensions(input_data: xr.Dataset, if "mask" not in input_data: input_data["mask"] = np.nan # if (props.useHeatPump() & & props.calculateCop() & & !props.hpApplicationMode() ) { # doublet.doubletCalc1DData.setInjectionTemp(doublet.calculateInjectionTempWithHeatPump(temperature, props.hpDirectHeatInputTemp())); # } # Instantiate ThermoGIS doublet doublet = instantiate_thermogis_doublet(input_params) # set injectionTemp differently for heat_pump # Setup output_data dataset output_data = input_data.thickness_mean.copy().to_dataset(name="thickness") output_data = output_data.expand_dims({"p_value": p_values}) Loading Loading @@ -248,6 +217,39 @@ def calculate_doublet_performance_across_dimensions(input_data: xr.Dataset, return output_data def validate_input_data(input_data): missing_variables = [] for variable in ["thickness_mean", "thickness_sd", "porosity", "ntg", "depth", "ln_permeability_mean", "ln_permeability_sd"]: if variable not in input_data: missing_variables.append(variable) if len(missing_variables) > 0: raise ValueError(f"provided input Dataset does not contain the following required variables: {missing_variables}") def implement_input_params(input_params): # Input parameters input_params_basecase = {"hp_minimum_injection_temperature": 15, "return_temperature": 30, "surface_temperature": 10, "degrees_per_km": 31, "max_cooling_temperature_range": 100, "stimKhMax": 20, "use_stimulation": False, "use_heat_pump": False, "calculate_cop": True, "hp_application_mode": False, "hp_direct_heat_input_temp": 70.0, "utc_cutoff_shallow": 5.1, "utc_cutoff_deep": 6.5, "utc_cutoff_depth": 4000.0, "rng_seed": np.random.randint(low=0, high=10000)} if input_params is None: # If no input_params provided, use the basecase input_params = input_params_basecase else: input_params = {key: input_params.get(key, input_params_basecase[key]) for key in input_params_basecase} return input_params def instantiate_thermogis_doublet(input_params): """ Instantiate a ThermoGIS Doublet class, with a set random seed if provided Loading Loading @@ -282,8 +284,7 @@ def instantiate_thermogis_doublet(input_params): return doublet def set_doublet_parameters(doublet, transmissivity_with_ntg, depth, porosity, ntg, temperature, useStimulation, stimKhMax, surface_temperature, return_temperature, use_heat_pump, max_cooling_temperature_range, hp_minimum_injection_temperature): def set_doublet_parameters(doublet, transmissivity_with_ntg, depth, porosity, ntg, temperature, input_params): """ For a single location sets the necessary data on the doublet class, to then run a doublet simulation :param doublet: Loading @@ -301,20 +302,22 @@ def set_doublet_parameters(doublet, transmissivity_with_ntg, depth, porosity, nt :param hp_minimum_injection_temperature: :return: """ if not useStimulation or transmissivity_with_ntg > stimKhMax: if not input_params["use_stimulation"] or transmissivity_with_ntg > input_params["stimKhMax"]: doublet.setNoStimulation() doublet.doubletCalc1DData.setDepth(depth) doublet.doubletCalc1DData.setPorosity(porosity) doublet.doubletCalc1DData.setNtg(ntg) doublet.doubletCalc1DData.setSurfaceTemperature(surface_temperature) doublet.doubletCalc1DData.setSurfaceTemperature(input_params["surface_temperature"]) doublet.doubletCalc1DData.setReservoirTemp(temperature) doublet.doubletCalc1DData.setUseHeatPump(use_heat_pump) doublet.doubletCalc1DData.setUseHeatPump(input_params["use_heat_pump"]) if use_heat_pump: injectionTemp = np.max([temperature - max_cooling_temperature_range, hp_minimum_injection_temperature]) if not ["use_heat_pump"]: injectionTemp = np.max([temperature - input_params["max_cooling_temperature_range"], input_params["return_temperature"]]) elif input_params["use_heat_pump"] and input_params["calculate_cop"] and not input_params["hp_application_mode"]: injectionTemp = doublet.calculateInjectionTempWithHeatPump(temperature, input_params["hp_direct_heat_input_temp"]) else: injectionTemp = np.max([temperature - max_cooling_temperature_range, return_temperature]) injectionTemp = np.max([temperature - input_params["max_cooling_temperature_range"], input_params["hp_minimum_injection_temperature"]]) doublet.doubletCalc1DData.setInjectionTemp(injectionTemp) doublet.doubletCalc1DData.setDhReturnTemp(return_temperature) doublet.doubletCalc1DData.setDhReturnTemp(input_params["return_temperature"])
tests/tests/test_doublet.py +1 −1 Original line number Diff line number Diff line Loading @@ -126,7 +126,7 @@ class PyThermoGIS(TestCase): xr.testing.assert_allclose(output_grids.hprod, read_grid(benchmark_path / f"simplified__hprod_P{p_value}{scenario}.nc"), atol=30000) xr.testing.assert_allclose(output_grids.cop, read_grid(benchmark_path / f"simplified__cop_P{p_value}{scenario}.nc"), atol=1.0) xr.testing.assert_allclose(output_grids.pres, read_grid(benchmark_path / f"simplified__pres_P{p_value}{scenario}.nc"), atol=1.0) xr.testing.assert_allclose(output_grids.flow_rate, read_grid(benchmark_path / f"simplified__flowr_P{p_value}{scenario}.nc"), atol=3.0) xr.testing.assert_allclose(output_grids.flow_rate, read_grid(benchmark_path / f"simplified__flowr_P{p_value}{scenario}.nc"), atol=3.5) xr.testing.assert_allclose(output_grids.welld, read_grid(benchmark_path / f"simplified__welld_P{p_value}{scenario}.nc"), atol=20) def read_input_grids(self): Loading