Skip to content

Commit 85d4e76

Browse files
authored
Merge pull request #394 from wouterpeere/162-size-borefield-configuration-function_new
162 size borefield configuration function
2 parents d8e0c25 + a54374b commit 85d4e76

22 files changed

+820
-28
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
99

1010
### Added
1111

12+
- Optimise number of boreholes (issue #162).
1213
- Artificial Neural Network to speed up calculations (issue #322, @tblanke).
1314

1415
### Changed

GHEtool/Borefield.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,6 @@ def set_borefield(self, borefield: gt.borefield.Borefield = None) -> None:
237237
-------
238238
None
239239
"""
240-
self._borefield_description = None
241240
self.borefield = borefield
242241

243242
def create_rectangular_borefield(self, N_1: int, N_2: int, B_1: float, B_2: float, H: float, D: float = 1,
@@ -476,6 +475,7 @@ def borefield(self, borefield: gt.borefield.Borefield = None) -> None:
476475
else:
477476
self.gfunction_calculation_object.store_previous_values = \
478477
self.gfunction_calculation_object._store_previous_values_backup
478+
self._borefield_description = None
479479

480480
@borefield.deleter
481481
def borefield(self):
@@ -1543,7 +1543,7 @@ def _size_based_on_temperature_profile(self, quadrant: int, hourly: bool = False
15431543
while not self._check_convergence(self.H, H_prev, i):
15441544
if H_prev != 0:
15451545
self.H = self.H * .5 + H_prev * 0.5
1546-
limit = self.Tf_min if quadrant in (3, 4, 20) else self.Tf_max
1546+
15471547
if hourly:
15481548
self._calculate_temperature_profile(self.H, hourly=True, sizing=True)
15491549
else:
@@ -1587,7 +1587,6 @@ def _size_based_on_temperature_profile(self, quadrant: int, hourly: bool = False
15871587
return 0, False
15881588

15891589
i += 1
1590-
15911590
return self.H, (np.max(self.results.peak_injection) <= self.Tf_max + 0.05 or (
15921591
quadrant == 10 or quadrant == 1 or quadrant == 2)) and (
15931592
np.min(self.results.peak_extraction) >= self.Tf_min - 0.05 or (
@@ -1760,6 +1759,9 @@ def _calculate_temperature_profile(self, H: float = None, hourly: bool = False,
17601759

17611760
# reset self.results
17621761
self.results = ResultsMonthly()
1762+
variable_efficiency = isinstance(self.load, _LoadDataBuilding) and not (
1763+
isinstance(self.load.cop, SCOP) and isinstance(self.load.cop_dhw, SCOP) and isinstance(
1764+
self.load.eer, SEER))
17631765

17641766
def calculate_temperatures(H, hourly=hourly, results_temperature=ResultsMonthly()):
17651767
# set Rb* value
@@ -1769,9 +1771,7 @@ def calculate_temperatures(H, hourly=hourly, results_temperature=ResultsMonthly(
17691771
results = None
17701772

17711773
def get_rb(temperature, limit=None):
1772-
variable_efficiency = isinstance(self.load, _LoadDataBuilding) and not (
1773-
isinstance(self.load.cop, SCOP) and isinstance(self.load.cop_dhw, SCOP) and isinstance(
1774-
self.load.eer, SEER))
1774+
17751775
if self.USE_SPEED_UP_IN_SIZING and sizing and not variable_efficiency:
17761776
# use only extreme temperatures when sizing
17771777
if limit is not None:
@@ -1901,7 +1901,10 @@ def calculate_difference(results_old: Union[ResultsMonthly, ResultsHourly],
19011901
self.load.reset_results(self.Tf_min, self.Tf_max)
19021902
results_old = calculate_temperatures(H, hourly=hourly)
19031903
self.load.set_results(results_old)
1904-
results = calculate_temperatures(H, hourly=hourly, results_temperature=results_old)
1904+
if sizing and not variable_efficiency and self._calculation_setup.approximate_req_depth:
1905+
results = results_old
1906+
else:
1907+
results = calculate_temperatures(H, hourly=hourly, results_temperature=results_old)
19051908

19061909
# safety
19071910
i = 0
Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
from GHEtool import *
2+
from GHEtool.Methods.optimise_borefield_configuration import optimise_borefield_configuration
3+
from GHEtool.Validation.cases import load_case
4+
5+
6+
def borefield_case_1():
7+
borefield = Borefield(ground_data=GroundConstantTemperature(3.5, 10),
8+
load=MonthlyGeothermalLoadAbsolute(*load_case(1)))
9+
borefield.create_rectangular_borefield(10, 6, 6.5, 6.5, 100, 4, 0.075)
10+
borefield.calculation_setup(use_neural_network=True)
11+
12+
# optimise for minimum borehole length
13+
result = optimise_borefield_configuration(borefield, 80, 70, 5, 7, 0.5, 60, 150)
14+
borefield.borefield = result[0][-1]
15+
print(
16+
f'{len(result)} solutions are found. The optimal borehole length is: {result[0][0]:.2f}m. '
17+
f'There are {result[0][2]} boreholes. The configuration is {result[0][1]}.')
18+
result = optimise_borefield_configuration(borefield, 80, 70, 5, 7, 0.5, 60, 150, optimise='nb')
19+
borefield.borefield = result[0][-1]
20+
print(
21+
f'{len(result)} solutions are found. The optimal number of boreholes {result[0][2]}. '
22+
f'The total borehole lengths is {result[0][0]:.2f}m. The configuration is {result[0][1]}.')
23+
24+
25+
def borefield_case_2():
26+
borefield = Borefield(ground_data=GroundConstantTemperature(3.5, 10),
27+
load=MonthlyGeothermalLoadAbsolute(*load_case(2)))
28+
borefield.create_rectangular_borefield(10, 6, 6.5, 6.5, 100, 4, 0.075)
29+
borefield.calculation_setup(use_neural_network=True)
30+
31+
# optimise for minimum borehole length
32+
result = optimise_borefield_configuration(borefield, 80, 70, 5, 7, 0.5, 60, 150)
33+
borefield.borefield = result[0][-1]
34+
print(
35+
f'{len(result)} solutions are found. The optimal borehole length is: {result[0][0]:.2f}m. '
36+
f'There are {result[0][2]} boreholes. The configuration is {result[0][1]}.')
37+
result = optimise_borefield_configuration(borefield, 80, 70, 5, 7, 0.5, 60, 150, optimise='nb')
38+
borefield.borefield = result[0][-1]
39+
print(
40+
f'{len(result)} solutions are found. The optimal number of boreholes {result[0][2]}. '
41+
f'The total borehole lengths is {result[0][0]:.2f}m. The configuration is {result[0][1]}.')
42+
43+
44+
def borefield_case_3():
45+
borefield = Borefield(ground_data=GroundConstantTemperature(3.5, 10),
46+
load=MonthlyGeothermalLoadAbsolute(*load_case(3)))
47+
borefield.create_rectangular_borefield(10, 6, 6.5, 6.5, 100, 4, 0.075)
48+
borefield.calculation_setup(use_neural_network=True)
49+
50+
# optimise for minimum borehole length
51+
result = optimise_borefield_configuration(borefield, 80, 70, 5, 7, 0.5, 60, 150)
52+
borefield.borefield = result[0][-1]
53+
print(
54+
f'{len(result)} solutions are found. The optimal borehole length is: {result[0][0]:.2f}m. '
55+
f'There are {result[0][2]} boreholes. The configuration is {result[0][1]}.')
56+
result = optimise_borefield_configuration(borefield, 80, 70, 5, 7, 0.5, 60, 150, optimise='nb')
57+
borefield.borefield = result[0][-1]
58+
print(
59+
f'{len(result)} solutions are found. The optimal number of boreholes {result[0][2]}. '
60+
f'The total borehole lengths is {result[0][0]:.2f}m. The configuration is {result[0][1]}.')
61+
62+
63+
def borefield_case_4():
64+
borefield = Borefield(ground_data=GroundConstantTemperature(3.5, 10),
65+
load=MonthlyGeothermalLoadAbsolute(*load_case(4)))
66+
borefield.create_rectangular_borefield(10, 6, 6.5, 6.5, 100, 4, 0.075)
67+
borefield.calculation_setup(use_neural_network=True)
68+
69+
# optimise for minimum borehole length
70+
result = optimise_borefield_configuration(borefield, 80, 70, 5, 7, 0.5, 60, 150)
71+
borefield.borefield = result[0][-1]
72+
print(
73+
f'{len(result)} solutions are found. The optimal borehole length is: {result[0][0]:.2f}m. '
74+
f'There are {result[0][2]} boreholes. The configuration is {result[0][1]}.')
75+
result = optimise_borefield_configuration(borefield, 80, 70, 5, 7, 0.5, 60, 150, optimise='nb')
76+
borefield.borefield = result[0][-1]
77+
print(
78+
f'{len(result)} solutions are found. The optimal number of boreholes {result[0][2]}. '
79+
f'The total borehole lengths is {result[0][0]:.2f}m. The configuration is {result[0][1]}.')
80+
81+
82+
def borefield_office():
83+
borefield = Borefield()
84+
borefield.create_rectangular_borefield(10, 10, 6, 6, 110, 4, 0.075)
85+
borefield.ground_data = GroundFluxTemperature(3, 10)
86+
borefield.fluid_data = ConstantFluidData(0.568, 998, 4180, 1e-3)
87+
borefield.flow_data = ConstantFlowRate(mfr=0.2)
88+
borefield.pipe_data = DoubleUTube(1, 0.015, 0.02, 0.4, 0.05)
89+
borefield.calculation_setup(use_constant_Rb=False)
90+
borefield.set_max_avg_fluid_temperature(17)
91+
borefield.set_min_avg_fluid_temperature(3)
92+
hourly_load = HourlyGeothermalLoad()
93+
hourly_load.simulation_period = 20
94+
hourly_load.load_hourly_profile(FOLDER.joinpath("test\methods\hourly_data\office.csv"), header=True, separator=";",
95+
col_injection=0, col_extraction=1)
96+
borefield.load = hourly_load
97+
borefield.calculation_setup(use_neural_network=True)
98+
99+
# optimise for minimum borehole length
100+
result = optimise_borefield_configuration(borefield, 80, 70, 5, 7, 0.5, 60, 150)
101+
borefield.borefield = result[0][-1]
102+
print(
103+
f'{len(result)} solutions are found. The optimal borehole length is: {result[0][0]:.2f}m. '
104+
f'There are {result[0][2]} boreholes. The configuration is {result[0][1]}.')
105+
result = optimise_borefield_configuration(borefield, 80, 70, 5, 7, 0.5, 60, 150, optimise='nb')
106+
borefield.borefield = result[0][-1]
107+
print(
108+
f'{len(result)} solutions are found. The optimal number of boreholes {result[0][2]}. '
109+
f'The total borehole lengths is {result[0][0]:.2f}m. The configuration is {result[0][1]}.')
110+
111+
112+
def borefield_auditorium():
113+
borefield = Borefield()
114+
borefield.create_rectangular_borefield(10, 10, 6, 6, 110, 4, 0.075)
115+
borefield.ground_data = GroundFluxTemperature(3, 10)
116+
borefield.fluid_data = ConstantFluidData(0.568, 998, 4180, 1e-3)
117+
borefield.flow_data = ConstantFlowRate(mfr=0.2)
118+
borefield.pipe_data = DoubleUTube(1, 0.015, 0.02, 0.4, 0.05)
119+
borefield.calculation_setup(use_constant_Rb=False)
120+
borefield.set_max_avg_fluid_temperature(17)
121+
borefield.set_min_avg_fluid_temperature(3)
122+
hourly_load = HourlyGeothermalLoad()
123+
hourly_load.simulation_period = 20
124+
hourly_load.load_hourly_profile(FOLDER.joinpath("test\methods\hourly_data\\auditorium.csv"), header=True,
125+
separator=";", col_injection=0, col_extraction=1)
126+
borefield.load = hourly_load
127+
borefield.calculation_setup(use_neural_network=True)
128+
129+
# optimise for minimum borehole length
130+
result = optimise_borefield_configuration(borefield, 80, 70, 5, 7, 0.5, 60, 150)
131+
borefield.borefield = result[0][-1]
132+
print(
133+
f'{len(result)} solutions are found. The optimal borehole length is: {result[0][0]:.2f}m. '
134+
f'There are {result[0][2]} boreholes. The configuration is {result[0][1]}.')
135+
result = optimise_borefield_configuration(borefield, 80, 70, 5, 7, 0.5, 60, 150,
136+
optimise='nb')
137+
borefield.borefield = result[0][-1]
138+
print(
139+
f'{len(result)} solutions are found. The optimal number of boreholes {result[0][2]}. '
140+
f'The total borehole lengths is {result[0][0]:.2f}m. The configuration is {result[0][1]}.')
141+
142+
result = optimise_borefield_configuration(borefield, 80, 70, 5, 7, 0.5, 60, 150, size_L3=False)
143+
144+
145+
def borefield_swimming_pool():
146+
borefield = Borefield()
147+
borefield.create_rectangular_borefield(10, 10, 6, 6, 110, 4, 0.075)
148+
borefield.ground_data = GroundFluxTemperature(3, 10)
149+
borefield.fluid_data = ConstantFluidData(0.568, 998, 4180, 1e-3)
150+
borefield.flow_data = ConstantFlowRate(mfr=0.2)
151+
borefield.pipe_data = DoubleUTube(1, 0.015, 0.02, 0.4, 0.05)
152+
borefield.calculation_setup(use_constant_Rb=False)
153+
borefield.set_max_avg_fluid_temperature(17)
154+
borefield.set_min_avg_fluid_temperature(3)
155+
hourly_load = HourlyGeothermalLoad()
156+
hourly_load.simulation_period = 20
157+
hourly_load.load_hourly_profile(FOLDER.joinpath("test\methods\hourly_data\swimming_pool.csv"), header=True,
158+
separator=";", col_injection=0, col_extraction=1)
159+
borefield.load = hourly_load
160+
borefield.calculation_setup(use_neural_network=True)
161+
162+
# optimise for minimum borehole length
163+
result = optimise_borefield_configuration(borefield, 200, 200, 5, 7, 0.5, 60, 300)
164+
borefield.borefield = result[0][-1]
165+
print(
166+
f'{len(result)} solutions are found. The optimal borehole length is: {result[0][0]:.2f}m. '
167+
f'There are {result[0][2]} boreholes. The configuration is {result[0][1]}.')
168+
result = optimise_borefield_configuration(borefield, 200, 200, 5, 7, 0.5, 60, 300, optimise='nb')
169+
borefield.borefield = result[0][-1]
170+
print(
171+
f'{len(result)} solutions are found. The optimal number of boreholes {result[0][2]}. '
172+
f'The total borehole lengths is {result[0][0]:.2f}m. The configuration is {result[0][1]}.')
173+
174+
175+
def borefield_case_1_flow_rate():
176+
borefield = Borefield(ground_data=GroundConstantTemperature(3.5, 10),
177+
load=MonthlyGeothermalLoadAbsolute(*load_case(1)))
178+
borefield.create_rectangular_borefield(10, 6, 6.5, 6.5, 100, 4, 0.075)
179+
borefield.ground_data = GroundFluxTemperature(3, 10)
180+
borefield.fluid_data = ConstantFluidData(0.568, 998, 4180, 1e-3)
181+
borefield.flow_data = ConstantFlowRate(mfr=0.3)
182+
borefield.pipe_data = DoubleUTube(1, 0.015, 0.02, 0.4, 0.05)
183+
borefield.calculation_setup(use_constant_Rb=False)
184+
borefield.calculation_setup(use_neural_network=True)
185+
186+
# optimise for minimum borehole length
187+
result = optimise_borefield_configuration(borefield, 80, 70, 5, 7, 0.5, 60, 150)
188+
print(
189+
f'{len(result)} solutions are found for a constant flow/borehole. The optimal borehole length is: {result[0][0]:.2f}m. '
190+
f'There are {result[0][2]} boreholes. The configuration is {result[0][1]}.')
191+
192+
result = optimise_borefield_configuration(borefield, 80, 70, 5, 7, 0.5, 60, 150,
193+
flow_field=ConstantFlowRate(mfr=10))
194+
print(
195+
f'{len(result)} solutions are found for a constant flow/borefield. The optimal number of boreholes {result[0][2]}. '
196+
f'The total borehole lengths is {result[0][0]:.2f}m. The configuration is {result[0][1]}.')
197+
result = optimise_borefield_configuration(borefield, 80, 70, 5, 7, 0.5, 60, 150,
198+
flow_field=ConstantFlowRate(vfr=10))
199+
200+
201+
if __name__ == "__main__": # pragma: no cover
202+
borefield_case_1()
203+
borefield_case_2()
204+
borefield_case_3()
205+
borefield_case_4()
206+
borefield_office()
207+
borefield_auditorium()
208+
borefield_swimming_pool()
209+
borefield_case_1_flow_rate()

GHEtool/Examples/optimise_load_profile_extra.py

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,29 @@
1010
from GHEtool import *
1111
from GHEtool.Methods import *
1212

13+
import time
14+
1315

1416
def optimise():
15-
data = GroundFluxTemperature(1.8, 9.7, flux=0.08)
17+
data = GroundFluxTemperature(2, 9.6, flux=0.07)
1618
borefield = Borefield()
1719
borefield.ground_data = data
18-
borefield.Rb = 0.131
19-
borefield.create_rectangular_borefield(3, 5, 6, 6, 100, 1, 0.07)
20-
load = HourlyBuildingLoad(efficiency_heating=4.5, efficiency_cooling=20)
21-
load.load_hourly_profile(FOLDER.joinpath("test\methods\hourly_data\\auditorium.csv"), header=True, separator=";",
22-
col_cooling=0, col_heating=1)
23-
24-
# optimise the load for a 10x10 field (see data above) and a fixed length of 150m.
25-
# first for an optimisation based on the power
20+
borefield.pipe_data = DoubleUTube(1.5, 0.013, 0.016, 0.4, 0.035)
21+
borefield.fluid_data = TemperatureDependentFluidData('MPG', 25)
22+
borefield.flow_data = ConstantFlowRate(mfr=0.3)
23+
borefield.borehole.use_constant_Rb = False
24+
borefield.create_rectangular_borefield(20, 4, 6, 6, 150, 1, 0.07)
25+
load = HourlyBuildingLoad(efficiency_heating=5, efficiency_cooling=20)
26+
load.load_hourly_profile(FOLDER.joinpath("test\methods\hourly_data\\hourly_profile.csv"), header=True,
27+
separator=";", col_cooling=1, col_heating=0)
28+
load.simulation_period = 10
29+
borefield.set_min_avg_fluid_temperature(3)
30+
borefield.USE_SPEED_UP_IN_SIZING = False
31+
# first optimise with the speed
32+
start = time.time()
2633
building_load, _ = optimise_load_profile_energy(borefield, load)
2734
borefield.load = building_load
28-
35+
print(time.time() - start)
2936
print(f'Max heating power (primary): {borefield.load.max_peak_extraction:,.0f}kW')
3037
print(f'Max cooling power (primary): {borefield.load.max_peak_injection:,.0f}kW')
3138

GHEtool/Methods/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
from .optimise_load_profile import optimise_load_profile_power, optimise_load_profile_energy, \
22
optimise_load_profile_balance
3+
from .optimise_borefield_configuration import *

0 commit comments

Comments
 (0)