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    borefield = gt.borefield.Borefield.rectangle_field(
 62        N_1, N_2, B, B, H, D, r_b)
 63
 64    # -------------------------------------------------------------------------
 65    # Evaluate g-functions
 66    # -------------------------------------------------------------------------
 67    t0 = perf_counter()
 68    gfunc_detailed = gt.gfunction.gFunction(
 69        borefield, alpha, time=time, options=options, method='detailed')
 70    t1 = perf_counter()
 71    t_detailed = t1 - t0
 72    gfunc_similarities = gt.gfunction.gFunction(
 73        borefield, alpha, time=time, options=options, method='similarities')
 74    t2 = perf_counter()
 75    t_similarities = t2 - t1
 76    gfunc_equivalent = gt.gfunction.gFunction(
 77        borefield, alpha, time=time, options=options, method='equivalent')
 78    t3 = perf_counter()
 79    t_equivalent = t3 - t2
 80
 81    # -------------------------------------------------------------------------
 82    # Plot results
 83    # -------------------------------------------------------------------------
 84    # Draw g-functions
 85    ax = gfunc_detailed.visualize_g_function().axes[0]
 86    ax.plot(lntts, gfunc_similarities.gFunc, 'bx')
 87    ax.plot(lntts, gfunc_equivalent.gFunc, 'ro')
 88    ax.legend([f'detailed (t = {t_detailed:.3f} sec)',
 89               f'similarities (t = {t_similarities:.3f} sec)',
 90               f'equivalent (t = {t_equivalent:.3f} sec)'])
 91    ax.set_title(f'Field of {N_1} by {N_2} boreholes')
 92    plt.tight_layout()
 93
 94    # Draw absolute error
 95    # Configure figure and axes
 96    fig = gt.utilities._initialize_figure()
 97    ax = fig.add_subplot(111)
 98    # Axis labels
 99    ax.set_xlabel(r'ln$(t/t_s)$')
100    ax.set_ylabel(r'Absolute error')
101    gt.utilities._format_axes(ax)
102    # Absolute error
103    ax.plot(lntts, np.abs(gfunc_similarities.gFunc - gfunc_detailed.gFunc),
104            '-', label='similarities')
105    ax.plot(lntts, np.abs(gfunc_equivalent.gFunc - gfunc_detailed.gFunc),
106            '--', label='equivalent')
107    ax.legend()
108    ax.set_title(f"Absolute error relative to the 'detailed' solver "
109                 f"(Field of {N_1} by {N_2} boreholes)")
110    # Adjust to plot window
111    fig.tight_layout()
112
113    # Draw relative error
114    # Configure figure and axes
115    fig = gt.utilities._initialize_figure()
116    ax = fig.add_subplot(111)
117    # Axis labels
118    ax.set_xlabel(r'ln$(t/t_s)$')
119    ax.set_ylabel(r'Relative error')
120    gt.utilities._format_axes(ax)
121    # Relative error
122    gFunc_ref = gfunc_detailed.gFunc  # reference g-function
123    ax.plot(lntts, (gfunc_similarities.gFunc - gFunc_ref) / gFunc_ref,
124            '-', label='similarities')
125    ax.plot(lntts, (gfunc_equivalent.gFunc - gFunc_ref) / gFunc_ref,
126            '--', label='equivalent')
127    ax.legend()
128    ax.set_title(f"Relative error relative to the 'detailed' solver "
129                 f"(Field of {N_1} by {N_2} boreholes)")
130    # Adjust to plot window
131    fig.tight_layout()
132
133    # -------------------------------------------------------------------------
134    # Borehole field (Second bore field)
135    # -------------------------------------------------------------------------
136
137    # Field of 6x4 (n=24) boreholes
138    N_1 = 12
139    N_2 = 10
140    field = gt.boreholes.rectangle_field(N_1, N_2, B, B, H, D, r_b)
141
142    # -------------------------------------------------------------------------
143    # Evaluate g-functions
144    # -------------------------------------------------------------------------
145    gfunc_similarities = gt.gfunction.gFunction(
146        field, alpha, time=time, options=options, method='similarities')
147    t2 = perf_counter()
148    t_similarities = t2 - t1
149    gfunc_equivalent = gt.gfunction.gFunction(
150        field, alpha, time=time, options=options, method='equivalent')
151    t3 = perf_counter()
152    t_equivalent = t3 - t2
153
154    # -------------------------------------------------------------------------
155    # Plot results
156    # -------------------------------------------------------------------------
157    # Draw g-functions
158    ax = gfunc_similarities.visualize_g_function().axes[0]
159    ax.plot(lntts, gfunc_equivalent.gFunc, 'ro')
160    ax.legend([f'similarities (t = {t_similarities:.3f} sec)',
161               f'equivalent (t = {t_equivalent:.3f} sec)'])
162    ax.set_title(f'Field of {N_1} by {N_2} boreholes')
163    plt.tight_layout()
164
165    # Draw absolute error
166    # Configure figure and axes
167    fig = gt.utilities._initialize_figure()
168    ax = fig.add_subplot(111)
169    # Axis labels
170    ax.set_xlabel(r'ln$(t/t_s)$')
171    ax.set_ylabel(r'Absolute error')
172    gt.utilities._format_axes(ax)
173    # Absolute error
174    ax.plot(lntts, np.abs(gfunc_equivalent.gFunc - gfunc_similarities.gFunc),
175            label='equivalent')
176    ax.legend()
177    ax.set_title(f"Absolute error relative to the 'similarities' solver "
178                 f"(Field of {N_1} by {N_2} boreholes)")
179    # Adjust to plot window
180    fig.tight_layout()
181
182    # Draw relative error
183    # Configure figure and axes
184    fig = gt.utilities._initialize_figure()
185    ax = fig.add_subplot(111)
186    # Axis labels
187    ax.set_xlabel(r'ln$(t/t_s)$')
188    ax.set_ylabel(r'Relative error')
189    gt.utilities._format_axes(ax)
190    # Relative error
191    ax.plot(lntts, (gfunc_equivalent.gFunc - gfunc_similarities.gFunc) / gfunc_similarities.gFunc,
192            label='equivalent')
193    ax.legend()
194    ax.set_title(f"Relative error relative to the 'similarities' solver "
195                 f"(Field of {N_1} by {N_2} boreholes)")
196    # Adjust to plot window
197    fig.tight_layout()
198
199    return
200
201
202# Main function
203if __name__ == '__main__':
204    main()

References