geoloop 0.0.1__py3-none-any.whl → 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- geoloop/axisym/AxisymetricEL.py +751 -0
- geoloop/axisym/__init__.py +3 -0
- geoloop/bin/Flowdatamain.py +89 -0
- geoloop/bin/Lithologymain.py +84 -0
- geoloop/bin/Loadprofilemain.py +100 -0
- geoloop/bin/Plotmain.py +250 -0
- geoloop/bin/Runbatch.py +81 -0
- geoloop/bin/Runmain.py +86 -0
- geoloop/bin/SingleRunSim.py +928 -0
- geoloop/bin/__init__.py +3 -0
- geoloop/cli/__init__.py +0 -0
- geoloop/cli/batch.py +106 -0
- geoloop/cli/main.py +105 -0
- geoloop/configuration.py +946 -0
- geoloop/constants.py +112 -0
- geoloop/geoloopcore/CoaxialPipe.py +503 -0
- geoloop/geoloopcore/CustomPipe.py +727 -0
- geoloop/geoloopcore/__init__.py +3 -0
- geoloop/geoloopcore/b2g.py +739 -0
- geoloop/geoloopcore/b2g_ana.py +516 -0
- geoloop/geoloopcore/boreholedesign.py +683 -0
- geoloop/geoloopcore/getloaddata.py +112 -0
- geoloop/geoloopcore/pyg_ana.py +280 -0
- geoloop/geoloopcore/pygfield_ana.py +519 -0
- geoloop/geoloopcore/simulationparameters.py +130 -0
- geoloop/geoloopcore/soilproperties.py +152 -0
- geoloop/geoloopcore/strat_interpolator.py +194 -0
- geoloop/lithology/__init__.py +3 -0
- geoloop/lithology/plot_lithology.py +277 -0
- geoloop/lithology/process_lithology.py +695 -0
- geoloop/loadflowdata/__init__.py +3 -0
- geoloop/loadflowdata/flow_data.py +161 -0
- geoloop/loadflowdata/loadprofile.py +325 -0
- geoloop/plotting/__init__.py +3 -0
- geoloop/plotting/create_plots.py +1142 -0
- geoloop/plotting/load_data.py +432 -0
- geoloop/utils/RunManager.py +164 -0
- geoloop/utils/__init__.py +0 -0
- geoloop/utils/helpers.py +841 -0
- geoloop-1.0.0.dist-info/METADATA +120 -0
- geoloop-1.0.0.dist-info/RECORD +46 -0
- geoloop-1.0.0.dist-info/entry_points.txt +2 -0
- geoloop-0.0.1.dist-info/licenses/LICENSE → geoloop-1.0.0.dist-info/licenses/LICENSE.md +2 -1
- geoloop-0.0.1.dist-info/METADATA +0 -10
- geoloop-0.0.1.dist-info/RECORD +0 -6
- {geoloop-0.0.1.dist-info → geoloop-1.0.0.dist-info}/WHEEL +0 -0
- {geoloop-0.0.1.dist-info → geoloop-1.0.0.dist-info}/top_level.txt +0 -0
geoloop/constants.py
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
repo_path = Path(__file__).parent.parent.parent
|
|
4
|
+
|
|
5
|
+
# Test directories
|
|
6
|
+
test_dir = repo_path / "test"
|
|
7
|
+
tests_input_path = test_dir / "input"
|
|
8
|
+
test_output_path = test_dir / "output"
|
|
9
|
+
|
|
10
|
+
# Resources directory
|
|
11
|
+
resources_path = repo_path / "resources"
|
|
12
|
+
|
|
13
|
+
# Lithology resources directory
|
|
14
|
+
lithology_properties_xlsx = (
|
|
15
|
+
resources_path / "lithology_properties" / "lithology_properties.xlsx"
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
# Dictionary of units for various parameters in the model.
|
|
19
|
+
units_dict = {
|
|
20
|
+
"Q_b": "W",
|
|
21
|
+
"flowrate": "kg/s",
|
|
22
|
+
"T_fi": "\u00b0C",
|
|
23
|
+
"T_fo": "\u00b0C",
|
|
24
|
+
"T_bave": "\u00b0C",
|
|
25
|
+
"dploop": "bar",
|
|
26
|
+
"qloop": "W",
|
|
27
|
+
"z": "m",
|
|
28
|
+
"T_b": "\u00b0C",
|
|
29
|
+
"T_f": "\u00b0C",
|
|
30
|
+
"qzb": "W/m",
|
|
31
|
+
"k_g": "W/mK",
|
|
32
|
+
"k_p": "W/mK",
|
|
33
|
+
"m_flow": "kg/s",
|
|
34
|
+
"Tin": "\u00b0C",
|
|
35
|
+
"H": "m",
|
|
36
|
+
"epsilon": "m",
|
|
37
|
+
"alfa": "m\u00b2/s",
|
|
38
|
+
"Tgrad": "\u00b0C/100m",
|
|
39
|
+
"Q": "W",
|
|
40
|
+
"qsign": "-",
|
|
41
|
+
"nPipes": "-",
|
|
42
|
+
"zseg": "-",
|
|
43
|
+
"k_s_scale": "-",
|
|
44
|
+
"Re_in": "-",
|
|
45
|
+
"Re_out": "-",
|
|
46
|
+
"h_f_max": "-",
|
|
47
|
+
"h_f_min": "-",
|
|
48
|
+
"k_s": "W/mK",
|
|
49
|
+
"k_s_res": "W/mK",
|
|
50
|
+
"fluid_percent": "%",
|
|
51
|
+
"insu_z": "m",
|
|
52
|
+
"insu_dr": "%",
|
|
53
|
+
"k_g_res": "W/mK",
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
# Dictionary of formatted names for various parameters in the model.
|
|
57
|
+
format_dict = {
|
|
58
|
+
"Q_b": "$Q_{b}$",
|
|
59
|
+
"flowrate": "$flowrate$",
|
|
60
|
+
"T_fi": "$T_{fi}$",
|
|
61
|
+
"T_fo": "$T_{fo}$",
|
|
62
|
+
"T_bave": "$T_{bave}$",
|
|
63
|
+
"dploop": "$dploop$",
|
|
64
|
+
"qloop": "$qloop$",
|
|
65
|
+
"z": "$z$",
|
|
66
|
+
"T_b": "$T_{b}$",
|
|
67
|
+
"T_f": "$T_{f}$",
|
|
68
|
+
"qzb": "$qzb$",
|
|
69
|
+
"k_g": "$k_{g}$",
|
|
70
|
+
"k_p": "$k_{p}$",
|
|
71
|
+
"m_flow": "$m_{flow}$",
|
|
72
|
+
"Tin": "$Tin$",
|
|
73
|
+
"H": "$H$",
|
|
74
|
+
"epsilon": r"$\epsilon$",
|
|
75
|
+
"alfa": r"$\alpha$",
|
|
76
|
+
"Tgrad": "$T_{grad}$",
|
|
77
|
+
"Q": "$Q$",
|
|
78
|
+
"qsign": "$q_{sign}$",
|
|
79
|
+
"nPipes": "$n_{Pipes}$",
|
|
80
|
+
"zseg": "$z_{seg}$",
|
|
81
|
+
"k_s_scale": "$k_{s}scale$",
|
|
82
|
+
"Re_in": "$Re_{in}$",
|
|
83
|
+
"Re_out": "$Re_{out}$",
|
|
84
|
+
"h_f_max": "$h_{f}max$",
|
|
85
|
+
"h_f_min": "$h_{f}min$",
|
|
86
|
+
"k_s": "$k_{s}$",
|
|
87
|
+
"k_s_res": "$k_{s-res}$",
|
|
88
|
+
"fluid_percent": "$fluid_{percent}$",
|
|
89
|
+
"insu_z": "$insu_{z}$",
|
|
90
|
+
"insu_dr": "$insu_{dr}$",
|
|
91
|
+
"k_g_res": "$k_{g-res}$",
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
# Dictionary with colors for lithology plotting
|
|
95
|
+
lithology_colors = {
|
|
96
|
+
"sand": "#FFFF00",
|
|
97
|
+
"clay": "#008000",
|
|
98
|
+
"shells": "#800080",
|
|
99
|
+
"chalk": "#FFFFFF",
|
|
100
|
+
"marl": "#A52A2A",
|
|
101
|
+
"claystone": "#1F1F1F",
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
# Dictionary for mapping lithology names from Dutch to English
|
|
105
|
+
lithology_names_english = {
|
|
106
|
+
"zand": "Sand",
|
|
107
|
+
"klei": "Clay",
|
|
108
|
+
"schelpen": "Shells",
|
|
109
|
+
"krijt": "Chalk",
|
|
110
|
+
"mergel": "Marl",
|
|
111
|
+
"kleisteen": "Claystone",
|
|
112
|
+
}
|
|
@@ -0,0 +1,503 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import pygfunction as gt
|
|
3
|
+
|
|
4
|
+
from geoloop.geoloopcore.CustomPipe import CustomPipe, thermal_resistance_pipe
|
|
5
|
+
from geoloop.geoloopcore.soilproperties import SoilProperties
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def Swap(arr: np.ndarray, start_index: int, last_index: int) -> None:
|
|
9
|
+
"""
|
|
10
|
+
Swap two columns in an array, in place, from start_index to last_index.
|
|
11
|
+
|
|
12
|
+
Parameters
|
|
13
|
+
----------
|
|
14
|
+
arr : np.ndarray
|
|
15
|
+
2D array where columns will be swapped.
|
|
16
|
+
start_index : int
|
|
17
|
+
Index of the first column to swap.
|
|
18
|
+
last_index : int
|
|
19
|
+
Index of the second column to swap.
|
|
20
|
+
|
|
21
|
+
Returns
|
|
22
|
+
-------
|
|
23
|
+
None
|
|
24
|
+
The operation is performed in place.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
arr[:, [start_index, last_index]] = arr[:, [last_index, start_index]]
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class CoaxialPipe(CustomPipe):
|
|
31
|
+
"""
|
|
32
|
+
This class is used to evaluate the thermal resistance network of a Coaxial borehole.
|
|
33
|
+
|
|
34
|
+
In its default mode the object
|
|
35
|
+
is marked by depth-indepedent design properties which can be altered, and can also access other methods from its baseclass
|
|
36
|
+
CustomPipe.
|
|
37
|
+
|
|
38
|
+
It uses pygfunction of Cimmino and Cook [#Cimmino2024]
|
|
39
|
+
for the determination of the thermal resistivity network of the borehole
|
|
40
|
+
|
|
41
|
+
It contains information regarding the physical dimensions and thermal
|
|
42
|
+
characteristics of the pipes and the grout material, as well as methods (through its base class) to
|
|
43
|
+
evaluate fluid temperatures and heat extraction rates based on the work of
|
|
44
|
+
Hellstrom [#Single-Hellstrom1991]_. Internal borehole thermal resistances
|
|
45
|
+
are evaluated using the multipole method of Claesson and Hellstrom
|
|
46
|
+
[#Single-Claesson2011b]_.
|
|
47
|
+
|
|
48
|
+
References
|
|
49
|
+
----------
|
|
50
|
+
.. [#Cimmino2022] Cimmino, M., & Cook, J.C. (2022). pygfunction 2.2: New features and improvements in accuracy and computational efficiency.
|
|
51
|
+
In Research Conference Proceedings, IGSHPA Annual Conference 2022 (pp. 45-52).
|
|
52
|
+
International Ground Source Heat Pump Association. DOI: https://doi.org/10.22488/okstate.22.000015.
|
|
53
|
+
.. [#Single-Hellstrom1991] Hellstrom, G. (1991). Ground heat storage.
|
|
54
|
+
Thermal Analyses of Duct Storage Systems I: Theory. PhD Thesis.
|
|
55
|
+
University of Lund, Department of Mathematical Physics. Lund, Sweden.
|
|
56
|
+
.. [#Single-Claesson2011b] Claesson, J., & Hellstrom, G. (2011).
|
|
57
|
+
Multipole method to calculate borehole thermal resistances in a borehole
|
|
58
|
+
heat exchanger. HVAC&R Research, 17(6), 895-911.
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
def __init__(
|
|
62
|
+
self,
|
|
63
|
+
r_in: np.ndarray | float,
|
|
64
|
+
r_out: np.ndarray | float,
|
|
65
|
+
borehole,
|
|
66
|
+
k_g: float | np.ndarray,
|
|
67
|
+
k_p: float | np.ndarray,
|
|
68
|
+
k_s: float = 1.0,
|
|
69
|
+
J: int = 2,
|
|
70
|
+
m_flow: float = 1.0,
|
|
71
|
+
T_f: float = 10.0,
|
|
72
|
+
fluid_str: str = "Water",
|
|
73
|
+
percent: float = 100.0,
|
|
74
|
+
epsilon: float = 1e-6,
|
|
75
|
+
ncalcsegments: int = 1,
|
|
76
|
+
R_p: list[np.ndarray] | None = None,
|
|
77
|
+
) -> None:
|
|
78
|
+
"""
|
|
79
|
+
Initialize a coaxial borehole pipe model and compute its thermal and
|
|
80
|
+
hydraulic properties.
|
|
81
|
+
|
|
82
|
+
Parameters
|
|
83
|
+
----------
|
|
84
|
+
r_in : float or ndarray
|
|
85
|
+
Inner radii of the coaxial pipes (m). If scalar, copied for both
|
|
86
|
+
inlet and outlet pipes. (first radius is largest as this is corresponding to the inlet)
|
|
87
|
+
r_out : float or ndarray
|
|
88
|
+
Outer radii of the coaxial pipes (m). If scalar, copied for both
|
|
89
|
+
inlet and outlet pipes.
|
|
90
|
+
borehole : gt.boreholes.Borehole
|
|
91
|
+
Borehole geometry object.
|
|
92
|
+
k_g : float or ndarray
|
|
93
|
+
Grout thermal conductivity (W/m·K). If array-like, represents
|
|
94
|
+
values per segment.
|
|
95
|
+
k_p : float or ndarray
|
|
96
|
+
Pipe wall thermal conductivity (W/m·K).
|
|
97
|
+
k_s : float, optional
|
|
98
|
+
Soil thermal conductivity (W/m·K). Default is 1.0.
|
|
99
|
+
J : int, optional
|
|
100
|
+
Number of multipoles used in the multipole expansion. Default is 2.
|
|
101
|
+
m_flow : float, optional
|
|
102
|
+
Total mass flow rate in the BHE (kg/s).
|
|
103
|
+
T_f : float, optional
|
|
104
|
+
Fluid temperature at inlet (°C).
|
|
105
|
+
fluid_str : str, optional
|
|
106
|
+
Working fluid name for thermal property lookup.
|
|
107
|
+
percent : float, optional
|
|
108
|
+
Concentration of glycol or other additive (%).
|
|
109
|
+
epsilon : float, optional
|
|
110
|
+
Relative pipe roughness for hydraulic calculations.
|
|
111
|
+
ncalcsegments : int, optional
|
|
112
|
+
Number of depth segments used in thermal resistance evaluation.
|
|
113
|
+
R_p : list of ndarray, optional
|
|
114
|
+
Precomputed pipe thermal resistances for each segment. If None,
|
|
115
|
+
resistances are computed automatically. Default is empty list, and routines will calculate the resistivity based on the
|
|
116
|
+
pipe dimensions and thermal conductivity.
|
|
117
|
+
|
|
118
|
+
Notes
|
|
119
|
+
-----
|
|
120
|
+
- Creates a :class:`gt.pipes.Coaxial` object for use in pygfunction.
|
|
121
|
+
- Computes convective coefficients, fluid properties, and initial
|
|
122
|
+
delta-circuit thermal resistance matrices.
|
|
123
|
+
"""
|
|
124
|
+
|
|
125
|
+
self.pos = [(0, 0), (0, 0)]
|
|
126
|
+
self.nPipes = 2
|
|
127
|
+
if np.isscalar(r_in):
|
|
128
|
+
r_in = r_in * np.ones(self.nPipes)
|
|
129
|
+
self.r_in = r_in
|
|
130
|
+
if np.isscalar(r_out):
|
|
131
|
+
r_out = r_out * np.ones(self.nPipes)
|
|
132
|
+
self.r_out = r_out
|
|
133
|
+
self.b = borehole
|
|
134
|
+
self.k_s = 0.01
|
|
135
|
+
self.k_g = k_g
|
|
136
|
+
self.k_p = k_p
|
|
137
|
+
self.J = J
|
|
138
|
+
self.nInlets = 1
|
|
139
|
+
self._iOuter = 0
|
|
140
|
+
self._iInner = 1
|
|
141
|
+
self.nOutlets = self.nPipes - self.nInlets
|
|
142
|
+
self.ncalcsegments = ncalcsegments
|
|
143
|
+
|
|
144
|
+
# Pipe thermal resistances
|
|
145
|
+
# create a list of R_p if required
|
|
146
|
+
if len(R_p) == 0:
|
|
147
|
+
rp = thermal_resistance_pipe(r_in, r_out, k_p)
|
|
148
|
+
self.R_p = []
|
|
149
|
+
for i in range(ncalcsegments):
|
|
150
|
+
self.R_p.append(rp)
|
|
151
|
+
else:
|
|
152
|
+
self.R_p = R_p
|
|
153
|
+
|
|
154
|
+
# Initialize flow rate and fluid properties including fluid resistivity with pipes
|
|
155
|
+
self.m_flow = m_flow
|
|
156
|
+
self.m_flow_pipe = m_flow * np.ones(self.nPipes)
|
|
157
|
+
self.m_flow_pipe[: self.nInlets] = m_flow / self.nInlets
|
|
158
|
+
self.m_flow_pipe[self.nInlets :] = -m_flow / self.nOutlets
|
|
159
|
+
fluid = gt.media.Fluid(fluid_str, percent, T=T_f)
|
|
160
|
+
self.cp_f = fluid.cp # Fluid specific isobaric heat capacity (J/kg.K)
|
|
161
|
+
self.rho_f = fluid.rho # Fluid density (kg/m3)
|
|
162
|
+
self.mu_f = fluid.mu # Fluid dynamic viscosity (kg/m.s)
|
|
163
|
+
self.k_f = fluid.k # Fluid thermal conductivity (W/m.K)
|
|
164
|
+
self.epsilon = epsilon
|
|
165
|
+
|
|
166
|
+
# default Pipe thermal resistance (take from the first segment)
|
|
167
|
+
# Inner pipe
|
|
168
|
+
R_p_in = self.R_p[0][self._iInner]
|
|
169
|
+
# Outer pipe
|
|
170
|
+
R_p_out = self.R_p[0][self._iOuter]
|
|
171
|
+
|
|
172
|
+
# Fluid-to-fluid thermal resistance
|
|
173
|
+
# Inner pipe
|
|
174
|
+
r_in_in = self.r_in[self._iInner]
|
|
175
|
+
h_f_in = gt.pipes.convective_heat_transfer_coefficient_circular_pipe(
|
|
176
|
+
m_flow, r_in_in, self.mu_f, self.rho_f, self.k_f, self.cp_f, self.epsilon
|
|
177
|
+
)
|
|
178
|
+
R_f_in = 1.0 / (h_f_in * 2 * np.pi * r_in_in)
|
|
179
|
+
# Outer pipe
|
|
180
|
+
r_in_out = self.r_out[self._iInner]
|
|
181
|
+
r_out_in = self.r_out[self._iOuter]
|
|
182
|
+
h_f_a_in, h_f_a_out = (
|
|
183
|
+
gt.pipes.convective_heat_transfer_coefficient_concentric_annulus(
|
|
184
|
+
m_flow,
|
|
185
|
+
r_in_out,
|
|
186
|
+
r_out_in,
|
|
187
|
+
self.mu_f,
|
|
188
|
+
self.rho_f,
|
|
189
|
+
self.k_f,
|
|
190
|
+
self.cp_f,
|
|
191
|
+
self.epsilon,
|
|
192
|
+
)
|
|
193
|
+
)
|
|
194
|
+
R_f_out_in = 1.0 / (h_f_a_in * 2 * np.pi * r_in_out)
|
|
195
|
+
R_ff = R_f_in + R_p_in + R_f_out_in
|
|
196
|
+
|
|
197
|
+
# Coaxial GHE in borehole
|
|
198
|
+
R_f_out_out = 1.0 / (h_f_a_out * 2 * np.pi * r_out_in)
|
|
199
|
+
R_fp = R_p_out + R_f_out_out
|
|
200
|
+
|
|
201
|
+
r_inner = np.roll(self.r_in, 1)
|
|
202
|
+
r_outer = np.roll(self.r_out, 1)
|
|
203
|
+
|
|
204
|
+
self.coaxial = gt.pipes.Coaxial(
|
|
205
|
+
(0, 0), r_inner, r_outer, self.b, k_s, k_g[0], R_ff, R_fp, J=self.J
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
self.h_f = np.zeros(2)
|
|
209
|
+
|
|
210
|
+
self.Rd = []
|
|
211
|
+
self.update_scaleflow(1.0, forceupdate=True)
|
|
212
|
+
|
|
213
|
+
return
|
|
214
|
+
|
|
215
|
+
def create_coaxial(self) -> gt.pipes.Coaxial:
|
|
216
|
+
"""
|
|
217
|
+
Return the underlying pygfunction :class:`Coaxial` object.
|
|
218
|
+
|
|
219
|
+
Returns
|
|
220
|
+
-------
|
|
221
|
+
gt.pipes.Coaxial
|
|
222
|
+
The pygfunction coaxial borehole object representing the thermal
|
|
223
|
+
resistance network.
|
|
224
|
+
"""
|
|
225
|
+
return self.coaxial
|
|
226
|
+
|
|
227
|
+
def init_thermal_resistances(self, k_g: np.ndarray, R_p: list[np.ndarray]) -> None:
|
|
228
|
+
"""
|
|
229
|
+
Initialize pipe and grout thermal resistances for all borehole segments.
|
|
230
|
+
|
|
231
|
+
This routine is called from the B2G.runsimulation method, in order to generate thermal resistances based
|
|
232
|
+
on actual segments determined by len(k_g) and len(R_p).
|
|
233
|
+
|
|
234
|
+
Parameters
|
|
235
|
+
----------
|
|
236
|
+
k_g : ndarray
|
|
237
|
+
Grout thermal conductivity values for each segment.
|
|
238
|
+
R_p : list of ndarray
|
|
239
|
+
Pipe thermal resistance values for each segment.
|
|
240
|
+
"""
|
|
241
|
+
self.ncalcsegments = len(k_g)
|
|
242
|
+
self.k_g = k_g
|
|
243
|
+
self.update_scaleflow(1.0)
|
|
244
|
+
self.R_p = R_p
|
|
245
|
+
|
|
246
|
+
def update_scaleflow(
|
|
247
|
+
self,
|
|
248
|
+
scaleflow: float = 1.0,
|
|
249
|
+
forceupdate: bool = False,
|
|
250
|
+
initialize_stored_coeff: bool = True,
|
|
251
|
+
) -> None:
|
|
252
|
+
"""
|
|
253
|
+
Update the scaling of flow rate and associated thermal resistance network.
|
|
254
|
+
|
|
255
|
+
This method adjusts the flow rate scaling and updates the thermal resistance
|
|
256
|
+
network based on the new flow rate. Optionally, it can force an update and
|
|
257
|
+
reinitialize stored coefficients.
|
|
258
|
+
|
|
259
|
+
Parameters
|
|
260
|
+
----------
|
|
261
|
+
scaleflow : float, optional
|
|
262
|
+
Scaling factor for flow rate. Default is 1.0.
|
|
263
|
+
forceupdate : bool, optional
|
|
264
|
+
If True, forces update of thermal resistances even if changes are small.
|
|
265
|
+
Default is False.
|
|
266
|
+
initialize_stored_coeff : bool, optional
|
|
267
|
+
If True, reinitializes stored thermal resistance coefficients.
|
|
268
|
+
Default is True.
|
|
269
|
+
|
|
270
|
+
Returns
|
|
271
|
+
-------
|
|
272
|
+
None
|
|
273
|
+
Updates internal state in place.
|
|
274
|
+
"""
|
|
275
|
+
self.scaleflow = scaleflow
|
|
276
|
+
m_flow = abs(self.m_flow_pipe[0] * self.scaleflow)
|
|
277
|
+
|
|
278
|
+
# Pipe thermal resistance (the two pipes have the same thermal conductivity, k_p)
|
|
279
|
+
# Fluid-to-fluid thermal resistance
|
|
280
|
+
# Inner pipe
|
|
281
|
+
r_in_in = self.r_in[self._iInner]
|
|
282
|
+
h_f_in = gt.pipes.convective_heat_transfer_coefficient_circular_pipe(
|
|
283
|
+
m_flow, r_in_in, self.mu_f, self.rho_f, self.k_f, self.cp_f, self.epsilon
|
|
284
|
+
)
|
|
285
|
+
R_f_in = 1.0 / (h_f_in * 2 * np.pi * r_in_in)
|
|
286
|
+
# Outer pipe
|
|
287
|
+
r_in_out = self.r_out[self._iInner]
|
|
288
|
+
r_out_in = self.r_out[self._iOuter]
|
|
289
|
+
h_f_a_in, h_f_a_out = (
|
|
290
|
+
gt.pipes.convective_heat_transfer_coefficient_concentric_annulus(
|
|
291
|
+
m_flow,
|
|
292
|
+
r_in_out,
|
|
293
|
+
r_out_in,
|
|
294
|
+
self.mu_f,
|
|
295
|
+
self.rho_f,
|
|
296
|
+
self.k_f,
|
|
297
|
+
self.cp_f,
|
|
298
|
+
self.epsilon,
|
|
299
|
+
)
|
|
300
|
+
)
|
|
301
|
+
|
|
302
|
+
R_f_out_in = 1.0 / (h_f_a_in * 2 * np.pi * r_in_out)
|
|
303
|
+
R_f_out_out = 1.0 / (h_f_a_out * 2 * np.pi * r_out_in)
|
|
304
|
+
|
|
305
|
+
hfnew = np.asarray([h_f_a_out, h_f_a_in])
|
|
306
|
+
hfdif = np.subtract(hfnew, self.h_f)
|
|
307
|
+
hfdot = np.dot(hfdif, hfdif)
|
|
308
|
+
|
|
309
|
+
if not forceupdate and self.ncalcsegments == len(self.Rd) and (hfdot < 1):
|
|
310
|
+
return
|
|
311
|
+
|
|
312
|
+
self.h_f = np.asarray([h_f_a_out, h_f_a_in])
|
|
313
|
+
self.coaxial.h_f = self.h_f
|
|
314
|
+
|
|
315
|
+
# --- recompute segment resistances ---
|
|
316
|
+
self.R = []
|
|
317
|
+
self.Rd = []
|
|
318
|
+
|
|
319
|
+
for k in range(self.ncalcsegments):
|
|
320
|
+
# Delta-circuit thermal resistances
|
|
321
|
+
# Inner pipe
|
|
322
|
+
R_p_in = self.R_p[k][self._iInner]
|
|
323
|
+
# Outer pipe
|
|
324
|
+
R_p_out = self.R_p[k][self._iOuter]
|
|
325
|
+
|
|
326
|
+
R_ff = R_f_in + R_p_in + R_f_out_in
|
|
327
|
+
R_fp = R_p_out + R_f_out_out
|
|
328
|
+
|
|
329
|
+
if k == 0:
|
|
330
|
+
self.coaxial.update_thermal_resistances(R_ff, R_fp)
|
|
331
|
+
|
|
332
|
+
R_fg = gt.pipes.thermal_resistances(
|
|
333
|
+
self.pos[0:1],
|
|
334
|
+
self.r_out[self._iOuter],
|
|
335
|
+
self.b.r_b,
|
|
336
|
+
self.k_s,
|
|
337
|
+
self.k_g[k],
|
|
338
|
+
R_fp,
|
|
339
|
+
J=self.J,
|
|
340
|
+
)[1][0]
|
|
341
|
+
|
|
342
|
+
# Delta-circuit thermal resistances
|
|
343
|
+
Rd = np.zeros((2, 2))
|
|
344
|
+
Rd[self._iInner, self._iInner] = np.inf
|
|
345
|
+
Rd[self._iInner, self._iOuter] = R_ff
|
|
346
|
+
Rd[self._iOuter, self._iInner] = R_ff
|
|
347
|
+
Rd[self._iOuter, self._iOuter] = R_fg
|
|
348
|
+
self.Rd.append(Rd)
|
|
349
|
+
|
|
350
|
+
if initialize_stored_coeff:
|
|
351
|
+
self.coaxial._initialize_stored_coefficients()
|
|
352
|
+
|
|
353
|
+
def get_temperature_depthvar(
|
|
354
|
+
self,
|
|
355
|
+
T_f_in: float,
|
|
356
|
+
signpower: float,
|
|
357
|
+
Rs: np.ndarray,
|
|
358
|
+
soil_props: SoilProperties,
|
|
359
|
+
nsegments: int = 10,
|
|
360
|
+
) -> tuple:
|
|
361
|
+
"""
|
|
362
|
+
Compute outlet temperature and thermal performance for depth-variable borehole.
|
|
363
|
+
|
|
364
|
+
This method partitions the borehole depth into segments and iteratively computes
|
|
365
|
+
fluid temperatures, borehole temperatures, and heat flows based on thermal
|
|
366
|
+
resistances and soil properties.
|
|
367
|
+
|
|
368
|
+
Parameters
|
|
369
|
+
----------
|
|
370
|
+
T_f_in : float
|
|
371
|
+
Inlet fluid temperature (°C).
|
|
372
|
+
signpower : float
|
|
373
|
+
Sign and magnitude for initial power guess.
|
|
374
|
+
Rs : np.ndarray
|
|
375
|
+
Array of thermal resistances for each segment.
|
|
376
|
+
soil_props : SoilProperties
|
|
377
|
+
Object defining soil properties and temperature gradient.
|
|
378
|
+
nsegments : int, optional
|
|
379
|
+
Number of depth segments. Default is 10.
|
|
380
|
+
|
|
381
|
+
Returns
|
|
382
|
+
-------
|
|
383
|
+
T_f_out : float
|
|
384
|
+
Outlet fluid temperature (°C).
|
|
385
|
+
power : float
|
|
386
|
+
Heat extraction or injection power (W).
|
|
387
|
+
Reff : float
|
|
388
|
+
Effective thermal resistance (m·K/W).
|
|
389
|
+
ptemp : np.ndarray
|
|
390
|
+
Fluid temperatures per segment.
|
|
391
|
+
Tb : np.ndarray
|
|
392
|
+
Borehole temperatures per segment.
|
|
393
|
+
qbz : np.ndarray
|
|
394
|
+
Heat flow per segment (W).
|
|
395
|
+
"""
|
|
396
|
+
bh = self.b
|
|
397
|
+
hstep = bh.H / nsegments
|
|
398
|
+
|
|
399
|
+
# Depth coordinates (mid of each segment)
|
|
400
|
+
zmin = bh.D + 0.5 * hstep
|
|
401
|
+
zmax = bh.D + bh.H - 0.5 * hstep
|
|
402
|
+
zseg = np.linspace(zmin, zmax, nsegments)
|
|
403
|
+
|
|
404
|
+
# soil temperature at each depth segment
|
|
405
|
+
Tg_borehole = soil_props.getTg(zseg)
|
|
406
|
+
|
|
407
|
+
# initalize arrays
|
|
408
|
+
qbz = Tg_borehole * 0.0
|
|
409
|
+
Tb = np.arange(nsegments, dtype=float)
|
|
410
|
+
Tf = Tb * 0.0
|
|
411
|
+
|
|
412
|
+
ptemp = np.arange((nsegments + 1) * self.nPipes, dtype=float).reshape(
|
|
413
|
+
nsegments + 1, self.nPipes
|
|
414
|
+
)
|
|
415
|
+
|
|
416
|
+
# initialize the top temperatures (inlet)
|
|
417
|
+
ptemp[0, : self.nInlets] = T_f_in
|
|
418
|
+
|
|
419
|
+
# iterate for T_f_out such that bottom temperatures become the same
|
|
420
|
+
dtfout = 0
|
|
421
|
+
dtempold = 0
|
|
422
|
+
dtempnew = 1
|
|
423
|
+
T_f_out = T_f_in + 1e-1 * signpower
|
|
424
|
+
cont = True
|
|
425
|
+
|
|
426
|
+
while abs(dtempnew) > 1e-4 or cont:
|
|
427
|
+
# set outlet boundary condition guess
|
|
428
|
+
ptemp[0, self.nInlets :] = T_f_out
|
|
429
|
+
|
|
430
|
+
# loop over each segment
|
|
431
|
+
for i in range(nsegments):
|
|
432
|
+
Rd = self._Rd[i]
|
|
433
|
+
b = 1.0 / Rd[0][0]
|
|
434
|
+
|
|
435
|
+
# Tf is only for output purposes
|
|
436
|
+
Tf[i] = np.average(ptemp[i])
|
|
437
|
+
|
|
438
|
+
# prep next segment's temperatures
|
|
439
|
+
ptemp[i + 1] = ptemp[i]
|
|
440
|
+
|
|
441
|
+
# iteration variables within the segment
|
|
442
|
+
tseg = 0.5 * (ptemp[i] + ptemp[i + 1])
|
|
443
|
+
dtemp = 1
|
|
444
|
+
icount = 0
|
|
445
|
+
|
|
446
|
+
# check that Rs[i]*b is not close to 1 if so modify with small number
|
|
447
|
+
if Rs[i] < 0:
|
|
448
|
+
Rs[i] = abs(Rs[i])
|
|
449
|
+
|
|
450
|
+
# iterate until pipe temperatures converge
|
|
451
|
+
while np.dot(dtemp, dtemp) > 1e-10:
|
|
452
|
+
icount += 1
|
|
453
|
+
tsegold = tseg
|
|
454
|
+
|
|
455
|
+
a = b * tseg[0]
|
|
456
|
+
Tb[i] = (Rs[i] * a + Tg_borehole[i]) / (1 + Rs[i] * b)
|
|
457
|
+
|
|
458
|
+
q1 = b * (tseg[0] - Tb[i])
|
|
459
|
+
q2 = (tseg[1] - tseg[0]) / Rd[0][1]
|
|
460
|
+
|
|
461
|
+
# Update fluid temperatures
|
|
462
|
+
mflow0 = self.m_flow_pipe[0] * self.scaleflow * self.cp_f
|
|
463
|
+
mflow1 = self.m_flow_pipe[1] * self.scaleflow * self.cp_f
|
|
464
|
+
|
|
465
|
+
ptemp[i + 1][0] = ptemp[i][0] - q1 * hstep / mflow0
|
|
466
|
+
ptemp[i + 1][0] += q2 * hstep / mflow0
|
|
467
|
+
|
|
468
|
+
ptemp[i + 1][1] = ptemp[i][1] - q2 * hstep / mflow1
|
|
469
|
+
|
|
470
|
+
tseg = 0.5 * (ptemp[i] + ptemp[i + 1])
|
|
471
|
+
dtemp = tseg - tsegold
|
|
472
|
+
|
|
473
|
+
# segment heat flow
|
|
474
|
+
qbz[i] = -q1 * hstep
|
|
475
|
+
|
|
476
|
+
# compute temperature mismatch for iteration
|
|
477
|
+
dtempnew = np.sum(
|
|
478
|
+
ptemp[nsegments, self.nInlets :] * self.m_flow_pipe[self.nInlets :]
|
|
479
|
+
) + np.sum(
|
|
480
|
+
ptemp[nsegments, : self.nInlets] * self.m_flow_pipe[: self.nInlets]
|
|
481
|
+
)
|
|
482
|
+
|
|
483
|
+
# Update outlet temperature guess
|
|
484
|
+
if abs(dtfout) > 0:
|
|
485
|
+
g = dtfout / (dtempnew - dtempold)
|
|
486
|
+
dtfout = -dtempnew * g
|
|
487
|
+
cont = False
|
|
488
|
+
else:
|
|
489
|
+
dtfout = 1e-1
|
|
490
|
+
cont = True
|
|
491
|
+
|
|
492
|
+
dtempold = dtempnew
|
|
493
|
+
T_f_out += dtfout
|
|
494
|
+
|
|
495
|
+
# Final power and effective resistance
|
|
496
|
+
power = (T_f_out - T_f_in) * self.m_flow * self.scaleflow * self.cp_f
|
|
497
|
+
|
|
498
|
+
if abs(np.sum(qbz) - power) > 1:
|
|
499
|
+
print("power is not sumq (sumq, power):", np.sum(qbz), ",", power)
|
|
500
|
+
|
|
501
|
+
Reff = -np.average(Tf - Tb) * bh.H / power
|
|
502
|
+
|
|
503
|
+
return T_f_out, power, Reff, ptemp, Tb, qbz
|