Compare the accuracy and speed of different g-function solvers

This example compares the simulation times and the accuracy of different solvers for the evaluation of g-functions.

The g-function of a field of 6 by4 boreholes is first calculated for a boundary condition of uniform borehole wall temperature along the boreholes, equal for all boreholes. Three different solvers are compared : ‘detailed’, ‘similarities’ 1 and ‘equivalent’ 2. Their accuracy and calculation time are compared using the ‘detailed’ solver as a reference. This shows that the ‘similarities’ solver can evaluate g-functions with high accuracy.

The g-function of a field of 12 by 10 boreholes is then calculated for a boundary condition of uniform borehole wall temperature along the boreholes, equal for all boreholes. Two different solvers are compared : ‘similarities’ and ‘equivalent’. The accuracy and calculation time of the ‘equivalent’ is compared using the ‘similarities’ solver as a reference. This shows that the ‘equivalent’ solver evaluates g-functions at a very high calculation speed while maintaining reasonable accuracy.

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

  1# -*- coding: utf-8 -*-
  2""" Comparison of solvers for the evaluation of g-functions using uniform and
  3    equal borehole wall temperatures.
  4
  5    The g-function of a field of 6x4 boreholes is calculated for a boundary
  6    condition of uniform borehole wall temperature along the boreholes, equal
  7    for all boreholes. Three different solvers are compared : 'detailed',
  8    'similarities' and 'equivalent'. Their accuracy and calculation time are
  9    compared using the 'detailed' solver as a reference. This shows that the
 10    'similarities' solver can evaluate g-functions with high accuracy.
 11
 12    The g-function of a field of 12x10 boreholes is calculated for a boundary
 13    condition of uniform borehole wall temperature along the boreholes, equal
 14    for all boreholes. Two different solvers are compared : 'similarities' and
 15    'equivalent'. The accuracy and calculation time of the 'equivalent' is
 16    compared using the 'similarities' solver as a reference. This shows that
 17    the 'equivalent' solver evaluates g-functions at a very high calculation
 18    speed while maintaining reasonable accuracy.
 19
 20"""
 21import matplotlib.pyplot as plt
 22import numpy as np
 23from time import perf_counter
 24
 25import pygfunction as gt
 26
 27
 28def main():
 29    # -------------------------------------------------------------------------
 30    # Simulation parameters
 31    # -------------------------------------------------------------------------
 32
 33    # Borehole dimensions
 34    D = 4.0             # Borehole buried depth (m)
 35    H = 150.0           # Borehole length (m)
 36    r_b = 0.075         # Borehole radius (m)
 37    B = 7.5             # Borehole spacing (m)
 38
 39    # Thermal properties
 40    alpha = 1.0e-6      # Ground thermal diffusivity (m2/s)
 41
 42    # g-Function calculation options
 43    options = {'nSegments': 8,
 44               'disp': True}
 45
 46    # Geometrically expanding time vector.
 47    dt = 100*3600.                  # Time step
 48    tmax = 3000. * 8760. * 3600.    # Maximum time
 49    Nt = 15                         # Number of time steps
 50    ts = H**2/(9.*alpha)            # Bore field characteristic time
 51    time = gt.utilities.time_geometric(dt, tmax, Nt)
 52    lntts = np.log(time/ts)
 53
 54    # -------------------------------------------------------------------------
 55    # Borehole field (First bore field)
 56    # -------------------------------------------------------------------------
 57
 58    # Field of 6x4 (n=24) boreholes
 59    N_1 = 6
 60    N_2 = 4
 61    field = gt.boreholes.rectangle_field(N_1, N_2, B, B, H, D, r_b)
 62
 63    # -------------------------------------------------------------------------
 64    # Evaluate g-functions
 65    # -------------------------------------------------------------------------
 66    t0 = perf_counter()
 67    gfunc_detailed = gt.gfunction.gFunction(
 68        field, alpha, time=time, options=options, method='detailed')
 69    t1 = perf_counter()
 70    t_detailed = t1 - t0
 71    gfunc_similarities = gt.gfunction.gFunction(
 72        field, alpha, time=time, options=options, method='similarities')
 73    t2 = perf_counter()
 74    t_similarities = t2 - t1
 75    gfunc_equivalent = gt.gfunction.gFunction(
 76        field, alpha, time=time, options=options, method='equivalent')
 77    t3 = perf_counter()
 78    t_equivalent = t3 - t2
 79
 80    # -------------------------------------------------------------------------
 81    # Plot results
 82    # -------------------------------------------------------------------------
 83    # Draw g-functions
 84    ax = gfunc_detailed.visualize_g_function().axes[0]
 85    ax.plot(lntts, gfunc_similarities.gFunc, 'bx')
 86    ax.plot(lntts, gfunc_equivalent.gFunc, 'ro')
 87    ax.legend([f'detailed (t = {t_detailed:.3f} sec)',
 88               f'similarities (t = {t_similarities:.3f} sec)',
 89               f'equivalent (t = {t_equivalent:.3f} sec)'])
 90    ax.set_title(f'Field of {N_1} by {N_2} boreholes')
 91    plt.tight_layout()
 92
 93    # Draw absolute error
 94    # Configure figure and axes
 95    fig = gt.utilities._initialize_figure()
 96    ax = fig.add_subplot(111)
 97    # Axis labels
 98    ax.set_xlabel(r'ln$(t/t_s)$')
 99    ax.set_ylabel(r'Absolute error')
100    gt.utilities._format_axes(ax)
101    # Absolute error
102    ax.plot(lntts, np.abs(gfunc_similarities.gFunc - gfunc_detailed.gFunc),
103            '-', label='similarities')
104    ax.plot(lntts, np.abs(gfunc_equivalent.gFunc - gfunc_detailed.gFunc),
105            '--', label='equivalent')
106    ax.legend()
107    ax.set_title(f"Absolute error relative to the 'detailed' solver "
108                 f"(Field of {N_1} by {N_2} boreholes)")
109    # Adjust to plot window
110    fig.tight_layout()
111
112    # Draw relative error
113    # Configure figure and axes
114    fig = gt.utilities._initialize_figure()
115    ax = fig.add_subplot(111)
116    # Axis labels
117    ax.set_xlabel(r'ln$(t/t_s)$')
118    ax.set_ylabel(r'Relative error')
119    gt.utilities._format_axes(ax)
120    # Relative error
121    gFunc_ref = gfunc_detailed.gFunc  # reference g-function
122    ax.plot(lntts, (gfunc_similarities.gFunc - gFunc_ref) / gFunc_ref,
123            '-', label='similarities')
124    ax.plot(lntts, (gfunc_equivalent.gFunc - gFunc_ref) / gFunc_ref,
125            '--', label='equivalent')
126    ax.legend()
127    ax.set_title(f"Relative error relative to the 'detailed' solver "
128                 f"(Field of {N_1} by {N_2} boreholes)")
129    # Adjust to plot window
130    fig.tight_layout()
131
132    # -------------------------------------------------------------------------
133    # Borehole field (Second bore field)
134    # -------------------------------------------------------------------------
135
136    # Field of 6x4 (n=24) boreholes
137    N_1 = 12
138    N_2 = 10
139    field = gt.boreholes.rectangle_field(N_1, N_2, B, B, H, D, r_b)
140
141    # -------------------------------------------------------------------------
142    # Evaluate g-functions
143    # -------------------------------------------------------------------------
144    gfunc_similarities = gt.gfunction.gFunction(
145        field, alpha, time=time, options=options, method='similarities')
146    t2 = perf_counter()
147    t_similarities = t2 - t1
148    gfunc_equivalent = gt.gfunction.gFunction(
149        field, alpha, time=time, options=options, method='equivalent')
150    t3 = perf_counter()
151    t_equivalent = t3 - t2
152
153    # -------------------------------------------------------------------------
154    # Plot results
155    # -------------------------------------------------------------------------
156    # Draw g-functions
157    ax = gfunc_similarities.visualize_g_function().axes[0]
158    ax.plot(lntts, gfunc_equivalent.gFunc, 'ro')
159    ax.legend([f'similarities (t = {t_similarities:.3f} sec)',
160               f'equivalent (t = {t_equivalent:.3f} sec)'])
161    ax.set_title(f'Field of {N_1} by {N_2} boreholes')
162    plt.tight_layout()
163
164    # Draw absolute error
165    # Configure figure and axes
166    fig = gt.utilities._initialize_figure()
167    ax = fig.add_subplot(111)
168    # Axis labels
169    ax.set_xlabel(r'ln$(t/t_s)$')
170    ax.set_ylabel(r'Absolute error')
171    gt.utilities._format_axes(ax)
172    # Absolute error
173    ax.plot(lntts, np.abs(gfunc_equivalent.gFunc - gfunc_similarities.gFunc),
174            label='equivalent')
175    ax.legend()
176    ax.set_title(f"Absolute error relative to the 'similarities' solver "
177                 f"(Field of {N_1} by {N_2} boreholes)")
178    # Adjust to plot window
179    fig.tight_layout()
180
181    # Draw relative error
182    # Configure figure and axes
183    fig = gt.utilities._initialize_figure()
184    ax = fig.add_subplot(111)
185    # Axis labels
186    ax.set_xlabel(r'ln$(t/t_s)$')
187    ax.set_ylabel(r'Relative error')
188    gt.utilities._format_axes(ax)
189    # Relative error
190    ax.plot(lntts, (gfunc_equivalent.gFunc - gfunc_similarities.gFunc) / gfunc_similarities.gFunc,
191            label='equivalent')
192    ax.legend()
193    ax.set_title(f"Relative error relative to the 'similarities' solver "
194                 f"(Field of {N_1} by {N_2} boreholes)")
195    # Adjust to plot window
196    fig.tight_layout()
197
198    return
199
200
201# Main function
202if __name__ == '__main__':
203    main()

References

1

Cimmino, M. (2018). Fast calculation of the g-functions of geothermal borehole fields using similarities in the evaluation of the finite line source solution. Journal of Building Performance Simulation, 11 (6), 655-668.

2

Prieto, C., & Cimmino, M. (2021). Thermal interactions in large irregular fields of geothermal boreholes: the method of equivalent borehole. Journal of Building Performance Simulation, 14 (4), 446-460.