Loading docs/changelog.md +4 −0 Original line number Diff line number Diff line # Change log ## v3.0.1 (06-7-2026) - Added pressureDifferenceGradient as property. - Implemented detailed SDE classes ## v3.0.0 (20-3-2026) A big update on the API of pythermogis. The input to run a doublet simulation is now all well defined on the Python side. With the new UTCSettings, Aquifer/StochasticAquifer and ThermoGISDoublet classes, Loading pythermogis/doublet.py +11 −7 Original line number Diff line number Diff line Loading @@ -220,7 +220,10 @@ class ThermoGISDoublet: output_arrays = xr.apply_ufunc( _run_doublet_at_location, *fields, kwargs={"utc_input": self.settings.to_java(), "mask_value": mask_value}, kwargs={ "utc_input": self.settings.to_java(), "mask_value": mask_value, }, dask="parallelized", input_core_dims=[[], [], [], [], [], [], [], []], output_core_dims=[[], [], [], [], [], [], [], [], [], [], [], [], [], []], Loading Loading @@ -378,15 +381,16 @@ def _run_doublet_at_location( return (mask_value,) * 14 hprod = results.hprod() utc_cut = ( utc_input.utcCutoffDeep() if depth > utc_input.utcDeepDepth() else utc_input.utcCutoff() power = results.power() utc_cut = float( JClass("thermogis.parameters.dataclasses.CutoffClass").lookupCutoffValue( utc_input.cutoffClasses(), float(depth), float(power) ) ) npv = 1e-6 * (utc_cut - results.utc()) * 3.6 * hprod * (1 - utc_input.taxRate()) return ( results.power(), power, results.hppower(), results.capex(), results.opex(), Loading pythermogis/resources/thermogis-1.7.0-pythermogis.jar LFS (134 B) File changed.No diff preview for this file type. View original file View changed file pythermogis/settings.py +76 −4 Original line number Diff line number Diff line from __future__ import annotations from dataclasses import dataclass from dataclasses import dataclass, field from typing import TYPE_CHECKING from jpype import JClass Loading @@ -9,6 +9,50 @@ if TYPE_CHECKING: from pathlib import Path @dataclass class CutoffClass: """A depth- and power-based UTC cutoff band. Attributes ---------- min_depth : float Lower depth bound [m]. max_depth : float Upper depth bound [m]. min_power : float Lower power bound [MW]. max_power : float Upper power bound [MW]. cutoff : float UTC cutoff value for this band [ct kWh⁻¹]. """ min_depth: float max_depth: float min_power: float max_power: float cutoff: float @staticmethod def lookup_cutoff_value( cutoff_classes: list[CutoffClass], depth: float, power: float ) -> float: """Return the cutoff for the first matching depth/power band, or 0.0.""" for c in cutoff_classes: if c.min_depth < depth < c.max_depth and c.min_power < power < c.max_power: return c.cutoff return 0.0 def _default_cutoff_classes() -> list[CutoffClass]: return [ CutoffClass(500, 1500, 0, 99999, 10.75), CutoffClass(1500, 4000, 0, 12, 7.99), CutoffClass(1500, 4000, 12, 20, 6.96), CutoffClass(1500, 4000, 20, 99999, 6.27), ] @dataclass class UTCSettings: """ Loading Loading @@ -105,6 +149,10 @@ class UTCSettings: Unit: bar Description: Max pressure pressure_difference_gradient: unit: - Description: utc_slope_tolerance: Unit: - Description: Loading @@ -121,6 +169,11 @@ class UTCSettings: Unit: mD m Description: cutoff_classes: Description: List of depth- and power-based UTC cutoff bands. Each band defines a depth range, a power range, and the corresponding UTC cutoff value [ct kWh⁻¹]. Defaults match ``CutoffClassDefaults`` on the Java side. doublet_anisotropy: Unit: - Description: Loading Loading @@ -326,11 +379,12 @@ class UTCSettings: hydraulic_gradient: float = 0.105 min_pump: float = 1.0 max_pump: float = 300.0 pressure_difference_gradient: float = 0.135 utc_slope_tolerance: float = 0.0 temperature_gradient: float = 31.0 surface_temperature: float = 10.0 kh_cutoff: float = 1.0 utc_cutoff: float = 5.1 cutoff_classes: list[CutoffClass] = field(default_factory=_default_cutoff_classes) doublet_anisotropy: float = 1.0 surface_salinity: float = 0.0 salinity_gradient: float = 46.67 Loading Loading @@ -419,11 +473,21 @@ class UTCSettings: hydraulic_gradient=float(java_settings.getHydraulicGradient()), min_pump=float(java_settings.getMinPump()), max_pump=float(java_settings.getMaxPump()), utc_cutoff=float(java_settings.getUtcCutoff()), pressure_difference_gradient=float(java_settings.getPressureDifferenceGradient()), utc_slope_tolerance=float(java_settings.getUtcSlopeTolerance()), temperature_gradient=float(java_settings.getTemperatureGradient()), surface_temperature=float(java_settings.getSurfaceTemperature()), kh_cutoff=float(java_settings.getKhCutoff()), cutoff_classes=[ CutoffClass( min_depth=float(jc.minDepth()), max_depth=float(jc.maxDepth()), min_power=float(jc.minPower()), max_power=float(jc.maxpower()), cutoff=float(jc.cutoff()), ) for jc in java_settings.getCutoffClasses() ], doublet_anisotropy=float(java_settings.getDoubletAnisotropy()), surface_salinity=float(java_settings.getSurfaceSalinity()), salinity_gradient=float(java_settings.getSalinityGradient()), Loading Loading @@ -505,11 +569,19 @@ class UTCSettings: java_settings.setHydraulicGradient(self.hydraulic_gradient) java_settings.setMinPump(self.min_pump) java_settings.setMaxPump(self.max_pump) java_settings.setPressureDifferenceGradient(self.pressure_difference_gradient) java_settings.setUtcSlopeTolerance(self.utc_slope_tolerance) java_settings.setTemperatureGradient(self.temperature_gradient) java_settings.setSurfaceTemperature(self.surface_temperature) java_settings.setKhCutoff(self.kh_cutoff) java_settings.setUtcCutoff(self.utc_cutoff) JavaCutoffClass = JClass("thermogis.parameters.dataclasses.CutoffClass") JavaArrayList = JClass("java.util.ArrayList") java_cutoff_list = JavaArrayList() for c in self.cutoff_classes: java_cutoff_list.add( JavaCutoffClass(c.min_depth, c.max_depth, c.min_power, c.max_power, c.cutoff) ) java_settings.setCutoffClasses(java_cutoff_list) java_settings.setDoubletAnisotropy(self.doublet_anisotropy) java_settings.setSurfaceSalinity(self.surface_salinity) java_settings.setSalinityGradient(self.salinity_gradient) Loading tests/resources/test_benchmark_output/doublet/HP/simplified__cop_P10_HP.nc (9.19 KiB) File changed.No diff preview for this file type. View original file View changed file Loading
docs/changelog.md +4 −0 Original line number Diff line number Diff line # Change log ## v3.0.1 (06-7-2026) - Added pressureDifferenceGradient as property. - Implemented detailed SDE classes ## v3.0.0 (20-3-2026) A big update on the API of pythermogis. The input to run a doublet simulation is now all well defined on the Python side. With the new UTCSettings, Aquifer/StochasticAquifer and ThermoGISDoublet classes, Loading
pythermogis/doublet.py +11 −7 Original line number Diff line number Diff line Loading @@ -220,7 +220,10 @@ class ThermoGISDoublet: output_arrays = xr.apply_ufunc( _run_doublet_at_location, *fields, kwargs={"utc_input": self.settings.to_java(), "mask_value": mask_value}, kwargs={ "utc_input": self.settings.to_java(), "mask_value": mask_value, }, dask="parallelized", input_core_dims=[[], [], [], [], [], [], [], []], output_core_dims=[[], [], [], [], [], [], [], [], [], [], [], [], [], []], Loading Loading @@ -378,15 +381,16 @@ def _run_doublet_at_location( return (mask_value,) * 14 hprod = results.hprod() utc_cut = ( utc_input.utcCutoffDeep() if depth > utc_input.utcDeepDepth() else utc_input.utcCutoff() power = results.power() utc_cut = float( JClass("thermogis.parameters.dataclasses.CutoffClass").lookupCutoffValue( utc_input.cutoffClasses(), float(depth), float(power) ) ) npv = 1e-6 * (utc_cut - results.utc()) * 3.6 * hprod * (1 - utc_input.taxRate()) return ( results.power(), power, results.hppower(), results.capex(), results.opex(), Loading
pythermogis/resources/thermogis-1.7.0-pythermogis.jar LFS (134 B) File changed.No diff preview for this file type. View original file View changed file
pythermogis/settings.py +76 −4 Original line number Diff line number Diff line from __future__ import annotations from dataclasses import dataclass from dataclasses import dataclass, field from typing import TYPE_CHECKING from jpype import JClass Loading @@ -9,6 +9,50 @@ if TYPE_CHECKING: from pathlib import Path @dataclass class CutoffClass: """A depth- and power-based UTC cutoff band. Attributes ---------- min_depth : float Lower depth bound [m]. max_depth : float Upper depth bound [m]. min_power : float Lower power bound [MW]. max_power : float Upper power bound [MW]. cutoff : float UTC cutoff value for this band [ct kWh⁻¹]. """ min_depth: float max_depth: float min_power: float max_power: float cutoff: float @staticmethod def lookup_cutoff_value( cutoff_classes: list[CutoffClass], depth: float, power: float ) -> float: """Return the cutoff for the first matching depth/power band, or 0.0.""" for c in cutoff_classes: if c.min_depth < depth < c.max_depth and c.min_power < power < c.max_power: return c.cutoff return 0.0 def _default_cutoff_classes() -> list[CutoffClass]: return [ CutoffClass(500, 1500, 0, 99999, 10.75), CutoffClass(1500, 4000, 0, 12, 7.99), CutoffClass(1500, 4000, 12, 20, 6.96), CutoffClass(1500, 4000, 20, 99999, 6.27), ] @dataclass class UTCSettings: """ Loading Loading @@ -105,6 +149,10 @@ class UTCSettings: Unit: bar Description: Max pressure pressure_difference_gradient: unit: - Description: utc_slope_tolerance: Unit: - Description: Loading @@ -121,6 +169,11 @@ class UTCSettings: Unit: mD m Description: cutoff_classes: Description: List of depth- and power-based UTC cutoff bands. Each band defines a depth range, a power range, and the corresponding UTC cutoff value [ct kWh⁻¹]. Defaults match ``CutoffClassDefaults`` on the Java side. doublet_anisotropy: Unit: - Description: Loading Loading @@ -326,11 +379,12 @@ class UTCSettings: hydraulic_gradient: float = 0.105 min_pump: float = 1.0 max_pump: float = 300.0 pressure_difference_gradient: float = 0.135 utc_slope_tolerance: float = 0.0 temperature_gradient: float = 31.0 surface_temperature: float = 10.0 kh_cutoff: float = 1.0 utc_cutoff: float = 5.1 cutoff_classes: list[CutoffClass] = field(default_factory=_default_cutoff_classes) doublet_anisotropy: float = 1.0 surface_salinity: float = 0.0 salinity_gradient: float = 46.67 Loading Loading @@ -419,11 +473,21 @@ class UTCSettings: hydraulic_gradient=float(java_settings.getHydraulicGradient()), min_pump=float(java_settings.getMinPump()), max_pump=float(java_settings.getMaxPump()), utc_cutoff=float(java_settings.getUtcCutoff()), pressure_difference_gradient=float(java_settings.getPressureDifferenceGradient()), utc_slope_tolerance=float(java_settings.getUtcSlopeTolerance()), temperature_gradient=float(java_settings.getTemperatureGradient()), surface_temperature=float(java_settings.getSurfaceTemperature()), kh_cutoff=float(java_settings.getKhCutoff()), cutoff_classes=[ CutoffClass( min_depth=float(jc.minDepth()), max_depth=float(jc.maxDepth()), min_power=float(jc.minPower()), max_power=float(jc.maxpower()), cutoff=float(jc.cutoff()), ) for jc in java_settings.getCutoffClasses() ], doublet_anisotropy=float(java_settings.getDoubletAnisotropy()), surface_salinity=float(java_settings.getSurfaceSalinity()), salinity_gradient=float(java_settings.getSalinityGradient()), Loading Loading @@ -505,11 +569,19 @@ class UTCSettings: java_settings.setHydraulicGradient(self.hydraulic_gradient) java_settings.setMinPump(self.min_pump) java_settings.setMaxPump(self.max_pump) java_settings.setPressureDifferenceGradient(self.pressure_difference_gradient) java_settings.setUtcSlopeTolerance(self.utc_slope_tolerance) java_settings.setTemperatureGradient(self.temperature_gradient) java_settings.setSurfaceTemperature(self.surface_temperature) java_settings.setKhCutoff(self.kh_cutoff) java_settings.setUtcCutoff(self.utc_cutoff) JavaCutoffClass = JClass("thermogis.parameters.dataclasses.CutoffClass") JavaArrayList = JClass("java.util.ArrayList") java_cutoff_list = JavaArrayList() for c in self.cutoff_classes: java_cutoff_list.add( JavaCutoffClass(c.min_depth, c.max_depth, c.min_power, c.max_power, c.cutoff) ) java_settings.setCutoffClasses(java_cutoff_list) java_settings.setDoubletAnisotropy(self.doublet_anisotropy) java_settings.setSurfaceSalinity(self.surface_salinity) java_settings.setSalinityGradient(self.salinity_gradient) Loading
tests/resources/test_benchmark_output/doublet/HP/simplified__cop_P10_HP.nc (9.19 KiB) File changed.No diff preview for this file type. View original file View changed file