geoloop 0.0.1__py3-none-any.whl → 1.0.0b1__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.
Files changed (47) hide show
  1. geoloop/axisym/AxisymetricEL.py +751 -0
  2. geoloop/axisym/__init__.py +3 -0
  3. geoloop/bin/Flowdatamain.py +89 -0
  4. geoloop/bin/Lithologymain.py +84 -0
  5. geoloop/bin/Loadprofilemain.py +100 -0
  6. geoloop/bin/Plotmain.py +250 -0
  7. geoloop/bin/Runbatch.py +81 -0
  8. geoloop/bin/Runmain.py +86 -0
  9. geoloop/bin/SingleRunSim.py +928 -0
  10. geoloop/bin/__init__.py +3 -0
  11. geoloop/cli/__init__.py +0 -0
  12. geoloop/cli/batch.py +106 -0
  13. geoloop/cli/main.py +105 -0
  14. geoloop/configuration.py +946 -0
  15. geoloop/constants.py +112 -0
  16. geoloop/geoloopcore/CoaxialPipe.py +503 -0
  17. geoloop/geoloopcore/CustomPipe.py +727 -0
  18. geoloop/geoloopcore/__init__.py +3 -0
  19. geoloop/geoloopcore/b2g.py +739 -0
  20. geoloop/geoloopcore/b2g_ana.py +535 -0
  21. geoloop/geoloopcore/boreholedesign.py +683 -0
  22. geoloop/geoloopcore/getloaddata.py +112 -0
  23. geoloop/geoloopcore/pyg_ana.py +280 -0
  24. geoloop/geoloopcore/pygfield_ana.py +519 -0
  25. geoloop/geoloopcore/simulationparameters.py +130 -0
  26. geoloop/geoloopcore/soilproperties.py +152 -0
  27. geoloop/geoloopcore/strat_interpolator.py +194 -0
  28. geoloop/lithology/__init__.py +3 -0
  29. geoloop/lithology/plot_lithology.py +277 -0
  30. geoloop/lithology/process_lithology.py +697 -0
  31. geoloop/loadflowdata/__init__.py +3 -0
  32. geoloop/loadflowdata/flow_data.py +161 -0
  33. geoloop/loadflowdata/loadprofile.py +325 -0
  34. geoloop/plotting/__init__.py +3 -0
  35. geoloop/plotting/create_plots.py +1137 -0
  36. geoloop/plotting/load_data.py +432 -0
  37. geoloop/utils/RunManager.py +164 -0
  38. geoloop/utils/__init__.py +0 -0
  39. geoloop/utils/helpers.py +841 -0
  40. geoloop-1.0.0b1.dist-info/METADATA +112 -0
  41. geoloop-1.0.0b1.dist-info/RECORD +46 -0
  42. geoloop-1.0.0b1.dist-info/entry_points.txt +2 -0
  43. geoloop-0.0.1.dist-info/licenses/LICENSE → geoloop-1.0.0b1.dist-info/licenses/LICENSE.md +2 -1
  44. geoloop-0.0.1.dist-info/METADATA +0 -10
  45. geoloop-0.0.1.dist-info/RECORD +0 -6
  46. {geoloop-0.0.1.dist-info → geoloop-1.0.0b1.dist-info}/WHEEL +0 -0
  47. {geoloop-0.0.1.dist-info → geoloop-1.0.0b1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,535 @@
1
+ import numpy as np
2
+ import pygfunction as gt
3
+ from scipy.constants import pi
4
+
5
+ from geoloop.geoloopcore.CustomPipe import CustomPipe
6
+ from geoloop.geoloopcore.simulationparameters import SimulationParameters
7
+ from geoloop.geoloopcore.soilproperties import SoilProperties
8
+
9
+
10
+ class B2G_ana:
11
+ """
12
+ Class for analytical / semi-analytical borehole-to-ground simulation.
13
+
14
+ This class uses pygfunction's g-function and a load aggregation scheme
15
+ (Claesson-Javed) to compute borehole wall temperatures and then obtains
16
+ fluid/pipe temperatures from `CustomPipe` methods.
17
+
18
+ Attributes
19
+ ----------
20
+ custom_pipe : CustomPipe
21
+ Depth-dependent borehole configuration and properties.
22
+ soil_props : SoilProperties
23
+ Depth-dependent soil parameters (conductivity and temperature).
24
+ sim_params : SimulationParameters
25
+ Simulation parameters (time, flow, power, temperature).
26
+
27
+ Notes
28
+ -----
29
+ The simulation can be run for input power or input temperature and calls the appropriate function.
30
+ `runsimulation_power` is called for power simulations
31
+ `runsimulation_temperature` is called for temperature simulations
32
+ """
33
+
34
+ def __init__(
35
+ self,
36
+ custom_pipe: CustomPipe,
37
+ soil_properties: SoilProperties,
38
+ simulation_parameters: SimulationParameters,
39
+ ) -> None:
40
+ """
41
+ Initialize the analytical BHE model wrapper.
42
+
43
+ Parameters
44
+ ----------
45
+ custom_pipe : CustomPipe
46
+ Pipe/borehole configuration object.
47
+ soil_properties : SoilProperties
48
+ Soil properties provider.
49
+ simulation_parameters : SimulationParameters
50
+ Operational and simulation parameters.
51
+ """
52
+ self.custom_pipe = custom_pipe
53
+ self.soil_props = soil_properties
54
+ self.sim_params = simulation_parameters
55
+
56
+ def runsimulation(self):
57
+ """
58
+ Run the simulation of the borehole to ground heat exchanger.
59
+
60
+ Returns
61
+ -------
62
+ tuple
63
+ (hours, Q_b, flowrate, qsign, T_fi, T_fo, T_bave,
64
+ z, zseg, T_b, T_ftimes, qbzseg, h_fpipes)
65
+ """
66
+ if self.sim_params.run_type == SimulationParameters.POWER:
67
+ return self.runsimulation_power()
68
+ else:
69
+ return self.runsimulation_temperature()
70
+
71
+ def runsimulation_temperature(self) -> tuple:
72
+ """
73
+ Run the simulation of the borehole to ground heat exchanger for an input inlet temperature.
74
+
75
+ The method:
76
+ - computes the segment-wise g-function scaling,
77
+ - uses load-aggregation to obtain borehole wall temperature response,
78
+ - calls CustomPipe methods to compute fluid temperatures for each time step.
79
+
80
+ Returns
81
+ -------
82
+ tuple
83
+ (hours, Q_b, flowrate, qsign, T_fi, T_fo, T_bave,
84
+ z, zseg, T_b, T_ftimes, qbzseg, h_fpipes)
85
+ """
86
+ sim_params = self.sim_params
87
+ custom_pipe = self.custom_pipe
88
+ soil_props = self.soil_props
89
+ nsegments = sim_params.nsegments
90
+
91
+ # temporal arrays and derived geometry
92
+ H = custom_pipe.b.H
93
+ D = custom_pipe.b.D
94
+ Nt = sim_params.Nt
95
+ time = sim_params.time
96
+ m_flow = sim_params.m_flow[0]
97
+ scaleflow = sim_params.m_flow / m_flow
98
+
99
+ dz = H / nsegments
100
+ zmin = D + 0.5 * dz
101
+ zmax = D + H - 0.5 * dz
102
+ zseg = np.linspace(zmin, zmax, nsegments)
103
+ zz = np.linspace(D, D + H, nsegments + 1)
104
+
105
+ k_s = soil_props.get_k_s(zz[0:-1], zz[1:], sim_params.isample)
106
+ z = np.linspace(D, D + H, nsegments + 1)
107
+
108
+ # Build load aggregation + g-function once
109
+ LoadAgg = []
110
+ for k in range(nsegments):
111
+ la = gt.load_aggregation.ClaessonJaved(sim_params.dt, sim_params.tmax)
112
+ LoadAgg.append(la)
113
+ # TODO: JD: the workaround below was not reuired anymore?
114
+ # The field contains only one borehole
115
+ # boreField = [gt.boreholes.Borehole(custom_pipe.b.H, custom_pipe.b.D, custom_pipe.b.r_b, x=0., y=0.)]
116
+ # The field contains only one borehole, but needs one extra at very large distance to be correct, ie. gfunc plateaus at 6.7)
117
+ boreField = [
118
+ gt.boreholes.Borehole(
119
+ custom_pipe.b.H,
120
+ custom_pipe.b.D,
121
+ custom_pipe.b.r_b,
122
+ x=0.0,
123
+ y=0.0,
124
+ tilt=np.radians(0.1),
125
+ ),
126
+ gt.boreholes.Borehole(
127
+ custom_pipe.b.H,
128
+ custom_pipe.b.D,
129
+ custom_pipe.b.r_b,
130
+ x=1000.0,
131
+ y=0.0,
132
+ tilt=np.radians(0.1),
133
+ ),
134
+ ]
135
+
136
+ # Get time values needed for g-function evaluation
137
+ time_req = LoadAgg[0].get_times_for_simulation()
138
+
139
+ # Calculate g-function
140
+ # g-Function calculation options
141
+ options = {"nSegments": 8, "disp": False}
142
+ np.seterr(under="ignore")
143
+
144
+ alpha = soil_props.alfa
145
+ gFunc = gt.gfunction.gFunction(
146
+ boreField, alpha, time=time_req, options=options, method="similarities"
147
+ )
148
+
149
+ # Initialize load aggregation scheme
150
+ for k in range(nsegments):
151
+ LoadAgg[k].initialize(gFunc.gFunc / (2 * pi * k_s[k]))
152
+
153
+ # Protect agains zero loads
154
+ Qabsmin = H * 0.1 # assume at least 0.1 W /m to avoid division by zero
155
+
156
+ # Compute deltaT_b by temporal superposition for each segment/time
157
+ deltaT_b = np.zeros(Nt)
158
+ deltaT_bk = np.zeros((Nt, nsegments))
159
+ power = np.zeros(Nt)
160
+ Q_b = sim_params.Q
161
+
162
+ # First pass: compute deltaT_b using aggregated loads
163
+ for i, (t, Q_b_i) in enumerate(zip(time, Q_b)):
164
+ # avoid the Q_B_i to be zero, it is at least the 10% of H in watts
165
+ if abs(Q_b_i) < Qabsmin:
166
+ Q_b_i = Qabsmin * np.sign(Q_b_i)
167
+
168
+ # Increment time step by (1)
169
+ for k in range(nsegments):
170
+ LoadAgg[k].next_time_step(t)
171
+ # Apply current load
172
+ LoadAgg[k].set_current_load(Q_b_i / H)
173
+
174
+ # Evaluate the average borehole wall temeprature
175
+ deltaT_b[i] = 0
176
+ for k in range(nsegments):
177
+ deltaT_bk[i, k] = LoadAgg[k].temporal_superposition()
178
+
179
+ deltaT_b[i] = np.average(deltaT_bk[i, :])
180
+ power[i] = Q_b_i
181
+
182
+ # Initialize output containers
183
+ T_b_top = np.zeros(Nt)
184
+ T_bave = np.zeros(Nt)
185
+ T_fi = np.zeros(Nt)
186
+ T_fo = np.zeros(Nt)
187
+
188
+ Q_b = np.zeros(Nt)
189
+ deltaT_b_ref = np.zeros(Nt)
190
+ flowrate = np.zeros(Nt)
191
+ Rs = np.zeros(Nt)
192
+ qsign = np.zeros(Nt)
193
+
194
+ # Initial guess for Rs (borehole thermal resistance) per time step
195
+ imax = -1
196
+ for i, t in enumerate(time):
197
+ if (i > imax) and (i < Nt):
198
+ p = power[i]
199
+ Rs[i] = deltaT_b[i] / (p / H)
200
+
201
+ minR = 0.01
202
+ Rs = np.where(np.logical_and(Rs < minR, Rs > -0.5), minR, Rs)
203
+
204
+ # iterate to refine Rsz using qbzseg from pipe model (few iterations)
205
+ iter = 0
206
+ niter = 3
207
+ Rsz = np.zeros((len(Rs), nsegments))
208
+ qbzseg = np.zeros((len(Rs), nsegments))
209
+ T_b = np.zeros((len(Rs), nsegments))
210
+ h_fpipes = np.zeros((len(Rs), custom_pipe.nPipes))
211
+ T_ftimes = np.zeros((len(Rs), nsegments + 1, custom_pipe.nPipes))
212
+
213
+ while iter < niter:
214
+ if iter == 0:
215
+ for i, rsi in enumerate(Rs):
216
+ Rsz[i] = rsi * np.ones(nsegments)
217
+
218
+ else:
219
+ # Recompute g-function/loadaggs (keeps same options)
220
+ alpha = soil_props.alfa
221
+ gFunc = gt.gfunction.gFunction(
222
+ boreField,
223
+ alpha,
224
+ time=time_req,
225
+ options=options,
226
+ method="similarities",
227
+ )
228
+
229
+ # Reset load aggregation
230
+ for k in range(nsegments):
231
+ LoadAgg[k] = gt.load_aggregation.ClaessonJaved(
232
+ sim_params.dt, sim_params.tmax
233
+ )
234
+ # Initialize load aggregation scheme
235
+ LoadAgg[k].initialize(gFunc.gFunc / (2 * pi * k_s[k]))
236
+
237
+ Rsz = np.zeros((len(Rs), nsegments))
238
+ for k in range(nsegments):
239
+ # this only works if time is same as reduced time array
240
+ for i, (t, Q_b_i) in enumerate(zip(time, qbzseg[:, k])):
241
+ # Increment time step by (1)
242
+ LoadAgg[k].next_time_step(t)
243
+
244
+ if abs(Q_b_i * H) < Qabsmin:
245
+ Q_b_i = Qabsmin * np.sign(Q_b_i) / H
246
+
247
+ # Apply current load
248
+ LoadAgg[k].set_current_load(Q_b_i)
249
+
250
+ # Evaluate borehole wall temeprature
251
+ deltaT_bk[i][k] = LoadAgg[k].temporal_superposition()
252
+ Rsz[i, k] = deltaT_bk[i][k] / qbzseg[i, k]
253
+
254
+ # For each time-step compute fluid solution using CustomPipe
255
+ iter += 1
256
+ imax = -1
257
+ for i, t in enumerate(time):
258
+ if (i > imax) and (i < Nt):
259
+ p = power[i]
260
+ custom_pipe.update_scaleflow(scaleflow[i])
261
+ h_f = custom_pipe.h_f
262
+ signpower = np.sign(p)
263
+ T_f_in = sim_params.Tin[i]
264
+
265
+ T_f_out, p, Reff, T_f, Tb, qbz = (
266
+ custom_pipe.get_temperature_depthvar(
267
+ T_f_in,
268
+ signpower,
269
+ Rsz[i],
270
+ soil_props=soil_props,
271
+ nsegments=nsegments,
272
+ )
273
+ )
274
+
275
+ Q_b[i] = p
276
+ T_b_top[i] = Tb[0]
277
+ deltaT_b_ref[i] = deltaT_b[i]
278
+ T_bave[i] = np.average(Tb)
279
+ T_fi[i] = T_f_in
280
+ h_fpipes[i] = h_f
281
+ T_fo[i] = T_f_out
282
+ flowrate[i] = scaleflow[i] * m_flow
283
+ T_ftimes[i] = T_f # stored index time, depth, pipe
284
+ T_b[i] = Tb
285
+ qbzseg[i] = qbz
286
+ qsign[i] = np.sign(max(qbz) * min(qbz))
287
+ imax = i
288
+
289
+ hours = time / 3600.0
290
+
291
+ return (
292
+ hours,
293
+ Q_b,
294
+ flowrate,
295
+ qsign,
296
+ T_fi,
297
+ T_fo,
298
+ T_bave,
299
+ z,
300
+ zseg,
301
+ T_b,
302
+ T_ftimes,
303
+ qbzseg,
304
+ h_fpipes,
305
+ )
306
+
307
+ def runsimulation_power(self) -> tuple:
308
+ """
309
+ Run the simulation of the borehole to ground heat exchanger for an input heat demand.
310
+
311
+ Returns
312
+ -------
313
+ tuple
314
+ (hours, Q_b, flowrate, qsign, T_fi, T_fo, T_bave,
315
+ z, zseg, T_b, T_ftimes, qbzseg, h_fpipes)
316
+ """
317
+ sim_params = self.sim_params
318
+ custom_pipe = self.custom_pipe
319
+ soil_props = self.soil_props
320
+ nsegments = sim_params.nsegments
321
+
322
+ # geomertry and derived arrays
323
+ H = custom_pipe.b.H
324
+ D = custom_pipe.b.D
325
+ Nt = sim_params.Nt
326
+ time = sim_params.time
327
+ m_flow = sim_params.m_flow[0]
328
+ scaleflow = sim_params.m_flow / m_flow
329
+
330
+ dz = H / nsegments
331
+ zmin = D + 0.5 * dz
332
+ zmax = D + H - 0.5 * dz
333
+ zseg = np.linspace(zmin, zmax, nsegments)
334
+ zz = np.linspace(D, D + H, nsegments + 1)
335
+
336
+ k_s = soil_props.get_k_s(zz[0:-1], zz[1:], sim_params.isample)
337
+ z = np.linspace(D, D + H, nsegments + 1)
338
+
339
+ # prepare load aggregation + gfunc
340
+ # The field contains only one borehole
341
+ old = False
342
+ if old:
343
+ boreField = [
344
+ gt.boreholes.Borehole(
345
+ custom_pipe.b.H, custom_pipe.b.D, custom_pipe.b.r_b, x=0.0, y=0.0
346
+ )
347
+ ]
348
+ # The field contains only one borehole, but needs one extra at very large distance to be correct, ie. gfunc plateaus at 6.7)
349
+ else:
350
+ boreField = [
351
+ gt.boreholes.Borehole(
352
+ custom_pipe.b.H,
353
+ custom_pipe.b.D,
354
+ custom_pipe.b.r_b,
355
+ x=0.0,
356
+ y=0.0,
357
+ tilt=np.radians(0.1),
358
+ ),
359
+ gt.boreholes.Borehole(
360
+ custom_pipe.b.H,
361
+ custom_pipe.b.D,
362
+ custom_pipe.b.r_b,
363
+ x=1000.0,
364
+ y=0.0,
365
+ tilt=np.radians(0.1),
366
+ ),
367
+ ]
368
+
369
+ LoadAgg = []
370
+ for k in range(nsegments):
371
+ la = gt.load_aggregation.ClaessonJaved(sim_params.dt, sim_params.tmax)
372
+ LoadAgg.append(la)
373
+
374
+ # Get time values needed for g-function evaluation
375
+ time_req = LoadAgg[0].get_times_for_simulation()
376
+
377
+ # Calculate g-function
378
+ # g-Function calculation options
379
+ options = {"nSegments": 8, "disp": False}
380
+ np.seterr(under="ignore")
381
+
382
+ alpha = soil_props.alfa
383
+ gFunc = gt.gfunction.gFunction(
384
+ boreField, alpha, time=time_req, options=options, method="similarities"
385
+ )
386
+
387
+ # initialize load aggregation scheme
388
+ for k in range(nsegments):
389
+ LoadAgg[k].initialize(gFunc.gFunc / (2 * pi * k_s[k]))
390
+
391
+ Qabsmin = H * 0.1 # assume at least 0.1 W /m to avoid division by zero
392
+
393
+ deltaT_b = np.zeros(Nt)
394
+ deltaT_bk = np.zeros((Nt, nsegments))
395
+ power = np.zeros(Nt)
396
+ Q_b = sim_params.Q
397
+
398
+ for i, (t, Q_b_i) in enumerate(zip(time, Q_b)):
399
+ # avoid the Q_B_i to be zero, it is at least the 10% of H in watts
400
+ if abs(Q_b_i) < Qabsmin:
401
+ Q_b_i = Qabsmin * np.sign(Q_b_i)
402
+
403
+ # Increment time step by (1)
404
+ for k in range(nsegments):
405
+ LoadAgg[k].next_time_step(t)
406
+ # Apply current load
407
+ LoadAgg[k].set_current_load(Q_b_i / H)
408
+
409
+ # Evaluate the average borehole wall temeprature
410
+ deltaT_b[i] = 0
411
+ for k in range(nsegments):
412
+ deltaT_bk[i, k] = LoadAgg[k].temporal_superposition()
413
+
414
+ deltaT_b[i] = np.average(deltaT_bk[i, :])
415
+ power[i] = Q_b_i
416
+
417
+ T_b_top = np.zeros(Nt)
418
+ T_bave = np.zeros(Nt)
419
+ T_fi = np.zeros(Nt)
420
+ T_fo = np.zeros(Nt)
421
+
422
+ Q_b = np.zeros(Nt)
423
+ deltaT_b_ref = np.zeros(Nt)
424
+ flowrate = np.zeros(Nt)
425
+ Rs = np.zeros(Nt)
426
+ qsign = np.zeros(Nt)
427
+
428
+ # compute initial Rs
429
+ imax = -1
430
+ for i, t in enumerate(time):
431
+ if (i > imax) and (i < Nt):
432
+ power_i = power[i]
433
+ p = np.maximum(power_i, 100)
434
+ Rs[i] = deltaT_b[i] / (p / H)
435
+
436
+ minR = 0.01
437
+ Rs = np.where(np.logical_and(Rs < minR, Rs > -0.5), minR, Rs)
438
+
439
+ # iterative refinement
440
+ iter = 0
441
+ niter = 3
442
+ Rsz = np.zeros((len(Rs), nsegments))
443
+ qbzseg = np.zeros((len(Rs), nsegments))
444
+ T_b = np.zeros((len(Rs), nsegments))
445
+ h_fpipes = np.zeros((len(Rs), custom_pipe.nPipes))
446
+ T_ftimes = np.zeros((len(Rs), nsegments + 1, custom_pipe.nPipes))
447
+
448
+ while iter < niter:
449
+ if iter == 0:
450
+ for i, rsi in enumerate(Rs):
451
+ Rsz[i] = rsi * np.ones(nsegments)
452
+
453
+ else:
454
+ # reinitilize g-function
455
+ alpha = soil_props.alfa
456
+ gFunc = gt.gfunction.gFunction(
457
+ boreField,
458
+ alpha,
459
+ time=time_req,
460
+ options=options,
461
+ method="similarities",
462
+ )
463
+
464
+ # Reinitialize load aggregation scheme
465
+ for k in range(nsegments):
466
+ LoadAgg[k] = gt.load_aggregation.ClaessonJaved(
467
+ sim_params.dt, sim_params.tmax
468
+ )
469
+ LoadAgg[k].initialize(gFunc.gFunc / (2 * pi * k_s[k]))
470
+
471
+ Rsz = np.zeros((len(Rs), nsegments))
472
+ for k in range(nsegments):
473
+ # this only works if time is same as reduced time array
474
+ for i, (t, Q_b_i) in enumerate(zip(time, qbzseg[:, k])):
475
+ # Increment time step by (1)
476
+ LoadAgg[k].next_time_step(t)
477
+
478
+ if abs(Q_b_i * H) < Qabsmin:
479
+ Q_b_i = Qabsmin * np.sign(Q_b_i) / H
480
+
481
+ # Apply current load
482
+ LoadAgg[k].set_current_load(Q_b_i)
483
+
484
+ # Evaluate borehole wall temeprature
485
+ deltaT_bk[i][k] = LoadAgg[k].temporal_superposition()
486
+ Rsz[i, k] = deltaT_bk[i][k] / qbzseg[i, k]
487
+ iter += 1
488
+ imax = -1
489
+
490
+ # compute fluid temperatures for this iteration
491
+ for i, t in enumerate(time):
492
+ if (i > imax) and (i < Nt):
493
+ # print(il)
494
+ power_i = power[i]
495
+ custom_pipe.update_scaleflow(scaleflow[i])
496
+ h_f = custom_pipe.h_f
497
+
498
+ (T_f_out, T_f_in, Reff, T_f, Tb, qbz) = (
499
+ custom_pipe.get_temperature_depthvar_power(
500
+ power_i, Rsz[i], soil_props, nsegments=nsegments
501
+ )
502
+ )
503
+
504
+ Q_b[i] = power[i]
505
+ T_b_top[i] = Tb[0]
506
+ deltaT_b_ref[i] = deltaT_b[i]
507
+ T_bave[i] = np.average(Tb)
508
+ T_fi[i] = T_f_in
509
+ h_fpipes[i] = h_f
510
+ T_fo[i] = T_f_out
511
+ flowrate[i] = scaleflow[i] * m_flow
512
+ T_ftimes[i] = T_f # stored index time, depth, pipe
513
+ T_b[i] = Tb
514
+ # qbz is calculated at the depth division in segments (zseg)
515
+ qbzseg[i] = qbz
516
+ qsign[i] = np.sign(max(qbz) * min(qbz))
517
+ imax = i
518
+
519
+ hours = time / 3600.0
520
+
521
+ return (
522
+ hours,
523
+ Q_b,
524
+ flowrate,
525
+ qsign,
526
+ T_fi,
527
+ T_fo,
528
+ T_bave,
529
+ z,
530
+ zseg,
531
+ T_b,
532
+ T_ftimes,
533
+ qbzseg,
534
+ h_fpipes,
535
+ )