Skip to content

Commit c6d8c2b

Browse files
authored
Merge pull request #382 from wouterpeere/issue380-wrong-result-when-working-with-optimise-power-and-start_month-1
First try to fix 380
2 parents 1f67465 + 5232717 commit c6d8c2b

File tree

4 files changed

+111
-22
lines changed

4 files changed

+111
-22
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
1111

1212
- Changed implementation of `optimise_for_energy` to make it three times faster (issue #308).
1313
- Add support for EPW files from PVGIS (issue #376).
14+
- Fix problem with start month in optimise for power/balance (issue #380).
15+
- Return multiyear external load if multiyear load is given as an imput (issue #380).
1416

1517
### Fixed
1618

GHEtool/Methods/optimise_load_profile.py

Lines changed: 50 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ def optimise_load_profile_power(
1616
max_peak_heating: float = None,
1717
max_peak_cooling: float = None,
1818
dhw_preferential: bool = None
19-
) -> tuple[HourlyBuildingLoad, HourlyBuildingLoad]:
19+
) -> tuple[
20+
Union[HourlyBuildingLoad, HourlyBuildingLoadMultiYear], Union[HourlyBuildingLoad, HourlyBuildingLoadMultiYear]]:
2021
"""
2122
This function optimises the load for maximum power in extraction and injection based on the given borefield and
2223
the given hourly building load. It does so based on a load-duration curve.
@@ -43,7 +44,7 @@ def optimise_load_profile_power(
4344
4445
Returns
4546
-------
46-
tuple [HourlyBuildingLoad, HourlyBuildingLoad]
47+
tuple [HourlyBuildingLoad, HourlyBuildingLoad] or tuple [HourlyBuildingLoadMultiYear, HourlyBuildingLoadMultiYear]
4748
borefield load, external load
4849
4950
Raises
@@ -70,7 +71,6 @@ def optimise_load_profile_power(
7071

7172
# set load
7273
borefield.load = copy.deepcopy(building_load)
73-
7474
# set initial peak loads
7575
init_peak_heating: float = borefield.load.max_peak_heating
7676
init_peak_dhw: float = borefield.load.max_peak_dhw
@@ -92,10 +92,10 @@ def optimise_load_profile_power(
9292
while not cool_ok or not heat_ok:
9393
# limit the primary geothermal extraction and injection load to peak_heat_load and peak_cool_load
9494
borefield.load.set_hourly_cooling_load(
95-
np.minimum(peak_cool_load, building_load.hourly_cooling_load
95+
np.minimum(peak_cool_load, building_load._hourly_cooling_load
9696
if isinstance(borefield.load, HourlyBuildingLoad) else building_load.hourly_cooling_load_simulation_period))
9797
borefield.load.set_hourly_heating_load(
98-
np.minimum(peak_heat_load, building_load.hourly_heating_load
98+
np.minimum(peak_heat_load, building_load._hourly_heating_load
9999
if isinstance(borefield.load, HourlyBuildingLoad) else building_load.hourly_heating_load_simulation_period))
100100
borefield.load.set_hourly_dhw_load(
101101
np.minimum(peak_dhw_load, building_load.hourly_dhw_load
@@ -145,13 +145,29 @@ def optimise_load_profile_power(
145145
cool_ok = True
146146

147147
# calculate external load
148-
external_load = HourlyBuildingLoad(simulation_period=building_load.simulation_period)
148+
if isinstance(building_load, HourlyBuildingLoad):
149+
external_load = HourlyBuildingLoad(simulation_period=building_load.simulation_period)
150+
external_load.start_month = building_load.start_month
151+
152+
external_load.set_hourly_heating_load(
153+
np.maximum(0, building_load._hourly_heating_load - borefield.load._hourly_heating_load))
154+
external_load.set_hourly_cooling_load(
155+
np.maximum(0, building_load._hourly_cooling_load - borefield.load._hourly_cooling_load))
156+
external_load.set_hourly_dhw_load(
157+
np.maximum(0, building_load.hourly_dhw_load - borefield.load.hourly_dhw_load))
158+
159+
return borefield.load, external_load
160+
161+
external_load = HourlyBuildingLoadMultiYear()
149162
external_load.set_hourly_heating_load(
150-
np.maximum(0, building_load.hourly_heating_load - borefield.load.hourly_heating_load))
163+
np.maximum(0,
164+
building_load.hourly_heating_load_simulation_period - borefield.load.hourly_heating_load_simulation_period))
151165
external_load.set_hourly_cooling_load(
152-
np.maximum(0, building_load.hourly_cooling_load - borefield.load.hourly_cooling_load))
166+
np.maximum(0,
167+
building_load.hourly_cooling_load_simulation_period - borefield.load.hourly_cooling_load_simulation_period))
153168
external_load.set_hourly_dhw_load(
154-
np.maximum(0, building_load.hourly_dhw_load - borefield.load.hourly_dhw_load))
169+
np.maximum(0,
170+
building_load.hourly_dhw_load_simulation_period - borefield.load.hourly_dhw_load_simulation_period))
155171

156172
return borefield.load, external_load
157173

@@ -454,7 +470,8 @@ def optimise_load_profile_balance(
454470
max_peak_cooling: float = None,
455471
dhw_preferential: bool = None,
456472
imbalance_factor: float = 0.01,
457-
) -> tuple[HourlyBuildingLoad, HourlyBuildingLoad]:
473+
) -> tuple[
474+
Union[HourlyBuildingLoad, HourlyBuildingLoadMultiYear], Union[HourlyBuildingLoad, HourlyBuildingLoadMultiYear]]:
458475
"""
459476
This function optimises the load for maximum power in extraction and injection based on the given borefield and
460477
the given hourly building load, by maintaining a zero imbalance. It does so based on a load-duration curve.
@@ -484,7 +501,7 @@ def optimise_load_profile_balance(
484501
485502
Returns
486503
-------
487-
tuple [HourlyBuildingLoad, HourlyBuildingLoad]
504+
tuple [HourlyBuildingLoad, HourlyBuildingLoad] or tuple [HourlyBuildingLoadMultiYear, HourlyBuildingLoadMultiYear]
488505
borefield load, external load
489506
490507
Raises
@@ -536,10 +553,10 @@ def optimise_load_profile_balance(
536553
while not cool_ok or not heat_ok:
537554
# limit the primary geothermal extraction and injection load to peak_heat_load and peak_cool_load
538555
borefield.load.set_hourly_cooling_load(
539-
np.minimum(peak_cool_load, building_load.hourly_cooling_load
556+
np.minimum(peak_cool_load, building_load._hourly_cooling_load
540557
if isinstance(borefield.load, HourlyBuildingLoad) else building_load.hourly_cooling_load_simulation_period))
541558
borefield.load.set_hourly_heating_load(
542-
np.minimum(peak_heat_load, building_load.hourly_heating_load
559+
np.minimum(peak_heat_load, building_load._hourly_heating_load
543560
if isinstance(borefield.load, HourlyBuildingLoad) else building_load.hourly_heating_load_simulation_period))
544561
borefield.load.set_hourly_dhw_load(
545562
np.minimum(peak_dhw_load, building_load.hourly_dhw_load
@@ -616,12 +633,28 @@ def optimise_load_profile_balance(
616633
cool_ok = True
617634

618635
# calculate external load
619-
external_load = HourlyBuildingLoad(simulation_period=building_load.simulation_period)
636+
if isinstance(building_load, HourlyBuildingLoad):
637+
external_load = HourlyBuildingLoad(simulation_period=building_load.simulation_period)
638+
external_load.start_month = building_load.start_month
639+
640+
external_load.set_hourly_heating_load(
641+
np.maximum(0, building_load._hourly_heating_load - borefield.load._hourly_heating_load))
642+
external_load.set_hourly_cooling_load(
643+
np.maximum(0, building_load._hourly_cooling_load - borefield.load._hourly_cooling_load))
644+
external_load.set_hourly_dhw_load(
645+
np.maximum(0, building_load.hourly_dhw_load - borefield.load.hourly_dhw_load))
646+
647+
return borefield.load, external_load
648+
649+
external_load = HourlyBuildingLoadMultiYear()
620650
external_load.set_hourly_heating_load(
621-
np.maximum(0, building_load.hourly_heating_load - borefield.load.hourly_heating_load))
651+
np.maximum(0,
652+
building_load.hourly_heating_load_simulation_period - borefield.load.hourly_heating_load_simulation_period))
622653
external_load.set_hourly_cooling_load(
623-
np.maximum(0, building_load.hourly_cooling_load - borefield.load.hourly_cooling_load))
654+
np.maximum(0,
655+
building_load.hourly_cooling_load_simulation_period - borefield.load.hourly_cooling_load_simulation_period))
624656
external_load.set_hourly_dhw_load(
625-
np.maximum(0, building_load.hourly_dhw_load - borefield.load.hourly_dhw_load))
657+
np.maximum(0,
658+
building_load.hourly_dhw_load_simulation_period - borefield.load.hourly_dhw_load_simulation_period))
626659

627660
return borefield.load, external_load

GHEtool/test/general_tests/test_GHEtool.py

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from GHEtool.VariableClasses.BaseClass import UnsolvableDueToTemperatureGradient, MaximumNumberOfIterations
1717
from GHEtool.Validation.cases import load_case
1818
from GHEtool.VariableClasses import MonthlyGeothermalLoadAbsolute, HourlyGeothermalLoad, EERCombined, \
19-
HourlyBuildingLoad, EER
19+
HourlyBuildingLoad, EER, HourlyBuildingLoadMultiYear
2020
from GHEtool.Methods import *
2121

2222
data = GroundConstantTemperature(3, 10)
@@ -353,9 +353,9 @@ def test_optimise_load_eer_combined():
353353
np.array([5, 30])) # based on the data of the WRE092 chiller of Galletti
354354
borefield1 = Borefield()
355355
borefield1.create_rectangular_borefield(4, 3, 6, 6, 110, 0.7, 0.075)
356-
borefield1.set_ground_parameters(ground_data)
357-
borefield1.set_fluid_parameters(fluid_data)
358-
borefield1.set_pipe_parameters(pipe_data)
356+
borefield1.ground_data = ground_data
357+
borefield1.fluid_data = fluid_data
358+
borefield1.pipe_data = pipe_data
359359
borefield1.set_max_avg_fluid_temperature(25)
360360
borefield1.set_min_avg_fluid_temperature(3)
361361

@@ -376,3 +376,57 @@ def test_optimise_load_eer_combined():
376376
borefield1.calculate_temperatures(hourly=True)
377377
results_25 = copy.deepcopy(borefield1.results)
378378
assert np.allclose(results_16.peak_injection, results_25.peak_injection)
379+
380+
381+
def test_optimise_methods_different_start_year():
382+
ground_data = GroundFluxTemperature(3, 10)
383+
fluid_data = FluidData(0.2, 0.568, 998, 4180, 1e-3)
384+
pipe_data = DoubleUTube(1, 0.015, 0.02, 0.4, 0.05)
385+
386+
load = HourlyBuildingLoad(efficiency_heating=5) # use SCOP of 5 for heating
387+
load.load_hourly_profile(FOLDER.joinpath("test\methods\hourly_data\\auditorium.csv"), header=True,
388+
separator=";", col_cooling=0, col_heating=1)
389+
load.start_month = 5
390+
391+
borefield = Borefield()
392+
borefield.create_rectangular_borefield(20, 5, 6, 6, 110, 0.7, 0.075)
393+
borefield.ground_data = ground_data
394+
borefield.fluid_data = fluid_data
395+
borefield.pipe_data = pipe_data
396+
397+
borefield_load, ext_load = optimise_load_profile_power(borefield, load)
398+
assert borefield_load.start_month == 5
399+
assert load.start_month == 5
400+
assert ext_load.start_month == 5
401+
assert ext_load.max_peak_heating == 0
402+
assert ext_load.max_peak_cooling == 0
403+
assert isinstance(ext_load, HourlyBuildingLoad)
404+
405+
borefield_load, ext_load = optimise_load_profile_balance(borefield, load)
406+
assert borefield_load.start_month == 5
407+
assert load.start_month == 5
408+
assert ext_load.start_month == 5
409+
assert np.allclose(borefield_load.hourly_heating_load + ext_load.hourly_heating_load, load.hourly_heating_load)
410+
assert np.allclose(borefield_load.hourly_cooling_load + ext_load.hourly_cooling_load, load.hourly_cooling_load)
411+
412+
load = HourlyBuildingLoadMultiYear(load.hourly_heating_load_simulation_period,
413+
load.hourly_cooling_load_simulation_period)
414+
415+
borefield_load, ext_load = optimise_load_profile_power(borefield, load)
416+
assert isinstance(ext_load, HourlyBuildingLoadMultiYear)
417+
assert ext_load.max_peak_heating == 0
418+
assert ext_load.max_peak_cooling == 0
419+
420+
borefield_load, ext_load = optimise_load_profile_balance(borefield, load)
421+
assert isinstance(ext_load, HourlyBuildingLoadMultiYear)
422+
assert np.allclose(borefield_load.hourly_heating_load + ext_load.hourly_heating_load, load.hourly_heating_load)
423+
assert np.allclose(borefield_load.hourly_cooling_load + ext_load.hourly_cooling_load, load.hourly_cooling_load)
424+
425+
borefield.create_rectangular_borefield(10, 2, 6, 6, 110, 0.7, 0.075)
426+
borefield.ground_data = ground_data
427+
borefield.fluid_data = fluid_data
428+
borefield.pipe_data = pipe_data
429+
430+
borefield_load, ext_load = optimise_load_profile_power(borefield, load)
431+
assert np.allclose(borefield_load.hourly_heating_load + ext_load.hourly_heating_load, load.hourly_heating_load)
432+
assert np.allclose(borefield_load.hourly_cooling_load + ext_load.hourly_cooling_load, load.hourly_cooling_load)

setup.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[metadata]
22
name = GHEtool
3-
version = 2.4.0.dev1
3+
version = 2.4.0.dev2
44
author = Wouter Peere
55
author_email = wouter@ghetool.eu
66
description = Python package for borefield sizing

0 commit comments

Comments
 (0)