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