Calculation of g-Functions computed with non-uniform segment lengthsΒΆ

This example demonstrates the use of the utilities module to determine discretized segment ratios along a borehole.

The following script computes g-Functions for a field of 6x4 boreholes utilizing the MIFT and UBWT boundary conditions with a 48 segments per borehole and equal segment lengths. The MIFT and UBWT g-functions are computed with only 8 segments per borehole and non-uniform segment lengths. RMSE values are compared. It is shown that g-functions can be calculated accurately using a small number of segments.

The script is located in: pygfunction/examples/discretize_boreholes.py

  1# -*- coding: utf-8 -*-
  2""" Example of g-function calculation using non-uniform segment lengths along
  3    the boreholes.
  4
  5    The g-functions of a field of 6x4 boreholes are calculated for two
  6    boundary conditions : (1) a uniform borehole wall temperature along the
  7    boreholes equal for all boreholes, and (2) an equal inlet fluid
  8    temperature into the boreholes. g-Functions using 8 segments in a
  9    non-uniform discretization are compared to reference g-functions
 10    calculated using 48 segments of equal lengths. It is shown that g-functions
 11    can be calculated accurately using a small number of segments.
 12"""
 13
 14import pygfunction as gt
 15from numpy import pi
 16import matplotlib.pyplot as plt
 17import numpy as np
 18
 19
 20def main():
 21    # -------------------------------------------------------------------------
 22    # Simulation parameters
 23    # -------------------------------------------------------------------------
 24
 25    # Borehole dimensions
 26    D = 4.0             # Borehole buried depth (m)
 27    H = 150.0           # Borehole length (m)
 28    r_b = 0.075         # Borehole radius (m)
 29    B = 7.5             # Borehole spacing (m)
 30
 31    # Pipe dimensions
 32    r_out = 0.0211      # Pipe outer radius (m)
 33    r_in = 0.0147       # Pipe inner radius (m)
 34    D_s = 0.052         # Shank spacing (m)
 35    epsilon = 1.0e-6    # Pipe roughness (m)
 36
 37    # Pipe positions
 38    # Single U-tube [(x_in, y_in), (x_out, y_out)]
 39    pos_pipes = [(-D_s, 0.), (D_s, 0.)]
 40
 41    # Ground properties
 42    alpha = 1.0e-6      # Ground thermal diffusivity (m2/s)
 43    k_s = 2.0           # Ground thermal conductivity (W/m.K)
 44
 45    # Grout properties
 46    k_g = 1.0           # Grout thermal conductivity (W/m.K)
 47
 48    # Pipe properties
 49    k_p = 0.4           # Pipe thermal conductivity (W/m.K)
 50
 51    # Fluid properties
 52    m_flow_borehole = 0.25  # Total fluid mass flow rate per borehole (kg/s)
 53    # The fluid is propylene-glycol (20 %) at 20 degC
 54    fluid = gt.media.Fluid('MPG', 20.)
 55    cp_f = fluid.cp     # Fluid specific isobaric heat capacity (J/kg.K)
 56    rho_f = fluid.rho   # Fluid density (kg/m3)
 57    mu_f = fluid.mu     # Fluid dynamic viscosity (kg/m.s)
 58    k_f = fluid.k       # Fluid thermal conductivity (W/m.K)
 59
 60    # g-Function calculation options
 61
 62    # Number of segments used in the reference calculation with uniform
 63    # discretization
 64    nSegments_uniform = 48
 65    options_uniform = {'nSegments': nSegments_uniform,
 66                       'segment_ratios': None,
 67                       'disp': True}
 68    # Number of segments used in the calculation with non-uniform
 69    # discretization
 70    nSegments_unequal = 8
 71    segment_ratios = gt.utilities.segment_ratios(
 72        nSegments_unequal, end_length_ratio=0.02)
 73    options_unequal = {'nSegments': nSegments_unequal,
 74                       'segment_ratios': segment_ratios,
 75                       'disp':True}
 76
 77    # Geometrically expanding time vector.
 78    dt = 100*3600.                  # Time step
 79    tmax = 3000. * 8760. * 3600.    # Maximum time
 80    Nt = 25                         # Number of time steps
 81    ts = H**2/(9.*alpha)            # Bore field characteristic time
 82    time = gt.utilities.time_geometric(dt, tmax, Nt)
 83
 84    # -------------------------------------------------------------------------
 85    # Borehole field
 86    # -------------------------------------------------------------------------
 87
 88    # Field of 6x4 (n=24) boreholes
 89    N_1 = 6
 90    N_2 = 4
 91    boreField = gt.boreholes.rectangle_field(N_1, N_2, B, B, H, D, r_b)
 92    gt.boreholes.visualize_field(boreField)
 93    nBoreholes = len(boreField)
 94
 95    # -------------------------------------------------------------------------
 96    # Initialize pipe model
 97    # -------------------------------------------------------------------------
 98
 99    # Pipe thermal resistance
100    R_p = gt.pipes.conduction_thermal_resistance_circular_pipe(
101        r_in, r_out, k_p)
102    # Fluid to inner pipe wall thermal resistance (Single U-tube)
103    m_flow_pipe = m_flow_borehole
104    h_f = gt.pipes.convective_heat_transfer_coefficient_circular_pipe(
105        m_flow_pipe, r_in, mu_f, rho_f, k_f, cp_f, epsilon)
106    R_f = 1.0/(h_f*2*pi*r_in)
107
108    # Single U-tube, same for all boreholes in the bore field
109    UTubes = []
110    for borehole in boreField:
111        SingleUTube = gt.pipes.SingleUTube(
112            pos_pipes, r_in, r_out, borehole, k_s, k_g, R_f + R_p)
113        UTubes.append(SingleUTube)
114    m_flow_network = m_flow_borehole*nBoreholes
115
116    # Network of boreholes connected in parallel
117    network = gt.networks.Network(
118        boreField, UTubes, m_flow_network=m_flow_network, cp_f=cp_f)
119
120    # -------------------------------------------------------------------------
121    # Evaluate the g-functions for the borefield
122    # -------------------------------------------------------------------------
123
124    # Compute g-function for the converged MIFT case with equal number of
125    # segments per borehole, and equal segment lengths along the boreholes
126    gfunc_MIFT_uniform = gt.gfunction.gFunction(
127        network, alpha, time=time, boundary_condition='MIFT',
128        options=options_uniform)
129
130    # Calculate the g-function for uniform borehole wall temperature
131    gfunc_UBWT_uniform = gt.gfunction.gFunction(
132        boreField, alpha, time=time, boundary_condition='UBWT',
133        options=options_uniform)
134
135    # Compute g-function for the MIFT case with equal number of segments per
136    # borehole, and non-uniform segment lengths along the boreholes
137    gfunc_MIFT_unequal = gt.gfunction.gFunction(
138        network, alpha, time=time, boundary_condition='MIFT',
139        options=options_unequal)
140
141    # Calculate the g-function for uniform borehole wall temperature
142    gfunc_UBWT_unequal = gt.gfunction.gFunction(
143        boreField, alpha, time=time, boundary_condition='UBWT',
144        options=options_unequal)
145
146    # Compute the rmse between the reference cases and the discretized
147    # (predicted) cases
148    RMSE_MIFT = RMSE(gfunc_MIFT_uniform.gFunc, gfunc_MIFT_unequal.gFunc)
149    print(f'RMSE (MIFT) = {RMSE_MIFT:.5f}')
150    RMSE_UBWT = RMSE(gfunc_UBWT_uniform.gFunc, gfunc_UBWT_unequal.gFunc)
151    print(f'RMSE (UBWT) = {RMSE_UBWT:.5f}')
152
153    # -------------------------------------------------------------------------
154    # Plot g-functions
155    # -------------------------------------------------------------------------
156
157    ax = gfunc_MIFT_uniform.visualize_g_function().axes[0]
158    ax.plot(np.log(time / ts), gfunc_UBWT_uniform.gFunc)
159    ax.plot(np.log(time / ts), gfunc_MIFT_unequal.gFunc, 'o')
160    ax.plot(np.log(time / ts), gfunc_UBWT_unequal.gFunc, 'o')
161    ax.legend(
162        ['Equal inlet temperature (uniform segments)',
163         'Uniform borehole wall temperature (uniform segments)',
164         'Equal inlet temperature (non-uniform segments)',
165         'Uniform borehole wall temperature (non-uniform segments)'])
166    plt.tight_layout()
167
168    return
169
170
171def RMSE(reference, predicted):
172    rmse = np.linalg.norm(predicted - reference) / len(reference)
173    return rmse
174
175
176# Main function
177if __name__ == '__main__':
178    main()