Skip to content

Commit

Permalink
Merge c12f224 into 1273dea
Browse files Browse the repository at this point in the history
  • Loading branch information
uvchik committed May 22, 2020
2 parents 1273dea + c12f224 commit 6ea9fcc
Show file tree
Hide file tree
Showing 7 changed files with 369 additions and 218 deletions.
2 changes: 1 addition & 1 deletion example/modelchain_example.ipynb
Expand Up @@ -41,7 +41,7 @@
"import requests\n",
"\n",
"from windpowerlib import ModelChain, WindTurbine, create_power_curve\n",
"from windpowerlib import wind_turbine as wt"
"from windpowerlib import data as wt"
]
},
{
Expand Down
10 changes: 10 additions & 0 deletions tests/test_data_handling.py
@@ -0,0 +1,10 @@
"""
SPDX-FileCopyrightText: 2019 oemof developer group <contact@oemof.org>
SPDX-License-Identifier: MIT
"""

from windpowerlib import data


def test_integretiy_check():
pass
6 changes: 3 additions & 3 deletions tests/test_wind_turbine.py
Expand Up @@ -12,11 +12,11 @@
from windpowerlib.wind_turbine import (
get_turbine_data_from_file,
WindTurbine,
get_turbine_types,
WindTurbineGroup,
load_turbine_data_from_oedb,
)

from windpowerlib.data import store_turbine_data_from_oedb, get_turbine_types


class TestWindTurbine:
@classmethod
Expand Down Expand Up @@ -54,7 +54,7 @@ def test_wrong_url_load_turbine_data(self):
with pytest.raises(
ConnectionError, match="Database connection not successful"
):
load_turbine_data_from_oedb("wrong_schema")
store_turbine_data_from_oedb("wrong_schema")

@pytest.mark.filterwarnings("ignore:The WindTurbine")
def test_string_representation_of_wind_turbine(self):
Expand Down
4 changes: 2 additions & 2 deletions windpowerlib/__init__.py
Expand Up @@ -3,8 +3,8 @@
__version__ = "0.2.1dev"

from .wind_turbine import WindTurbine # noqa: F401
from .wind_turbine import get_turbine_types # noqa: F401
from .wind_turbine import create_power_curve # noqa: F401
from .data import get_turbine_types # noqa: F401
from .power_curves import create_power_curve # noqa: F401
from .wind_farm import WindFarm # noqa: F401
from .wind_turbine_cluster import WindTurbineCluster # noqa: F401
from .modelchain import ModelChain # noqa: F401
Expand Down
326 changes: 326 additions & 0 deletions windpowerlib/data.py
@@ -0,0 +1,326 @@
"""
The ``data`` module contains functions to handle the needed data.
SPDX-FileCopyrightText: 2019 oemof developer group <contact@oemof.org>
SPDX-License-Identifier: MIT
"""

import os
import warnings
import logging
from datetime import datetime
from shutil import copyfile

import pandas as pd
import requests

from windpowerlib.wind_turbine import WindTurbine


def get_turbine_types(turbine_library="local", print_out=True, filter_=True):
r"""
Get all provided wind turbine types provided.
Choose by `turbine_library` whether to get wind turbine types provided by
the OpenEnergy Database ('oedb') or wind turbine types provided in your
local file(s) ('local').
By default only turbine types for which a power coefficient curve or power
curve is provided are returned. Set `filter_=False` to see all turbine
types for which any data (e.g. hub height, rotor diameter, ...) is
provided.
Parameters
----------
turbine_library : str
Specifies if the oedb turbine library ('oedb') or your local turbine
data file ('local') is evaluated. Default: 'local'.
print_out : bool
Directly prints a tabular containing the turbine types in column
'turbine_type', the manufacturer in column 'manufacturer' and
information about whether a power (coefficient) curve exists (True) or
not (False) in columns 'has_power_curve' and 'has_cp_curve'.
Default: True.
filter_ : bool
If True only turbine types for which a power coefficient curve or
power curve is provided in the oedb turbine library are
returned. Default: True.
Returns
-------
:pandas:`pandas.DataFrame<frame>`
Contains turbine types in column 'turbine_type', the manufacturer in
column 'manufacturer' and information about whether a power
(coefficient) curve exists (True) or not (False) in columns
'has_power_curve' and 'has_cp_curve'.
Notes
-----
If the power (coefficient) curve of the desired turbine type (or the
turbine type itself) is missing you can contact us via github or
windpowerlib@rl-institut.de. You can help us by providing data in the
format as shown in
`the data base <https://openenergy-platform.org/dataedit/view/supply/wind_turbine_library>`_.
Examples
--------
>>> from windpowerlib import get_turbine_types
>>> df=get_turbine_types(print_out=False)
>>> print(df[df["turbine_type"].str.contains("E-126")].iloc[0])
manufacturer Enercon
turbine_type E-126/4200
has_power_curve True
has_cp_curve True
Name: 5, dtype: object
>>> print(df[df["manufacturer"].str.contains("Enercon")].iloc[0])
manufacturer Enercon
turbine_type E-101/3050
has_power_curve True
has_cp_curve True
Name: 1, dtype: object
"""
if turbine_library == "local":
filename = os.path.join(
os.path.dirname(__file__), "oedb", "turbine_data.csv"
)
df = pd.read_csv(filename, index_col=0).reset_index()
elif turbine_library == "oedb":
df = fetch_turbine_data_from_oedb()

else:
raise ValueError(
"`turbine_library` is '{}' ".format(turbine_library)
+ "but must be 'local' or 'oedb'."
)
if filter_:
cp_curves_df = df.loc[df["has_cp_curve"]][
["manufacturer", "turbine_type", "has_cp_curve"]
]
p_curves_df = df.loc[df["has_power_curve"]][
["manufacturer", "turbine_type", "has_power_curve"]
]
curves_df = pd.merge(
p_curves_df, cp_curves_df, how="outer", sort=True
).fillna(False)
else:
curves_df = df[
["manufacturer", "turbine_type", "has_power_curve", "has_cp_curve"]
]
if print_out:
pd.set_option("display.max_rows", len(curves_df))
print(curves_df)
pd.reset_option("display.max_rows")
return curves_df


def fetch_turbine_data_from_oedb(
schema="supply", table="wind_turbine_library"
):
r"""
Fetches turbine library from the OpenEnergy database (oedb).
Parameters
----------
schema : str
Database schema of the turbine library.
table : str
Table name of the turbine library.
Returns
-------
:pandas:`pandas.DataFrame<frame>`
Turbine data of different turbines such as 'manufacturer',
'turbine_type', 'nominal_power'.
"""
# url of OpenEnergy Platform that contains the oedb
oep_url = "http://oep.iks.cs.ovgu.de/"

# load data
result = requests.get(
oep_url + "/api/v0/schema/{}/tables/{}/rows/?".format(schema, table),
)
if not result.status_code == 200:
raise ConnectionError(
"Database connection not successful. "
"Response: [{}]".format(result.status_code)
)
# extract data to dataframe
return pd.DataFrame(result.json())


def load_turbine_data_from_oedb(schema="supply", table="wind_turbine_library"):
msg = (
"\nUse >>store_turbine_data_from_oedb<< and not"
" >>load_turbine_data_from_oedb<<"
)
warnings.warn(msg, FutureWarning)
return store_turbine_data_from_oedb(schema=schema, table=table)


def store_turbine_data_from_oedb(
schema="supply", table="wind_turbine_library"
):
r"""
Loads turbine library from the OpenEnergy database (oedb).
Turbine data is saved to csv files ('oedb_power_curves.csv',
'oedb_power_coefficient_curves.csv' and 'oedb_nominal_power') for offline
usage of the windpowerlib. If the files already exist they are overwritten.
Parameters
----------
schema : str
Database schema of the turbine library.
table : str
Table name of the turbine library.
Returns
-------
:pandas:`pandas.DataFrame<frame>`
Turbine data of different turbines such as 'manufacturer',
'turbine_type', 'nominal_power'.
"""
turbine_data = fetch_turbine_data_from_oedb(schema=schema, table=table)
# standard file name for saving data
filename = os.path.join(os.path.dirname(__file__), "oedb", "{}.csv")

time_stamp = datetime.now().strftime("%Y%m%d%H%M%S")
# get all power (coefficient) curves and save to file
# for curve_type in ['power_curve', 'power_coefficient_curve']:
for curve_type in ["power_curve", "power_coefficient_curve"]:
curves_df = pd.DataFrame(columns=["wind_speed"])
for index in turbine_data.index:
if (
turbine_data["{}_wind_speeds".format(curve_type)][index]
and turbine_data["{}_values".format(curve_type)][index]
):
df = (
pd.DataFrame(
data=[
eval(
turbine_data[
"{}_wind_speeds".format(curve_type)
][index]
),
eval(
turbine_data["{}_values".format(curve_type)][
index
]
),
]
)
.transpose()
.rename(
columns={
0: "wind_speed",
1: turbine_data["turbine_type"][index],
}
)
)
curves_df = pd.merge(
left=curves_df, right=df, how="outer", on="wind_speed"
)
curves_df = curves_df.set_index("wind_speed").sort_index().transpose()
# power curve values in W
if curve_type == "power_curve":
curves_df *= 1000
curves_df.index.name = "turbine_type"
copyfile(
filename.format("{}s".format(curve_type)),
filename.format("{0}s_{1}".format(curve_type, time_stamp)),
)
curves_df.to_csv(filename.format("{}s".format(curve_type)))

# get turbine data and save to file (excl. curves)
turbine_data_df = turbine_data.drop(
[
"power_curve_wind_speeds",
"power_curve_values",
"power_coefficient_curve_wind_speeds",
"power_coefficient_curve_values",
"thrust_coefficient_curve_wind_speeds",
"thrust_coefficient_curve_values",
],
axis=1,
).set_index("turbine_type")
# nominal power in W
turbine_data_df["nominal_power"] *= 1000
copyfile(
filename.format("turbine_data"),
filename.format("turbine_data_{0}".format(time_stamp)),
)
check_imported_data(turbine_data_df, filename, time_stamp)
turbine_data_df.to_csv(filename.format("turbine_data"))
remove_tmp_file(filename, time_stamp)
return turbine_data


def remove_tmp_file(filename, time_stamp):
os.remove(filename.format("turbine_data_{0}".format(time_stamp)))
for curve_type in ["power_curve", "power_coefficient_curve"]:
copyfile(
filename.format("{0}s_{1}".format(curve_type, time_stamp)),
filename.format("{}s".format(curve_type)),
)
os.remove(filename.format("{0}s_{1}".format(curve_type, time_stamp)))


def check_imported_data(data, filename, time_stamp):
data.to_csv(filename.format("turbine_data"))
try:
data = check_data_integretiy(data)
except Exception as e:
copyfile(
filename.format("turbine_data"),
filename.format("turbine_data_error{0}".format(time_stamp)),
)
copyfile(
filename.format("turbine_data_{0}".format(time_stamp)),
filename.format("turbine_data"),
)
for curve_type in ["power_curve", "power_coefficient_curve"]:
copyfile(
filename.format("{}s".format(curve_type)),
filename.format(
"{0}s_error_{1}".format(curve_type, time_stamp)
),
)
copyfile(
filename.format("{0}s_{1}".format(curve_type, time_stamp)),
filename.format("{}s".format(curve_type)),
)
remove_tmp_file(filename, time_stamp)
raise e
return data


def check_data_integretiy(data):
for dataset in data.iterrows():
ttype = dataset[0]
enercon_e126 = {"turbine_type": "{0}".format(ttype), "hub_height": 135}
with warnings.catch_warnings():
warnings.simplefilter("ignore")
wt = WindTurbine(**enercon_e126)
if wt.power_curve is None and dataset[1].has_power_curve is True:
logging.warning(
"{0}: No power curve but has_power_curve=True.".format(
ttype
)
)
if (
wt.power_coefficient_curve is None
and dataset[1].has_cp_curve is True
):
logging.warning(
"{0}: No cp-curve but has_cp_curve=True.".format(ttype)
)
if dataset[1].has_power_curve is True:
if len(wt.power_curve) < 22:
logging.warning(
"{0}: power_curve is to short ({1} values),".format(
ttype, len(wt.power_curve)
)
)
return data

0 comments on commit 6ea9fcc

Please sign in to comment.