Skip to content

Commit 5c70526

Browse files
authored
Merge pull request #52 from wind-python/turbine_library_as_csv
Turbine library as csv
2 parents 1e5b1a0 + 2d0b3b8 commit 5c70526

File tree

5 files changed

+116
-77
lines changed

5 files changed

+116
-77
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,5 @@ ENV/
101101

102102
# oedb data dump
103103
/windpowerlib/data/turbine_data_oedb.h5
104+
/windpowerlib/data/oedb_power_coefficient_curves.csv
105+
/windpowerlib/data/oedb_power_curves.csv

doc/whatsnew/v0-1-2.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ Bug fixes
1919

2020
Other changes
2121
#############
22-
* Make windpowerlib work offline: turbine data from oedb is stored in a hdf5 file for offline usage
22+
* Make windpowerlib work offline: turbine data from oedb is stored in csv files for offline usage
2323
* Make :py:func:`~windpowerlib.wind_turbine.get_turbine_types` also accessible via `get_turbine_types()` --> from windpowerlib import get_turbine_types
2424

2525

tests/test_wind_turbine.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,5 @@ def test_get_turbine_data_from_file(self):
3838
file_='not_existent')
3939

4040
def test_get_turbine_types(self):
41-
get_turbine_types(print_out=False)
41+
get_turbine_types(print_out=True, filter_=True)
42+
get_turbine_types(print_out=False, filter_=False)

windpowerlib/turbine_cluster_modelchain.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,8 +183,7 @@ def assign_power_curve(self, weather_df):
183183
self
184184
185185
"""
186-
187-
# Set turbulence intensity for assigning power curve
186+
# Get turbulence intensity from weather if existent
188187
turbulence_intensity = (
189188
weather_df['turbulence_intensity'].values.mean() if
190189
'turbulence_intensity' in

windpowerlib/wind_turbine.py

Lines changed: 110 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,10 @@ def fetch_turbine_data(self, fetch_curve, data_source):
171171
4200000.0
172172
173173
"""
174+
if fetch_curve not in ['power_curve', 'power_coefficient_curve']:
175+
raise ValueError("'{0}' is an invalid value for ".format(
176+
fetch_curve) + "`fetch_curve`. Must be " +
177+
"'power_curve' or 'power_coefficient_curve'.")
174178
if data_source == 'oedb':
175179
curve_df, nominal_power = get_turbine_data_from_oedb(
176180
turbine_type=self.name, fetch_curve=fetch_curve)
@@ -181,10 +185,6 @@ def fetch_turbine_data(self, fetch_curve, data_source):
181185
self.power_curve = curve_df
182186
elif fetch_curve == 'power_coefficient_curve':
183187
self.power_coefficient_curve = curve_df
184-
else:
185-
raise ValueError("'{0}' is an invalid value. ".format(
186-
fetch_curve) + "`fetch_curve` must be " +
187-
"'power_curve' or 'power_coefficient_curve'.")
188188
if self.nominal_power is None:
189189
self.nominal_power = nominal_power
190190
return self
@@ -202,15 +202,15 @@ def get_turbine_data_from_file(turbine_type, file_):
202202
203203
Parameters
204204
----------
205-
turbine_type : string
205+
turbine_type : str
206206
Specifies the turbine type data is fetched for.
207-
file_ : string
207+
file_ : str
208208
Specifies the source of the turbine data.
209209
See the example below for how to use the example data.
210210
211211
Returns
212212
-------
213-
Tuple (pandas.DataFrame, float)
213+
tuple(pandas.DataFrame, float)
214214
Power curve or power coefficient curve (pandas.DataFrame) and nominal
215215
power (float). Power (coefficient) curve DataFrame contains power
216216
coefficient curve values (dimensionless) or power curve values in W
@@ -246,11 +246,17 @@ def isfloat(x):
246246
df = pd.read_csv(file_, index_col=0)
247247
except FileNotFoundError:
248248
raise FileNotFoundError("The file '{}' was not found.".format(file_))
249-
wpp_df = df[df.turbine_id == turbine_type]
249+
# todo: note: this try except statement will be removed in 0.2.0 and only
250+
# the exception will stay. The example power (coefficient) curve files
251+
# will then be adapted
252+
try:
253+
wpp_df = df[df['turbine_id'] == turbine_type]
254+
except KeyError:
255+
wpp_df = df[df.index == turbine_type]
250256
# if turbine not in data file
251257
if wpp_df.shape[0] == 0:
252258
pd.set_option('display.max_rows', len(df))
253-
logging.info('Possible types: \n{0}'.format(df.turbine_id))
259+
logging.info('Possible types: \n{0}'.format(df['turbine_id']))
254260
pd.reset_option('display.max_rows')
255261
sys.exit('Cannot find the wind converter type: {0}'.format(
256262
turbine_type))
@@ -261,73 +267,62 @@ def isfloat(x):
261267
df = curve_data.transpose().reset_index()
262268
df.columns = ['wind_speed', 'value']
263269
df['wind_speed'] = df['wind_speed'].apply(lambda x: float(x))
264-
nominal_power = wpp_df['p_nom'].iloc[0]
270+
# todo: note: this try except statement will be removed in 0.2.0 and only
271+
# the exception will stay. The example power (coefficient) curve files
272+
# will then be adapted
273+
try:
274+
nominal_power = wpp_df['p_nom'].iloc[0]
275+
except KeyError:
276+
nominal_power = float(wpp_df['nominal_power'].iloc[0])
265277
return df, nominal_power
266278

267279

268280
def get_turbine_data_from_oedb(turbine_type, fetch_curve, overwrite=False):
269281
r"""
270-
Fetches data for one wind turbine type from the OpenEnergy Database (oedb).
282+
Fetches wind turbine data from the OpenEnergy database (oedb).
271283
272284
If turbine data exists in local repository it is loaded from this file. The
273-
file is created when turbine data was loaded from oedb in
285+
file is created when turbine data is loaded from oedb in
274286
:py:func:`~.load_turbine_data_from_oedb`. Use this function with
275287
`overwrite=True` to overwrite your file with newly fetched data.
276-
Use :py:func:`~.check_local_turbine_data` to check
277-
weather your local file is up to date.
278288
279289
Parameters
280290
----------
281-
turbine_type : string
291+
turbine_type : str
282292
Specifies the turbine type data is fetched for.
283293
Use :py:func:`~.get_turbine_types` to see a table of all wind turbines
284-
for which power (coefficient) curve data is provided.
285-
fetch_curve : string
294+
in oedb containing information about whether power (coefficient) curve
295+
data is provided.
296+
fetch_curve : str
286297
Parameter to specify whether a power or power coefficient curve
287298
should be retrieved from the provided turbine data. Valid options are
288299
'power_curve' and 'power_coefficient_curve'. Default: None.
289-
overwrite : boolean
290-
If True local file is overwritten by newly fetch data from oedb, if
300+
overwrite : bool
301+
If True local file is overwritten by newly fetched data from oedb, if
291302
False turbine data is fetched from previously saved file.
292303
293304
Returns
294305
-------
295-
Tuple (pandas.DataFrame, float)
306+
tuple(pandas.DataFrame, float)
296307
Power curve or power coefficient curve (pandas.DataFrame) and nominal
297308
power (float) of one wind turbine type. Power (coefficient) curve
298309
DataFrame contains power coefficient curve values (dimensionless) or
299310
power curve values in W with the corresponding wind speeds in m/s.
300311
301312
"""
302-
# hdf5 filename
303313
filename = os.path.join(os.path.dirname(__file__), 'data',
304-
'turbine_data_oedb.h5')
305-
if os.path.isfile(filename) and not overwrite:
306-
logging.debug("Turbine data is fetched from {}".format(filename))
307-
with pd.HDFStore(filename) as hdf_store:
308-
turbine_data = hdf_store.get('turbine_data')
309-
else:
310-
turbine_data = load_turbine_data_from_oedb()
311-
turbine_data.set_index('turbine_type', inplace=True)
312-
# Set `curve` depending on `fetch_curve` to match names in oedb
313-
curve = ('cp_curve' if fetch_curve == 'power_coefficient_curve'
314-
else fetch_curve)
315-
# Select curve and nominal power of turbine type
316-
try:
317-
df = turbine_data.loc[turbine_type]
318-
except KeyError:
319-
raise KeyError("Turbine type '{}' not in database. ".format(
320-
turbine_type) + "Use 'get_turbine_types()' to see a table of " +
321-
"possible wind turbine types.")
322-
if df[curve] is not None:
323-
df = pd.DataFrame(df[curve])
314+
'oedb_{}s.csv'.format(fetch_curve))
315+
if not os.path.isfile(filename) or overwrite:
316+
# Load data from oedb and save to csv file
317+
load_turbine_data_from_oedb()
324318
else:
325-
sys.exit("{} of {} not available in ".format(curve, turbine_type) +
326-
"oedb. Use 'get_turbine_types()' to see for which turbine " +
327-
"types power coefficient curves are available.")
328-
nominal_power = turbine_data.loc[turbine_type][
329-
'installed_capacity_kw'] * 1000
330-
df.columns = ['wind_speed', 'value']
319+
logging.debug("Turbine data is fetched from {}".format(filename))
320+
# turbine_data = pd.read_csv(filename, index_col=0)
321+
df, nominal_power = get_turbine_data_from_file(turbine_type=turbine_type,
322+
file_=filename)
323+
324+
# nominal power and power curve values in W
325+
nominal_power = nominal_power * 1000
331326
if fetch_curve == 'power_curve':
332327
# power in W
333328
df['value'] = df['value'] * 1000
@@ -336,64 +331,103 @@ def get_turbine_data_from_oedb(turbine_type, fetch_curve, overwrite=False):
336331

337332
def load_turbine_data_from_oedb():
338333
r"""
339-
Loads turbine data from the OpenEnergy Database (oedb).
334+
Loads turbine data from the OpenEnergy database (oedb).
340335
341-
Turbine data is saved to `filename` for offline usage of windpowerlib.
336+
Turbine data is saved to csv files ('oedb_power_curves.csv' and
337+
'oedb_power_coefficient_curves.csv') for offline usage of windpowerlib.
338+
If the files already exist they are overwritten.
342339
343340
Returns
344341
-------
345-
turbine_data : pd.DataFrame
342+
pd.DataFrame
346343
Contains turbine data of different turbines such as 'manufacturer',
347-
'turbine_type', nominal power ('installed_capacity_kw').
344+
'turbine_type', 'nominal_power'.
348345
349346
"""
350347
# url of OpenEnergy Platform that contains the oedb
351348
oep_url = 'http://oep.iks.cs.ovgu.de/'
352349
# location of data
353-
schema = 'model_draft'
354-
table = 'openfred_windpower_powercurve'
350+
schema = 'supply'
351+
table = 'turbine_library'
355352
# load data
356353
result = requests.get(
357354
oep_url + '/api/v0/schema/{}/tables/{}/rows/?'.format(
358355
schema, table), )
359356
if not result.status_code == 200:
360357
raise ConnectionError("Database connection not successful. "
361358
"Response: [{}]".format(result.status_code))
362-
# extract data to data frame
359+
# extract data to dataframe
363360
turbine_data = pd.DataFrame(result.json())
364-
# store data as hdf5
361+
# standard file name for saving data
365362
filename = os.path.join(os.path.dirname(__file__), 'data',
366-
'turbine_data_oedb.h5')
367-
with pd.HDFStore(filename) as hdf_store:
368-
hdf_store.put('turbine_data', turbine_data)
369-
logging.debug("Turbine data is fetched from oedb and saved "
370-
"to {}".format(filename))
363+
'oedb_{}.csv')
364+
# get all power (coefficient) curves and save to file
365+
# for curve_type in ['power_curve', 'power_coefficient_curve']:
366+
for curve_type in ['power_curve', 'power_coefficient_curve']:
367+
curves_df = pd.DataFrame(columns=['wind_speed'])
368+
for index in turbine_data.index:
369+
if (turbine_data['{}_wind_speeds'.format(curve_type)][index]
370+
and turbine_data['{}_values'.format(curve_type)][index]):
371+
df = pd.DataFrame(data=[
372+
eval(turbine_data['{}_wind_speeds'.format(curve_type)][
373+
index]),
374+
eval(turbine_data['{}_values'.format(curve_type)][
375+
index])]).transpose().rename(
376+
columns={0: 'wind_speed',
377+
1: turbine_data['turbine_type'][index]})
378+
curves_df = pd.merge(left=curves_df, right=df, how='outer',
379+
on='wind_speed')
380+
curves_df = curves_df.set_index('wind_speed').sort_index().transpose()
381+
curves_df['turbine_type'] = curves_df.index
382+
# add nominal power to power (coefficient) data frame
383+
curves_df = pd.merge(
384+
left=curves_df, right=turbine_data[['turbine_type',
385+
'installed_capacity']],
386+
on='turbine_type').set_index('turbine_type').rename(
387+
columns={'installed_capacity': 'nominal_power'})
388+
curves_df.to_csv(filename.format('{}s'.format(curve_type)))
389+
371390
return turbine_data
372391

373392

374-
def get_turbine_types(print_out=True):
393+
def get_turbine_types(print_out=True, filter_=True):
375394
r"""
376-
Get the names of all possible wind turbine types for which the power
377-
coefficient curve or power curve is provided in the OpenEnergy Data Base
378-
(oedb).
395+
Get all wind turbine types provided in the OpenEnergy database (oedb).
396+
397+
By default only turbine types for which a power coefficient curve or power
398+
curve is provided are returned. Set `filter_=False` to see all turbine
399+
types for which any data (f.e. hub height, rotor diameter, ...) is
400+
provided.
379401
380402
Parameters
381403
----------
382-
print_out : boolean
404+
print_out : bool
383405
Directly prints a tabular containing the turbine types in column
384406
'turbine_type', the manufacturer in column 'manufacturer' and
385407
information about whether a power (coefficient) curve exists (True) or
386408
not (False) in columns 'has_power_curve' and 'has_cp_curve'.
387409
Default: True.
410+
filter_ : bool
411+
If True only turbine types for which a power coefficient curve or
412+
power curve is provided in the OpenEnergy database (oedb) are
413+
returned. Default: True.
388414
389415
Returns
390416
-------
391-
curves_df : pd.DataFrame
417+
pd.DataFrame
392418
Contains turbine types in column 'turbine_type', the manufacturer in
393419
column 'manufacturer' and information about whether a power
394420
(coefficient) curve exists (True) or not (False) in columns
395421
'has_power_curve' and 'has_cp_curve'.
396422
423+
Notes
424+
-----
425+
If the power (coefficient) curve of the desired turbine type (or the
426+
turbine type itself) is missing you can contact us via github or
427+
[email protected]. You can help us by providing data in the
428+
format as shown in
429+
`the data base <https://openenergy-platform.org/dataedit/view/model_draft/openfred_windpower_powercurve>`_.
430+
397431
Examples
398432
--------
399433
>>> from windpowerlib import wind_turbine
@@ -412,14 +446,17 @@ def get_turbine_types(print_out=True):
412446
Name: 1, dtype: object
413447
414448
"""
415-
416449
df = load_turbine_data_from_oedb()
417-
cp_curves_df = df.iloc[df.loc[df['has_cp_curve']].index][
418-
['manufacturer', 'turbine_type', 'has_cp_curve']]
419-
p_curves_df = df.iloc[df.loc[df['has_power_curve']].index][
420-
['manufacturer', 'turbine_type', 'has_power_curve']]
421-
curves_df = pd.merge(p_curves_df, cp_curves_df, how='outer',
422-
sort=True).fillna(False)
450+
if filter_:
451+
cp_curves_df = df.loc[df['has_cp_curve']][
452+
['manufacturer', 'turbine_type', 'has_cp_curve']]
453+
p_curves_df = df.loc[df['has_power_curve']][
454+
['manufacturer', 'turbine_type', 'has_power_curve']]
455+
curves_df = pd.merge(p_curves_df, cp_curves_df, how='outer',
456+
sort=True).fillna(False)
457+
else:
458+
curves_df = df[['manufacturer', 'turbine_type', 'has_power_curve',
459+
'has_cp_curve']]
423460
if print_out:
424461
pd.set_option('display.max_rows', len(curves_df))
425462
print(curves_df)

0 commit comments

Comments
 (0)