Loading src/pythermogis/workflow/utc/doublet.py +13 −1 Original line number Diff line number Diff line Loading @@ -2,6 +2,7 @@ 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 from pythermogis.workflow.utc.pressure import calculate_max_pressure @dataclass Loading Loading @@ -36,7 +37,7 @@ class DoubletOutput: production_temp: float injection_temp: float def calculate_doublet_performance(props: UTCConfiguration, input: DoubletInput) -> DoubletOutput: def calculate_doublet_performance(props: UTCConfiguration, input: DoubletInput) -> DoubletOutput | None: well_distance = ( (props.optim_dist_well_dist_min + props.optim_dist_well_dist_max) / 2 if props.optim_well_dist Loading @@ -61,6 +62,17 @@ def calculate_doublet_performance(props: UTCConfiguration, input: DoubletInput) props.hp_minimum_injection_temperature ) drawdown_pressure = calculate_max_pressure( props, input, False, well_distance, injection_temperature, ) if drawdown_pressure == 0: return None return DoubletOutput( power=0.0, hppower=0.0, Loading src/pythermogis/workflow/utc/doublet_utils.py +24 −1 Original line number Diff line number Diff line Loading @@ -33,3 +33,26 @@ def calculate_injection_temp_with_heat_pump( needed_injection_temp, max(reservoir_temp - max_cooling_temp_range, hp_minimum_injection_temperature) ) @njit def get_orc_efficiency(Tx: float, Ts: float, etarel: float) -> float: return etarel * (Tx - Ts) / (Tx + Ts + 2 * 273.1) @njit def get_cop_carnot(eta: float, Tout: float, Tin: float) -> float: if Tout < 0.0 or Tin < 0.0: return 0.0 if eta < 0.0 or eta > 1.0: return 0.0 if Tout < Tin: return 0.0 DHP = 3.0 TKELVIN = 273.15 Tcond = Tout + DHP Tevap = Tin - DHP return eta * (Tcond + TKELVIN) / (Tcond - Tevap) No newline at end of file src/pythermogis/workflow/utc/doubletcalc.py 0 → 100644 +21 −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 import DoubletInput @dataclass class Doublet1DResults: geothermal_powers: float cop: float flowrate: float pump_power_required: float production_temp: float heat_power_produced: list[float] def doubletcalc( props: UTCConfiguration, input: DoubletInput, drawdown_pressure: float, well_distance: float, injection_temp: float, ) -> Doublet1DResults: ... No newline at end of file src/pythermogis/workflow/utc/flow.py 0 → 100644 +105 −0 Original line number Diff line number Diff line from dataclasses import dataclass from pythermogis.workflow.utc.heatpump import calculate_heat_pump_performance from pythermogis.workflow.utc.doublet_utils import get_orc_efficiency from pythermogis.workflow.utc.doubletcalc import doubletcalc @dataclass class VolumetricFlowResults: hp_cop: float hp_added_power: float heat_power_per_doublet: float cop: float flowrate: float pump_power_required: float production_temp: float heat_power_produced: list[float] def calculate_volumetric_flow( props, input_data, original_pressure: float, well_distance: float, injection_temp: float ): STEPS = [0, 1, -1, 2, -2, 3, -3, 4, -4, 5, -5, 6, -6] BAR_SI = 1e5 # Units.BAR_SI hp_cop = 3.0 hp_added_power = 0.0 d1d_results = None iter_index = 0 while d1d_results is None and iter_index < len(STEPS): drawdown_pressure = original_pressure + STEPS[iter_index] * BAR_SI d1d_results = doubletcalc( props, input_data, drawdown_pressure, well_distance, injection_temp ) iter_index += 1 if d1d_results is None: return None geothermal_powers = d1d_results.geothermal_powers cop = d1d_results.cop flowrate = d1d_results.flowrate pump_power_required = d1d_results.pump_power_required production_temp = d1d_results.production_temp heat_power_produced = d1d_results.heat_power_produced he2 = props.heat_exchanger_efficiency if props.use_orc: Ts = props.heat_exchanger_basetemp he2 = get_orc_efficiency( production_temp, Ts, props.heat_exchanger_efficiency ) heat_power_per_doublet = max(1e-6, geothermal_powers * he2) for i in range(len(heat_power_produced)): heat_power_produced[i] = max(1e-6, heat_power_produced[i] * he2) ignore_subsurface = ( props.well_cost_scaling + props.well_cost_const + props.well_cost_z + props.well_cost_z2 ) < 1e-3 if ignore_subsurface: cop = 1e4 pump_power_required = 0.0 power_consumption = ((heat_power_per_doublet / he2) / cop) + \ (heat_power_per_doublet * props.heat_exchanger_parasitic) if props.use_orc: heat_power_per_doublet -= power_consumption cop = heat_power_per_doublet / power_consumption if props.use_heat_pump: hp_results = calculate_heat_pump_performance( props, input_data, production_temp, injection_temp, flowrate ) hp_cop = hp_results.hp_cop hp_added_power = hp_results.hp_added_power return VolumetricFlowResults( hp_cop, hp_added_power, heat_power_per_doublet, cop, flowrate, pump_power_required, production_temp, heat_power_produced ) No newline at end of file src/pythermogis/workflow/utc/heatpump.py 0 → 100644 +75 −0 Original line number Diff line number Diff line from dataclasses import dataclass from pythermogis.workflow.utc.doublet_utils import get_cop_carnot from pythermogis.workflow.utc.water import get_hydrostatic_pressure, get_salinity, density, heat_capacity @dataclass class HeatPumpPerformanceResults: hp_cop: float hp_added_power: float def calculate_heat_pump_performance( props, input_data, production_temp: float, injection_temp: float, flowrate: float, ) -> HeatPumpPerformanceResults: ETA_CARNOT = 0.6 heat_pump_start_temp = calculate_heat_pump_start_temp( props, production_temp, injection_temp ) hydrostatic_pressure = get_hydrostatic_pressure(0) salinity = get_salinity( props.salinity_surface, props.salinity_gradient, input_data.depth, ) rho_water = density( hydrostatic_pressure, props.surface_temperature, salinity ) cp_water = heat_capacity( hydrostatic_pressure, props.surface_temperature, salinity ) if props.hp_calc_cop: Tout = props.hp_direct_heat_input_temp Tin = min(injection_temp, props.dh_return_temp) hp_cop = get_cop_carnot(ETA_CARNOT, Tout, Tin) else: hp_cop = props.hp_capex waste_temp = min(heat_pump_start_temp, props.dh_return_temp) delta_temp = max(0.0, waste_temp - injection_temp) hp_added_power = (flowrate / 3600.0) * delta_temp * rho_water * cp_water * 1e-6 if hp_added_power == 0: hp_cop = 0.0 return HeatPumpPerformanceResults( hp_cop=hp_cop, hp_added_power=hp_added_power, ) def calculate_heat_pump_start_temp(props, production_temp: float, injection_temp: float) -> float: """ Python version of calculateHeatPumpStartTemp(...) """ delta_temp_geothermal = production_temp - injection_temp delta_temp_for_hex = 0.0 if props.hp_application_mode and production_temp > props.dh_return_temp: delta_temp_for_hex = production_temp - props.dh_return_temp delta_temp_for_hex = max(0.0, min(delta_temp_for_hex, delta_temp_geothermal)) return production_temp - delta_temp_for_hex No newline at end of file Loading
src/pythermogis/workflow/utc/doublet.py +13 −1 Original line number Diff line number Diff line Loading @@ -2,6 +2,7 @@ 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 from pythermogis.workflow.utc.pressure import calculate_max_pressure @dataclass Loading Loading @@ -36,7 +37,7 @@ class DoubletOutput: production_temp: float injection_temp: float def calculate_doublet_performance(props: UTCConfiguration, input: DoubletInput) -> DoubletOutput: def calculate_doublet_performance(props: UTCConfiguration, input: DoubletInput) -> DoubletOutput | None: well_distance = ( (props.optim_dist_well_dist_min + props.optim_dist_well_dist_max) / 2 if props.optim_well_dist Loading @@ -61,6 +62,17 @@ def calculate_doublet_performance(props: UTCConfiguration, input: DoubletInput) props.hp_minimum_injection_temperature ) drawdown_pressure = calculate_max_pressure( props, input, False, well_distance, injection_temperature, ) if drawdown_pressure == 0: return None return DoubletOutput( power=0.0, hppower=0.0, Loading
src/pythermogis/workflow/utc/doublet_utils.py +24 −1 Original line number Diff line number Diff line Loading @@ -33,3 +33,26 @@ def calculate_injection_temp_with_heat_pump( needed_injection_temp, max(reservoir_temp - max_cooling_temp_range, hp_minimum_injection_temperature) ) @njit def get_orc_efficiency(Tx: float, Ts: float, etarel: float) -> float: return etarel * (Tx - Ts) / (Tx + Ts + 2 * 273.1) @njit def get_cop_carnot(eta: float, Tout: float, Tin: float) -> float: if Tout < 0.0 or Tin < 0.0: return 0.0 if eta < 0.0 or eta > 1.0: return 0.0 if Tout < Tin: return 0.0 DHP = 3.0 TKELVIN = 273.15 Tcond = Tout + DHP Tevap = Tin - DHP return eta * (Tcond + TKELVIN) / (Tcond - Tevap) No newline at end of file
src/pythermogis/workflow/utc/doubletcalc.py 0 → 100644 +21 −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 import DoubletInput @dataclass class Doublet1DResults: geothermal_powers: float cop: float flowrate: float pump_power_required: float production_temp: float heat_power_produced: list[float] def doubletcalc( props: UTCConfiguration, input: DoubletInput, drawdown_pressure: float, well_distance: float, injection_temp: float, ) -> Doublet1DResults: ... No newline at end of file
src/pythermogis/workflow/utc/flow.py 0 → 100644 +105 −0 Original line number Diff line number Diff line from dataclasses import dataclass from pythermogis.workflow.utc.heatpump import calculate_heat_pump_performance from pythermogis.workflow.utc.doublet_utils import get_orc_efficiency from pythermogis.workflow.utc.doubletcalc import doubletcalc @dataclass class VolumetricFlowResults: hp_cop: float hp_added_power: float heat_power_per_doublet: float cop: float flowrate: float pump_power_required: float production_temp: float heat_power_produced: list[float] def calculate_volumetric_flow( props, input_data, original_pressure: float, well_distance: float, injection_temp: float ): STEPS = [0, 1, -1, 2, -2, 3, -3, 4, -4, 5, -5, 6, -6] BAR_SI = 1e5 # Units.BAR_SI hp_cop = 3.0 hp_added_power = 0.0 d1d_results = None iter_index = 0 while d1d_results is None and iter_index < len(STEPS): drawdown_pressure = original_pressure + STEPS[iter_index] * BAR_SI d1d_results = doubletcalc( props, input_data, drawdown_pressure, well_distance, injection_temp ) iter_index += 1 if d1d_results is None: return None geothermal_powers = d1d_results.geothermal_powers cop = d1d_results.cop flowrate = d1d_results.flowrate pump_power_required = d1d_results.pump_power_required production_temp = d1d_results.production_temp heat_power_produced = d1d_results.heat_power_produced he2 = props.heat_exchanger_efficiency if props.use_orc: Ts = props.heat_exchanger_basetemp he2 = get_orc_efficiency( production_temp, Ts, props.heat_exchanger_efficiency ) heat_power_per_doublet = max(1e-6, geothermal_powers * he2) for i in range(len(heat_power_produced)): heat_power_produced[i] = max(1e-6, heat_power_produced[i] * he2) ignore_subsurface = ( props.well_cost_scaling + props.well_cost_const + props.well_cost_z + props.well_cost_z2 ) < 1e-3 if ignore_subsurface: cop = 1e4 pump_power_required = 0.0 power_consumption = ((heat_power_per_doublet / he2) / cop) + \ (heat_power_per_doublet * props.heat_exchanger_parasitic) if props.use_orc: heat_power_per_doublet -= power_consumption cop = heat_power_per_doublet / power_consumption if props.use_heat_pump: hp_results = calculate_heat_pump_performance( props, input_data, production_temp, injection_temp, flowrate ) hp_cop = hp_results.hp_cop hp_added_power = hp_results.hp_added_power return VolumetricFlowResults( hp_cop, hp_added_power, heat_power_per_doublet, cop, flowrate, pump_power_required, production_temp, heat_power_produced ) No newline at end of file
src/pythermogis/workflow/utc/heatpump.py 0 → 100644 +75 −0 Original line number Diff line number Diff line from dataclasses import dataclass from pythermogis.workflow.utc.doublet_utils import get_cop_carnot from pythermogis.workflow.utc.water import get_hydrostatic_pressure, get_salinity, density, heat_capacity @dataclass class HeatPumpPerformanceResults: hp_cop: float hp_added_power: float def calculate_heat_pump_performance( props, input_data, production_temp: float, injection_temp: float, flowrate: float, ) -> HeatPumpPerformanceResults: ETA_CARNOT = 0.6 heat_pump_start_temp = calculate_heat_pump_start_temp( props, production_temp, injection_temp ) hydrostatic_pressure = get_hydrostatic_pressure(0) salinity = get_salinity( props.salinity_surface, props.salinity_gradient, input_data.depth, ) rho_water = density( hydrostatic_pressure, props.surface_temperature, salinity ) cp_water = heat_capacity( hydrostatic_pressure, props.surface_temperature, salinity ) if props.hp_calc_cop: Tout = props.hp_direct_heat_input_temp Tin = min(injection_temp, props.dh_return_temp) hp_cop = get_cop_carnot(ETA_CARNOT, Tout, Tin) else: hp_cop = props.hp_capex waste_temp = min(heat_pump_start_temp, props.dh_return_temp) delta_temp = max(0.0, waste_temp - injection_temp) hp_added_power = (flowrate / 3600.0) * delta_temp * rho_water * cp_water * 1e-6 if hp_added_power == 0: hp_cop = 0.0 return HeatPumpPerformanceResults( hp_cop=hp_cop, hp_added_power=hp_added_power, ) def calculate_heat_pump_start_temp(props, production_temp: float, injection_temp: float) -> float: """ Python version of calculateHeatPumpStartTemp(...) """ delta_temp_geothermal = production_temp - injection_temp delta_temp_for_hex = 0.0 if props.hp_application_mode and production_temp > props.dh_return_temp: delta_temp_for_hex = production_temp - props.dh_return_temp delta_temp_for_hex = max(0.0, min(delta_temp_for_hex, delta_temp_geothermal)) return production_temp - delta_temp_for_hex No newline at end of file