TNO Intern

Commit 6584d1f2 authored by Florian Knappers's avatar Florian Knappers
Browse files

Start of rewriting ThermoGisDoublet in python

parent 2856cbf3
Loading
Loading
Loading
Loading
Loading
+90 −1
Original line number Diff line number Diff line
@@ -140,6 +140,7 @@ environments:
      - conda: https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.17.0-h8a09558_0.conda
      - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.13.8-h4bc477f_0.conda
      - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.1-hb9d3cd8_2.conda
      - conda: https://conda.anaconda.org/conda-forge/linux-64/llvmlite-0.45.1-py313hdd307be_0.conda
      - conda: https://conda.anaconda.org/conda-forge/noarch/locket-1.0.0-pyhd8ed1ab_0.tar.bz2
      - conda: https://conda.anaconda.org/conda-forge/linux-64/lz4-4.4.4-py313h8756d67_0.conda
      - conda: https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.10.0-h5888daf_1.conda
@@ -162,6 +163,7 @@ environments:
      - conda: https://conda.anaconda.org/conda-forge/linux-64/nh3-0.2.21-py39h77e2912_1.conda
      - conda: https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.12.0-h3f2d84a_0.conda
      - conda: https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.9.1-pyhd8ed1ab_1.conda
      - conda: https://conda.anaconda.org/conda-forge/linux-64/numba-0.62.1-py313hd8e3f9f_0.conda
      - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.2.5-py313h17eae1a_0.conda
      - conda: https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.3-h5fbd93e_0.conda
      - conda: https://conda.anaconda.org/conda-forge/linux-64/openpyxl-3.1.5-py313h9c9eb82_1.conda
@@ -371,6 +373,7 @@ environments:
      - conda: https://conda.anaconda.org/conda-forge/win-64/libxcb-1.17.0-h0e4246c_0.conda
      - conda: https://conda.anaconda.org/conda-forge/win-64/libxml2-2.13.8-h442d1da_0.conda
      - conda: https://conda.anaconda.org/conda-forge/win-64/libzlib-1.3.1-h2466b09_2.conda
      - conda: https://conda.anaconda.org/conda-forge/win-64/llvmlite-0.45.1-py313h5c49287_0.conda
      - conda: https://conda.anaconda.org/conda-forge/noarch/locket-1.0.0-pyhd8ed1ab_0.tar.bz2
      - conda: https://conda.anaconda.org/conda-forge/win-64/lz4-4.4.4-py313h05901a4_0.conda
      - conda: https://conda.anaconda.org/conda-forge/win-64/lz4-c-1.10.0-h2466b09_1.conda
@@ -392,6 +395,7 @@ environments:
      - conda: https://conda.anaconda.org/conda-forge/noarch/narwhals-1.43.1-pyhe01879c_0.conda
      - conda: https://conda.anaconda.org/conda-forge/win-64/nh3-0.2.21-py39he870945_1.conda
      - conda: https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.9.1-pyhd8ed1ab_1.conda
      - conda: https://conda.anaconda.org/conda-forge/win-64/numba-0.62.1-py313h924e429_0.conda
      - conda: https://conda.anaconda.org/conda-forge/win-64/numpy-2.2.5-py313hefb8edb_0.conda
      - conda: https://conda.anaconda.org/conda-forge/win-64/openjpeg-2.5.3-h4d64b90_0.conda
      - conda: https://conda.anaconda.org/conda-forge/win-64/openpyxl-3.1.5-py313he57e174_1.conda
@@ -3622,6 +3626,40 @@ packages:
  purls: []
  size: 55476
  timestamp: 1727963768015
- conda: https://conda.anaconda.org/conda-forge/linux-64/llvmlite-0.45.1-py313hdd307be_0.conda
  sha256: 5b8e2063e93bea160fd50274d05ce4436f01c383a392f293b769dfb973c4df21
  md5: 5afb15643ef1fcea20798bb6086bb3f9
  depends:
  - __glibc >=2.17,<3.0.a0
  - libgcc >=14
  - libstdcxx >=14
  - libzlib >=1.3.1,<2.0a0
  - python >=3.13,<3.14.0a0
  - python_abi 3.13.* *_cp313
  - zstd >=1.5.7,<1.6.0a0
  license: BSD-2-Clause
  license_family: BSD
  purls:
  - pkg:pypi/llvmlite?source=hash-mapping
  size: 34153671
  timestamp: 1759394632193
- conda: https://conda.anaconda.org/conda-forge/win-64/llvmlite-0.45.1-py313h5c49287_0.conda
  sha256: 0b63923082e724b2c2939621aef77d9ec65aa468a7b29917a850e47e2083adda
  md5: d946ee3e7228e48270589791871a891e
  depends:
  - libzlib >=1.3.1,<2.0a0
  - python >=3.13,<3.14.0a0
  - python_abi 3.13.* *_cp313
  - ucrt >=10.0.20348.0
  - vc >=14.3,<15
  - vc14_runtime >=14.44.35208
  - zstd >=1.5.7,<1.6.0a0
  license: BSD-2-Clause
  license_family: BSD
  purls:
  - pkg:pypi/llvmlite?source=hash-mapping
  size: 22905696
  timestamp: 1759394712687
- conda: https://conda.anaconda.org/conda-forge/noarch/locket-1.0.0-pyhd8ed1ab_0.tar.bz2
  sha256: 9afe0b5cfa418e8bdb30d8917c5a6cec10372b037924916f1f85b9f4899a67a6
  md5: 91e27ef3d05cc772ce627e51cff111c4
@@ -4081,6 +4119,57 @@ packages:
  - pkg:pypi/nodeenv?source=hash-mapping
  size: 34574
  timestamp: 1734112236147
- conda: https://conda.anaconda.org/conda-forge/linux-64/numba-0.62.1-py313hd8e3f9f_0.conda
  sha256: 0b0ccf81ecd0cfb934818c3fb88404821904fe84e67815ab9958d37b0dca61e4
  md5: 82ffdc573a667626351f4110605da846
  depends:
  - __glibc >=2.17,<3.0.a0
  - _openmp_mutex >=4.5
  - libgcc >=14
  - libstdcxx >=14
  - llvmlite >=0.45.0,<0.46.0a0
  - numpy >=1.23,<3
  - numpy >=1.24,<2.4
  - python >=3.13,<3.14.0a0
  - python_abi 3.13.* *_cp313
  constrains:
  - cudatoolkit >=11.2
  - cuda-version >=11.2
  - tbb >=2021.6.0
  - cuda-python >=11.6
  - scipy >=1.0
  - libopenblas !=0.3.6
  license: BSD-2-Clause
  license_family: BSD
  purls:
  - pkg:pypi/numba?source=hash-mapping
  size: 5743830
  timestamp: 1759165232580
- conda: https://conda.anaconda.org/conda-forge/win-64/numba-0.62.1-py313h924e429_0.conda
  sha256: 79835953985d64565f76f912517ab5700148e86659b8e79ecd2d0e6d7377ac46
  md5: ae201f33cbcbb2aba93daf4b3263b4a5
  depends:
  - llvmlite >=0.45.0,<0.46.0a0
  - numpy >=1.23,<3
  - numpy >=1.24,<2.4
  - python >=3.13,<3.14.0a0
  - python_abi 3.13.* *_cp313
  - ucrt >=10.0.20348.0
  - vc >=14.3,<15
  - vc14_runtime >=14.44.35208
  constrains:
  - libopenblas !=0.3.6
  - cudatoolkit >=11.2
  - tbb >=2021.6.0
  - scipy >=1.0
  - cuda-python >=11.6
  - cuda-version >=11.2
  license: BSD-2-Clause
  license_family: BSD
  purls:
  - pkg:pypi/numba?source=hash-mapping
  size: 5706597
  timestamp: 1759165298367
- conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.2.5-py313h17eae1a_0.conda
  sha256: c0a200d0e53a1acbfa1d1e2277e3337ea2aa8cb584448790317a98c62dcaebce
  md5: 6ceeff9ed72e54e4a2f9a1c88f47bdde
@@ -4830,7 +4919,7 @@ packages:
- pypi: ./
  name: pythermogis
  version: 1.2.0
  sha256: 50c9d857c9314b246b28d7e610647475414c718d839408818aa4f441813b51a7
  sha256: bbba086a07a9972c4416d90c0cddf7f691529a60cac13dd8dd9fb2a236d68059
  requires_dist:
  - jpype1>=1.5.2,<2
  - xarray==2024.9.0.*
+1 −0
Original line number Diff line number Diff line
@@ -69,6 +69,7 @@ dask = ">=2025.5.1,<2026"
narwhals = ">=1.43.1,<2"
pre-commit = ">=4.3.0,<5"
python-dotenv = ">=1.2.1,<2"
numba = ">=0.62.1,<0.63"

[tool.ruff]
line-length = 88
+84 −0
Original line number Diff line number Diff line
from dataclasses import dataclass

from pythermogis.workflow.utc.utc_properties import UTCConfiguration
from pythermogis.workflow.utc.doublet_utils import calculate_injection_temp_with_heat_pump


@dataclass
class DoubletInput:
    unknown_input_value: float
    thickness: float
    transmissivity: float
    transmissivity_with_ntg: float
    ntg: float
    depth: float
    porosity: float
    temperature: float

@dataclass
class DoubletOutput:
    power: float
    hppower: float
    capex: float
    var_opex: float
    fixed_opex: float
    opex: float
    utc: float
    npv: float
    hprod: float
    cop: float
    cophp: float
    pres: float
    flow: float
    welld: float
    breakthrough: float
    cooling: float
    production_temp: float
    injection_temp: float

def calculate_doublet_performance(props: UTCConfiguration, input: DoubletInput) -> DoubletOutput:
    well_distance = (
        (props.optim_dist_well_dist_min + props.optim_dist_well_dist_max) / 2
        if props.optim_well_dist
        else props.default_well_distance
    )

    injection_temperature = (
        max(input.temperature - props.max_cooling_temp_range,
            props.hp_minimum_injection_temperature)
        if props.use_heat_pump
        else max(input.temperature - props.max_cooling_temp_range,
                 props.dh_return_temp)
    )

    if props.use_heat_pump and props.calculate_cop and not props.hp_application_mode:
        injection_temperature = calculate_injection_temp_with_heat_pump(
            input.temperature,
            props.hp_direct_heat_input_temp,
            props.dh_return_temp,
            input.temperature,
            props.max_cooling_temp_range,
            props.hp_minimum_injection_temperature
        )

    return DoubletOutput(
        power=0.0,
        hppower=0.0,
        capex=0.0,
        var_opex=0.0,
        fixed_opex=0.0,
        opex=0.0,
        utc=0.0,
        npv=0.0,
        hprod=0.0,
        cop=0.0,
        cophp=0.0,
        pres=0.0,
        flow=0.0,
        welld=0.0,
        breakthrough=0.0,
        cooling=0.0,
        production_temp=0.0,
        injection_temp=0.0
    )
+35 −0
Original line number Diff line number Diff line
from numba import njit

@njit
def calculate_injection_temp_with_heat_pump(
    t_prod: float,
    t_goal: float,
    dh_return_temp: float,
    reservoir_temp: float,
    max_cooling_temp_range: float,
    hp_minimum_injection_temperature: float,
):
    t_kelvin = 273.15

    eta = 0.5
    delta_t = 3  # deg C

    tc = t_goal + t_kelvin
    tr = t_prod + t_kelvin
    t_waste = min(dh_return_temp, t_prod) + t_kelvin

    num = (
        -eta * (tc + delta_t) * (t_waste + tr - tc)
        - tc * tc
        + tr * tc
        - 2 * delta_t * (tc - tr)
    )

    denom = tr - tc - eta * (tc + delta_t)

    needed_injection_temp = num / denom - t_kelvin

    return max(
        needed_injection_temp,
        max(reservoir_temp - max_cooling_temp_range, hp_minimum_injection_temperature)
    )
 No newline at end of file
+26 −0
Original line number Diff line number Diff line
from pythermogis.workflow.utc.doublet import calculate_doublet_performance, DoubletInput, DoubletOutput
from pythermogis.workflow.utc.utc_properties import UTCConfiguration



def test_calculate_doublet_performance_runs_with_default_props():
    # Arrange: instantiate default UTCConfiguration
    props = UTCConfiguration()

    # Create a minimal valid DoubletInput
    input_data = DoubletInput(
        unknown_input_value=0.0,
        thickness=100.0,
        transmissivity=5.0,
        transmissivity_with_ntg=3.0,
        ntg=0.1,
        depth=1500,
        porosity=0.2,
        temperature=80.0,
    )

    # Act
    result = calculate_doublet_performance(props, input_data)

    # Assert
    assert isinstance(result, DoubletOutput)
 No newline at end of file
Loading