Skip to content

Commit 0ca4ef8

Browse files
Merge pull request #326 from mitchute/gfunc_api
Add Methods for Creating `gFunction` and `Network` Classes from Static Parameters
2 parents 8151179 + 2631443 commit 0ca4ef8

File tree

9 files changed

+849
-19
lines changed

9 files changed

+849
-19
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
### New features
66

77
* [Pull Request 325](https://github.com/MassimoCimmino/pygfunction/pull/325) - Borefields and boreholes can now be concatenated using the `+` operator, e.g. using `new_field = field_1 + field_2`.
8+
* [Pull Request 326](https://github.com/MassimoCimmino/pygfunction/pull/326) - Introduced `gFunction.from_static_params` and `Network.from_static_params` methods. These methods facilitate the creation of `Network` objects and the evaluation of g-functions by automatically evaluating the required thermal resistances for the creation of `Pipe` objects.
89

910
### Other changes
1011

pygfunction/enums.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from enum import Enum, auto
2+
from typing import Annotated
3+
4+
5+
class PipeType(Enum):
6+
"""Enumerator for pipe configuration type."""
7+
COAXIAL_ANNULAR_IN: Annotated[
8+
int, "Coaxial pipe (annular inlet)"
9+
] = auto()
10+
COAXIAL_ANNULAR_OUT: Annotated[
11+
int, "Coaxial pipe (annular outlet)"
12+
] = auto()
13+
DOUBLE_UTUBE_PARALLEL: Annotated[
14+
int, "Double U-tube (parallel)"
15+
] = auto()
16+
DOUBLE_UTUBE_SERIES: Annotated[
17+
int, "Double U-tube (series)"
18+
] = auto()
19+
SINGLE_UTUBE: Annotated[
20+
int, "Single U-tube"
21+
] = auto()

pygfunction/gfunction.py

Lines changed: 170 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,26 @@
11
# -*- coding: utf-8 -*-
22
import warnings
33
from time import perf_counter
4+
from typing import Union, List
45

56
import numpy as np
7+
import numpy.typing as npt
68
from scipy.interpolate import interp1d as interp1d
79

810
from .borefield import Borefield
911
from .boreholes import Borehole, find_duplicates
12+
from .media import Fluid
1013
from .networks import Network
1114
from .solvers import (
1215
Detailed,
1316
Equivalent,
1417
Similarities
15-
)
18+
)
1619
from .utilities import (
1720
segment_ratios,
1821
_initialize_figure,
1922
_format_axes
20-
)
23+
)
2124

2225

2326
class gFunction(object):
@@ -282,6 +285,170 @@ def __init__(self, boreholes_or_network, alpha, time=None,
282285
if self.time is not None:
283286
self.gFunc = self.evaluate_g_function(self.time)
284287

288+
@classmethod
289+
def from_static_params(cls,
290+
H: npt.ArrayLike,
291+
D: npt.ArrayLike,
292+
r_b: npt.ArrayLike,
293+
x: npt.ArrayLike,
294+
y: npt.ArrayLike,
295+
alpha: float,
296+
time: npt.ArrayLike = None,
297+
method: str = 'equivalent',
298+
m_flow_network: float = None,
299+
options={},
300+
tilt: npt.ArrayLike = 0.,
301+
orientation: npt.ArrayLike = 0.,
302+
boundary_condition: str = 'MIFT',
303+
pipe_type_str: str = None,
304+
pos: List[tuple] = None,
305+
r_in: Union[float, tuple, npt.ArrayLike] = None,
306+
r_out: Union[float, tuple, npt.ArrayLike] = None,
307+
k_s: float = None,
308+
k_g: float = None,
309+
k_p: Union[float, tuple, npt.ArrayLike] = None,
310+
fluid_str: str = None,
311+
fluid_concentration_pct: float = None,
312+
fluid_temperature: float = 20,
313+
epsilon: float = None,
314+
reversible_flow: bool = True,
315+
bore_connectivity: list = None,
316+
J: int = 2,
317+
):
318+
319+
"""
320+
Constructs the 'gFunction' class from static parameters.
321+
322+
Parameters
323+
----------
324+
H : float or (nBoreholes,) array
325+
Borehole lengths (in meters).
326+
D : float or (nBoreholes,) array
327+
Borehole buried depths (in meters).
328+
r_b : float or (nBoreholes,) array
329+
Borehole radii (in meters).
330+
x : float or (nBoreholes,) array
331+
Position (in meters) of the head of the boreholes along the x-axis.
332+
y : float or (nBoreholes,) array
333+
Position (in meters) of the head of the boreholes along the y-axis.
334+
alpha : float
335+
Soil thermal diffusivity (in m2/s).
336+
time : float or array, optional
337+
Values of time (in seconds) for which the g-function is evaluated. The
338+
g-function is only evaluated at initialization if a value is provided.
339+
Default is None.
340+
method : str, optional
341+
Method for the evaluation of the g-function. Should be one of 'similarities', 'detailed', or 'equivalent'.
342+
Default is 'equivalent'. See 'gFunction' __init__ for more details.
343+
m_flow_network : float, optional
344+
Fluid mass flow rate into the network of boreholes (in kg/s).
345+
Default is None.
346+
options : dict, optional
347+
A dictionary of solver options. See 'gFunction' __init__ for more details.
348+
tilt : float or (nBoreholes,) array, optional
349+
Angle (in radians) from vertical of the axis of the boreholes.
350+
Default is 0.
351+
orientation : float or (nBoreholes,) array, optional
352+
Direction (in radians) of the tilt of the boreholes. Defaults to zero
353+
if the borehole is vertical.
354+
Default is 0.
355+
boundary_condition : str, optional
356+
Boundary condition for the evaluation of the g-function. Should be one of 'UHTR', 'UBWT', or 'MIFT'.
357+
Default is 'MIFT'.
358+
pipe_type_str : str, optional
359+
Pipe type used for 'MIFT' boundary condition. Should be one of 'COAXIAL_ANNULAR_IN', 'COAXIAL_ANNULAR_OUT',
360+
'DOUBLE_UTUBE_PARALLEL', 'DOUBLE_UTUBE_SERIES', or 'SINGLE_UTUBE'.
361+
pos : list of tuples, optional
362+
Position (x, y) (in meters) of the pipes inside the borehole.
363+
r_in : float, optional
364+
Inner radius (in meters) of the U-Tube pipes.
365+
r_out : float, optional
366+
Outer radius (in meters) of the U-Tube pipes.
367+
k_s : float, optional
368+
Soil thermal conductivity (in W/m-K).
369+
k_g : float, optional
370+
Grout thermal conductivity (in W/m-K).
371+
k_p : float, optional
372+
Pipe thermal conductivity (in W/m-K).
373+
fluid_str: str, optional
374+
The mixer for this application should be one of:
375+
- 'Water' - Complete water solution
376+
- 'MEG' - Ethylene glycol mixed with water
377+
- 'MPG' - Propylene glycol mixed with water
378+
- 'MEA' - Ethanol mixed with water
379+
- 'MMA' - Methanol mixed with water
380+
fluid_concentration_pct: float, optional
381+
Mass fraction of the mixing fluid added to water (in %).
382+
Lower bound = 0. Upper bound is dependent on the mixture.
383+
fluid_temperature: float, optional
384+
Temperature used for evaluating fluid properties (in degC).
385+
Default is 20.
386+
epsilon : float, optional
387+
Pipe roughness (in meters).
388+
reversible_flow : bool, optional
389+
True to treat a negative mass flow rate as the reversal of flow
390+
direction within the borehole. If False, the direction of flow is not
391+
reversed when the mass flow rate is negative, and the absolute value is
392+
used for calculations.
393+
Default True.
394+
bore_connectivity : list, optional
395+
Index of fluid inlet into each borehole. -1 corresponds to a borehole
396+
connected to the bore field inlet. If this parameter is not provided,
397+
parallel connections between boreholes is used.
398+
Default is None.
399+
J : int, optional
400+
Number of multipoles per pipe to evaluate the thermal resistances.
401+
J=1 or J=2 usually gives sufficient accuracy. J=0 corresponds to the
402+
line source approximation.
403+
Default is 2.
404+
405+
Returns
406+
-------
407+
gFunction : 'gFunction' object
408+
The g-function.
409+
410+
Notes
411+
-----
412+
- When using the 'MIFT' boundary condition, the parameters `pipe_type_str`,
413+
`fluid_str`, `fluid_concentration_pct`, `fluid_temperature`, and
414+
`epsilon` are required.
415+
416+
"""
417+
418+
if boundary_condition.upper() not in ['UBWT', 'UHTR', 'MIFT']:
419+
raise ValueError(f"'{boundary_condition}' is not a valid boundary condition.")
420+
421+
# construct all required pieces
422+
borefield = Borefield(H, D, r_b, x, y, tilt, orientation)
423+
424+
if boundary_condition.upper() == 'MIFT':
425+
boreholes = borefield.to_boreholes()
426+
cp_f = Fluid(fluid_str, fluid_concentration_pct).cp
427+
boreholes_or_network= Network.from_static_params(
428+
boreholes,
429+
pipe_type_str,
430+
pos,
431+
r_in,
432+
r_out,
433+
k_s,
434+
k_g,
435+
k_p,
436+
m_flow_network,
437+
epsilon,
438+
fluid_str,
439+
fluid_concentration_pct,
440+
fluid_temperature,
441+
reversible_flow,
442+
bore_connectivity,
443+
J,
444+
)
445+
else:
446+
boreholes_or_network = borefield
447+
cp_f = None
448+
449+
return cls(boreholes_or_network, alpha, time=time, method=method, boundary_condition=boundary_condition,
450+
m_flow_network=m_flow_network, cp_f=cp_f, options=options)
451+
285452
def evaluate_g_function(self, time):
286453
"""
287454
Evaluate the g-function.
@@ -520,7 +687,7 @@ def visualize_heat_extraction_rates(
520687

521688
# Adjust figure to window
522689
plt.tight_layout()
523-
690+
524691
return fig
525692

526693
def visualize_heat_extraction_rate_profiles(

0 commit comments

Comments
 (0)