From e42a3366e9d2b85da1883bebd28f388c66408114 Mon Sep 17 00:00:00 2001 From: Alex Swindler Date: Tue, 28 Jan 2025 14:24:39 -0700 Subject: [PATCH 1/4] Fixed typos --- README.md | 2 +- .../examples/comparison_load_aggregation.rst | 2 +- doc/source/examples/load_aggregation.rst | 2 +- doc/source/examples/mixed_inlet_conditions.rst | 2 +- .../examples/multiple_independent_Utubes.rst | 2 +- doc/source/nomenclature_tables/heat_transfer.csv | 2 +- examples/comparison_load_aggregation.py | 2 +- examples/custom_borehole.py | 2 +- ...luid_temperature_reversible_flow_direction.py | 4 ++-- examples/load_aggregation.py | 2 +- pygfunction/gfunction.py | 2 +- pygfunction/heat_transfer.py | 6 +++--- pygfunction/load_aggregation.py | 4 ++-- pygfunction/pipes.py | 16 ++++++++-------- pygfunction/utilities.py | 6 +++--- requirements.txt | 2 +- requirements_dev.txt | 6 +++--- 17 files changed, 32 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 0be2da52..1bb1b6d9 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ This allows for the very fast calculation of *g*-functions, even for very large bore fields with hundreds of boreholes. Using *pygfunction*, *g*-functions can be calculated for any bore field -configuration (i.e. arbitrarily positionned in space), including fields of +configuration (i.e. arbitrarily positioned in space), including fields of boreholes with individually different lengths and radiuses. For regular fields of boreholes of equal size, setting-up the calculation of the *g*-function is as simple as a few lines of code. For example, the code for the calculation of diff --git a/doc/source/examples/comparison_load_aggregation.rst b/doc/source/examples/comparison_load_aggregation.rst index cebee39d..6fd18779 100644 --- a/doc/source/examples/comparison_load_aggregation.rst +++ b/doc/source/examples/comparison_load_aggregation.rst @@ -6,7 +6,7 @@ Compare the accuracy and speed of different load aggregation algorithms This example compares the simulation times and the accuracy of borehole wall temperature predictions of different load aggregation algorithms implemented -into the :doc:`load agggregation ` module. +into the :doc:`load aggregation ` module. The g-function of a single borehole is first calculated. Then, the borehole wall temperature variations are calculated using the load aggregation schemes of diff --git a/doc/source/examples/load_aggregation.rst b/doc/source/examples/load_aggregation.rst index 48396b89..45d49759 100644 --- a/doc/source/examples/load_aggregation.rst +++ b/doc/source/examples/load_aggregation.rst @@ -5,7 +5,7 @@ Simulation of a borehole using load aggregation *********************************************** This example demonstrates the use of the -:doc:`load agggregation ` module to predict the borehole +:doc:`load aggregation ` module to predict the borehole wall temperature of a single temperature with known heat extraction rates. The g-function of a single borehole is first calculated. Then, the borehole wall diff --git a/doc/source/examples/mixed_inlet_conditions.rst b/doc/source/examples/mixed_inlet_conditions.rst index bff4afb7..4f1d3800 100644 --- a/doc/source/examples/mixed_inlet_conditions.rst +++ b/doc/source/examples/mixed_inlet_conditions.rst @@ -15,7 +15,7 @@ constant. The following script generates the *g*-functions of a field of 5 equally spaced borehole on a straight line and connected in series. The boreholes have -different lengths. The *g*-function considering piping conections is compared to +different lengths. The *g*-function considering piping connections is compared to the *g*-function obtained using a boundary condition of uniform borehole wall temperature. diff --git a/doc/source/examples/multiple_independent_Utubes.rst b/doc/source/examples/multiple_independent_Utubes.rst index 59328360..a33e3113 100644 --- a/doc/source/examples/multiple_independent_Utubes.rst +++ b/doc/source/examples/multiple_independent_Utubes.rst @@ -12,7 +12,7 @@ in this example. The following script evaluates the fluid temperatures in a borehole with 4 independent U-tubes with different inlet fluid temperatures and different inlet fluid mass flow rates. The resulting fluid temperature profiles are verified -against the fluid temeprature profiles presented by Cimmino [1]_. +against the fluid temperature profiles presented by Cimmino [1]_. The script is located in: `pygfunction/examples/multiple_independent_Utubes.py` diff --git a/doc/source/nomenclature_tables/heat_transfer.csv b/doc/source/nomenclature_tables/heat_transfer.csv index 4d3b7c48..214584fa 100644 --- a/doc/source/nomenclature_tables/heat_transfer.csv +++ b/doc/source/nomenclature_tables/heat_transfer.csv @@ -14,5 +14,5 @@ Q_t,Watts,Total net heat extraction rate of a borehole or network R_b,m.K/W,Effective borehole thermal resistance R_fp,m.K/W,Fluid to outer pipe wall thermal resistance R_p,m.K/W,Conduction thermal resistance of a pipe wall -T_b,degC,Effective borehole wall temprature +T_b,degC,Effective borehole wall temperature T_f,degC,Fluid temperature diff --git a/examples/comparison_load_aggregation.py b/examples/comparison_load_aggregation.py index 2825f494..beade017 100644 --- a/examples/comparison_load_aggregation.py +++ b/examples/comparison_load_aggregation.py @@ -97,7 +97,7 @@ def main(): # Apply current load LoadAgg.set_current_load(Q_b[i]/H) - # Evaluate borehole wall temeprature + # Evaluate borehole wall temperature deltaT_b = LoadAgg.temporal_superposition() T_b[n,i] = T_g - deltaT_b toc = perf_counter() diff --git a/examples/custom_borehole.py b/examples/custom_borehole.py index 0de0f974..02aa48b8 100644 --- a/examples/custom_borehole.py +++ b/examples/custom_borehole.py @@ -87,7 +87,7 @@ def main(): # Check the geometry to make sure it is physically possible - # This class method is automatically called at the instanciation of the + # This class method is automatically called at the instantiation of the # pipe object and raises an error if the pipe geometry is invalid. It is # manually called here for demonstration. check_single = SingleUTube._check_geometry() diff --git a/examples/fluid_temperature_reversible_flow_direction.py b/examples/fluid_temperature_reversible_flow_direction.py index d8dca41d..116d4582 100644 --- a/examples/fluid_temperature_reversible_flow_direction.py +++ b/examples/fluid_temperature_reversible_flow_direction.py @@ -45,7 +45,7 @@ def main(): # Ground properties alpha = 2.5/2.2e6 # Ground thermal diffusivity (m2/s) k_s = 2.5 # Ground thermal conductivity (W/m.K) - T_g = 10. # Undisturbed ground temperatue (degC) + T_g = 10. # Undisturbed ground temperature (degC) # Grout properties k_g = 1.5 # Grout thermal conductivity (W/m.K) @@ -91,7 +91,7 @@ def main(): # Initialize bore field and pipe models # ------------------------------------------------------------------------- - # The field is a retangular array + # The field is a rectangular array borefield = gt.borefield.Borefield.rectangle_field( N_1, N_2, B, B, H, D, r_b) nBoreholes = len(borefield) diff --git a/examples/load_aggregation.py b/examples/load_aggregation.py index c0604a96..a8af230a 100644 --- a/examples/load_aggregation.py +++ b/examples/load_aggregation.py @@ -72,7 +72,7 @@ def main(): # Apply current load LoadAgg.set_current_load(Q_b_i/H) - # Evaluate borehole wall temeprature + # Evaluate borehole wall temperature deltaT_b = LoadAgg.temporal_superposition() T_b[i] = T_g - deltaT_b diff --git a/pygfunction/gfunction.py b/pygfunction/gfunction.py index 20cc29b9..4e0cc0e3 100644 --- a/pygfunction/gfunction.py +++ b/pygfunction/gfunction.py @@ -4634,7 +4634,7 @@ def _find_unique_boreholes(self, boreholes): def _find_unique_distances(self, dis, indices): """ - Find the number of occurences of each unique distances between pairs + Find the number of occurrences of each unique distances between pairs of boreholes. Parameters diff --git a/pygfunction/heat_transfer.py b/pygfunction/heat_transfer.py index 9e5b457f..55f3cf9c 100644 --- a/pygfunction/heat_transfer.py +++ b/pygfunction/heat_transfer.py @@ -532,18 +532,18 @@ def finite_line_source_inclined_approximation( rb1, x1, y1, H1, D1, tilt1, orientation1, x2, y2, H2, D2, tilt2, orientation2)]) # Number of dimensions of the output, excluding time - ouput_ndim = len(output_shape) + output_ndim = len(output_shape) # Shape of the time variable time_shape = np.shape(time) # Number of dimensions of the time variable time_ndim = len(time_shape) # Roots for Gauss-Legendre quadrature x, w = roots_legendre(M) - u = (0.5 * x + 0.5).reshape((-1, 1) + (1,) * ouput_ndim) + u = (0.5 * x + 0.5).reshape((-1, 1) + (1,) * output_ndim) w = w / 2 # Coefficients of the approximation of the error function a, b = _erf_coeffs(N) - b = b.reshape((1, -1) + (1,) * ouput_ndim) + b = b.reshape((1, -1) + (1,) * output_ndim) # Sines and cosines of tilt (b: beta) and orientation (t: theta) sb1 = np.sin(tilt1) sb2 = np.sin(tilt2) diff --git a/pygfunction/load_aggregation.py b/pygfunction/load_aggregation.py index 9b7dcbe6..9416ece0 100644 --- a/pygfunction/load_aggregation.py +++ b/pygfunction/load_aggregation.py @@ -39,7 +39,7 @@ def set_current_load(self, Q): def temporal_superposition(self): raise NotImplementedError( 'temporal_superposition class method not implemented, this ' - 'method should return the borehole wall tempreatures at the ' + 'method should return the borehole wall temperatures at the ' 'current time step.') @@ -122,7 +122,7 @@ def get_thermal_response_factor_increment(self): Array of **dimensional** thermal response factor increments used for temporal superposition (:math:`g(t_{i+1})/(2 \\pi k_s) - g(t_{i})/(2 \\pi k_s)`), - in correspondance with the intialized values of the thermal + in correspondence with the initialized values of the thermal response factors in :func:`~load_aggregation.ClaessonJaved.initialize`. The output size of the array is (nSources, nSources, Nt) if diff --git a/pygfunction/pipes.py b/pygfunction/pipes.py index 0eb028e2..b7f58d32 100644 --- a/pygfunction/pipes.py +++ b/pygfunction/pipes.py @@ -2413,7 +2413,7 @@ def _pipe_connectivity( self._check_model_variables( m_flow_borehole, cp_f, nSegments, segment_ratios) - # All upward flowing pipes are connceted to their respective outlet + # All upward flowing pipes are connected to their respective outlet c_fu = np.eye(self.nPipes) return c_fu @@ -2770,9 +2770,9 @@ def _check_geometry(self): return True -# Dictionnary of inputs and outputs for thermal_resistance function +# Dictionary of inputs and outputs for thermal_resistance function # The inputs and outputs of the last call to the function are saved into this -# dictionnary to save calculation time on repeated calls. +# dictionary to save calculation time on repeated calls. _thermal_resistances_dict = { 'pos': None, 'r_out': None, 'r_b': None, 'k_s': None, 'k_g': None, 'R_fp': None, 'J': None, 'R': None, 'Rd': None} @@ -2781,7 +2781,7 @@ def _check_geometry(self): def _compare_thermal_resistances_inputs( pos, r_out, r_b, k_s, k_g, R_fp, J, tol=1e-6): """ - Compare inputs to the content of the _thermal_resistances_dict dictionnary. + Compare inputs to the content of the _thermal_resistances_dict dictionary. Parameters ---------- @@ -2807,10 +2807,10 @@ def _compare_thermal_resistances_inputs( Returns ------- bool - True if the inputs are the same as the content of the dictionnary. + True if the inputs are the same as the content of the dictionary. """ - # Return False if dictionnary is empty + # Return False if dictionary is empty for arg in ('pos', 'r_out', 'r_b', 'k_s', 'k_g', 'R_fp', 'J'): if _thermal_resistances_dict[arg] is None: return False @@ -2954,7 +2954,7 @@ def thermal_resistances(pos, r_out, r_b, k_s, k_g, R_fp, J=2): sum([K[i, j] for j in range(n_p) if not i == j])) Rd = 1.0/K - # Save outputs into dictionnary + # Save outputs into dictionary _thermal_resistances_dict['pos'] = pos _thermal_resistances_dict['r_out'] = r_out _thermal_resistances_dict['r_b'] = r_b @@ -3099,7 +3099,7 @@ def convective_heat_transfer_coefficient_circular_pipe( for constant pipe wall surface temperature is used for laminar flow. Since :func:`_Nusselt_number_turbulent_flow` is only valid for Re > 3000. - and to avoid dicontinuities in the values of the convective heat transfer + and to avoid discontinuities in the values of the convective heat transfer coefficient near the onset of the turbulence region (approximately Re = 2300.), linear interpolation is used over the range 2300 < Re < 4000 for the evaluation of the Nusselt number. diff --git a/pygfunction/utilities.py b/pygfunction/utilities.py index 44ac2c5c..56d22b05 100644 --- a/pygfunction/utilities.py +++ b/pygfunction/utilities.py @@ -480,7 +480,7 @@ def _erf_coeffs(N): """ Return the coefficients of the approximation of the error function. - This returns the coefficents (a_n, b_n) of the approximation of the error + This returns the coefficients (a_n, b_n) of the approximation of the error function adapted from the work of Tanash and Riihonen (2020) [#erf-TanRii2020]_. The approximation of the error function is given by: @@ -497,9 +497,9 @@ def _erf_coeffs(N): Returns ------- a : array - Array of oefficients a_n. + Array of coefficients a_n. b : array - Array of oefficients b_n. + Array of coefficients b_n. References ---------- diff --git a/requirements.txt b/requirements.txt index ccceff3d..3a43b2fa 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ +matplotlib numpy scipy -matplotlib SecondaryCoolantProps typing_extensions diff --git a/requirements_dev.txt b/requirements_dev.txt index 96dfce62..dc79c7c8 100644 --- a/requirements_dev.txt +++ b/requirements_dev.txt @@ -1,6 +1,6 @@ numpydoc == 1.2.0 -recommonmark == 0.6.0 -sphinx == 4.4.0 pytest == 7.1.1 pytest-cov == 3.0.0 -tox == 3.24.5 \ No newline at end of file +recommonmark == 0.6.0 +sphinx == 4.4.0 +tox == 3.24.5 From 12889317a67702f1884bf89e8e5bd27c37775b2b Mon Sep 17 00:00:00 2001 From: Alex Swindler Date: Tue, 18 Mar 2025 13:01:28 -0600 Subject: [PATCH 2/4] Removed matplotlib from main library --- pygfunction/__init__.py | 20 +- pygfunction/borefield.py | 94 ------ pygfunction/boreholes.py | 111 ------- pygfunction/gfunction.py | 642 +-------------------------------------- pygfunction/pipes.py | 143 --------- pygfunction/utilities.py | 63 ---- requirements.txt | 1 - requirements_dev.txt | 1 + 8 files changed, 14 insertions(+), 1061 deletions(-) diff --git a/pygfunction/__init__.py b/pygfunction/__init__.py index 61ca2bad..055c50bf 100644 --- a/pygfunction/__init__.py +++ b/pygfunction/__init__.py @@ -1,9 +1,11 @@ -from . import boreholes -from . import borefield -from . import gfunction -from . import heat_transfer -from . import load_aggregation -from . import media -from . import networks -from . import pipes -from . import utilities +from . import ( + boreholes, + borefield, + gfunction, + heat_transfer, + load_aggregation, + media, + networks, + pipes, + utilities, +) diff --git a/pygfunction/borefield.py b/pygfunction/borefield.py index 8641e56c..db336649 100644 --- a/pygfunction/borefield.py +++ b/pygfunction/borefield.py @@ -2,13 +2,10 @@ from typing import Union, List, Dict, Tuple from typing_extensions import Self # for compatibility with Python <= 3.10 -import matplotlib.pyplot as plt -from matplotlib.figure import Figure import numpy as np import numpy.typing as npt from .boreholes import Borehole -from .utilities import _initialize_figure, _format_axes, _format_axes_3d class Borefield: @@ -306,97 +303,6 @@ def evaluate_g_function( return gfunc.gFunc - def visualize_field( - self, viewTop: bool = True, view3D: bool = True, - labels: bool = True, showTilt: bool = True) -> Figure: - """ - Plot the top view and 3D view of borehole positions. - - Parameters - ---------- - viewTop : bool, optional - Set to True to plot top view. - Default is True - view3D : bool, optional - Set to True to plot 3D view. - Default is True - labels : bool, optional - Set to True to annotate borehole indices to top view plot. - Default is True - showTilt : bool, optional - Set to True to show borehole inclination on top view plot. - Default is True - - Returns - ------- - fig : figure - Figure object (matplotlib). - - """ - # Configure figure and axes - fig = _initialize_figure() - if viewTop and view3D: - ax1 = fig.add_subplot(121) - ax2 = fig.add_subplot(122, projection='3d') - elif viewTop: - ax1 = fig.add_subplot(111) - elif view3D: - ax2 = fig.add_subplot(111, projection='3d') - if viewTop: - ax1.set_xlabel(r'$x$ [m]') - ax1.set_ylabel(r'$y$ [m]') - ax1.axis('equal') - _format_axes(ax1) - if view3D: - ax2.set_xlabel(r'$x$ [m]') - ax2.set_ylabel(r'$y$ [m]') - ax2.set_zlabel(r'$z$ [m]') - _format_axes_3d(ax2) - ax2.invert_zaxis() - - # Bottom end of boreholes - x_H = self.x + self.H * np.sin(self.tilt) * np.cos(self.orientation) - y_H = self.y + self.H * np.sin(self.tilt) * np.sin(self.orientation) - z_H = self.D + self.H * np.cos(self.tilt) - - # ------------------------------------------------------------------------- - # Top view - # ------------------------------------------------------------------------- - if viewTop: - if showTilt: - ax1.plot( - np.stack((self.x, x_H), axis=0), - np.stack((self.y, y_H), axis=0), - 'k--') - ax1.plot(self.x, self.y, 'ko') - if labels: - for i, borehole in enumerate(self): - ax1.text( - borehole.x, - borehole.y, - f' {i}', - ha="left", - va="bottom") - - # ------------------------------------------------------------------------- - # 3D view - # ------------------------------------------------------------------------- - if view3D: - ax2.plot(self.x, self.y, self.D, 'ko') - for i in range(self.nBoreholes): - ax2.plot( - (self.x[i], x_H[i]), - (self.y[i], y_H[i]), - (self.D[i], z_H[i]), - 'k-') - - if viewTop and view3D: - plt.tight_layout(rect=[0, 0.0, 0.90, 1.0]) - else: - plt.tight_layout() - - return fig - def to_boreholes(self) -> List[Borehole]: """ Return a list of boreholes in the bore field. diff --git a/pygfunction/boreholes.py b/pygfunction/boreholes.py index 0cc8e709..9794bc55 100644 --- a/pygfunction/boreholes.py +++ b/pygfunction/boreholes.py @@ -1,12 +1,9 @@ # -*- coding: utf-8 -*- import warnings -import matplotlib.pyplot as plt import numpy as np from scipy.spatial.distance import pdist -from .utilities import _initialize_figure, _format_axes, _format_axes_3d - class Borehole(object): """ @@ -1351,111 +1348,3 @@ def field_from_file(filename): Borehole(H, D, r_b, x=x, y=y, tilt=tilt, orientation=orientation)) return borefield - - -def visualize_field( - borefield, viewTop=True, view3D=True, labels=True, showTilt=True): - """ - Plot the top view and 3D view of borehole positions. - - Parameters - ---------- - borefield : list - List of boreholes in the bore field. - viewTop : bool, optional - Set to True to plot top view. - Default is True - view3D : bool, optional - Set to True to plot 3D view. - Default is True - labels : bool, optional - Set to True to annotate borehole indices to top view plot. - Default is True - showTilt : bool, optional - Set to True to show borehole inclination on top view plot. - Default is True - - Returns - ------- - fig : figure - Figure object (matplotlib). - - """ - # This function is deprecated as of v2.3. It will be removed in v3.0. - warnings.warn("`pygfunction.boreholes.visualize_field` is " - "deprecated as of v2.3. It will be removed in v3.0. " - "Use the `pygfunction.borefield.Borefield` class instead.", - DeprecationWarning) - - # Configure figure and axes - fig = _initialize_figure() - if viewTop and view3D: - ax1 = fig.add_subplot(121) - ax2 = fig.add_subplot(122, projection='3d') - elif viewTop: - ax1 = fig.add_subplot(111) - elif view3D: - ax2 = fig.add_subplot(111, projection='3d') - if viewTop: - ax1.set_xlabel(r'$x$ [m]') - ax1.set_ylabel(r'$y$ [m]') - ax1.axis('equal') - _format_axes(ax1) - if view3D: - ax2.set_xlabel(r'$x$ [m]') - ax2.set_ylabel(r'$y$ [m]') - ax2.set_zlabel(r'$z$ [m]') - _format_axes_3d(ax2) - ax2.invert_zaxis() - - # ------------------------------------------------------------------------- - # Top view - # ------------------------------------------------------------------------- - if viewTop: - i = 0 # Initialize borehole index - for borehole in borefield: - # Extract borehole parameters - (x, y) = borehole.position() - H = borehole.H - tilt = borehole.tilt - orientation = borehole.orientation - # Add current borehole to the figure - if showTilt: - ax1.plot( - [x, x + H * np.sin(tilt) * np.cos(orientation)], - [y, y + H * np.sin(tilt) * np.sin(orientation)], - 'k--') - ax1.plot(x, y, 'ko') - if labels: ax1.text(x, y, - f' {i}', - ha="left", va="bottom") - i += 1 # Increment borehole index - - # ------------------------------------------------------------------------- - # 3D view - # ------------------------------------------------------------------------- - if view3D: - for borehole in borefield: - # Position of head of borehole - (x, y) = borehole.position() - # Position of bottom of borehole - x_H = x + borehole.H*np.sin(borehole.tilt)*np.cos(borehole.orientation) - y_H = y + borehole.H*np.sin(borehole.tilt)*np.sin(borehole.orientation) - z_H = borehole.D + borehole.H*np.cos(borehole.tilt) - # Add current borehole to the figure - ax2.plot(np.atleast_1d(x), - np.atleast_1d(y), - np.atleast_1d(borehole.D), - 'ko') - ax2.plot(np.array([x, x_H]), - np.array([y, y_H]), - np.array([borehole.D, z_H]), - 'k-') - - - if viewTop and view3D: - plt.tight_layout(rect=[0, 0.0, 0.90, 1.0]) - else: - plt.tight_layout() - - return fig diff --git a/pygfunction/gfunction.py b/pygfunction/gfunction.py index 4e0cc0e3..537ef375 100644 --- a/pygfunction/gfunction.py +++ b/pygfunction/gfunction.py @@ -2,7 +2,6 @@ from time import perf_counter import warnings -import matplotlib.pyplot as plt import numpy as np from scipy.cluster.hierarchy import cut_tree, dendrogram, linkage from scipy.constants import pi @@ -14,13 +13,12 @@ finite_line_source_equivalent_boreholes_vectorized, \ finite_line_source_inclined_vectorized from .networks import Network, _EquivalentNetwork, network_thermal_resistance -from .utilities import _initialize_figure, _format_axes from . import utilities class gFunction(object): """ - Class for the calculation and visualization of the g-functions of + Class for the calculation of the g-functions of geothermal bore fields. This class superimposes the finite line source (FLS) solution to @@ -318,642 +316,6 @@ def evaluate_g_function(self, time): print(60*'-') return self.gFunc - def visualize_g_function(self, which=None): - """ - Plot the g-function of the borefield. - - Parameters - ---------- - which : list of tuple, optional - Tuples (i, j) of the variable mass flow rate g-functions to plot. - If None, all g-functions are plotted. - Default is None. - - Returns - ------- - fig : figure - Figure object (matplotlib). - - """ - # Configure figure and axes - fig = _initialize_figure() - ax = fig.add_subplot(111) - ax.set_xlabel(r'ln$(t/t_s)$') - ax.set_ylabel(r'$g$-function') - _format_axes(ax) - - # Borefield characteristic time - ts = np.mean([b.H for b in self.boreholes])**2/(9.*self.alpha) - # Dimensionless time (log) - lntts = np.log(self.time/ts) - # Draw g-function - if self.solver.nMassFlow == 0: - ax.plot(lntts, self.gFunc) - elif which is None: - for j in range(self.solver.nMassFlow): - for i in range(self.solver.nMassFlow): - ax.plot( - lntts, - self.gFunc[i,j,:], - label=f'$g_{{{i}{j}}}$') - plt.legend() - else: - if which is None: - which = [ - (i, j) for j in range(self.solver.nMassFlow) - for i in range(self.solver.nMassFlow)] - for (i, j) in which: - ax.plot( - lntts, - self.gFunc[i,j,:], - label=f'$g_{{{i}{j}}}$') - plt.legend() - - # Adjust figure to window - plt.tight_layout() - return fig - - def visualize_heat_extraction_rates( - self, iBoreholes=None, showTilt=True, which=None): - """ - Plot the time-variation of the average heat extraction rates. - - Parameters - ---------- - iBoreholes : list of int - Borehole indices to plot heat extraction rates. - If iBoreholes is None, heat extraction rates are plotted for all - boreholes. - Default is None. - showTilt : bool - Set to True to show borehole inclination. - Default is True - which : list of int, optional - Indices i of the diagonal variable mass flow rate g-functions for - which to plot heat extraction rates. - If None, all diagonal g-functions are plotted. - Default is None. - - Returns - ------- - fig : figure - Figure object (matplotlib). - - """ - # If iBoreholes is None, then plot all boreholes - if iBoreholes is None: - iBoreholes = range(len(self.solver.boreholes)) - # Import heat extraction rates - Q_t = self._heat_extraction_rates(iBoreholes) - # Borefield characteristic time - ts = np.mean([b.H for b in self.solver.boreholes])**2/(9.*self.alpha) - # Dimensionless time (log) - lntts = np.log(self.time/ts) - - if self.solver.nMassFlow == 0: - # Configure figure and axes - fig = _initialize_figure() - ax1 = fig.add_subplot(121) - ax1.set_xlabel(r'$x$ [m]') - ax1.set_ylabel(r'$y$ [m]') - ax1.axis('equal') - _format_axes(ax1) - ax2 = fig.add_subplot(122) - ax2.set_xlabel(r'ln$(t/t_s)$') - ax2.set_ylabel(r'$\bar{Q}_b$') - _format_axes(ax2) - - # Plot curves for requested boreholes - for i, borehole in enumerate(self.solver.boreholes): - if i in iBoreholes: - # Draw heat extraction rate - line = ax2.plot(lntts, Q_t[iBoreholes.index(i)]) - color = line[-1]._color - # Draw colored marker for borehole position - if showTilt: - ax1.plot( - [borehole.x, borehole.x + borehole.H*np.sin(borehole.tilt)*np.cos(borehole.orientation)], - [borehole.y, borehole.y + borehole.H*np.sin(borehole.tilt)*np.sin(borehole.orientation)], - linestyle='--', - marker='None', - color=color) - ax1.plot(borehole.x, - borehole.y, - linestyle='None', - marker='o', - color=color) - else: - # Draw black marker for borehole position - if showTilt: - ax1.plot( - [borehole.x, borehole.x + borehole.H*np.sin(borehole.tilt)*np.cos(borehole.orientation)], - [borehole.y, borehole.y + borehole.H*np.sin(borehole.tilt)*np.sin(borehole.orientation)], - linestyle='--', - marker='None', - color='k') - ax1.plot(borehole.x, - borehole.y, - linestyle='None', - marker='o', - color='k') - - # Adjust figure to window - plt.tight_layout() - else: - m_flow = self.solver.m_flow - if which is None: - which = [n for n in range(self.solver.nMassFlow)] - for n in which: - # Configure figure and axes - fig = _initialize_figure() - fig.suptitle( - f'Heat extraction rates for m_flow={m_flow[n]} kg/s') - ax1 = fig.add_subplot(121) - ax1.set_xlabel(r'$x$ [m]') - ax1.set_ylabel(r'$y$ [m]') - ax1.axis('equal') - _format_axes(ax1) - ax2 = fig.add_subplot(122) - ax2.set_xlabel(r'ln$(t/t_s)$') - ax2.set_ylabel(r'$\bar{Q}_b$') - _format_axes(ax2) - - # Plot curves for requested boreholes - for i, borehole in enumerate(self.solver.boreholes): - if i in iBoreholes: - # Draw heat extraction rate - line = ax2.plot(lntts, Q_t[iBoreholes.index(i)][n]) - color = line[-1]._color - # Draw colored marker for borehole position - if showTilt: - ax1.plot( - [borehole.x, borehole.x + borehole.H*np.sin(borehole.tilt)*np.cos(borehole.orientation)], - [borehole.y, borehole.y + borehole.H*np.sin(borehole.tilt)*np.sin(borehole.orientation)], - linestyle='--', - marker='None', - color=color) - ax1.plot(borehole.x, - borehole.y, - linestyle='None', - marker='o', - color=color) - else: - # Draw black marker for borehole position - if showTilt: - ax1.plot( - [borehole.x, borehole.x + borehole.H*np.sin(borehole.tilt)*np.cos(borehole.orientation)], - [borehole.y, borehole.y + borehole.H*np.sin(borehole.tilt)*np.sin(borehole.orientation)], - linestyle='--', - marker='None', - color='k') - ax1.plot(borehole.x, - borehole.y, - linestyle='None', - marker='o', - color='k') - - # Adjust figure to window - plt.tight_layout() - - return fig - - def visualize_heat_extraction_rate_profiles( - self, time=None, iBoreholes=None, showTilt=True, which=None): - """ - Plot the heat extraction rate profiles at chosen time. - - Parameters - ---------- - time : float - Values of time (in seconds) to plot heat extraction rate profiles. - If time is None, heat extraction rates are plotted at the last - time step. - Default is None. - iBoreholes : list of int - Borehole indices to plot heat extraction rate profiles. - If iBoreholes is None, heat extraction rates are plotted for all - boreholes. - Default is None. - showTilt : bool - Set to True to show borehole inclination. - Default is True - which : list of int, optional - Indices i of the diagonal variable mass flow rate g-functions for - which to plot heat extraction rates. - If None, all diagonal g-functions are plotted. - Default is None. - - Returns - ------- - fig : figure - Figure object (matplotlib). - - """ - # If iBoreholes is None, then plot all boreholes - if iBoreholes is None: - iBoreholes = range(len(self.solver.boreholes)) - # Import heat extraction rate profiles - z, Q_b = self._heat_extraction_rate_profiles(time, iBoreholes) - - if self.solver.nMassFlow == 0: - # Configure figure and axes - fig = _initialize_figure() - ax1 = fig.add_subplot(121) - ax1.set_xlabel(r'$x$ [m]') - ax1.set_ylabel(r'$y$ [m]') - ax1.axis('equal') - _format_axes(ax1) - ax2 = fig.add_subplot(122) - ax2.set_xlabel(r'$Q_b$') - ax2.set_ylabel(r'$z$ [m]') - ax2.invert_yaxis() - _format_axes(ax2) - - # Plot curves for requested boreholes - for i, borehole in enumerate(self.solver.boreholes): - if i in iBoreholes: - # Draw heat extraction rate profile - line = ax2.plot( - Q_b[iBoreholes.index(i)], z[iBoreholes.index(i)]) - color = line[-1]._color - # Draw colored marker for borehole position - if showTilt: - ax1.plot( - [borehole.x, borehole.x + borehole.H*np.sin(borehole.tilt)*np.cos(borehole.orientation)], - [borehole.y, borehole.y + borehole.H*np.sin(borehole.tilt)*np.sin(borehole.orientation)], - linestyle='--', - marker='None', - color=color) - ax1.plot(borehole.x, - borehole.y, - linestyle='None', - marker='o', - color=color) - else: - # Draw black marker for borehole position - if showTilt: - ax1.plot( - [borehole.x, borehole.x + borehole.H*np.sin(borehole.tilt)*np.cos(borehole.orientation)], - [borehole.y, borehole.y + borehole.H*np.sin(borehole.tilt)*np.sin(borehole.orientation)], - linestyle='--', - marker='None', - color='k') - ax1.plot(borehole.x, - borehole.y, - linestyle='None', - marker='o', - color='k') - - # Adjust figure to window - plt.tight_layout() - else: - m_flow = self.solver.m_flow - if which is None: - which = [n for n in range(self.solver.nMassFlow)] - for n in which: - # Configure figure and axes - fig = _initialize_figure() - fig.suptitle( - f'Heat extraction rate profiles for m_flow={m_flow[n]} kg/s') - ax1 = fig.add_subplot(121) - ax1.set_xlabel(r'$x$ [m]') - ax1.set_ylabel(r'$y$ [m]') - ax1.axis('equal') - _format_axes(ax1) - ax2 = fig.add_subplot(122) - ax2.set_xlabel(r'$Q_b$') - ax2.set_ylabel(r'$z$ [m]') - ax2.invert_yaxis() - _format_axes(ax2) - - # Plot curves for requested boreholes - for i, borehole in enumerate(self.solver.boreholes): - if i in iBoreholes: - # Draw heat extraction rate profile - line = ax2.plot( - Q_b[iBoreholes.index(i)][n], - z[iBoreholes.index(i)]) - color = line[-1]._color - # Draw colored marker for borehole position - if showTilt: - ax1.plot( - [borehole.x, borehole.x + borehole.H*np.sin(borehole.tilt)*np.cos(borehole.orientation)], - [borehole.y, borehole.y + borehole.H*np.sin(borehole.tilt)*np.sin(borehole.orientation)], - linestyle='--', - marker='None', - color=color) - ax1.plot(borehole.x, - borehole.y, - linestyle='None', - marker='o', - color=color) - else: - # Draw black marker for borehole position - if showTilt: - ax1.plot( - [borehole.x, borehole.x + borehole.H*np.sin(borehole.tilt)*np.cos(borehole.orientation)], - [borehole.y, borehole.y + borehole.H*np.sin(borehole.tilt)*np.sin(borehole.orientation)], - linestyle='--', - marker='None', - color='k') - ax1.plot(borehole.x, - borehole.y, - linestyle='None', - marker='o', - color='k') - - # Adjust figure to window - plt.tight_layout() - - return fig - - def visualize_temperatures( - self, iBoreholes=None, showTilt=True, which=None): - """ - Plot the time-variation of the average borehole wall temperatures. - - Parameters - ---------- - iBoreholes : list of int - Borehole indices to plot temperatures. - If iBoreholes is None, temperatures are plotted for all boreholes. - Default is None. - showTilt : bool - Set to True to show borehole inclination. - Default is True - which : list of int, optional - Indices i of the diagonal variable mass flow rate g-functions for - which to plot borehole wall temperatures. - If None, all diagonal g-functions are plotted. - Default is None. - - Returns - ------- - fig : figure - Figure object (matplotlib). - - """ - # If iBoreholes is None, then plot all boreholes - if iBoreholes is None: - iBoreholes = range(len(self.solver.boreholes)) - # Import temperatures - T_b = self._temperatures(iBoreholes) - # Borefield characteristic time - ts = np.mean([b.H for b in self.solver.boreholes])**2/(9.*self.alpha) - # Dimensionless time (log) - lntts = np.log(self.time/ts) - - - if self.solver.nMassFlow == 0: - # Configure figure and axes - fig = _initialize_figure() - ax1 = fig.add_subplot(121) - ax1.set_xlabel(r'$x$ [m]') - ax1.set_ylabel(r'$y$ [m]') - ax1.axis('equal') - _format_axes(ax1) - ax2 = fig.add_subplot(122) - ax2.set_xlabel(r'ln$(t/t_s)$') - ax2.set_ylabel(r'$\bar{T}_b$') - _format_axes(ax2) - # Plot curves for requested boreholes - for i, borehole in enumerate(self.solver.boreholes): - if i in iBoreholes: - # Draw borehole wall temperature - line = ax2.plot(lntts, T_b[iBoreholes.index(i)]) - color = line[-1]._color - # Draw colored marker for borehole position - if showTilt: - ax1.plot( - [borehole.x, borehole.x + borehole.H*np.sin(borehole.tilt)*np.cos(borehole.orientation)], - [borehole.y, borehole.y + borehole.H*np.sin(borehole.tilt)*np.sin(borehole.orientation)], - linestyle='--', - marker='None', - color=color) - ax1.plot(borehole.x, - borehole.y, - linestyle='None', - marker='o', - color=color) - else: - # Draw black marker for borehole position - if showTilt: - ax1.plot( - [borehole.x, borehole.x + borehole.H*np.sin(borehole.tilt)*np.cos(borehole.orientation)], - [borehole.y, borehole.y + borehole.H*np.sin(borehole.tilt)*np.sin(borehole.orientation)], - linestyle='--', - marker='None', - color='k') - ax1.plot(borehole.x, - borehole.y, - linestyle='None', - marker='o', - color='k') - - # Adjust figure to window - plt.tight_layout() - else: - m_flow = self.solver.m_flow - if which is None: - which = [n for n in range(self.solver.nMassFlow)] - for n in which: - # Configure figure and axes - fig = _initialize_figure() - fig.suptitle( - f'Borehole wall temperatures for m_flow={m_flow[n]} kg/s') - ax1 = fig.add_subplot(121) - ax1.set_xlabel(r'$x$ [m]') - ax1.set_ylabel(r'$y$ [m]') - ax1.axis('equal') - _format_axes(ax1) - ax2 = fig.add_subplot(122) - ax2.set_xlabel(r'ln$(t/t_s)$') - ax2.set_ylabel(r'$\bar{T}_b$') - _format_axes(ax2) - # Plot curves for requested boreholes - for i, borehole in enumerate(self.solver.boreholes): - if i in iBoreholes: - # Draw borehole wall temperature - line = ax2.plot(lntts, T_b[iBoreholes.index(i)][n]) - color = line[-1]._color - # Draw colored marker for borehole position - if showTilt: - ax1.plot( - [borehole.x, borehole.x + borehole.H*np.sin(borehole.tilt)*np.cos(borehole.orientation)], - [borehole.y, borehole.y + borehole.H*np.sin(borehole.tilt)*np.sin(borehole.orientation)], - linestyle='--', - marker='None', - color=color) - ax1.plot(borehole.x, - borehole.y, - linestyle='None', - marker='o', - color=color) - else: - # Draw black marker for borehole position - if showTilt: - ax1.plot( - [borehole.x, borehole.x + borehole.H*np.sin(borehole.tilt)*np.cos(borehole.orientation)], - [borehole.y, borehole.y + borehole.H*np.sin(borehole.tilt)*np.sin(borehole.orientation)], - linestyle='--', - marker='None', - color='k') - ax1.plot(borehole.x, - borehole.y, - linestyle='None', - marker='o', - color='k') - - # Adjust figure to window - plt.tight_layout() - return fig - - def visualize_temperature_profiles( - self, time=None, iBoreholes=None, showTilt=True, which=None): - """ - Plot the borehole wall temperature profiles at chosen time. - - Parameters - ---------- - time : float - Values of time (in seconds) to plot temperature profiles. - If time is None, temperatures are plotted at the last time step. - Default is None. - iBoreholes : list of int - Borehole indices to plot temperature profiles. - If iBoreholes is None, temperatures are plotted for all boreholes. - Default is None. - showTilt : bool - Set to True to show borehole inclination. - Default is True - which : list of int, optional - Indices i of the diagonal variable mass flow rate g-functions for - which to plot borehole wall temperatures. - If None, all diagonal g-functions are plotted. - Default is None. - - Returns - ------- - fig : figure - Figure object (matplotlib). - - """ - # If iBoreholes is None, then plot all boreholes - if iBoreholes is None: - iBoreholes = range(len(self.boreholes)) - # Import temperature profiles - z, T_b = self._temperature_profiles(time, iBoreholes) - - if self.solver.nMassFlow == 0: - # Configure figure and axes - fig = _initialize_figure() - ax1 = fig.add_subplot(121) - ax1.set_xlabel(r'$x$ [m]') - ax1.set_ylabel(r'$y$ [m]') - ax1.axis('equal') - _format_axes(ax1) - ax2 = fig.add_subplot(122) - ax2.set_xlabel(r'$T_b$') - ax2.set_ylabel(r'$z$ [m]') - ax2.invert_yaxis() - _format_axes(ax2) - - # Plot curves for requested boreholes - for i, borehole in enumerate(self.solver.boreholes): - if i in iBoreholes: - # Draw borehole wall temperature profile - line = ax2.plot( - T_b[iBoreholes.index(i)], - z[iBoreholes.index(i)]) - color = line[-1]._color - # Draw colored marker for borehole position - if showTilt: - ax1.plot( - [borehole.x, borehole.x + borehole.H * np.sin(borehole.tilt) * np.cos(borehole.orientation)], - [borehole.y, borehole.y + borehole.H * np.sin(borehole.tilt) * np.sin(borehole.orientation)], - linestyle='--', - marker='None', - color=color) - ax1.plot(borehole.x, - borehole.y, - linestyle='None', - marker='o', - color=color) - else: - # Draw black marker for borehole position - if showTilt: - ax1.plot( - [borehole.x, borehole.x + borehole.H * np.sin(borehole.tilt) * np.cos(borehole.orientation)], - [borehole.y, borehole.y + borehole.H * np.sin(borehole.tilt) * np.sin(borehole.orientation)], - linestyle='--', - marker='None', - color='k') - ax1.plot(borehole.x, - borehole.y, - linestyle='None', - marker='o', - color='k') - - plt.tight_layout() - else: - m_flow = self.solver.m_flow - if which is None: - which = [n for n in range(self.solver.nMassFlow)] - for n in which: - # Configure figure and axes - fig = _initialize_figure() - fig.suptitle( - f'Borehole wall temperature profiles for m_flow={m_flow[n]} kg/s') - ax1 = fig.add_subplot(121) - ax1.set_xlabel(r'$x$ [m]') - ax1.set_ylabel(r'$y$ [m]') - ax1.axis('equal') - _format_axes(ax1) - ax2 = fig.add_subplot(122) - ax2.set_xlabel(r'$T_b$') - ax2.set_ylabel(r'$z$ [m]') - ax2.invert_yaxis() - _format_axes(ax2) - - # Plot curves for requested boreholes - for i, borehole in enumerate(self.solver.boreholes): - if i in iBoreholes: - # Draw borehole wall temperature profile - line = ax2.plot( - T_b[iBoreholes.index(i)][n], - z[iBoreholes.index(i)]) - color = line[-1]._color - # Draw colored marker for borehole position - if showTilt: - ax1.plot( - [borehole.x, borehole.x + borehole.H * np.sin(borehole.tilt) * np.cos(borehole.orientation)], - [borehole.y, borehole.y + borehole.H * np.sin(borehole.tilt) * np.sin(borehole.orientation)], - linestyle='--', - marker='None', - color=color) - ax1.plot(borehole.x, - borehole.y, - linestyle='None', - marker='o', - color=color) - else: - # Draw black marker for borehole position - if showTilt: - ax1.plot( - [borehole.x, borehole.x + borehole.H * np.sin(borehole.tilt) * np.cos(borehole.orientation)], - [borehole.y, borehole.y + borehole.H * np.sin(borehole.tilt) * np.sin(borehole.orientation)], - linestyle='--', - marker='None', - color='k') - ax1.plot(borehole.x, - borehole.y, - linestyle='None', - marker='o', - color='k') - - plt.tight_layout() - return fig - def _heat_extraction_rates(self, iBoreholes): """ Extract and format heat extraction rates for plotting. @@ -961,7 +323,7 @@ def _heat_extraction_rates(self, iBoreholes): Parameters ---------- iBoreholes : list of int - Borehole indices to extract heat extration rates. + Borehole indices to extract heat extraction rates. Returns ------- diff --git a/pygfunction/pipes.py b/pygfunction/pipes.py index b7f58d32..fead10de 100644 --- a/pygfunction/pipes.py +++ b/pygfunction/pipes.py @@ -1,12 +1,9 @@ # -*- coding: utf-8 -*- -import matplotlib.pyplot as plt import numpy as np from scipy.constants import pi from scipy.special import binom import warnings -from .utilities import _initialize_figure, _format_axes - class _BasePipe(object): """ @@ -735,73 +732,6 @@ def update_thermal_resistances(self): 'update_thermal_resistances class method not implemented, ' 'this method should update the array of delta-circuit thermal ' 'resistances.') - return - - def visualize_pipes(self): - """ - Plot the cross-section view of the borehole. - - Returns - ------- - fig : figure - Figure object (matplotlib). - - """ - # Configure figure and axes - fig = _initialize_figure() - ax = fig.add_subplot(111) - ax.set_xlabel(r'$x$ [m]') - ax.set_ylabel(r'$y$ [m]') - ax.axis('equal') - _format_axes(ax) - - # Color cycle - prop_cycle = plt.rcParams['axes.prop_cycle'] - colors = prop_cycle.by_key()['color'] - lw = plt.rcParams['lines.linewidth'] - - # Borehole wall outline - ax.plot([-self.b.r_b, 0., self.b.r_b, 0.], - [0., self.b.r_b, 0., -self.b.r_b], - 'k.', alpha=0.) - borewall = plt.Circle( - (0., 0.), radius=self.b.r_b, fill=False, - color='k', linestyle='--', lw=lw) - ax.add_patch(borewall) - - # Pipes - for i in range(self.nPipes): - # Coordinates of pipes - (x_in, y_in) = self.pos[i] - (x_out, y_out) = self.pos[i + self.nPipes] - - # Pipe outline (inlet) - pipe_in_in = plt.Circle( - (x_in, y_in), radius=self.r_in, - fill=False, linestyle='-', color=colors[i], lw=lw) - pipe_in_out = plt.Circle( - (x_in, y_in), radius=self.r_out, - fill=False, linestyle='-', color=colors[i], lw=lw) - ax.text(x_in, y_in, i, ha="center", va="center") - - # Pipe outline (outlet) - pipe_out_in = plt.Circle( - (x_out, y_out), radius=self.r_in, - fill=False, linestyle='-', color=colors[i], lw=lw) - pipe_out_out = plt.Circle( - (x_out, y_out), radius=self.r_out, - fill=False, linestyle='-', color=colors[i], lw=lw) - ax.text(x_out, y_out, i + self.nPipes, - ha="center", va="center") - - ax.add_patch(pipe_in_in) - ax.add_patch(pipe_in_out) - ax.add_patch(pipe_out_in) - ax.add_patch(pipe_out_out) - - plt.tight_layout() - - return fig def _initialize_stored_coefficients(self): nMethods = 8 # Number of class methods @@ -2635,79 +2565,6 @@ def update_thermal_resistances(self, R_ff, R_fp): self._initialize_stored_coefficients() return - def visualize_pipes(self): - """ - Plot the cross-section view of the borehole. - - Returns - ------- - fig : figure - Figure object (matplotlib). - - """ - # Configure figure and axes - fig = _initialize_figure() - ax = fig.add_subplot(111) - ax.set_xlabel(r'$x$ [m]') - ax.set_ylabel(r'$y$ [m]') - ax.axis('equal') - _format_axes(ax) - - # Color cycle - prop_cycle = plt.rcParams['axes.prop_cycle'] - colors = prop_cycle.by_key()['color'] - lw = plt.rcParams['lines.linewidth'] - - # Borehole wall outline - ax.plot([-self.b.r_b, 0., self.b.r_b, 0.], - [0., self.b.r_b, 0., -self.b.r_b], - 'k.', alpha=0.) - borewall = plt.Circle( - (0., 0.), radius=self.b.r_b, fill=False, - color='k', linestyle='--', lw=lw) - ax.add_patch(borewall) - - # Pipes - for i, (pos, color) in enumerate(zip(self.pos, colors)): - # Coordinates of pipes - (x_in, y_in) = pos - (x_out, y_out) = pos - - # Pipe outline (inlet) - pipe_in_in = plt.Circle( - (x_in, y_in), radius=self.r_in[0], - fill=False, linestyle='-', color=color, lw=lw) - pipe_in_out = plt.Circle( - (x_in, y_in), radius=self.r_out[0], - fill=False, linestyle='-', color=color, lw=lw) - if self._iInner == 0: - ax.text(x_in, y_in, i, ha="center", va="center") - else: - ax.text(x_in + 0.5 * (self.r_out[0] + self.r_in[1]), y_in, i, - ha="center", va="center") - - # Pipe outline (outlet) - pipe_out_in = plt.Circle( - (x_out, y_out), radius=self.r_in[1], - fill=False, linestyle='-', color=color, lw=lw) - pipe_out_out = plt.Circle( - (x_out, y_out), radius=self.r_out[1], - fill=False, linestyle='-', color=color, lw=lw) - if self._iInner == 1: - ax.text(x_out, y_out, i + self.nPipes, ha="center", va="center") - else: - ax.text(x_out + 0.5 * (self.r_out[0] + self.r_in[1]), y_out, - i + self.nPipes, ha="center", va="center") - - ax.add_patch(pipe_in_in) - ax.add_patch(pipe_in_out) - ax.add_patch(pipe_out_in) - ax.add_patch(pipe_out_out) - - plt.tight_layout() - - return fig - def _check_geometry(self): """ Verifies the inputs to the pipe object and raises an error if the geometry is not valid. diff --git a/pygfunction/utilities.py b/pygfunction/utilities.py index 56d22b05..3cf0e561 100644 --- a/pygfunction/utilities.py +++ b/pygfunction/utilities.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- -import matplotlib.pyplot as plt import numpy as np import numpy.polynomial.polynomial as poly from scipy.special import erf @@ -356,68 +355,6 @@ def time_geometric(dt, tmax, Nt): return time -def _initialize_figure(): - """ - Initialize a matplotlib figure object with overwritten default parameters. - - Returns - ------- - fig : figure - Figure object (matplotlib). - - """ - plt.rc('font', size=9) - plt.rc('xtick', labelsize=9) - plt.rc('ytick', labelsize=9) - plt.rc('lines', lw=1.5, markersize=5.0) - plt.rc('savefig', dpi=500) - fig = plt.figure() - return fig - - -def _format_axes(ax): - """ - Adjust axis parameters. - - Parameters - ---------- - ax : axis - Axis object (matplotlib). - - """ - from matplotlib.ticker import AutoMinorLocator - # Draw major and minor tick marks inwards - ax.tick_params( - axis='both', which='both', direction='in', - bottom=True, top=True, left=True, right=True) - # Auto-adjust minor tick marks - ax.xaxis.set_minor_locator(AutoMinorLocator()) - ax.yaxis.set_minor_locator(AutoMinorLocator()) - return - - -def _format_axes_3d(ax): - """ - Adjust axis parameters. - - Parameters - ---------- - ax : axis - Axis object (matplotlib). - - """ - from matplotlib.ticker import AutoMinorLocator - # Draw major and minor tick marks inwards - ax.tick_params( - axis='both', which='major', direction='in', - bottom=True, top=True, left=True, right=True) - # Auto-adjust minor tick marks - # ax.xaxis.set_minor_locator(AutoMinorLocator()) - # ax.yaxis.set_minor_locator(AutoMinorLocator()) - # ax.zaxis.set_minor_locator(AutoMinorLocator()) - return - - # Coefficients of the approximation of the error function from Tanash and # Riihonen (2020). _a_Q = [np.array([0.5]), diff --git a/requirements.txt b/requirements.txt index 3a43b2fa..78f1dde3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,3 @@ -matplotlib numpy scipy SecondaryCoolantProps diff --git a/requirements_dev.txt b/requirements_dev.txt index dc79c7c8..6ed63898 100644 --- a/requirements_dev.txt +++ b/requirements_dev.txt @@ -1,3 +1,4 @@ +matplotlib == 3.10.1 numpydoc == 1.2.0 pytest == 7.1.1 pytest-cov == 3.0.0 From b4ac6b4e439a24a658010e7d8a8bb217a456f734 Mon Sep 17 00:00:00 2001 From: Alex Swindler Date: Tue, 18 Mar 2025 14:38:33 -0600 Subject: [PATCH 3/4] Isolated matplotlib to examples --- .gitignore | 3 + README.md | 2 +- examples/bore_field_thermal_resistance.py | 6 +- examples/comparison_gfunction_solvers.py | 21 +- examples/comparison_load_aggregation.py | 9 +- examples/custom_bore_field.py | 3 +- examples/custom_bore_field_from_file.py | 12 +- examples/custom_borehole.py | 7 +- examples/discretize_boreholes.py | 10 +- examples/equal_inlet_temperature.py | 4 +- examples/fluid_temperature.py | 15 +- .../fluid_temperature_multiple_boreholes.py | 11 +- ...d_temperature_reversible_flow_direction.py | 9 +- examples/inclined_boreholes.py | 13 +- examples/load_aggregation.py | 9 +- examples/mixed_inlet_conditions.py | 12 +- examples/multiple_independent_Utubes.py | 13 +- examples/multipole_temperature.py | 17 +- examples/regular_bore_field.py | 3 +- examples/unequal_segments.py | 14 +- examples/uniform_heat_extraction_rate.py | 16 +- examples/uniform_temperature.py | 18 +- examples/utilities/__init__.py | 0 examples/utilities/utilities.py | 968 ++++++++++++++++++ pygfunction/borefield.py | 2 +- pygfunction/gfunction.py | 6 +- pygfunction/pipes.py | 3 +- pygfunction/utilities.py | 3 +- requirements_dev.txt | 2 +- setup.cfg | 2 +- 30 files changed, 1107 insertions(+), 106 deletions(-) create mode 100644 examples/utilities/__init__.py create mode 100644 examples/utilities/utilities.py diff --git a/.gitignore b/.gitignore index e1bf194f..fcd466d4 100644 --- a/.gitignore +++ b/.gitignore @@ -62,3 +62,6 @@ target/ # VirtualEnvironment venv/ + +# Generated files +*.png diff --git a/README.md b/README.md index 1bb1b6d9..05e74a7c 100644 --- a/README.md +++ b/README.md @@ -42,10 +42,10 @@ fluid temperatures in the boreholes for several U-tube pipe configurations. *pygfunction* was developed and tested using Python 3.7. In addition, the following packages are needed to run *pygfunction* and its examples: -- matplotlib (>= 3.5.1), - numpy (>= 1.21.5) - scipy (>= 1.7.3) - SecondaryCoolantProps (>= 1.1) +- typing_extensions >= 4.0.1 The documentation is generated using [Sphinx](http://www.sphinx-doc.org). The following packages are needed to build the documentation: diff --git a/examples/bore_field_thermal_resistance.py b/examples/bore_field_thermal_resistance.py index f8b3193c..b47454c7 100644 --- a/examples/bore_field_thermal_resistance.py +++ b/examples/bore_field_thermal_resistance.py @@ -8,9 +8,9 @@ """ import matplotlib.pyplot as plt import numpy as np -from matplotlib.ticker import AutoMinorLocator import pygfunction as gt +from utilities import utilities def main(): @@ -110,7 +110,7 @@ def main(): # ------------------------------------------------------------------------- # Configure figure and axes - fig = gt.utilities._initialize_figure() + fig = utilities.initialize_figure() ax1 = fig.add_subplot(111) # Axis labels @@ -120,7 +120,7 @@ def main(): ax1.set_xlim([0., 1.]) ax1.set_ylim([0., 1.]) - gt.utilities._format_axes(ax1) + utilities.format_axes(ax1) # Bore field thermal resistances ax1.plot(m_flow_network, R[0,:], '-', label='1 borehole') diff --git a/examples/comparison_gfunction_solvers.py b/examples/comparison_gfunction_solvers.py index 89ad678f..3f5dade6 100644 --- a/examples/comparison_gfunction_solvers.py +++ b/examples/comparison_gfunction_solvers.py @@ -23,6 +23,7 @@ from time import perf_counter import pygfunction as gt +from utilities import utilities def main(): @@ -82,7 +83,7 @@ def main(): # Plot results # ------------------------------------------------------------------------- # Draw g-functions - ax = gfunc_detailed.visualize_g_function().axes[0] + ax = utilities.visualize_g_function(gfunc_detailed).axes[0] ax.plot(lntts, gfunc_similarities.gFunc, 'bx') ax.plot(lntts, gfunc_equivalent.gFunc, 'ro') ax.legend([f'detailed (t = {t_detailed:.3f} sec)', @@ -93,12 +94,12 @@ def main(): # Draw absolute error # Configure figure and axes - fig = gt.utilities._initialize_figure() + fig = utilities.initialize_figure() ax = fig.add_subplot(111) # Axis labels ax.set_xlabel(r'ln$(t/t_s)$') ax.set_ylabel(r'Absolute error') - gt.utilities._format_axes(ax) + utilities.format_axes(ax) # Absolute error ax.plot(lntts, np.abs(gfunc_similarities.gFunc - gfunc_detailed.gFunc), '-', label='similarities') @@ -112,12 +113,12 @@ def main(): # Draw relative error # Configure figure and axes - fig = gt.utilities._initialize_figure() + fig = utilities.initialize_figure() ax = fig.add_subplot(111) # Axis labels ax.set_xlabel(r'ln$(t/t_s)$') ax.set_ylabel(r'Relative error') - gt.utilities._format_axes(ax) + utilities.format_axes(ax) # Relative error gFunc_ref = gfunc_detailed.gFunc # reference g-function ax.plot(lntts, (gfunc_similarities.gFunc - gFunc_ref) / gFunc_ref, @@ -155,7 +156,7 @@ def main(): # Plot results # ------------------------------------------------------------------------- # Draw g-functions - ax = gfunc_similarities.visualize_g_function().axes[0] + ax = utilities.visualize_g_function(gfunc_similarities).axes[0] ax.plot(lntts, gfunc_equivalent.gFunc, 'ro') ax.legend([f'similarities (t = {t_similarities:.3f} sec)', f'equivalent (t = {t_equivalent:.3f} sec)']) @@ -164,12 +165,12 @@ def main(): # Draw absolute error # Configure figure and axes - fig = gt.utilities._initialize_figure() + fig = utilities.initialize_figure() ax = fig.add_subplot(111) # Axis labels ax.set_xlabel(r'ln$(t/t_s)$') ax.set_ylabel(r'Absolute error') - gt.utilities._format_axes(ax) + utilities.format_axes(ax) # Absolute error ax.plot(lntts, np.abs(gfunc_equivalent.gFunc - gfunc_similarities.gFunc), label='equivalent') @@ -181,12 +182,12 @@ def main(): # Draw relative error # Configure figure and axes - fig = gt.utilities._initialize_figure() + fig = utilities.initialize_figure() ax = fig.add_subplot(111) # Axis labels ax.set_xlabel(r'ln$(t/t_s)$') ax.set_ylabel(r'Relative error') - gt.utilities._format_axes(ax) + utilities.format_axes(ax) # Relative error ax.plot(lntts, (gfunc_equivalent.gFunc - gfunc_similarities.gFunc) / gfunc_similarities.gFunc, label='equivalent') diff --git a/examples/comparison_load_aggregation.py b/examples/comparison_load_aggregation.py index beade017..cf26ec12 100644 --- a/examples/comparison_load_aggregation.py +++ b/examples/comparison_load_aggregation.py @@ -20,6 +20,7 @@ from scipy.signal import fftconvolve import pygfunction as gt +from utilities import utilities def main(): @@ -123,13 +124,13 @@ def main(): # ------------------------------------------------------------------------- # Configure figure and axes - fig = gt.utilities._initialize_figure() + fig = utilities.initialize_figure() ax1 = fig.add_subplot(311) # Axis labels ax1.set_xlabel(r'$t$ [hours]') ax1.set_ylabel(r'$Q_b$ [W]') - gt.utilities._format_axes(ax1) + utilities.format_axes(ax1) hours = np.array([(j+1)*dt/3600. for j in range(Nt)]) ax1.plot(hours, Q_b) @@ -137,7 +138,7 @@ def main(): # Axis labels ax2.set_xlabel(r'$t$ [hours]') ax2.set_ylabel(r'$T_b$ [degC]') - gt.utilities._format_axes(ax2) + utilities.format_axes(ax2) for T_b_n, line, label in zip(T_b, loadAgg_lines, loadAgg_labels): ax2.plot(hours, T_b_n, line, label=label) ax2.plot(hours, T_b_exact, 'k.', label='exact') @@ -147,7 +148,7 @@ def main(): # Axis labels ax3.set_xlabel(r'$t$ [hours]') ax3.set_ylabel(r'Error [degC]') - gt.utilities._format_axes(ax3) + utilities.format_axes(ax3) for T_b_n, line, label in zip(T_b, loadAgg_lines, loadAgg_labels): ax3.plot(hours, T_b_n - T_b_exact, line, label=label) # Adjust to plot window diff --git a/examples/custom_bore_field.py b/examples/custom_bore_field.py index 55444c0d..2de746ce 100644 --- a/examples/custom_bore_field.py +++ b/examples/custom_bore_field.py @@ -5,6 +5,7 @@ import numpy as np import pygfunction as gt +from utilities import utilities def main(): @@ -42,7 +43,7 @@ def main(): # Draw bore field # ------------------------------------------------------------------------- - borefield.visualize_field() + utilities.visualize_field(borefield) return diff --git a/examples/custom_bore_field_from_file.py b/examples/custom_bore_field_from_file.py index f97a4691..9a931f7a 100644 --- a/examples/custom_bore_field_from_file.py +++ b/examples/custom_bore_field_from_file.py @@ -2,7 +2,10 @@ """ Example of definition of a bore field using custom borehole positions. """ +import os + import pygfunction as gt +from utilities import utilities def main(): @@ -10,21 +13,22 @@ def main(): # Parameters # ------------------------------------------------------------------------- - # Filepath to bore field text file - filename = './data/custom_field_32_boreholes.txt' + # File path to bore field text file + base_dir = os.path.dirname(os.path.abspath(__file__)) + file_path = os.path.join(base_dir, 'data', 'custom_field_32_boreholes.txt') # ------------------------------------------------------------------------- # Borehole field # ------------------------------------------------------------------------- # Build list of boreholes - borefield = gt.borefield.Borefield.from_file(filename) + borefield = gt.borefield.Borefield.from_file(file_path) # ------------------------------------------------------------------------- # Draw bore field # ------------------------------------------------------------------------- - borefield.visualize_field() + utilities.visualize_field(borefield) return diff --git a/examples/custom_borehole.py b/examples/custom_borehole.py index 02aa48b8..f445237c 100644 --- a/examples/custom_borehole.py +++ b/examples/custom_borehole.py @@ -7,6 +7,7 @@ from scipy.constants import pi import pygfunction as gt +from utilities import utilities def main(): @@ -101,7 +102,7 @@ def main(): f'{R_b:.4f} m.K/W') # Visualize the borehole geometry and save the figure - fig_single = SingleUTube.visualize_pipes() + fig_single = utilities.visualize_pipes(SingleUTube) fig_single.savefig('single-u-tube-borehole.png') # ------------------------------------------------------------------------- @@ -153,7 +154,7 @@ def main(): f'{R_b_parallel:.4f} m.K/W') # Visualize the borehole geometry and save the figure - fig_double = DoubleUTube_series.visualize_pipes() + fig_double = utilities.visualize_pipes(DoubleUTube_series) fig_double.savefig('double-u-tube-borehole.png') # ------------------------------------------------------------------------- @@ -198,7 +199,7 @@ def main(): print(f'Coaxial tube Borehole thermal resistance: {R_b:.4f} m.K/W') # Visualize the borehole geometry and save the figure - fig_coaxial = Coaxial.visualize_pipes() + fig_coaxial = utilities.visualize_coaxial_pipes(Coaxial) fig_coaxial.savefig('coaxial-borehole.png') diff --git a/examples/discretize_boreholes.py b/examples/discretize_boreholes.py index f4a03f3d..91f2386b 100644 --- a/examples/discretize_boreholes.py +++ b/examples/discretize_boreholes.py @@ -11,10 +11,12 @@ can be calculated accurately using a small number of segments. """ -import pygfunction as gt -from numpy import pi import matplotlib.pyplot as plt import numpy as np +from numpy import pi + +import pygfunction as gt +from utilities import utilities def main(): @@ -90,7 +92,7 @@ def main(): N_2 = 4 borefield = gt.borefield.Borefield.rectangle_field( N_1, N_2, B, B, H, D, r_b) - gt.boreholes.visualize_field(borefield) + utilities.visualize_field(borefield) nBoreholes = len(borefield) # ------------------------------------------------------------------------- @@ -154,7 +156,7 @@ def main(): # Plot g-functions # ------------------------------------------------------------------------- - ax = gfunc_MIFT_uniform.visualize_g_function().axes[0] + ax = utilities.visualize_g_function(gfunc_MIFT_uniform).axes[0] ax.plot(np.log(time / ts), gfunc_UBWT_uniform.gFunc) ax.plot(np.log(time / ts), gfunc_MIFT_unequal.gFunc, 'o') ax.plot(np.log(time / ts), gfunc_UBWT_unequal.gFunc, 'o') diff --git a/examples/equal_inlet_temperature.py b/examples/equal_inlet_temperature.py index 2dab61a1..fb627e7a 100644 --- a/examples/equal_inlet_temperature.py +++ b/examples/equal_inlet_temperature.py @@ -9,9 +9,9 @@ """ import matplotlib.pyplot as plt import numpy as np -from matplotlib.ticker import AutoMinorLocator import pygfunction as gt +from utilities import utilities def main(): @@ -122,7 +122,7 @@ def main(): # Plot g-functions # ------------------------------------------------------------------------- - ax = gfunc_uniform_Q.visualize_g_function().axes[0] + ax = utilities.visualize_g_function(gfunc_uniform_Q).axes[0] ax.plot(np.log(time / ts), gfunc_uniform_T.gFunc, 'k--') ax.plot(np.log(time / ts), gfunc_equal_Tf_in.gFunc, 'r-.') ax.legend(['Uniform heat extraction rate', diff --git a/examples/fluid_temperature.py b/examples/fluid_temperature.py index 4055fd07..7e94f38e 100644 --- a/examples/fluid_temperature.py +++ b/examples/fluid_temperature.py @@ -15,6 +15,7 @@ import numpy as np import pygfunction as gt +from utilities import utilities def main(): @@ -164,13 +165,13 @@ def main(): # ------------------------------------------------------------------------- # Configure figure and axes - fig = gt.utilities._initialize_figure() + fig = utilities.initialize_figure() ax1 = fig.add_subplot(211) # Axis labels ax1.set_xlabel(r'Time [hours]') ax1.set_ylabel(r'Total heat extraction rate [W]') - gt.utilities._format_axes(ax1) + utilities.format_axes(ax1) # Plot heat extraction rates hours = np.arange(1, Nt+1) * dt / 3600. @@ -180,7 +181,7 @@ def main(): # Axis labels ax2.set_xlabel(r'Time [hours]') ax2.set_ylabel(r'Temperature [degC]') - gt.utilities._format_axes(ax2) + utilities.format_axes(ax2) # Plot temperatures ax2.plot(hours, T_b, 'k-', lw=1.5, label='Borehole wall') @@ -221,13 +222,13 @@ def main(): cp_f) # Configure figure and axes - fig = gt.utilities._initialize_figure() + fig = utilities.initialize_figure() ax3 = fig.add_subplot(131) # Axis labels ax3.set_xlabel(r'Temperature [degC]') ax3.set_ylabel(r'Depth from borehole head [m]') - gt.utilities._format_axes(ax3) + utilities.format_axes(ax3) # Plot temperatures ax3.plot(np.array([T_b[it], T_b[it]]), np.array([0., H]), 'k--') @@ -238,7 +239,7 @@ def main(): # Axis labels ax4.set_xlabel(r'Temperature [degC]') ax4.set_ylabel(r'Depth from borehole head [m]') - gt.utilities._format_axes(ax4) + utilities.format_axes(ax4) # Plot temperatures ax4.plot(T_f_double_par, z, 'b-') @@ -248,7 +249,7 @@ def main(): # Axis labels ax5.set_xlabel(r'Temperature [degC]') ax5.set_ylabel(r'Depth from borehole head [m]') - gt.utilities._format_axes(ax5) + utilities.format_axes(ax5) # Plot temperatures ax5.plot(T_f_double_ser, z, 'b-') diff --git a/examples/fluid_temperature_multiple_boreholes.py b/examples/fluid_temperature_multiple_boreholes.py index cf5b8e9f..359f7cb2 100644 --- a/examples/fluid_temperature_multiple_boreholes.py +++ b/examples/fluid_temperature_multiple_boreholes.py @@ -13,6 +13,7 @@ import numpy as np import pygfunction as gt +from utilities import utilities def main(): @@ -153,13 +154,13 @@ def main(): # ------------------------------------------------------------------------- # Configure figure and axes - fig = gt.utilities._initialize_figure() + fig = utilities.initialize_figure() ax1 = fig.add_subplot(211) # Axis labels ax1.set_xlabel(r'Time [hours]') ax1.set_ylabel(r'Total heat extraction rate [W]') - gt.utilities._format_axes(ax1) + utilities.format_axes(ax1) # Plot heat extraction rates hours = np.arange(1, Nt+1) * dt / 3600. @@ -169,7 +170,7 @@ def main(): # Axis labels ax2.set_xlabel(r'Time [hours]') ax2.set_ylabel(r'Temperature [degC]') - gt.utilities._format_axes(ax2) + utilities.format_axes(ax2) # Plot temperatures ax2.plot(hours, T_b, label='Borehole wall') @@ -193,13 +194,13 @@ def main(): z, T_f_in[it], T_b[it], m_flow_borehole, cp_f) # Configure figure and axes - fig = gt.utilities._initialize_figure() + fig = utilities.initialize_figure() ax3 = fig.add_subplot(111) # Axis labels ax3.set_xlabel(r'Temperature [degC]') ax3.set_ylabel(r'Depth from borehole head [m]') - gt.utilities._format_axes(ax3) + utilities.format_axes(ax3) # Plot temperatures pltFlu = ax3.plot(T_f, z, 'b-', label='Fluid') diff --git a/examples/fluid_temperature_reversible_flow_direction.py b/examples/fluid_temperature_reversible_flow_direction.py index 116d4582..a8dbf3b1 100644 --- a/examples/fluid_temperature_reversible_flow_direction.py +++ b/examples/fluid_temperature_reversible_flow_direction.py @@ -15,6 +15,7 @@ import numpy as np import pygfunction as gt +from utilities import utilities def main(): @@ -187,13 +188,13 @@ def main(): # ------------------------------------------------------------------------- # Configure figure and axes - fig = gt.utilities._initialize_figure() + fig = utilities.initialize_figure() ax1 = fig.add_subplot(221) # Axis labels ax1.set_xlabel(r'Time [hours]') ax1.set_ylabel(r'Total heat extraction rate [W/m]') - gt.utilities._format_axes(ax1) + utilities.format_axes(ax1) # Plot heat extraction rates hours = np.arange(1, Nt+1) * dt / 3600. @@ -203,7 +204,7 @@ def main(): # Axis labels ax2.set_xlabel(r'Time [hours]') ax2.set_ylabel(r'Fluid mass flow rate [kg/s]') - gt.utilities._format_axes(ax2) + utilities.format_axes(ax2) # Plot temperatures ax2.plot(hours, m_flow) @@ -212,7 +213,7 @@ def main(): # Axis labels ax3.set_xlabel(r'Time [hours]') ax3.set_ylabel(r'Temperature [degC]') - gt.utilities._format_axes(ax3) + utilities.format_axes(ax3) # Plot temperatures ax3.plot(hours, T_b, label='Borehole wall') diff --git a/examples/inclined_boreholes.py b/examples/inclined_boreholes.py index d25ac2f0..bbff9ec2 100644 --- a/examples/inclined_boreholes.py +++ b/examples/inclined_boreholes.py @@ -14,9 +14,10 @@ extraction boreholes". Ph.D. Thesis, University of Lund, Lund, Sweden. """ -import pygfunction as gt import numpy as np -import matplotlib.pyplot as plt + +import pygfunction as gt +from utilities import utilities def main(): @@ -75,7 +76,7 @@ def main(): borefield1 = gt.borefield.Borefield.from_boreholes(boreholes) # Visualize the borehole field - fig1 = gt.boreholes.visualize_field(borefield1) + fig1 = utilities.visualize_field(borefield1) """ Bore field #2 @@ -92,7 +93,7 @@ def main(): N, R, H, D, r_b, tilt=tilt) # Visualize the borehole field - fig2 = gt.boreholes.visualize_field(borefield2) + fig2 = utilities.visualize_field(borefield2) # ------------------------------------------------------------------------- # Evaluate g-functions for all fields @@ -100,13 +101,13 @@ def main(): # Bore field #1 gfunc1 = gt.gfunction.gFunction( borefield1, alpha, time=time, options=options, method='similarities') - fig3 = gfunc1.visualize_g_function() + fig3 = utilities.visualize_g_function(gfunc1) fig3.suptitle('"Optimal" field of 8 boreholes') fig3.tight_layout() # Bore field #2 gfunc2 = gt.gfunction.gFunction( borefield2, alpha, time=time, options=options, method='similarities') - fig4 = gfunc2.visualize_g_function() + fig4 = utilities.visualize_g_function(gfunc2) fig4.suptitle(f'Field of {N} boreholes in a circle') fig4.tight_layout() diff --git a/examples/load_aggregation.py b/examples/load_aggregation.py index a8af230a..e7af08b6 100644 --- a/examples/load_aggregation.py +++ b/examples/load_aggregation.py @@ -13,6 +13,7 @@ from scipy.signal import fftconvolve import pygfunction as gt +from utilities import utilities def main(): @@ -96,13 +97,13 @@ def main(): # ------------------------------------------------------------------------- # Configure figure and axes - fig = gt.utilities._initialize_figure() + fig = utilities.initialize_figure() ax1 = fig.add_subplot(311) # Axis labels ax1.set_xlabel(r'$t$ [hours]') ax1.set_ylabel(r'$Q_b$ [W]') - gt.utilities._format_axes(ax1) + utilities.format_axes(ax1) hours = np.arange(1, Nt+1) * dt / 3600. ax1.plot(hours, Q_b) @@ -111,7 +112,7 @@ def main(): # Axis labels ax2.set_xlabel(r'$t$ [hours]') ax2.set_ylabel(r'$T_b$ [degC]') - gt.utilities._format_axes(ax2) + utilities.format_axes(ax2) ax2.plot(hours, T_b) ax2.plot(hours, T_b_exact, 'k.') @@ -120,7 +121,7 @@ def main(): # Axis labels ax3.set_xlabel(r'$t$ [hours]') ax3.set_ylabel(r'Error [degC]') - gt.utilities._format_axes(ax3) + utilities.format_axes(ax3) ax3.plot(hours, T_b - T_b_exact) diff --git a/examples/mixed_inlet_conditions.py b/examples/mixed_inlet_conditions.py index 32c6ba96..6e4d4131 100644 --- a/examples/mixed_inlet_conditions.py +++ b/examples/mixed_inlet_conditions.py @@ -10,9 +10,9 @@ """ import matplotlib.pyplot as plt import numpy as np -from matplotlib.ticker import AutoMinorLocator import pygfunction as gt +from utilities import utilities def main(): @@ -127,7 +127,7 @@ def main(): # Plot g-functions # ------------------------------------------------------------------------- - ax = gfunc_Tb.visualize_g_function().axes[0] + ax = utilities.visualize_g_function(gfunc_Tb).axes[0] ax.plot(np.log(time/ts), gfunc_equal_Tf_mixed.gFunc[0, 0, :], 'C1') ax.plot(np.log(time/ts), gfunc_equal_Tf_mixed.gFunc[1, 1, :], 'C2') ax.legend([ @@ -138,10 +138,10 @@ def main(): # For the mixed inlet fluid temperature condition, draw the temperatures # and heat extraction rates - gfunc_equal_Tf_mixed.visualize_temperatures() - gfunc_equal_Tf_mixed.visualize_temperature_profiles() - gfunc_equal_Tf_mixed.visualize_heat_extraction_rates() - gfunc_equal_Tf_mixed.visualize_heat_extraction_rate_profiles() + utilities.visualize_temperatures(gfunc_equal_Tf_mixed) + utilities.visualize_temperature_profiles(gfunc_equal_Tf_mixed) + utilities.visualize_heat_extraction_rates(gfunc_equal_Tf_mixed) + utilities.visualize_heat_extraction_rate_profiles(gfunc_equal_Tf_mixed) return diff --git a/examples/multiple_independent_Utubes.py b/examples/multiple_independent_Utubes.py index 658242a6..385f8087 100644 --- a/examples/multiple_independent_Utubes.py +++ b/examples/multiple_independent_Utubes.py @@ -9,12 +9,14 @@ Cimmino (2016). """ +import os + import matplotlib.lines as mlines import matplotlib.pyplot as plt import numpy as np -from matplotlib.ticker import AutoMinorLocator import pygfunction as gt +from utilities import utilities def main(): @@ -55,7 +57,8 @@ def main(): T_f_in = np.array([6.0, -6.0, 5.0, -5.0]) # Path to validation data - filePath = './data/Cimmi16_multiple_independent_Utubes.txt' + base_dir = os.path.dirname(os.path.abspath(__file__)) + file_path = os.path.join(base_dir, 'data', 'Cimmi16_multiple_independent_Utubes.txt') # ------------------------------------------------------------------------- # Initialize pipe model @@ -85,13 +88,13 @@ def main(): # ------------------------------------------------------------------------- # Configure figure and axes - fig = gt.utilities._initialize_figure() + fig = utilities.initialize_figure() ax1 = fig.add_subplot(111) # Axis labels ax1.set_xlabel(r'Temperature [degC]') ax1.set_ylabel(r'Depth from borehole head [m]') - gt.utilities._format_axes(ax1) + utilities.format_axes(ax1) # Plot temperatures ax1.plot(T_f, z, 'k.') @@ -112,7 +115,7 @@ def main(): # ------------------------------------------------------------------------- # Load data from Cimmino (2016) # ------------------------------------------------------------------------- - data = np.loadtxt(filePath, skiprows=1) + data = np.loadtxt(file_path, skiprows=1) ax1.plot(data[:,2:], data[:,0], 'b-',) reference = mlines.Line2D([], [], color='blue', diff --git a/examples/multipole_temperature.py b/examples/multipole_temperature.py index 76375384..182b4e8b 100644 --- a/examples/multipole_temperature.py +++ b/examples/multipole_temperature.py @@ -10,11 +10,13 @@ against the results of Claesson and Hellstrom (2011). """ +import os + import matplotlib.pyplot as plt import numpy as np -from matplotlib.ticker import AutoMinorLocator import pygfunction as gt +from utilities import utilities def main(): @@ -51,7 +53,8 @@ def main(): T_f = np.array([1., 1.]) # Path to validation data - filePath = './data/ClaHel11_multipole_temperature.txt' + base_dir = os.path.dirname(os.path.abspath(__file__)) + file_path = os.path.join(base_dir, 'data', 'ClaHel11_multipole_temperature.txt') # Thermal resistances for J=3 R_Claesson = 0.01*np.array([25.592, 1.561, 25.311]) @@ -91,10 +94,10 @@ def main(): x_T=x, y_T=y) # Load validation data - data = np.loadtxt(filePath, skiprows=1) + data = np.loadtxt(file_path, skiprows=1) # Configure figure and axes - fig = gt.utilities._initialize_figure() + fig = utilities.initialize_figure() ax1 = fig.add_subplot(111) # Axis labels @@ -105,7 +108,7 @@ def main(): ax1.set_ylim([-0.2, 1.2]) # Show grid ax1.grid() - gt.utilities._format_axes(ax1) + utilities.format_axes(ax1) ax1.plot(x, T, label='pygfunction') ax1.plot(data[:,0], data[:,1], 'ko', @@ -132,7 +135,7 @@ def main(): y_T=Y.flatten()) # Configure figure and axes - fig = gt.utilities._initialize_figure() + fig = utilities.initialize_figure() ax1 = fig.add_subplot(111) # Axis labels @@ -141,7 +144,7 @@ def main(): # Axis limits plt.axis([-0.1, 0.1, -0.1, 0.1]) plt.gca().set_aspect('equal', adjustable='box') - gt.utilities._format_axes(ax1) + utilities.format_axes(ax1) # Borehole wall outline borewall = plt.Circle((0., 0.), radius=r_b, diff --git a/examples/regular_bore_field.py b/examples/regular_bore_field.py index 8012d56e..07b4a75b 100644 --- a/examples/regular_bore_field.py +++ b/examples/regular_bore_field.py @@ -5,6 +5,7 @@ import matplotlib.pyplot as plt import pygfunction as gt +from utilities import utilities def main(): @@ -62,7 +63,7 @@ def main(): for borefield in [ rectangle_field, staggered_rectangle_field, dense_rectangle_field, box_shaped_field, U_shaped_field, L_shaped_field, circle_field]: - borefield.visualize_field() + utilities.visualize_field(borefield) plt.show() return diff --git a/examples/unequal_segments.py b/examples/unequal_segments.py index 1746abb2..0ae901b2 100644 --- a/examples/unequal_segments.py +++ b/examples/unequal_segments.py @@ -6,10 +6,10 @@ number of segments. """ import matplotlib.pyplot as plt -from matplotlib.ticker import AutoMinorLocator import numpy as np import pygfunction as gt +from utilities import utilities def main(): @@ -42,7 +42,7 @@ def main(): N_2 = 4 borefield = gt.borefield.Borefield.rectangle_field( N_1, N_2, B, B, H, D, r_b) - gt.boreholes.visualize_field(borefield) + utilities.visualize_field(borefield) # ------------------------------------------------------------------------- # Evaluate g-functions with different segment options @@ -101,7 +101,7 @@ def main(): # Plot g-functions # ------------------------------------------------------------------------- - ax = gfunc_equal.visualize_g_function().axes[0] + ax = utilities.visualize_g_function(gfunc_equal).axes[0] ax.plot(np.log(time/ts), gfunc_unequal.gFunc, 'r-.') ax.plot(np.log(time/ts), g_func_predefined.gFunc, 'k-.') ax.legend(['Equal number of segments', @@ -110,19 +110,19 @@ def main(): plt.tight_layout() # Heat extraction rate profiles - fig = gfunc_unequal.visualize_heat_extraction_rates( + fig = utilities.visualize_heat_extraction_rates(gfunc_unequal, iBoreholes=[18, 12, 14]) fig.suptitle('Heat extraction rates (unequal number of segments)') fig.tight_layout() - fig = g_func_predefined.visualize_heat_extraction_rates( + fig = utilities.visualize_heat_extraction_rates(g_func_predefined, iBoreholes=[18, 12, 14]) fig.suptitle('Heat extraction rates (unequal segment lengths)') fig.tight_layout() - fig = gfunc_unequal.visualize_heat_extraction_rate_profiles( + fig = utilities.visualize_heat_extraction_rate_profiles(gfunc_unequal, iBoreholes=[18, 12, 14]) fig.suptitle('Heat extraction rate profiles (unequal number of segments)') fig.tight_layout() - fig = g_func_predefined.visualize_heat_extraction_rate_profiles( + fig = utilities.visualize_heat_extraction_rate_profiles(g_func_predefined, iBoreholes=[18, 12, 14]) fig.suptitle('Heat extraction rate profiles (unequal segment lengths)') fig.tight_layout() diff --git a/examples/uniform_heat_extraction_rate.py b/examples/uniform_heat_extraction_rate.py index 8a8eda29..3bb42af3 100644 --- a/examples/uniform_heat_extraction_rate.py +++ b/examples/uniform_heat_extraction_rate.py @@ -6,12 +6,13 @@ equal for all boreholes. """ -import matplotlib.lines as mlines +import os + import matplotlib.pyplot as plt import numpy as np -from matplotlib.ticker import AutoMinorLocator import pygfunction as gt +from utilities import utilities def main(): @@ -29,7 +30,8 @@ def main(): alpha = 1.0e-6 # Ground thermal diffusivity (m2/s) # Path to validation data - filePath = './data/CiBe14_uniform_heat_extraction_rate.txt' + base_dir = os.path.dirname(os.path.abspath(__file__)) + file_path = os.path.join(base_dir, 'data', 'CiBe14_uniform_heat_extraction_rate.txt') # g-Function calculation options # The second field is evaluated with more segments to draw the @@ -85,7 +87,7 @@ def main(): # ------------------------------------------------------------------------- # Load data from Cimmino and Bernier (2014) # ------------------------------------------------------------------------- - data = np.loadtxt(filePath, skiprows=55) + data = np.loadtxt(file_path, skiprows=55) # ------------------------------------------------------------------------- # Evaluate g-functions for all fields @@ -95,7 +97,7 @@ def main(): field, alpha, time=time, boundary_condition='UHTR', options=options[i], method=method) # Draw g-function - ax = gfunc.visualize_g_function().axes[0] + ax = utilities.visualize_g_function(gfunc).axes[0] # Draw reference g-function ax.plot(data[:,0], data[:,i+1], 'bx') ax.legend(['pygfunction', 'Cimmino and Bernier (2014)']) @@ -104,8 +106,8 @@ def main(): # For the second borefield, draw the evolution of heat extraction rates if i == 1: - gfunc.visualize_temperatures(iBoreholes=[18, 12, 14]) - gfunc.visualize_temperature_profiles(iBoreholes=[14]) + utilities.visualize_temperatures(gfunc, iBoreholes=[18, 12, 14]) + utilities.visualize_temperature_profiles(gfunc, iBoreholes=[14]) return diff --git a/examples/uniform_temperature.py b/examples/uniform_temperature.py index 6936dbef..b7940229 100644 --- a/examples/uniform_temperature.py +++ b/examples/uniform_temperature.py @@ -7,11 +7,14 @@ boreholes, equal for all boreholes. """ +import os + import matplotlib.pyplot as plt import numpy as np from time import perf_counter import pygfunction as gt +from utilities import utilities def main(): @@ -29,7 +32,8 @@ def main(): alpha = 1.0e-6 # Ground thermal diffusivity (m2/s) # Path to validation data - filePath = './data/CiBe14_uniform_temperature.txt' + base_dir = os.path.dirname(os.path.abspath(__file__)) + file_path = os.path.join(base_dir, 'data', 'CiBe14_uniform_temperature.txt') # g-Function calculation options # A uniform discretization is used to compare results with Cimmino and @@ -72,7 +76,7 @@ def main(): # ------------------------------------------------------------------------- # Load data from Cimmino and Bernier (2014) # ------------------------------------------------------------------------- - data = np.loadtxt(filePath, skiprows=55) + data = np.loadtxt(file_path, skiprows=55) # ------------------------------------------------------------------------- # Evaluate g-functions for all fields @@ -90,7 +94,7 @@ def main(): t2 = perf_counter() t_equivalent = t2 - t1 # Draw g-function - ax = gfunc_similarities.visualize_g_function().axes[0] + ax = utilities.visualize_g_function(gfunc_similarities).axes[0] ax.plot(lntts, gfunc_equivalent.gFunc) # Draw reference g-function ax.plot(data[:,0], data[:,i+1], 'o') @@ -102,24 +106,24 @@ def main(): # For the second borefield, draw the evolution of heat extraction rates if i == 1: - fig = gfunc_similarities.visualize_heat_extraction_rates( + fig = utilities.visualize_heat_extraction_rates(gfunc_similarities, iBoreholes=[18, 12, 14]) fig.suptitle(f"Field of {nBoreholes} boreholes: 'similarities' " f"solver") fig.tight_layout() - fig = gfunc_equivalent.visualize_heat_extraction_rates() + fig = utilities.visualize_heat_extraction_rates(gfunc_equivalent) fig.suptitle(f"Field of {nBoreholes} boreholes: 'equivalent' " f"solver") fig.tight_layout() - fig = gfunc_similarities.visualize_heat_extraction_rate_profiles( + fig = utilities.visualize_heat_extraction_rate_profiles(gfunc_similarities, iBoreholes=[18, 12, 14]) fig.suptitle(f"Field of {nBoreholes} boreholes: 'similarities' " f"solver") fig.tight_layout() - fig = gfunc_equivalent.visualize_heat_extraction_rate_profiles() + fig = utilities.visualize_heat_extraction_rate_profiles(gfunc_equivalent) fig.suptitle(f"Field of {nBoreholes} boreholes: 'equivalent' " f"solver") fig.tight_layout() diff --git a/examples/utilities/__init__.py b/examples/utilities/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/examples/utilities/utilities.py b/examples/utilities/utilities.py new file mode 100644 index 00000000..7ebef14d --- /dev/null +++ b/examples/utilities/utilities.py @@ -0,0 +1,968 @@ +# -*- coding: utf-8 -*- +from typing import Union + +import matplotlib.pyplot as plt +import numpy as np +from matplotlib.axes import Axes +from matplotlib.figure import Figure + +from pygfunction.borefield import Borefield +from pygfunction.gfunction import gFunction +from pygfunction.pipes import SingleUTube, MultipleUTube, Coaxial + + +def initialize_figure() -> Figure: + """ + Initialize a matplotlib figure object with overwritten default parameters. + + Returns + ------- + fig : figure + Figure object (matplotlib). + + """ + plt.rc('font', size=9) + plt.rc('xtick', labelsize=9) + plt.rc('ytick', labelsize=9) + plt.rc('lines', lw=1.5, markersize=5.0) + plt.rc('savefig', dpi=500) + fig = plt.figure() + return fig + + +def format_axes(ax: Axes): + """ + Adjust axis parameters. + + Parameters + ---------- + ax : axis + Axis object (matplotlib). + + """ + from matplotlib.ticker import AutoMinorLocator + # Draw major and minor tick marks inwards + ax.tick_params( + axis='both', which='both', direction='in', + bottom=True, top=True, left=True, right=True) + # Auto-adjust minor tick marks + ax.xaxis.set_minor_locator(AutoMinorLocator()) + ax.yaxis.set_minor_locator(AutoMinorLocator()) + return + + +def format_axes_3d(ax: Axes): + """ + Adjust axis parameters. + + Parameters + ---------- + ax : axis + Axis object (matplotlib). + + """ + # Draw major and minor tick marks inwards + ax.tick_params( + axis='both', which='major', direction='in', + bottom=True, top=True, left=True, right=True) + # Auto-adjust minor tick marks + # ax.xaxis.set_minor_locator(AutoMinorLocator()) + # ax.yaxis.set_minor_locator(AutoMinorLocator()) + # ax.zaxis.set_minor_locator(AutoMinorLocator()) + return + + +def visualize_g_function(g_function: gFunction, which=None) -> Figure: + """ + Plot the g-function of the borefield. + + Parameters + ---------- + g_function : gFunction + which : list of tuple, optional + Tuples (i, j) of the variable mass flow rate g-functions to plot. + If None, all g-functions are plotted. + Default is None. + + Returns + ------- + fig : figure + Figure object (matplotlib). + + """ + # Configure figure and axes + fig = initialize_figure() + ax = fig.add_subplot(111) + ax.set_xlabel(r'ln$(t/t_s)$') + ax.set_ylabel(r'$g$-function') + format_axes(ax) + + # Borefield characteristic time + ts = np.mean([b.H for b in g_function.boreholes]) ** 2 / (9. * g_function.alpha) + # Dimensionless time (log) + lntts = np.log(g_function.time / ts) + # Draw g-function + if g_function.solver.nMassFlow == 0: + ax.plot(lntts, g_function.gFunc) + elif which is None: + for j in range(g_function.solver.nMassFlow): + for i in range(g_function.solver.nMassFlow): + ax.plot( + lntts, + g_function.gFunc[i, j, :], + label=f'$g_{{{i}{j}}}$') + plt.legend() + else: + if which is None: + which = [ + (i, j) for j in range(g_function.solver.nMassFlow) + for i in range(g_function.solver.nMassFlow)] + for (i, j) in which: + ax.plot( + lntts, + g_function.gFunc[i, j, :], + label=f'$g_{{{i}{j}}}$') + plt.legend() + + # Adjust figure to window + plt.tight_layout() + return fig + + +def visualize_field( + borefield: Borefield, viewTop: bool = True, view3D: bool = True, + labels: bool = True, showTilt: bool = True) -> Figure: + """ + Plot the top view and 3D view of borehole positions. + + Parameters + ---------- + borefield : Borefield + viewTop : bool, optional + Set to True to plot top view. + Default is True + view3D : bool, optional + Set to True to plot 3D view. + Default is True + labels : bool, optional + Set to True to annotate borehole indices to top view plot. + Default is True + showTilt : bool, optional + Set to True to show borehole inclination on top view plot. + Default is True + + Returns + ------- + fig : figure + Figure object (matplotlib). + + """ + # Configure figure and axes + fig = initialize_figure() + if viewTop and view3D: + ax1 = fig.add_subplot(121) + ax2 = fig.add_subplot(122, projection='3d') + elif viewTop: + ax1 = fig.add_subplot(111) + elif view3D: + ax2 = fig.add_subplot(111, projection='3d') + if viewTop: + ax1.set_xlabel(r'$x$ [m]') + ax1.set_ylabel(r'$y$ [m]') + ax1.axis('equal') + format_axes(ax1) + if view3D: + ax2.set_xlabel(r'$x$ [m]') + ax2.set_ylabel(r'$y$ [m]') + ax2.set_zlabel(r'$z$ [m]') + format_axes_3d(ax2) + ax2.invert_zaxis() + + # Bottom end of boreholes + x_H = borefield.x + borefield.H * np.sin(borefield.tilt) * np.cos(borefield.orientation) + y_H = borefield.y + borefield.H * np.sin(borefield.tilt) * np.sin(borefield.orientation) + z_H = borefield.D + borefield.H * np.cos(borefield.tilt) + + # ------------------------------------------------------------------------- + # Top view + # ------------------------------------------------------------------------- + if viewTop: + if showTilt: + ax1.plot( + np.stack((borefield.x, x_H), axis=0), + np.stack((borefield.y, y_H), axis=0), + 'k--') + ax1.plot(borefield.x, borefield.y, 'ko') + if labels: + for i, borehole in enumerate(borefield): + ax1.text( + borehole.x, + borehole.y, + f' {i}', + ha="left", + va="bottom") + + # ------------------------------------------------------------------------- + # 3D view + # ------------------------------------------------------------------------- + if view3D: + ax2.plot(borefield.x, borefield.y, borefield.D, 'ko') + for i in range(borefield.nBoreholes): + ax2.plot( + (borefield.x[i], x_H[i]), + (borefield.y[i], y_H[i]), + (borefield.D[i], z_H[i]), + 'k-') + + if viewTop and view3D: + plt.tight_layout(rect=[0, 0.0, 0.90, 1.0]) + else: + plt.tight_layout() + + return fig + + +def visualize_pipes(pipe: Union[SingleUTube, MultipleUTube]) -> Figure: + """ + Plot the cross-section view of the borehole. + + Parameters + ---------- + pipe : SingleUTube | MultipleUTube + + Returns + ------- + fig : figure + Figure object (matplotlib). + + """ + # Configure figure and axes + fig = initialize_figure() + ax = fig.add_subplot(111) + ax.set_xlabel(r'$x$ [m]') + ax.set_ylabel(r'$y$ [m]') + ax.axis('equal') + format_axes(ax) + + # Color cycle + prop_cycle = plt.rcParams['axes.prop_cycle'] + colors = prop_cycle.by_key()['color'] + lw = plt.rcParams['lines.linewidth'] + + # Borehole wall outline + ax.plot([-pipe.b.r_b, 0., pipe.b.r_b, 0.], + [0., pipe.b.r_b, 0., -pipe.b.r_b], + 'k.', alpha=0.) + borewall = plt.Circle( + (0., 0.), radius=pipe.b.r_b, fill=False, + color='k', linestyle='--', lw=lw) + ax.add_patch(borewall) + + # Pipes + for i in range(pipe.nPipes): + # Coordinates of pipes + (x_in, y_in) = pipe.pos[i] + (x_out, y_out) = pipe.pos[i + pipe.nPipes] + + # Pipe outline (inlet) + pipe_in_in = plt.Circle( + (x_in, y_in), radius=pipe.r_in, + fill=False, linestyle='-', color=colors[i], lw=lw) + pipe_in_out = plt.Circle( + (x_in, y_in), radius=pipe.r_out, + fill=False, linestyle='-', color=colors[i], lw=lw) + ax.text(x_in, y_in, i, ha="center", va="center") + + # Pipe outline (outlet) + pipe_out_in = plt.Circle( + (x_out, y_out), radius=pipe.r_in, + fill=False, linestyle='-', color=colors[i], lw=lw) + pipe_out_out = plt.Circle( + (x_out, y_out), radius=pipe.r_out, + fill=False, linestyle='-', color=colors[i], lw=lw) + ax.text(x_out, y_out, i + pipe.nPipes, + ha="center", va="center") + + ax.add_patch(pipe_in_in) + ax.add_patch(pipe_in_out) + ax.add_patch(pipe_out_in) + ax.add_patch(pipe_out_out) + + plt.tight_layout() + + return fig + + +def visualize_coaxial_pipes(pipe: Coaxial) -> Figure: + """ + Plot the cross-section view of the borehole. + + Parameters + ---------- + pipe : Coaxial + + Returns + ------- + fig : figure + Figure object (matplotlib). + + """ + # Configure figure and axes + fig = initialize_figure() + ax = fig.add_subplot(111) + ax.set_xlabel(r'$x$ [m]') + ax.set_ylabel(r'$y$ [m]') + ax.axis('equal') + format_axes(ax) + + # Color cycle + prop_cycle = plt.rcParams['axes.prop_cycle'] + colors = prop_cycle.by_key()['color'] + lw = plt.rcParams['lines.linewidth'] + + # Borehole wall outline + ax.plot([-pipe.b.r_b, 0., pipe.b.r_b, 0.], + [0., pipe.b.r_b, 0., -pipe.b.r_b], + 'k.', alpha=0.) + borewall = plt.Circle( + (0., 0.), radius=pipe.b.r_b, fill=False, + color='k', linestyle='--', lw=lw) + ax.add_patch(borewall) + + # Pipes + for i, (pos, color) in enumerate(zip(pipe.pos, colors)): + # Coordinates of pipes + (x_in, y_in) = pos + (x_out, y_out) = pos + + # Pipe outline (inlet) + pipe_in_in = plt.Circle( + (x_in, y_in), radius=pipe.r_in[0], + fill=False, linestyle='-', color=color, lw=lw) + pipe_in_out = plt.Circle( + (x_in, y_in), radius=pipe.r_out[0], + fill=False, linestyle='-', color=color, lw=lw) + if pipe._iInner == 0: + ax.text(x_in, y_in, i, ha="center", va="center") + else: + ax.text(x_in + 0.5 * (pipe.r_out[0] + pipe.r_in[1]), y_in, i, + ha="center", va="center") + + # Pipe outline (outlet) + pipe_out_in = plt.Circle( + (x_out, y_out), radius=pipe.r_in[1], + fill=False, linestyle='-', color=color, lw=lw) + pipe_out_out = plt.Circle( + (x_out, y_out), radius=pipe.r_out[1], + fill=False, linestyle='-', color=color, lw=lw) + if pipe._iInner == 1: + ax.text(x_out, y_out, i + pipe.nPipes, ha="center", va="center") + else: + ax.text(x_out + 0.5 * (pipe.r_out[0] + pipe.r_in[1]), y_out, + i + pipe.nPipes, ha="center", va="center") + + ax.add_patch(pipe_in_in) + ax.add_patch(pipe_in_out) + ax.add_patch(pipe_out_in) + ax.add_patch(pipe_out_out) + + plt.tight_layout() + + return fig + + +def visualize_temperatures( + g_function: gFunction, iBoreholes=None, showTilt=True, which=None) -> Figure: + """ + Plot the time-variation of the average borehole wall temperatures. + + Parameters + ---------- + g_function : gFunction + iBoreholes : list of int + Borehole indices to plot temperatures. + If iBoreholes is None, temperatures are plotted for all boreholes. + Default is None. + showTilt : bool + Set to True to show borehole inclination. + Default is True + which : list of int, optional + Indices i of the diagonal variable mass flow rate g-functions for + which to plot borehole wall temperatures. + If None, all diagonal g-functions are plotted. + Default is None. + + Returns + ------- + fig : figure + Figure object (matplotlib). + + """ + # If iBoreholes is None, then plot all boreholes + if iBoreholes is None: + iBoreholes = range(len(g_function.solver.boreholes)) + # Import temperatures + T_b = g_function._temperatures(iBoreholes) + # Borefield characteristic time + ts = np.mean([b.H for b in g_function.solver.boreholes])**2/(9.*g_function.alpha) + # Dimensionless time (log) + lntts = np.log(g_function.time/ts) + + + if g_function.solver.nMassFlow == 0: + # Configure figure and axes + fig = initialize_figure() + ax1 = fig.add_subplot(121) + ax1.set_xlabel(r'$x$ [m]') + ax1.set_ylabel(r'$y$ [m]') + ax1.axis('equal') + format_axes(ax1) + ax2 = fig.add_subplot(122) + ax2.set_xlabel(r'ln$(t/t_s)$') + ax2.set_ylabel(r'$\bar{T}_b$') + format_axes(ax2) + # Plot curves for requested boreholes + for i, borehole in enumerate(g_function.solver.boreholes): + if i in iBoreholes: + # Draw borehole wall temperature + line = ax2.plot(lntts, T_b[iBoreholes.index(i)]) + color = line[-1]._color + # Draw colored marker for borehole position + if showTilt: + ax1.plot( + [borehole.x, borehole.x + borehole.H*np.sin(borehole.tilt)*np.cos(borehole.orientation)], + [borehole.y, borehole.y + borehole.H*np.sin(borehole.tilt)*np.sin(borehole.orientation)], + linestyle='--', + marker='None', + color=color) + ax1.plot(borehole.x, + borehole.y, + linestyle='None', + marker='o', + color=color) + else: + # Draw black marker for borehole position + if showTilt: + ax1.plot( + [borehole.x, borehole.x + borehole.H*np.sin(borehole.tilt)*np.cos(borehole.orientation)], + [borehole.y, borehole.y + borehole.H*np.sin(borehole.tilt)*np.sin(borehole.orientation)], + linestyle='--', + marker='None', + color='k') + ax1.plot(borehole.x, + borehole.y, + linestyle='None', + marker='o', + color='k') + + # Adjust figure to window + plt.tight_layout() + else: + m_flow = g_function.solver.m_flow + if which is None: + which = [n for n in range(g_function.solver.nMassFlow)] + for n in which: + # Configure figure and axes + fig = initialize_figure() + fig.suptitle( + f'Borehole wall temperatures for m_flow={m_flow[n]} kg/s') + ax1 = fig.add_subplot(121) + ax1.set_xlabel(r'$x$ [m]') + ax1.set_ylabel(r'$y$ [m]') + ax1.axis('equal') + format_axes(ax1) + ax2 = fig.add_subplot(122) + ax2.set_xlabel(r'ln$(t/t_s)$') + ax2.set_ylabel(r'$\bar{T}_b$') + format_axes(ax2) + # Plot curves for requested boreholes + for i, borehole in enumerate(g_function.solver.boreholes): + if i in iBoreholes: + # Draw borehole wall temperature + line = ax2.plot(lntts, T_b[iBoreholes.index(i)][n]) + color = line[-1]._color + # Draw colored marker for borehole position + if showTilt: + ax1.plot( + [borehole.x, borehole.x + borehole.H*np.sin(borehole.tilt)*np.cos(borehole.orientation)], + [borehole.y, borehole.y + borehole.H*np.sin(borehole.tilt)*np.sin(borehole.orientation)], + linestyle='--', + marker='None', + color=color) + ax1.plot(borehole.x, + borehole.y, + linestyle='None', + marker='o', + color=color) + else: + # Draw black marker for borehole position + if showTilt: + ax1.plot( + [borehole.x, borehole.x + borehole.H*np.sin(borehole.tilt)*np.cos(borehole.orientation)], + [borehole.y, borehole.y + borehole.H*np.sin(borehole.tilt)*np.sin(borehole.orientation)], + linestyle='--', + marker='None', + color='k') + ax1.plot(borehole.x, + borehole.y, + linestyle='None', + marker='o', + color='k') + + # Adjust figure to window + plt.tight_layout() + return fig + + +def visualize_temperature_profiles( + g_function: gFunction, time=None, iBoreholes=None, showTilt=True, which=None) -> Figure: + """ + Plot the borehole wall temperature profiles at chosen time. + + Parameters + ---------- + g_function : gFunction + time : float + Values of time (in seconds) to plot temperature profiles. + If time is None, temperatures are plotted at the last time step. + Default is None. + iBoreholes : list of int + Borehole indices to plot temperature profiles. + If iBoreholes is None, temperatures are plotted for all boreholes. + Default is None. + showTilt : bool + Set to True to show borehole inclination. + Default is True + which : list of int, optional + Indices i of the diagonal variable mass flow rate g-functions for + which to plot borehole wall temperatures. + If None, all diagonal g-functions are plotted. + Default is None. + + Returns + ------- + fig : figure + Figure object (matplotlib). + + """ + # If iBoreholes is None, then plot all boreholes + if iBoreholes is None: + iBoreholes = range(len(g_function.boreholes)) + # Import temperature profiles + z, T_b = g_function._temperature_profiles(time, iBoreholes) + + if g_function.solver.nMassFlow == 0: + # Configure figure and axes + fig = initialize_figure() + ax1 = fig.add_subplot(121) + ax1.set_xlabel(r'$x$ [m]') + ax1.set_ylabel(r'$y$ [m]') + ax1.axis('equal') + format_axes(ax1) + ax2 = fig.add_subplot(122) + ax2.set_xlabel(r'$T_b$') + ax2.set_ylabel(r'$z$ [m]') + ax2.invert_yaxis() + format_axes(ax2) + + # Plot curves for requested boreholes + for i, borehole in enumerate(g_function.solver.boreholes): + if i in iBoreholes: + # Draw borehole wall temperature profile + line = ax2.plot( + T_b[iBoreholes.index(i)], + z[iBoreholes.index(i)]) + color = line[-1]._color + # Draw colored marker for borehole position + if showTilt: + ax1.plot( + [borehole.x, borehole.x + borehole.H * np.sin(borehole.tilt) * np.cos(borehole.orientation)], + [borehole.y, borehole.y + borehole.H * np.sin(borehole.tilt) * np.sin(borehole.orientation)], + linestyle='--', + marker='None', + color=color) + ax1.plot(borehole.x, + borehole.y, + linestyle='None', + marker='o', + color=color) + else: + # Draw black marker for borehole position + if showTilt: + ax1.plot( + [borehole.x, borehole.x + borehole.H * np.sin(borehole.tilt) * np.cos(borehole.orientation)], + [borehole.y, borehole.y + borehole.H * np.sin(borehole.tilt) * np.sin(borehole.orientation)], + linestyle='--', + marker='None', + color='k') + ax1.plot(borehole.x, + borehole.y, + linestyle='None', + marker='o', + color='k') + + plt.tight_layout() + else: + m_flow = g_function.solver.m_flow + if which is None: + which = [n for n in range(g_function.solver.nMassFlow)] + for n in which: + # Configure figure and axes + fig = initialize_figure() + fig.suptitle( + f'Borehole wall temperature profiles for m_flow={m_flow[n]} kg/s') + ax1 = fig.add_subplot(121) + ax1.set_xlabel(r'$x$ [m]') + ax1.set_ylabel(r'$y$ [m]') + ax1.axis('equal') + format_axes(ax1) + ax2 = fig.add_subplot(122) + ax2.set_xlabel(r'$T_b$') + ax2.set_ylabel(r'$z$ [m]') + ax2.invert_yaxis() + format_axes(ax2) + + # Plot curves for requested boreholes + for i, borehole in enumerate(g_function.solver.boreholes): + if i in iBoreholes: + # Draw borehole wall temperature profile + line = ax2.plot( + T_b[iBoreholes.index(i)][n], + z[iBoreholes.index(i)]) + color = line[-1]._color + # Draw colored marker for borehole position + if showTilt: + ax1.plot( + [borehole.x, borehole.x + borehole.H * np.sin(borehole.tilt) * np.cos(borehole.orientation)], + [borehole.y, borehole.y + borehole.H * np.sin(borehole.tilt) * np.sin(borehole.orientation)], + linestyle='--', + marker='None', + color=color) + ax1.plot(borehole.x, + borehole.y, + linestyle='None', + marker='o', + color=color) + else: + # Draw black marker for borehole position + if showTilt: + ax1.plot( + [borehole.x, borehole.x + borehole.H * np.sin(borehole.tilt) * np.cos(borehole.orientation)], + [borehole.y, borehole.y + borehole.H * np.sin(borehole.tilt) * np.sin(borehole.orientation)], + linestyle='--', + marker='None', + color='k') + ax1.plot(borehole.x, + borehole.y, + linestyle='None', + marker='o', + color='k') + + plt.tight_layout() + return fig + + +def visualize_heat_extraction_rates( + g_function: gFunction, iBoreholes=None, showTilt=True, which=None) -> Figure: + """ + Plot the time-variation of the average heat extraction rates. + + Parameters + ---------- + g_function : gFunction + iBoreholes : list of int + Borehole indices to plot heat extraction rates. + If iBoreholes is None, heat extraction rates are plotted for all + boreholes. + Default is None. + showTilt : bool + Set to True to show borehole inclination. + Default is True + which : list of int, optional + Indices i of the diagonal variable mass flow rate g-functions for + which to plot heat extraction rates. + If None, all diagonal g-functions are plotted. + Default is None. + + Returns + ------- + fig : figure + Figure object (matplotlib). + + """ + # If iBoreholes is None, then plot all boreholes + if iBoreholes is None: + iBoreholes = range(len(g_function.solver.boreholes)) + # Import heat extraction rates + Q_t = g_function._heat_extraction_rates(iBoreholes) + # Borefield characteristic time + ts = np.mean([b.H for b in g_function.solver.boreholes]) ** 2 / (9. * g_function.alpha) + # Dimensionless time (log) + lntts = np.log(g_function.time / ts) + + if g_function.solver.nMassFlow == 0: + # Configure figure and axes + fig = initialize_figure() + ax1 = fig.add_subplot(121) + ax1.set_xlabel(r'$x$ [m]') + ax1.set_ylabel(r'$y$ [m]') + ax1.axis('equal') + format_axes(ax1) + ax2 = fig.add_subplot(122) + ax2.set_xlabel(r'ln$(t/t_s)$') + ax2.set_ylabel(r'$\bar{Q}_b$') + format_axes(ax2) + + # Plot curves for requested boreholes + for i, borehole in enumerate(g_function.solver.boreholes): + if i in iBoreholes: + # Draw heat extraction rate + line = ax2.plot(lntts, Q_t[iBoreholes.index(i)]) + color = line[-1]._color + # Draw colored marker for borehole position + if showTilt: + ax1.plot( + [borehole.x, + borehole.x + borehole.H * np.sin(borehole.tilt) * np.cos(borehole.orientation)], + [borehole.y, + borehole.y + borehole.H * np.sin(borehole.tilt) * np.sin(borehole.orientation)], + linestyle='--', + marker='None', + color=color) + ax1.plot(borehole.x, + borehole.y, + linestyle='None', + marker='o', + color=color) + else: + # Draw black marker for borehole position + if showTilt: + ax1.plot( + [borehole.x, + borehole.x + borehole.H * np.sin(borehole.tilt) * np.cos(borehole.orientation)], + [borehole.y, + borehole.y + borehole.H * np.sin(borehole.tilt) * np.sin(borehole.orientation)], + linestyle='--', + marker='None', + color='k') + ax1.plot(borehole.x, + borehole.y, + linestyle='None', + marker='o', + color='k') + + # Adjust figure to window + plt.tight_layout() + else: + m_flow = g_function.solver.m_flow + if which is None: + which = [n for n in range(g_function.solver.nMassFlow)] + for n in which: + # Configure figure and axes + fig = initialize_figure() + fig.suptitle( + f'Heat extraction rates for m_flow={m_flow[n]} kg/s') + ax1 = fig.add_subplot(121) + ax1.set_xlabel(r'$x$ [m]') + ax1.set_ylabel(r'$y$ [m]') + ax1.axis('equal') + format_axes(ax1) + ax2 = fig.add_subplot(122) + ax2.set_xlabel(r'ln$(t/t_s)$') + ax2.set_ylabel(r'$\bar{Q}_b$') + format_axes(ax2) + + # Plot curves for requested boreholes + for i, borehole in enumerate(g_function.solver.boreholes): + if i in iBoreholes: + # Draw heat extraction rate + line = ax2.plot(lntts, Q_t[iBoreholes.index(i)][n]) + color = line[-1]._color + # Draw colored marker for borehole position + if showTilt: + ax1.plot( + [borehole.x, + borehole.x + borehole.H * np.sin(borehole.tilt) * np.cos(borehole.orientation)], + [borehole.y, + borehole.y + borehole.H * np.sin(borehole.tilt) * np.sin(borehole.orientation)], + linestyle='--', + marker='None', + color=color) + ax1.plot(borehole.x, + borehole.y, + linestyle='None', + marker='o', + color=color) + else: + # Draw black marker for borehole position + if showTilt: + ax1.plot( + [borehole.x, + borehole.x + borehole.H * np.sin(borehole.tilt) * np.cos(borehole.orientation)], + [borehole.y, + borehole.y + borehole.H * np.sin(borehole.tilt) * np.sin(borehole.orientation)], + linestyle='--', + marker='None', + color='k') + ax1.plot(borehole.x, + borehole.y, + linestyle='None', + marker='o', + color='k') + + # Adjust figure to window + plt.tight_layout() + + return fig + + +def visualize_heat_extraction_rate_profiles( + g_function: gFunction, time=None, iBoreholes=None, showTilt=True, which=None) -> Figure: + """ + Plot the heat extraction rate profiles at chosen time. + + Parameters + ---------- + g_function : gFunction + time : float + Values of time (in seconds) to plot heat extraction rate profiles. + If time is None, heat extraction rates are plotted at the last + time step. + Default is None. + iBoreholes : list of int + Borehole indices to plot heat extraction rate profiles. + If iBoreholes is None, heat extraction rates are plotted for all + boreholes. + Default is None. + showTilt : bool + Set to True to show borehole inclination. + Default is True + which : list of int, optional + Indices i of the diagonal variable mass flow rate g-functions for + which to plot heat extraction rates. + If None, all diagonal g-functions are plotted. + Default is None. + + Returns + ------- + fig : figure + Figure object (matplotlib). + + """ + # If iBoreholes is None, then plot all boreholes + if iBoreholes is None: + iBoreholes = range(len(g_function.solver.boreholes)) + # Import heat extraction rate profiles + z, Q_b = g_function._heat_extraction_rate_profiles(time, iBoreholes) + + if g_function.solver.nMassFlow == 0: + # Configure figure and axes + fig = initialize_figure() + ax1 = fig.add_subplot(121) + ax1.set_xlabel(r'$x$ [m]') + ax1.set_ylabel(r'$y$ [m]') + ax1.axis('equal') + format_axes(ax1) + ax2 = fig.add_subplot(122) + ax2.set_xlabel(r'$Q_b$') + ax2.set_ylabel(r'$z$ [m]') + ax2.invert_yaxis() + format_axes(ax2) + + # Plot curves for requested boreholes + for i, borehole in enumerate(g_function.solver.boreholes): + if i in iBoreholes: + # Draw heat extraction rate profile + line = ax2.plot( + Q_b[iBoreholes.index(i)], z[iBoreholes.index(i)]) + color = line[-1]._color + # Draw colored marker for borehole position + if showTilt: + ax1.plot( + [borehole.x, borehole.x + borehole.H*np.sin(borehole.tilt)*np.cos(borehole.orientation)], + [borehole.y, borehole.y + borehole.H*np.sin(borehole.tilt)*np.sin(borehole.orientation)], + linestyle='--', + marker='None', + color=color) + ax1.plot(borehole.x, + borehole.y, + linestyle='None', + marker='o', + color=color) + else: + # Draw black marker for borehole position + if showTilt: + ax1.plot( + [borehole.x, borehole.x + borehole.H*np.sin(borehole.tilt)*np.cos(borehole.orientation)], + [borehole.y, borehole.y + borehole.H*np.sin(borehole.tilt)*np.sin(borehole.orientation)], + linestyle='--', + marker='None', + color='k') + ax1.plot(borehole.x, + borehole.y, + linestyle='None', + marker='o', + color='k') + + # Adjust figure to window + plt.tight_layout() + else: + m_flow = g_function.solver.m_flow + if which is None: + which = [n for n in range(g_function.solver.nMassFlow)] + for n in which: + # Configure figure and axes + fig = initialize_figure() + fig.suptitle( + f'Heat extraction rate profiles for m_flow={m_flow[n]} kg/s') + ax1 = fig.add_subplot(121) + ax1.set_xlabel(r'$x$ [m]') + ax1.set_ylabel(r'$y$ [m]') + ax1.axis('equal') + format_axes(ax1) + ax2 = fig.add_subplot(122) + ax2.set_xlabel(r'$Q_b$') + ax2.set_ylabel(r'$z$ [m]') + ax2.invert_yaxis() + format_axes(ax2) + + # Plot curves for requested boreholes + for i, borehole in enumerate(g_function.solver.boreholes): + if i in iBoreholes: + # Draw heat extraction rate profile + line = ax2.plot( + Q_b[iBoreholes.index(i)][n], + z[iBoreholes.index(i)]) + color = line[-1]._color + # Draw colored marker for borehole position + if showTilt: + ax1.plot( + [borehole.x, borehole.x + borehole.H*np.sin(borehole.tilt)*np.cos(borehole.orientation)], + [borehole.y, borehole.y + borehole.H*np.sin(borehole.tilt)*np.sin(borehole.orientation)], + linestyle='--', + marker='None', + color=color) + ax1.plot(borehole.x, + borehole.y, + linestyle='None', + marker='o', + color=color) + else: + # Draw black marker for borehole position + if showTilt: + ax1.plot( + [borehole.x, borehole.x + borehole.H*np.sin(borehole.tilt)*np.cos(borehole.orientation)], + [borehole.y, borehole.y + borehole.H*np.sin(borehole.tilt)*np.sin(borehole.orientation)], + linestyle='--', + marker='None', + color='k') + ax1.plot(borehole.x, + borehole.y, + linestyle='None', + marker='o', + color='k') + + # Adjust figure to window + plt.tight_layout() + + return fig diff --git a/pygfunction/borefield.py b/pygfunction/borefield.py index db336649..86d1f726 100644 --- a/pygfunction/borefield.py +++ b/pygfunction/borefield.py @@ -1,9 +1,9 @@ # -*- coding: utf-8 -*- from typing import Union, List, Dict, Tuple -from typing_extensions import Self # for compatibility with Python <= 3.10 import numpy as np import numpy.typing as npt +from typing_extensions import Self # for compatibility with Python <= 3.10 from .boreholes import Borehole diff --git a/pygfunction/gfunction.py b/pygfunction/gfunction.py index 537ef375..0e124088 100644 --- a/pygfunction/gfunction.py +++ b/pygfunction/gfunction.py @@ -1,19 +1,19 @@ # -*- coding: utf-8 -*- -from time import perf_counter import warnings +from time import perf_counter import numpy as np from scipy.cluster.hierarchy import cut_tree, dendrogram, linkage from scipy.constants import pi from scipy.interpolate import interp1d as interp1d -from .boreholes import Borehole, _EquivalentBorehole, find_duplicates +from . import utilities from .borefield import Borefield +from .boreholes import Borehole, _EquivalentBorehole, find_duplicates from .heat_transfer import finite_line_source, finite_line_source_vectorized, \ finite_line_source_equivalent_boreholes_vectorized, \ finite_line_source_inclined_vectorized from .networks import Network, _EquivalentNetwork, network_thermal_resistance -from . import utilities class gFunction(object): diff --git a/pygfunction/pipes.py b/pygfunction/pipes.py index fead10de..d11b0de5 100644 --- a/pygfunction/pipes.py +++ b/pygfunction/pipes.py @@ -1,8 +1,9 @@ # -*- coding: utf-8 -*- +import warnings + import numpy as np from scipy.constants import pi from scipy.special import binom -import warnings class _BasePipe(object): diff --git a/pygfunction/utilities.py b/pygfunction/utilities.py index 3cf0e561..6690d555 100644 --- a/pygfunction/utilities.py +++ b/pygfunction/utilities.py @@ -1,8 +1,9 @@ # -*- coding: utf-8 -*- +import warnings + import numpy as np import numpy.polynomial.polynomial as poly from scipy.special import erf -import warnings def cardinal_point(direction): diff --git a/requirements_dev.txt b/requirements_dev.txt index 6ed63898..62f56ef9 100644 --- a/requirements_dev.txt +++ b/requirements_dev.txt @@ -1,4 +1,4 @@ -matplotlib == 3.10.1 +matplotlib == 3.5.1 numpydoc == 1.2.0 pytest == 7.1.1 pytest-cov == 3.0.0 diff --git a/setup.cfg b/setup.cfg index 8cffabf0..61d02718 100644 --- a/setup.cfg +++ b/setup.cfg @@ -24,7 +24,6 @@ classifiers = [options] packages = pygfunction install_requires = - matplotlib >= 3.5.1 numpy >= 1.21.5 scipy >= 1.7.3 secondarycoolantprops >= 1.1 @@ -37,6 +36,7 @@ doc = recommonmark >= 0.6.0 sphinx >= 4.4.0 testing = + matplotlib >= 3.5.1 pytest >= 7.1.1 pytest-cov >= 3.0.0 tox >= 3.24.5 From 8e96aff0301facb3b2e1c335a5e03e9a6a6dc813 Mon Sep 17 00:00:00 2001 From: Alex Swindler Date: Tue, 18 Mar 2025 15:58:40 -0600 Subject: [PATCH 4/4] Ensure matplotlib and numpy 2 compatibility --- doc/requirements.txt | 2 +- doc/source/install.rst | 1 - requirements_dev.txt | 2 +- setup.cfg | 2 +- 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/doc/requirements.txt b/doc/requirements.txt index 1f428e63..41a1521e 100644 --- a/doc/requirements.txt +++ b/doc/requirements.txt @@ -1,6 +1,6 @@ numpy >= 1.21.5 scipy >= 1.7.3 -matplotlib >= 3.5.1 +matplotlib >= 3.8.4 numpydoc >= 1.2.0 recommonmark >= 0.6.0 sphinx >= 4.4.0 diff --git a/doc/source/install.rst b/doc/source/install.rst index 383b6888..39fa833c 100644 --- a/doc/source/install.rst +++ b/doc/source/install.rst @@ -5,7 +5,6 @@ Setting up pygfunction ********************** *pygfunction* uses Python 3.8, along with the following packages: - - matplotlib (>= 3.5.1), - numpy (>= 1.21.5) - scipy (>= 1.7.3) - SecondaryCoolantProps (>= 1.1) diff --git a/requirements_dev.txt b/requirements_dev.txt index 62f56ef9..17b2278a 100644 --- a/requirements_dev.txt +++ b/requirements_dev.txt @@ -1,4 +1,4 @@ -matplotlib == 3.5.1 +matplotlib == 3.8.4 numpydoc == 1.2.0 pytest == 7.1.1 pytest-cov == 3.0.0 diff --git a/setup.cfg b/setup.cfg index 61d02718..372c8594 100644 --- a/setup.cfg +++ b/setup.cfg @@ -36,7 +36,7 @@ doc = recommonmark >= 0.6.0 sphinx >= 4.4.0 testing = - matplotlib >= 3.5.1 + matplotlib >= 3.8.4 pytest >= 7.1.1 pytest-cov >= 3.0.0 tox >= 3.24.5