1+ """
2+ The resource module provides functions for analyzing river and tidal energy resources.
3+
4+ This module includes utilities for:
5+ - Calculating flow characteristics (Froude number)
6+ - Computing exceedance probabilities
7+ - Fitting polynomial relationships between discharge, velocity, and power
8+ - Converting between different resource metrics (discharge to velocity, velocity to power)
9+ - Calculating energy production from power data
10+
11+ All functions include input validation and follow consistent unit conventions.
12+ """
13+
114import xarray as xr
215import numpy as np
316from scipy .stats import linregress as _linregress
417from scipy .stats import rv_histogram as _rv_histogram
518from mhkit .utils import convert_to_dataarray
619
720
8- def Froude_number (v , h , g = 9.80665 ):
21+ def froude_number (v , h , g = 9.80665 ):
922 """
1023 Calculate the Froude Number of the river, channel or duct flow,
1124 to check subcritical flow assumption (if Fr <1).
@@ -21,7 +34,7 @@ def Froude_number(v, h, g=9.80665):
2134
2235 Returns
2336 ---------
24- Fr : float
37+ froude_num : float
2538 Froude Number of the river [unitless].
2639
2740 """
@@ -32,18 +45,18 @@ def Froude_number(v, h, g=9.80665):
3245 if not isinstance (g , (int , float )):
3346 raise TypeError (f"g must be of type int or float. Got: { type (g )} " )
3447
35- Fr = v / np .sqrt (g * h )
48+ froude_num = v / np .sqrt (g * h )
3649
37- return Fr
50+ return froude_num
3851
3952
40- def exceedance_probability (D , dimension = "" , to_pandas = True ):
53+ def exceedance_probability (discharge , dimension = "" , to_pandas = True ):
4154 """
4255 Calculates the exceedance probability
4356
4457 Parameters
4558 ----------
46- D : pandas Series, pandas DataFrame, xarray DataArray, or xarray Dataset
59+ discharge : pandas Series, pandas DataFrame, xarray DataArray, or xarray Dataset
4760 Discharge indexed by time [datetime or s].
4861
4962 dimension: string (optional)
@@ -55,31 +68,31 @@ def exceedance_probability(D, dimension="", to_pandas=True):
5568
5669 Returns
5770 -------
58- F : pandas DataFrame or xarray Dataset
71+ exceedance_prob : pandas DataFrame or xarray Dataset
5972 Exceedance probability [unitless] indexed by time [datetime or s]
6073 """
6174 if not isinstance (dimension , str ):
6275 raise TypeError (f"dimension must be of type str. Got: { type (dimension )} " )
6376 if not isinstance (to_pandas , bool ):
6477 raise TypeError (f"to_pandas must be of type bool. Got: { type (to_pandas )} " )
6578
66- D = convert_to_dataarray (D )
79+ discharge = convert_to_dataarray (discharge )
6780
6881 if dimension == "" :
69- dimension = list (D .coords )[0 ]
82+ dimension = list (discharge .coords )[0 ]
7083
71- # Calculate exceedance probability (F)
72- rank = D .rank (dim = dimension )
73- rank = len (D [dimension ]) - rank + 1 # convert to descending rank
74- F = 100 * rank / (len (D [dimension ]) + 1 )
75- F .name = "F "
84+ # Calculate exceedance probability
85+ rank = discharge .rank (dim = dimension )
86+ rank = len (discharge [dimension ]) - rank + 1 # convert to descending rank
87+ exceedance_prob = 100 * rank / (len (discharge [dimension ]) + 1 )
88+ exceedance_prob .name = "exceedance_probability "
7689
77- F = F .to_dataset () # for matlab
90+ exceedance_prob = exceedance_prob .to_dataset () # for matlab
7891
7992 if to_pandas :
80- F = F .to_pandas ()
93+ exceedance_prob = exceedance_prob .to_pandas ()
8194
82- return F
95+ return exceedance_prob
8396
8497
8598def polynomial_fit (x , y , n ):
@@ -100,45 +113,48 @@ def polynomial_fit(x, y, n):
100113 ----------
101114 polynomial_coefficients : numpy polynomial
102115 List of polynomial coefficients
103- R2 : float
104- Polynomical fit coeffcient of determination
116+ r_squared : float
117+ Polynomial fit coefficient of determination
105118
106119 """
107120 try :
108121 x = np .array (x )
109- except :
110- pass
122+ except ( ValueError , TypeError ) as exc :
123+ raise TypeError ( "x must be convertible to np.ndarray" ) from exc
111124 try :
112125 y = np .array (y )
113- except :
114- pass
126+ except (ValueError , TypeError ) as exc :
127+ raise TypeError ("y must be convertible to np.ndarray" ) from exc
128+
115129 if not isinstance (x , np .ndarray ):
116130 raise TypeError (f"x must be of type np.ndarray. Got: { type (x )} " )
117131 if not isinstance (y , np .ndarray ):
118132 raise TypeError (f"y must be of type np.ndarray. Got: { type (y )} " )
119133 if not isinstance (n , int ):
120134 raise TypeError (f"n must be of type int. Got: { type (n )} " )
121135
122- # Get coeffcients of polynomial of order n
136+ # Get coefficients of polynomial of order n
123137 polynomial_coefficients = np .poly1d (np .polyfit (x , y , n ))
124138
125- # Calculate the coeffcient of determination
126- slope , intercept , r_value , p_value , std_err = _linregress (
127- y , polynomial_coefficients (x )
128- )
129- R2 = r_value ** 2
139+ # Calculate the coefficient of determination
140+ _ , _ , r_value , _ , _ = _linregress (y , polynomial_coefficients (x ))
141+ r_squared = r_value ** 2
130142
131- return polynomial_coefficients , R2
143+ return polynomial_coefficients , r_squared
132144
133145
134- def discharge_to_velocity (D , polynomial_coefficients , dimension = "" , to_pandas = True ):
146+ # pylint: disable=too-many-arguments
147+ # pylint: disable=too-many-positional-arguments
148+ def discharge_to_velocity (
149+ discharge , polynomial_coefficients , dimension = "" , to_pandas = True
150+ ):
135151 """
136152 Calculates velocity given discharge data and the relationship between
137153 discharge and velocity at an individual turbine
138154
139155 Parameters
140156 ------------
141- D : numpy ndarray, pandas DataFrame, pandas Series, xarray DataArray, or xarray Dataset
157+ discharge : numpy ndarray, pandas DataFrame, pandas Series, xarray DataArray, or xarray Dataset
142158 Discharge data [m3/s] indexed by time [datetime or s]
143159 polynomial_coefficients : numpy polynomial
144160 List of polynomial coefficients that describe the relationship between
@@ -151,57 +167,58 @@ def discharge_to_velocity(D, polynomial_coefficients, dimension="", to_pandas=Tr
151167
152168 Returns
153169 ------------
154- V : pandas DataFrame or xarray Dataset
170+ velocity : pandas DataFrame or xarray Dataset
155171 Velocity [m/s] indexed by time [datetime or s]
156172 """
157173 if not isinstance (polynomial_coefficients , np .poly1d ):
158174 raise TypeError (
159- f"polynomial_coefficients must be of type np.poly1d. Got: { type (polynomial_coefficients )} "
175+ "polynomial_coefficients must be of "
176+ f"type np.poly1d. Got: { type (polynomial_coefficients )} "
160177 )
161178 if not isinstance (dimension , str ):
162179 raise TypeError (f"dimension must be of type str. Got: { type (dimension )} " )
163180 if not isinstance (to_pandas , bool ):
164181 raise TypeError (f"to_pandas must be of type str. Got: { type (to_pandas )} " )
165182
166- D = convert_to_dataarray (D )
183+ discharge = convert_to_dataarray (discharge )
167184
168185 if dimension == "" :
169- dimension = list (D .coords )[0 ]
186+ dimension = list (discharge .coords )[0 ]
170187
171188 # Calculate velocity using polynomial
172- V = xr .DataArray (
173- data = polynomial_coefficients (D ),
189+ velocity = xr .DataArray (
190+ data = polynomial_coefficients (discharge ),
174191 dims = dimension ,
175- coords = {dimension : D [dimension ]},
192+ coords = {dimension : discharge [dimension ]},
176193 )
177- V .name = "V "
194+ velocity .name = "velocity "
178195
179- V = V .to_dataset () # for matlab
196+ velocity = velocity .to_dataset () # for matlab
180197
181198 if to_pandas :
182- V = V .to_pandas ()
199+ velocity = velocity .to_pandas ()
183200
184- return V
201+ return velocity
185202
186203
187204def velocity_to_power (
188- V , polynomial_coefficients , cut_in , cut_out , dimension = "" , to_pandas = True
205+ velocity , polynomial_coefficients , cut_in , cut_out , dimension = "" , to_pandas = True
189206):
190207 """
191208 Calculates power given velocity data and the relationship
192209 between velocity and power from an individual turbine
193210
194211 Parameters
195212 ----------
196- V : numpy ndarray, pandas DataFrame, pandas Series, xarray DataArray, or xarray Dataset
213+ velocity : numpy ndarray, pandas DataFrame, pandas Series, xarray DataArray, or xarray Dataset
197214 Velocity [m/s] indexed by time [datetime or s]
198215 polynomial_coefficients : numpy polynomial
199216 List of polynomial coefficients that describe the relationship between
200217 velocity and power at an individual turbine
201218 cut_in: int/float
202- Velocity values below cut_in are not used to compute P
219+ Velocity values below cut_in are not used to compute power
203220 cut_out: int/float
204- Velocity values above cut_out are not used to compute P
221+ Velocity values above cut_out are not used to compute power
205222 dimension: string (optional)
206223 Name of the relevant xarray dimension. If not supplied,
207224 defaults to the first dimension. Does not affect pandas input.
@@ -210,12 +227,13 @@ def velocity_to_power(
210227
211228 Returns
212229 -------
213- P : pandas DataFrame or xarray Dataset
230+ power : pandas DataFrame or xarray Dataset
214231 Power [W] indexed by time [datetime or s]
215232 """
216233 if not isinstance (polynomial_coefficients , np .poly1d ):
217234 raise TypeError (
218- f"polynomial_coefficients must be of type np.poly1d. Got: { type (polynomial_coefficients )} "
235+ "polynomial_coefficients must be"
236+ f"of type np.poly1d. Got: { type (polynomial_coefficients )} "
219237 )
220238 if not isinstance (cut_in , (int , float )):
221239 raise TypeError (f"cut_in must be of type int or float. Got: { type (cut_in )} " )
@@ -224,64 +242,66 @@ def velocity_to_power(
224242 if not isinstance (dimension , str ):
225243 raise TypeError (f"dimension must be of type str. Got: { type (dimension )} " )
226244 if not isinstance (to_pandas , bool ):
227- raise TypeError (f"to_pandas must be of type str . Got: { type (to_pandas )} " )
245+ raise TypeError (f"to_pandas must be of type bool . Got: { type (to_pandas )} " )
228246
229- V = convert_to_dataarray (V )
247+ velocity = convert_to_dataarray (velocity )
230248
231249 if dimension == "" :
232- dimension = list (V .coords )[0 ]
250+ dimension = list (velocity .coords )[0 ]
233251
234- # Calculate velocity using polynomial
235- power = polynomial_coefficients (V )
252+ # Calculate power using polynomial
253+ power_values = polynomial_coefficients (velocity )
236254
237255 # Power for velocity values outside lower and upper bounds Turbine produces 0 power
238- power [ V < cut_in ] = 0.0
239- power [ V > cut_out ] = 0.0
256+ power_values [ velocity < cut_in ] = 0.0
257+ power_values [ velocity > cut_out ] = 0.0
240258
241- P = xr .DataArray (data = power , dims = dimension , coords = {dimension : V [dimension ]})
242- P .name = "P"
259+ power = xr .DataArray (
260+ data = power_values , dims = dimension , coords = {dimension : velocity [dimension ]}
261+ )
262+ power .name = "power"
243263
244- P = P .to_dataset ()
264+ power = power .to_dataset ()
245265
246266 if to_pandas :
247- P = P .to_pandas ()
267+ power = power .to_pandas ()
248268
249- return P
269+ return power
250270
251271
252- def energy_produced (P , seconds ):
272+ def energy_produced (power_data , seconds ):
253273 """
254274 Returns the energy produced for a given time period provided
255275 exceedance probability and power.
256276
257277 Parameters
258278 ----------
259- P : numpy ndarray, pandas DataFrame, pandas Series, xarray DataArray, or xarray Dataset
279+ power_data : numpy ndarray, pandas DataFrame, pandas Series, xarray DataArray, or xarray Dataset
260280 Power [W] indexed by time [datetime or s]
261281 seconds: int or float
262282 Seconds in the time period of interest
263283
264284 Returns
265285 -------
266- E : float
286+ energy : float
267287 Energy [J] produced in the given length of time
268288 """
269289 if not isinstance (seconds , (int , float )):
270290 raise TypeError (f"seconds must be of type int or float. Got: { type (seconds )} " )
271291
272- P = convert_to_dataarray (P )
292+ power_data = convert_to_dataarray (power_data )
273293
274- # Calculate Histogram of power
275- H , edges = np .histogram (P , 100 )
294+ # Calculate histogram of power
295+ hist_values , edges = np .histogram (power_data , 100 )
276296 # Create a distribution
277- hist_dist = _rv_histogram ([H , edges ])
297+ hist_dist = _rv_histogram ([hist_values , edges ])
278298 # Sample range for pdf
279299 x = np .linspace (edges .min (), edges .max (), 1000 )
280- # Calculate the expected value of Power
281- expected_val_of_power = np .trapz (x * hist_dist .pdf (x ), x = x )
300+ # Calculate the expected value of power
301+ expected_power = np .trapz (x * hist_dist .pdf (x ), x = x )
282302 # Note: Built-in Expected Value method often throws warning
283303 # EV = hist_dist.expect(lb=edges.min(), ub=edges.max())
284- # Energy
285- E = seconds * expected_val_of_power
304+ # Calculate energy
305+ energy = seconds * expected_power
286306
287- return E
307+ return energy
0 commit comments