Skip to content

Commit 5e0aed8

Browse files
authored
Tidal power performance (#236)
Tidal power performance capabilities specified in IEC/TS 6200-200. Also includes bugfixes, docstring clarifications, and useability edits for the Tidal module in general that I came across from a users standpoint. Changelog as follows: Bugfixes: - Standardized function inputs to accept both numpy.ndarrays and pandas.Series (some functions already have this implemented). - Fixed assertions so that if a numpy array is supplied, the following assertions that rely on pandas don't fail (some functions already have this implemented). - Added a (temporary) fix so that assertions can handle nans - Fixed river.performance capture area calculation the multiplies by instead of dividing by 4. - Fixed a misnamed variable in tidal.performance.principal_flow_directions. - Corrected the "Returns" statement in the tidal.performance.principal_flow_directions docstring and added a "Notes" section. API/useability - Added 'ax' argument passthrough to tidal.graphics.plot_rose and tidal.graphics.plot_joint_prob_distribution to enable more complex matplotlib capabilities outside of the function. - Added check and updated docstring in tidal.performance.principal_flow_directions to make sure directions are between 0 and 360 degrees, which the function requires.
1 parent 7845dd2 commit 5e0aed8

File tree

12 files changed

+1733
-439
lines changed

12 files changed

+1733
-439
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ $ cat .gitignore
99
*.swp
1010
*.tws
1111
*~
12+
*.png
1213

1314
# Directories
1415
**/__pycache__/

examples/adcp_example.ipynb

Lines changed: 80 additions & 80 deletions
Large diffs are not rendered by default.

examples/adv_example.ipynb

Lines changed: 33 additions & 58 deletions
Large diffs are not rendered by default.
34.4 MB
Binary file not shown.

examples/tidal_example.ipynb

Lines changed: 49 additions & 124 deletions
Large diffs are not rendered by default.

examples/tidal_performance_example.ipynb

Lines changed: 690 additions & 0 deletions
Large diffs are not rendered by default.

mhkit/river/performance.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ def circular(diameter):
2020
assert isinstance(diameter, (int,float)), 'diameter must be of type int or float'
2121

2222
equivalent_diameter = diameter
23-
projected_capture_area = 4.*np.pi*(equivalent_diameter**2.)
23+
projected_capture_area = (1/4)*np.pi*(equivalent_diameter**2)
2424

2525
return equivalent_diameter, projected_capture_area
2626

@@ -44,7 +44,7 @@ def ducted(duct_diameter):
4444
assert isinstance(duct_diameter, (int,float)), 'duct_diameter must be of type int or float'
4545

4646
equivalent_diameter = duct_diameter
47-
projected_capture_area = 4.*np.pi*(equivalent_diameter**2.)
47+
projected_capture_area = (1/4)*np.pi*(equivalent_diameter**2)
4848

4949
return equivalent_diameter, projected_capture_area
5050

mhkit/tests/river/test_performance.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,12 @@ def tearDownClass(self):
3333
def test_circular(self):
3434
eq, ca = river.performance.circular(self.diameter)
3535
self.assertEqual(eq, self.diameter)
36-
self.assertEqual(ca, 4*np.pi*self.diameter**2.)
36+
self.assertEqual(ca, 0.25*np.pi*self.diameter**2.)
3737

3838
def test_ducted(self):
3939
eq, ca =river.performance.ducted(self.diameter)
4040
self.assertEqual(eq, self.diameter)
41-
self.assertEqual(ca, 4*np.pi*self.diameter**2.)
41+
self.assertEqual(ca, 0.25*np.pi*self.diameter**2.)
4242

4343
def test_rectangular(self):
4444
eq, ca = river.performance.rectangular(self.height, self.width)
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
import unittest
2+
from os.path import abspath, dirname, join, isfile, normpath, relpath
3+
import os
4+
import numpy as np
5+
from numpy.testing import assert_allclose
6+
7+
from mhkit.tidal import resource, graphics, performance
8+
from mhkit.dolfyn import load
9+
10+
testdir = dirname(abspath(__file__))
11+
plotdir = join(testdir, 'plots')
12+
isdir = os.path.isdir(plotdir)
13+
if not isdir: os.mkdir(plotdir)
14+
datadir = normpath(join(testdir,relpath('../../../examples/data/tidal')))
15+
16+
17+
class TestResource(unittest.TestCase):
18+
19+
@classmethod
20+
def setUpClass(self):
21+
filename = join(datadir, 'adcp.principal.a1.20200815.nc')
22+
self.ds = load(filename)
23+
# Emulate power data
24+
self.power = abs(self.ds['vel'][0,10]**3 * 1e5)
25+
26+
@classmethod
27+
def tearDownClass(self):
28+
pass
29+
30+
def test_power_curve(self,):
31+
df93_circ = performance.power_curve(
32+
power=self.power,
33+
velocity=self.ds['vel'].sel(dir='streamwise'),
34+
hub_height=4.2,
35+
doppler_cell_size=0.5,
36+
sampling_frequency=1,
37+
window_avg_time=600,
38+
turbine_profile='circular',
39+
diameter=3,
40+
height=None,
41+
width=None)
42+
test_circ = np.array([1.26250990e+00,
43+
1.09230978e+00,
44+
1.89122103e+05,
45+
1.03223668e+04,
46+
2.04261423e+05,
47+
1.72095731e+05])
48+
49+
df93_rect = performance.power_curve(
50+
power=self.power,
51+
velocity=self.ds['vel'].sel(dir='streamwise'),
52+
hub_height=4.2,
53+
doppler_cell_size=0.5,
54+
sampling_frequency=1,
55+
window_avg_time=600,
56+
turbine_profile='rectangular',
57+
diameter=None,
58+
height=1,
59+
width=3)
60+
test_rect = np.array([1.15032239e+00,
61+
3.75747621e-01,
62+
1.73098627e+05,
63+
3.04090212e+04,
64+
2.09073742e+05,
65+
1.27430552e+05])
66+
67+
assert_allclose(df93_circ.values[-2], test_circ, atol=1e-5)
68+
assert_allclose(df93_rect.values[-3], test_rect, atol=1e-5)
69+
70+
def test_velocity_profiles(self):
71+
df94 = performance.velocity_profiles(
72+
velocity=self.ds['vel'].sel(dir='streamwise'),
73+
hub_height=4.2,
74+
water_depth=10,
75+
sampling_frequency=1,
76+
window_avg_time=600,
77+
function='mean')
78+
df95a = performance.velocity_profiles(
79+
velocity=self.ds['vel'].sel(dir='streamwise'),
80+
hub_height=4.2,
81+
water_depth=10,
82+
sampling_frequency=1,
83+
window_avg_time=600,
84+
function='rms')
85+
df95b = performance.velocity_profiles(
86+
velocity=self.ds['vel'].sel(dir='streamwise'),
87+
hub_height=4.2,
88+
water_depth=10,
89+
sampling_frequency=1,
90+
window_avg_time=600,
91+
function='std')
92+
93+
test_df94 = np.array([0.32782955, 0.69326691, 1.00948623])
94+
test_df95a = np.array([0.3329345 , 0.69936798, 1.01762123])
95+
test_df95b = np.array([0.05635571, 0.08671777, 0.12735139])
96+
97+
assert_allclose(df94.values[1], test_df94, atol=1e-5)
98+
assert_allclose(df95a.values[1], test_df95a, atol=1e-5)
99+
assert_allclose(df95b.values[1], test_df95b, atol=1e-5)
100+
101+
102+
def test_power_efficiency(self):
103+
df97 = performance.device_efficiency(
104+
self.power,
105+
velocity=self.ds['vel'].sel(dir='streamwise'),
106+
water_density=self.ds['water_density'],
107+
capture_area=np.pi*1.5**2,
108+
hub_height=4.2,
109+
sampling_frequency=1,
110+
window_avg_time=600)
111+
112+
test_df97 = np.array(24.79197)
113+
assert_allclose(df97.values[-1,-1], test_df97, atol=1e-5)
114+
115+
116+
if __name__ == '__main__':
117+
unittest.main()

0 commit comments

Comments
 (0)