diff --git a/README.rst b/README.rst index 41a18e02..edc8d255 100644 --- a/README.rst +++ b/README.rst @@ -8,6 +8,9 @@ :target: https://mybinder.org/v2/gh/wind-python/windpowerlib/dev?filepath=example .. image:: https://img.shields.io/badge/code%20style-black-000000.svg :target: https://github.com/psf/black + +.. image:: https://img.shields.io/lgtm/grade/python/g/wind-python/windpowerlib.svg?logo=lgtm&logoWidth=18 + :target: https://lgtm.com/projects/g/wind-python/windpowerlib/context:python Introduction ============= @@ -82,8 +85,14 @@ You can also look at the examples in the `Examples section `_ -(power curves, hub heights, etc.) for a large set of wind turbines. Have a look at the `example `_ on how +(power curves, hub heights, etc.) for a large set of wind turbines. See `Initialize wind turbine` in :ref:`examples_section_label` on how to use this data in your simulations. The dataset is hosted and maintained on the `OpenEnergy database `_ (oedb). @@ -94,9 +103,61 @@ To update your local files with the latest version of the `oedb turbine library from windpowerlib.wind_turbine import load_turbine_data_from_oedb load_turbine_data_from_oedb() +If you find your turbine in the database it is very easy to use it in the +windpowerlib + +.. code:: python + + from windpowerlib import WindTurbine + enercon_e126 = { + "turbine_type": "E-126/4200", # turbine type as in register + "hub_height": 135, # in m + } + e126 = WindTurbine(**enercon_e126) + We would like to encourage anyone to contribute to the turbine library by adding turbine data or reporting errors in the data. See `here `_ for more information on how to contribute. +Use your own turbine data +~~~~~~~~~~~~~~~~~~~~~~~~~ + +It is possible to use your own power curve. However, the most sustainable way +is to send us the data to be included in the windpowerlib and to be available +for all users. This may not be possible in all cases. + +Assuming the data files looks like this: + +.. code:: + + wind,power + 0.0,0.0 + 3.0,39000.0 + 5.0,270000.0 + 10.0,2250000.0 + 15.0,4500000.0 + 25.0,4500000.0 + +You can use pandas to read the file and pass it to the turbine dictionary. I +you have basic knowledge of pandas it is easy to use any kind of data file. + +.. code:: python + + import pandas as pd + from windpowerlib import WindTurbine, create_power_curve + my_data = pd.read_csv("path/to/my/data/file.csv") + + my_turbine_data = { + "nominal_power": 6e6, # in W + "hub_height": 115, # in m + "power_curve": create_power_curve( + wind_speed=my_data["wind"], power=my_data["power"] + ), + } + + my_turbine = WindTurbine(**my_turbine2) + +See the `modelchain_example` for more information. + Contributing ============== diff --git a/doc/getting_started.rst b/doc/getting_started.rst index c4373330..e883612a 100644 --- a/doc/getting_started.rst +++ b/doc/getting_started.rst @@ -13,6 +13,9 @@ Getting started .. image:: https://img.shields.io/badge/code%20style-black-000000.svg :target: https://github.com/psf/black +.. image:: https://img.shields.io/lgtm/grade/python/g/wind-python/windpowerlib.svg?logo=lgtm&logoWidth=18 + :target: https://lgtm.com/projects/g/wind-python/windpowerlib/context:python + Introduction ============= @@ -84,6 +87,12 @@ You can also look at the examples in the :ref:`examples_section_label` section. Wind turbine data ================== +The windpowerlib provides data of many wind turbines but it is also possible to +use your own turbine data. + +Use internal data +~~~~~~~~~~~~~~~~~ + The windpowerlib provides `wind turbine data `_ (power curves, hub heights, etc.) for a large set of wind turbines. See `Initialize wind turbine` in :ref:`examples_section_label` on how to use this data in your simulations. @@ -96,9 +105,62 @@ To update your local files with the latest version of the `oedb turbine library from windpowerlib.wind_turbine import load_turbine_data_from_oedb load_turbine_data_from_oedb() +If you find your turbine in the database it is very easy to use it in the +windpowerlib + +.. code:: python + + from windpowerlib import WindTurbine + enercon_e126 = { + "turbine_type": "E-126/4200", # turbine type as in register + "hub_height": 135, # in m + } + e126 = WindTurbine(**enercon_e126) + We would like to encourage anyone to contribute to the turbine library by adding turbine data or reporting errors in the data. See `here `_ for more information on how to contribute. +Use your own turbine data +~~~~~~~~~~~~~~~~~~~~~~~~~ + +It is possible to use your own power curve. However, the most sustainable way +is to send us the data to be included in the windpowerlib and to be available +for all users. This may not be possible in all cases. + +Assuming the data files looks like this: + +.. code:: + + wind,power + 0.0,0.0 + 3.0,39000.0 + 5.0,270000.0 + 10.0,2250000.0 + 15.0,4500000.0 + 25.0,4500000.0 + +You can use pandas to read the file and pass it to the turbine dictionary. I +you have basic knowledge of pandas it is easy to use any kind of data file. + +.. code:: python + + import pandas as pd + from windpowerlib import WindTurbine, create_power_curve + my_data = pd.read_csv("path/to/my/data/file.csv") + + my_turbine_data = { + "nominal_power": 6e6, # in W + "hub_height": 115, # in m + "power_curve": create_power_curve( + wind_speed=my_data["wind"], power=my_data["power"] + ), + } + + my_turbine = WindTurbine(**my_turbine2) + +See the `modelchain_example` for more information. + + Contributing ============== diff --git a/example/modelchain_example.ipynb b/example/modelchain_example.ipynb index f4b1f748..1b4dfa9e 100644 --- a/example/modelchain_example.ipynb +++ b/example/modelchain_example.ipynb @@ -288,7 +288,7 @@ "source": [ "# specification of wind turbine where power coefficient curve and nominal\n", "# power is provided in an own csv file\n", - "csv_path = 'data'\n", + "csv_path = ''\n", "dummy_turbine = {\n", " 'turbine_type': 'DUMMY 1', # turbine type as in file\n", " 'hub_height': 100, # in m\n", diff --git a/example/modelchain_example.py b/example/modelchain_example.py index acf85b8e..5619a668 100644 --- a/example/modelchain_example.py +++ b/example/modelchain_example.py @@ -10,27 +10,29 @@ you need to specify your wind turbine, and in the last step call the windpowerlib functions to calculate the feed-in time series. +Install the windpowerlib and optionally matplotlib to see the plots: + + pip install windpowerlib + pip install matplotlib + +Go down to the "run_example()" function to start the example. + SPDX-FileCopyrightText: 2019 oemof developer group SPDX-License-Identifier: MIT """ import os import pandas as pd +import requests +import logging +from windpowerlib import ModelChain, WindTurbine, create_power_curve try: from matplotlib import pyplot as plt except ImportError: plt = None -from windpowerlib import ModelChain -from windpowerlib import WindTurbine - -# You can use the logging package to get logging messages from the windpowerlib -# Change the logging level if you want more or less messages -import logging -logging.getLogger().setLevel(logging.DEBUG) - -def get_weather_data(filename='weather.csv', **kwargs): +def get_weather_data(filename="weather.csv", **kwargs): r""" Imports weather data from a file. @@ -65,11 +67,16 @@ def get_weather_data(filename='weather.csv', **kwargs): """ if "datapath" not in kwargs: - kwargs["datapath"] = os.path.join( - os.path.split(os.path.dirname(__file__))[0], "example" - ) + kwargs["datapath"] = os.path.dirname(__file__) + file = os.path.join(kwargs["datapath"], filename) + if not os.path.isfile(file): + logging.debug("Download weather data for example.") + req = requests.get("https://osf.io/59bqn/download") + with open(file, "wb") as fout: + fout.write(req.content) + # read csv file weather_df = pd.read_csv( file, @@ -95,7 +102,7 @@ def initialize_wind_turbines(): that is provided along with the windpowerlib, as done for the 'enercon_e126', or specify your own turbine by directly providing a power (coefficient) curve, as done below for 'my_turbine', or provide your own - turbine data in csv files, as done for 'dummy_turbine'. + turbine data in csv files, as done for 'my_turbine2'. To get a list of all wind turbines for which power and/or power coefficient curves are provided execute ` @@ -108,18 +115,19 @@ def initialize_wind_turbines(): :class:`~.wind_turbine.WindTurbine`) """ + # ************************************************************************ + # **** Data is provided in the oedb turbine library ********************** - # specification of wind turbine where data is provided in the oedb - # turbine library enercon_e126 = { "turbine_type": "E-126/4200", # turbine type as in register "hub_height": 135, # in m } - # initialize WindTurbine object e126 = WindTurbine(**enercon_e126) - # specification of own wind turbine (Note: power values and nominal power - # have to be in Watt) + # ************************************************************************ + # **** Specification of wind turbine with your own data ****************** + # **** NOTE: power values and nominal power have to be in Watt + my_turbine = { "nominal_power": 3e6, # in W "hub_height": 105, # in m @@ -133,25 +141,36 @@ def initialize_wind_turbines(): } ), # in m/s } - # initialize WindTurbine object my_turbine = WindTurbine(**my_turbine) - # specification of wind turbine where power coefficient curve and nominal - # power is provided in an own csv file - csv_path = os.path.join(os.path.dirname(__file__), "data") - dummy_turbine = { - "turbine_type": "DUMMY 1", - "hub_height": 100, # in m - "rotor_diameter": 70, # in m - "path": csv_path, + # ************************************************************************ + # **** Specification of wind turbine with data in own file *************** + + # Read your turbine data from your data file using functions like + # pandas.read_csv(). + # >>> import pandas as pd + # >>> my_data = pd.read_csv("path/to/my/data/file") + # >>> my_power = my_data["my_power"] + # >>> my_wind_speed = my_data["my_wind_speed"] + + my_power = pd.Series( + [0.0, 39000.0, 270000.0, 2250000.0, 4500000.0, 4500000.0] + ) + my_wind_speed = (0.0, 3.0, 5.0, 10.0, 15.0, 25.0) + + my_turbine2 = { + "nominal_power": 6e6, # in W + "hub_height": 115, # in m + "power_curve": create_power_curve( + wind_speed=my_wind_speed, power=my_power + ), } - # initialize WindTurbine object - dummy_turbine = WindTurbine(**dummy_turbine) + my_turbine2 = WindTurbine(**my_turbine2) - return my_turbine, e126, dummy_turbine + return my_turbine, e126, my_turbine2 -def calculate_power_output(weather, my_turbine, e126, dummy_turbine): +def calculate_power_output(weather, my_turbine, e126, my_turbine2): r""" Calculates power output of wind turbines using the :class:`~.modelchain.ModelChain`. @@ -161,7 +180,7 @@ def calculate_power_output(weather, my_turbine, e126, dummy_turbine): the default methods for the calculation steps, as done for 'my_turbine', or choose different methods, as done for the 'e126'. Of course, you can also use the default methods while only changing one or two of them, as - done for 'dummy_turbine'. + done for 'my_turbine2'. Parameters ---------- @@ -172,20 +191,14 @@ def calculate_power_output(weather, my_turbine, e126, dummy_turbine): e126 : :class:`~.wind_turbine.WindTurbine` WindTurbine object with power curve from the OpenEnergy Database turbine library. - dummy_turbine : :class:`~.wind_turbine.WindTurbine` + my_turbine2 : :class:`~.wind_turbine.WindTurbine` WindTurbine object with power coefficient curve from example file. """ - # power output calculation for my_turbine - # initialize ModelChain with default parameters and use run_model method - # to calculate power output - mc_my_turbine = ModelChain(my_turbine).run_model(weather) - # write power output time series to WindTurbine object - my_turbine.power_output = mc_my_turbine.power_output - - # power output calculation for e126 - # own specifications for ModelChain setup + # ************************************************************************ + # **** Data is provided in the oedb turbine library ********************** + # **** ModelChain with non-default specifications modelchain_data = { "wind_speed_model": "logarithmic", # 'logarithmic' (default), # 'hellman' or @@ -206,17 +219,25 @@ def calculate_power_output(weather, my_turbine, e126, dummy_turbine): # write power output time series to WindTurbine object e126.power_output = mc_e126.power_output - # power output calculation for example_turbine - # own specification for 'power_output_model' + # ************************************************************************ + # **** Specification of wind turbine with your own data ****************** + # **** ModelChain with default parameter + mc_my_turbine = ModelChain(my_turbine).run_model(weather) + # write power output time series to WindTurbine object + my_turbine.power_output = mc_my_turbine.power_output + + # ************************************************************************ + # **** Specification of wind turbine with data in own file *************** + # **** Using "power_coefficient_curve" as "power_output_model". mc_example_turbine = ModelChain( - dummy_turbine, power_output_model="power_coefficient_curve" + my_turbine2, power_output_model="power_curve" ).run_model(weather) - dummy_turbine.power_output = mc_example_turbine.power_output + my_turbine2.power_output = mc_example_turbine.power_output return -def plot_or_print(my_turbine, e126, dummy_turbine): +def plot_or_print(my_turbine, e126, my_turbine2): r""" Plots or prints power output and power (coefficient) curves. @@ -227,44 +248,55 @@ def plot_or_print(my_turbine, e126, dummy_turbine): e126 : :class:`~.wind_turbine.WindTurbine` WindTurbine object with power curve from the OpenEnergy Database turbine library. - dummy_turbine : :class:`~.wind_turbine.WindTurbine` + my_turbine2 : :class:`~.wind_turbine.WindTurbine` WindTurbine object with power coefficient curve from example file. """ # plot or print turbine power output if plt: - e126.power_output.plot(legend=True, label='Enercon E126') - my_turbine.power_output.plot(legend=True, label='myTurbine') - dummy_turbine.power_output.plot(legend=True, label='dummyTurbine') - plt.xlabel('Time') - plt.ylabel('Power in W') + e126.power_output.plot(legend=True, label="Enercon E126") + my_turbine.power_output.plot(legend=True, label="myTurbine") + my_turbine2.power_output.plot(legend=True, label="myTurbine2") + plt.xlabel("Time") + plt.ylabel("Power in W") plt.show() else: print(e126.power_output) print(my_turbine.power_output) - print(dummy_turbine.power_output) + print(my_turbine2.power_output) # plot or print power curve if plt: if e126.power_curve is not False: - e126.power_curve.plot(x='wind_speed', y='value', style='*', - title='Enercon E126 power curve') - plt.xlabel('Wind speed in m/s') - plt.ylabel('Power in W') + e126.power_curve.plot( + x="wind_speed", + y="value", + style="*", + title="Enercon E126 power curve", + ) + plt.xlabel("Wind speed in m/s") + plt.ylabel("Power in W") plt.show() if my_turbine.power_curve is not False: - my_turbine.power_curve.plot(x='wind_speed', y='value', style='*', - title='myTurbine power curve') - plt.xlabel('Wind speed in m/s') - plt.ylabel('Power in W') + my_turbine.power_curve.plot( + x="wind_speed", + y="value", + style="*", + title="myTurbine power curve", + ) + plt.xlabel("Wind speed in m/s") + plt.ylabel("Power in W") plt.show() - if dummy_turbine.power_coefficient_curve is not False: - dummy_turbine.power_coefficient_curve.plot( - x='wind_speed', y='value', style='*', - title='dummyTurbine power coefficient curve') - plt.xlabel('Wind speed in m/s') - plt.ylabel('Power coefficient') + if my_turbine2.power_curve is not False: + my_turbine2.power_curve.plot( + x="wind_speed", + y="value", + style="*", + title="myTurbine2 power curve", + ) + plt.xlabel("Wind speed in m/s") + plt.ylabel("Power in W") plt.show() else: if e126.power_coefficient_curve is not False: @@ -278,10 +310,16 @@ def run_example(): Runs the basic example. """ + # You can use the logging package to get logging messages from the + # windpowerlib. Change the logging level if you want more or less messages: + # logging.DEBUG -> many messages + # logging.INFO -> few messages + logging.getLogger().setLevel(logging.DEBUG) + weather = get_weather_data("weather.csv") - my_turbine, e126, dummy_turbine = initialize_wind_turbines() - calculate_power_output(weather, my_turbine, e126, dummy_turbine) - plot_or_print(my_turbine, e126, dummy_turbine) + my_turbine, e126, my_turbine2 = initialize_wind_turbines() + calculate_power_output(weather, my_turbine, e126, my_turbine2) + plot_or_print(my_turbine, e126, my_turbine2) if __name__ == "__main__": diff --git a/example/data/power_coefficient_curves.csv b/example/power_coefficient_curves.csv similarity index 100% rename from example/data/power_coefficient_curves.csv rename to example/power_coefficient_curves.csv diff --git a/example/data/power_curves.csv b/example/power_curves.csv similarity index 100% rename from example/data/power_curves.csv rename to example/power_curves.csv diff --git a/example/turbine_cluster_modelchain_example.py b/example/turbine_cluster_modelchain_example.py index ea0584bd..1d6cb953 100644 --- a/example/turbine_cluster_modelchain_example.py +++ b/example/turbine_cluster_modelchain_example.py @@ -25,6 +25,7 @@ # You can use the logging package to get logging messages from the windpowerlib # Change the logging level if you want more or less messages import logging + logging.getLogger().setLevel(logging.DEBUG) @@ -202,10 +203,10 @@ def plot_or_print(example_farm, example_cluster): # plot or print power output if plt: - example_cluster.power_output.plot(legend=True, label='example cluster') - example_farm.power_output.plot(legend=True, label='example farm') - plt.xlabel('Wind speed in m/s') - plt.ylabel('Power in W') + example_cluster.power_output.plot(legend=True, label="example cluster") + example_farm.power_output.plot(legend=True, label="example farm") + plt.xlabel("Wind speed in m/s") + plt.ylabel("Power in W") plt.show() else: print(example_cluster.power_output) diff --git a/example/data/turbine_data.csv b/example/turbine_data.csv similarity index 100% rename from example/data/turbine_data.csv rename to example/turbine_data.csv diff --git a/setup.py b/setup.py index bd0a32ed..2a25ce00 100644 --- a/setup.py +++ b/setup.py @@ -6,22 +6,33 @@ def read(fname): return open(os.path.join(os.path.dirname(__file__), fname)).read() -setup(name='windpowerlib', - version='0.2.1dev', - description='Creating time series of wind power plants.', - url='http://github.com/wind-python/windpowerlib', - author='oemof developer group', - author_email='windpowerlib@rl-institut.de', - license='MIT', - packages=['windpowerlib'], - package_data={ - 'windpowerlib': [os.path.join('data', '*.csv'), - os.path.join('oedb', '*.csv')]}, - long_description=read('README.rst'), - long_description_content_type='text/x-rst', - zip_safe=False, - install_requires=['pandas >= 0.20.0, < 0.26', - 'requests < 3.0'], - extras_require={ - 'dev': ['pytest', 'jupyter', 'sphinx_rtd_theme', 'nbformat', - 'numpy', 'matplotlib']}) +setup( + name="windpowerlib", + version="0.2.1dev", + description="Creating time series of wind power plants.", + url="http://github.com/wind-python/windpowerlib", + author="oemof developer group", + author_email="windpowerlib@rl-institut.de", + license="MIT", + packages=["windpowerlib"], + package_data={ + "windpowerlib": [ + os.path.join("data", "*.csv"), + os.path.join("oedb", "*.csv"), + ] + }, + long_description=read("README.rst"), + long_description_content_type="text/x-rst", + zip_safe=False, + install_requires=["pandas >= 0.20.0, < 0.26", "requests < 3.0"], + extras_require={ + "dev": [ + "pytest", + "jupyter", + "sphinx_rtd_theme", + "nbformat", + "numpy", + "matplotlib", + ] + }, +) diff --git a/tests/data/power_coefficient_curves.csv b/tests/data/power_coefficient_curves.csv new file mode 100755 index 00000000..a3c70cc1 --- /dev/null +++ b/tests/data/power_coefficient_curves.csv @@ -0,0 +1,3 @@ +turbine_type,0,0.5,1,1.5,2,2.5,3,3.5,4,4.5,5,5.5,6,6.5,7,7.5,8,8.5,9,9.5,10,10.5,11,11.5,12,12.5,13,13.5,14,14.5,15,15.5,16,16.5,17,17.5,18,18.5,19,19.5,20,20.5,21,21.5,22,22.5,23,23.5,24,24.5,25,25.5,26 +DUMMY 1,0,,0,,0,,0,0,0.13,,0.38,,0.46,,0.48,,0.47,,0.44,,0.4,,0.36,,0.31,,0.26,,0.23,,0.2,,0.18,,0.14,,0.11,,0.1,,0.09,,0.07,,0.05,,0.04,,0.04,,0.03,,0 +DUMMY 2,0,,0,,0,,0.16,0.29,0.35,0.38,0.4,0.41,0.42,0.43,0.43,0.44,0.44,0.44,0.44,0.43,0.42,0.39,0.36,0.32,0.29,0.26,0.23,0.2,0.18,0.16,0.15,0.14,0.12,0.11,0.1,0.09,0.09,0.08,0.07,0.07,0.06,0.06,0.05,0.05,0.05,0.04,0.04,0.04,0.04,0.03,0.03,0,0 diff --git a/tests/data/power_curves.csv b/tests/data/power_curves.csv new file mode 100755 index 00000000..85890d50 --- /dev/null +++ b/tests/data/power_curves.csv @@ -0,0 +1,3 @@ +turbine_type,0,0.5,1,1.5,2,2.5,3,3.5,4,4.5,5,5.5,6,6.5,7,7.5,8,8.5,9,9.5,10,10.5,11,11.5,12,12.5,13,13.5,14,14.5,15,15.5,16,16.5,17,17.5,18,18.5,19,19.5,20,20.5,21,21.5,22,22.5,23,23.5,24,24.5,25,25.5,26 +DUMMY 3,0,0,0,0,0,0,0,18000,34000,70000,10000,150000,190000,260000,330000,420000,510000,620000,740000,880000,1020000,1180000,1330000,1420000,1500000,1500000,1500000,1500000,1500000,1500000,1500000,1500000,1500000,1500000,1500000,1500000,1500000,1500000,1500000,1500000,1500000,1500000,1500000,1500000,1500000,1500000,1500000,1500000,1500000,1500000,1500000,0, +DUMMY 4,0,,0,,0,,0,,4000,,22000,,46000,,76000,,111000,,147000,,184000,,219000,,249000,,274000,,290000,,297000,,302000,,307000,,307000,,305000,,295000,,280000,,260000,,240000,,230000,,225000,0, diff --git a/tests/data/turbine_data.csv b/tests/data/turbine_data.csv new file mode 100644 index 00000000..0e9b9f9f --- /dev/null +++ b/tests/data/turbine_data.csv @@ -0,0 +1,5 @@ +turbine_type,nominal_power +DUMMY 1,4200000 +DUMMY 2,4200000 +DUMMY 3,1500000 +DUMMY 4,225000 diff --git a/tests/test_turbine_cluster_modelchain.py b/tests/test_turbine_cluster_modelchain.py index 8a827978..463328b5 100644 --- a/tests/test_turbine_cluster_modelchain.py +++ b/tests/test_turbine_cluster_modelchain.py @@ -364,15 +364,20 @@ def test_heigths_as_string(self): # Convert data heights to str string_weather = self.weather_df.copy() - string_weather.columns = pd.MultiIndex.from_arrays([ - string_weather.columns.get_level_values(0), - string_weather.columns.get_level_values(1).astype(str)]) + string_weather.columns = pd.MultiIndex.from_arrays( + [ + string_weather.columns.get_level_values(0), + string_weather.columns.get_level_values(1).astype(str), + ] + ) # Heights in the original DataFrame are of type np.int64 - assert isinstance(self.weather_df.columns.get_level_values(1)[0], - np.int64) + assert isinstance( + self.weather_df.columns.get_level_values(1)[0], np.int64 + ) assert isinstance(string_weather.columns.get_level_values(1)[0], str) test_mc = tc_mc.TurbineClusterModelChain( - power_plant=wtc.WindTurbineCluster(**self.test_cluster)) + power_plant=wtc.WindTurbineCluster(**self.test_cluster) + ) test_mc.run_model(string_weather) diff --git a/tests/test_wind_turbine.py b/tests/test_wind_turbine.py index 4140911f..12af8763 100644 --- a/tests/test_wind_turbine.py +++ b/tests/test_wind_turbine.py @@ -22,7 +22,7 @@ class TestWindTurbine: @classmethod def setup_class(cls): """Setup default values""" - cls.source = os.path.join(os.path.dirname(__file__), "../example/data") + cls.source = os.path.join(os.path.dirname(__file__), "data") def test_warning(self, recwarn): test_turbine_data = { @@ -114,10 +114,10 @@ def test_wrongly_defined_to_group_method(self): def test_create_unphysical_turbine(self): err_msg = "1/2rotor_diameter cannot be greater than hub_height" char = { - 'hub_height': 80, - 'rotor_diameter': 160, - 'turbine_type': 'DUMMY 3', - 'path': self.source + "hub_height": 80, + "rotor_diameter": 160, + "turbine_type": "DUMMY 3", + "path": self.source, } with pytest.raises(ValueError, match=err_msg): WindTurbine(**char) diff --git a/windpowerlib/__init__.py b/windpowerlib/__init__.py index a206ff5a..86aa5125 100644 --- a/windpowerlib/__init__.py +++ b/windpowerlib/__init__.py @@ -2,9 +2,10 @@ __license__ = "MIT" __version__ = "0.2.1dev" -from windpowerlib.wind_turbine import WindTurbine -from windpowerlib.wind_farm import WindFarm -from windpowerlib.wind_turbine_cluster import WindTurbineCluster -from windpowerlib.modelchain import ModelChain -from windpowerlib.turbine_cluster_modelchain import TurbineClusterModelChain -from windpowerlib.wind_turbine import get_turbine_types +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 .wind_farm import WindFarm # noqa: F401 +from .wind_turbine_cluster import WindTurbineCluster # noqa: F401 +from .modelchain import ModelChain # noqa: F401 +from .turbine_cluster_modelchain import TurbineClusterModelChain # noqa: F401 diff --git a/windpowerlib/density.py b/windpowerlib/density.py index 2630438d..4855a301 100644 --- a/windpowerlib/density.py +++ b/windpowerlib/density.py @@ -62,8 +62,13 @@ def barometric(pressure, pressure_height, hub_height, temperature_hub_height): http://www.dwd.de/DE/service/lexikon/begriffe/D/Druckgradient_pdf.pdf?__blob=publicationFile&v=4 """ - return ((pressure / 100 - (hub_height - pressure_height) * 1 / 8) * 1.225 * - 288.15 * 100 / (101330 * temperature_hub_height)) + return ( + (pressure / 100 - (hub_height - pressure_height) * 1 / 8) + * 1.225 + * 288.15 + * 100 + / (101330 * temperature_hub_height) + ) def ideal_gas(pressure, pressure_height, hub_height, temperature_hub_height): @@ -125,5 +130,8 @@ def ideal_gas(pressure, pressure_height, hub_height, temperature_hub_height): http://www.dwd.de/DE/service/lexikon/begriffe/D/Druckgradient_pdf.pdf?__blob=publicationFile&v=4 """ - return ((pressure / 100 - (hub_height - pressure_height) * 1 / 8) * 100 / - (287.058 * temperature_hub_height)) + return ( + (pressure / 100 - (hub_height - pressure_height) * 1 / 8) + * 100 + / (287.058 * temperature_hub_height) + ) diff --git a/windpowerlib/modelchain.py b/windpowerlib/modelchain.py index 57d9dfd4..128d3b77 100644 --- a/windpowerlib/modelchain.py +++ b/windpowerlib/modelchain.py @@ -144,7 +144,7 @@ def __init__( density_correction=False, obstacle_height=0, hellman_exp=None, - **kwargs + **kwargs, ): self.power_plant = power_plant diff --git a/windpowerlib/power_curves.py b/windpowerlib/power_curves.py index ef9eb138..00549a01 100644 --- a/windpowerlib/power_curves.py +++ b/windpowerlib/power_curves.py @@ -11,10 +11,15 @@ from windpowerlib import tools -def smooth_power_curve(power_curve_wind_speeds, power_curve_values, - block_width=0.5, wind_speed_range=15.0, - standard_deviation_method='turbulence_intensity', - mean_gauss=0, **kwargs): +def smooth_power_curve( + power_curve_wind_speeds, + power_curve_values, + block_width=0.5, + wind_speed_range=15.0, + standard_deviation_method="turbulence_intensity", + mean_gauss=0, + **kwargs, +): r""" Smoothes a power curve by using a Gauss distribution. @@ -159,7 +164,7 @@ def smooth_power_curve(power_curve_wind_speeds, power_curve_values, # Get standard deviation for Gauss function standard_deviation = ( (power_curve_wind_speed * normalized_standard_deviation + 0.6) - if standard_deviation_method is "Staffell_Pfenninger" + if standard_deviation_method == "Staffell_Pfenninger" else power_curve_wind_speed * normalized_standard_deviation ) # Get the smoothed value of the power output diff --git a/windpowerlib/power_output.py b/windpowerlib/power_output.py index 4db874b9..d254200c 100644 --- a/windpowerlib/power_output.py +++ b/windpowerlib/power_output.py @@ -9,9 +9,13 @@ import pandas as pd -def power_coefficient_curve(wind_speed, power_coefficient_curve_wind_speeds, - power_coefficient_curve_values, rotor_diameter, - density): +def power_coefficient_curve( + wind_speed, + power_coefficient_curve_wind_speeds, + power_coefficient_curve_values, + rotor_diameter, + density, +): r""" Calculates the turbine power output using a power coefficient curve. diff --git a/windpowerlib/tools.py b/windpowerlib/tools.py index 07ec376f..f033e6b5 100644 --- a/windpowerlib/tools.py +++ b/windpowerlib/tools.py @@ -22,6 +22,7 @@ class WindpowerlibUserWarning(UserWarning): >>> import warnings >>> warnings.filterwarnings("ignore", category=WindpowerlibUserWarning) """ + pass @@ -187,9 +188,13 @@ def gauss_distribution(function_variable, standard_deviation, mean=0): New York, Cambridge University Press, 2011, p. 37 """ - return (1 / (standard_deviation * np.sqrt(2 * np.pi)) * - np.exp(-(function_variable - mean)**2 / - (2 * standard_deviation**2))) + return ( + 1 + / (standard_deviation * np.sqrt(2 * np.pi)) + * np.exp( + -((function_variable - mean) ** 2) / (2 * standard_deviation ** 2) + ) + ) def estimate_turbulence_intensity(height, roughness_length): diff --git a/windpowerlib/turbine_cluster_modelchain.py b/windpowerlib/turbine_cluster_modelchain.py index b6309ac2..8f44f940 100644 --- a/windpowerlib/turbine_cluster_modelchain.py +++ b/windpowerlib/turbine_cluster_modelchain.py @@ -152,7 +152,7 @@ def __init__( block_width=0.5, standard_deviation_method="turbulence_intensity", smoothing_order="wind_farm_power_curves", - **kwargs + **kwargs, ): super(TurbineClusterModelChain, self).__init__(power_plant, **kwargs) diff --git a/windpowerlib/wake_losses.py b/windpowerlib/wake_losses.py index 77e46834..822efe7a 100644 --- a/windpowerlib/wake_losses.py +++ b/windpowerlib/wake_losses.py @@ -10,7 +10,7 @@ import os -def reduce_wind_speed(wind_speed, wind_efficiency_curve_name='dena_mean'): +def reduce_wind_speed(wind_speed, wind_efficiency_curve_name="dena_mean"): r""" Reduces wind speed by a wind efficiency curve. diff --git a/windpowerlib/wind_farm.py b/windpowerlib/wind_farm.py index e7deb42d..aa806aa1 100644 --- a/windpowerlib/wind_farm.py +++ b/windpowerlib/wind_farm.py @@ -9,7 +9,6 @@ from windpowerlib import tools, power_curves, WindTurbine import numpy as np import pandas as pd -import logging import warnings @@ -308,7 +307,7 @@ def assign_power_curve( standard_deviation_method="turbulence_intensity", smoothing_order="wind_farm_power_curves", turbulence_intensity=None, - **kwargs + **kwargs, ): r""" Calculates the power curve of a wind farm. diff --git a/windpowerlib/wind_speed.py b/windpowerlib/wind_speed.py index c620dd43..6bbe24b9 100644 --- a/windpowerlib/wind_speed.py +++ b/windpowerlib/wind_speed.py @@ -9,8 +9,13 @@ import pandas as pd -def logarithmic_profile(wind_speed, wind_speed_height, hub_height, - roughness_length, obstacle_height=0.0): +def logarithmic_profile( + wind_speed, + wind_speed_height, + hub_height, + roughness_length, + obstacle_height=0.0, +): r""" Calculates the wind speed at hub height using a logarithmic wind profile. diff --git a/windpowerlib/wind_turbine.py b/windpowerlib/wind_turbine.py index 6ab1c52a..1c71aab9 100644 --- a/windpowerlib/wind_turbine.py +++ b/windpowerlib/wind_turbine.py @@ -101,7 +101,7 @@ class WindTurbine(object): >>> print(e126.nominal_power) 4200000.0 >>> # Example with own path - >>> path=os.path.join(os.path.dirname(__file__), '../example/data') + >>> path=os.path.join(os.path.dirname(__file__), '../tests/data') >>> example_turbine={ ... 'hub_height': 100, ... 'rotor_diameter': 70, @@ -123,7 +123,7 @@ def __init__( power_coefficient_curve=None, rotor_diameter=None, turbine_type=None, - **kwargs + **kwargs, ): self.hub_height = hub_height @@ -176,7 +176,7 @@ def __init__( self.rotor_diameter = float(turbine_data["rotor_diameter"]) if self.rotor_diameter: - if self.hub_height <= 0.5*self.rotor_diameter: + if self.hub_height <= 0.5 * self.rotor_diameter: msg = "1/2rotor_diameter cannot be greater than hub_height" raise ValueError(msg) @@ -378,7 +378,7 @@ def get_turbine_data_from_file(turbine_type, path): -------- >>> from windpowerlib import wind_turbine >>> import os - >>> path=os.path.join(os.path.dirname(__file__), '../example/data', + >>> path=os.path.join(os.path.dirname(__file__), '../tests/data', ... 'power_curves.csv') >>> d3=get_turbine_data_from_file('DUMMY 3', path) >>> print(d3['value'][7]) @@ -409,6 +409,27 @@ def get_turbine_data_from_file(turbine_type, path): return wpp_df +def create_power_curve(wind_speed, power): + """ + A list, numpy.array, pandas.Series or other iterables can be passed to + define the wind speed and the power output. Make sure that the order is + not mutable because, values from both parameters will be used as value + pairs. + + Parameters + ---------- + wind_speed : iterable + A series of wind speed values in meter per second [m/s]. + power : iterable + A series of power values in Watt [W]. + + Returns + ------- + pandas.DataFrame + """ + return pd.DataFrame(data={"value": power, "wind_speed": wind_speed}) + + def load_turbine_data_from_oedb(schema="supply", table="wind_turbine_library"): r""" Loads turbine library from the OpenEnergy database (oedb). @@ -502,7 +523,7 @@ def load_turbine_data_from_oedb(schema="supply", table="wind_turbine_library"): axis=1, ).set_index("turbine_type") # nominal power in W - turbine_data_df["nominal_power"] = turbine_data_df["nominal_power"] * 1000 + turbine_data_df["nominal_power"] *= 1000 turbine_data_df.to_csv(filename.format("turbine_data")) return turbine_data diff --git a/windpowerlib/wind_turbine_cluster.py b/windpowerlib/wind_turbine_cluster.py index 5507aecb..166ea64f 100644 --- a/windpowerlib/wind_turbine_cluster.py +++ b/windpowerlib/wind_turbine_cluster.py @@ -132,7 +132,7 @@ def assign_power_curve( standard_deviation_method="turbulence_intensity", smoothing_order="wind_farm_power_curves", turbulence_intensity=None, - **kwargs + **kwargs, ): r""" Calculates the power curve of a wind turbine cluster.