From 33a173003f5d1df56b3a7afb2285185015513af1 Mon Sep 17 00:00:00 2001 From: uvchik Date: Thu, 13 Feb 2020 17:48:10 +0100 Subject: [PATCH 01/33] Download weather file if not present --- example/modelchain_example.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/example/modelchain_example.py b/example/modelchain_example.py index acf85b8e..916ce24a 100644 --- a/example/modelchain_example.py +++ b/example/modelchain_example.py @@ -15,6 +15,7 @@ """ import os import pandas as pd +import requests try: from matplotlib import pyplot as plt @@ -65,11 +66,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, From ca2f4277e74d8be92b66fdab534db934e676003a Mon Sep 17 00:00:00 2001 From: uvchik Date: Thu, 13 Feb 2020 17:48:40 +0100 Subject: [PATCH 02/33] Add comments to make example cleaner --- example/modelchain_example.py | 69 +++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 31 deletions(-) diff --git a/example/modelchain_example.py b/example/modelchain_example.py index 916ce24a..7a73a222 100644 --- a/example/modelchain_example.py +++ b/example/modelchain_example.py @@ -10,26 +10,27 @@ 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 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): r""" @@ -114,18 +115,18 @@ 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 @@ -139,11 +140,10 @@ 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 + # ************************************************************************ + # **** Specification of wind turbine with data in own file *************** csv_path = os.path.join(os.path.dirname(__file__), "data") dummy_turbine = { "turbine_type": "DUMMY 1", @@ -151,7 +151,6 @@ def initialize_wind_turbines(): "rotor_diameter": 70, # in m "path": csv_path, } - # initialize WindTurbine object dummy_turbine = WindTurbine(**dummy_turbine) return my_turbine, e126, dummy_turbine @@ -183,15 +182,9 @@ def calculate_power_output(weather, my_turbine, e126, dummy_turbine): """ - # 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 @@ -212,8 +205,16 @@ 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" ).run_model(weather) @@ -284,10 +285,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 = initialize_wind_turbines() + calculate_power_output(weather, my_turbine, e126) + plot_or_print(my_turbine, e126) if __name__ == "__main__": From 777cf9798f1eaa59d5d050c8812a70a0d8dc6c24 Mon Sep 17 00:00:00 2001 From: uvchik Date: Thu, 13 Feb 2020 20:20:00 +0100 Subject: [PATCH 03/33] Move data from data dir to parent dir --- example/modelchain_example.ipynb | 2 +- example/modelchain_example.py | 3 +-- example/{data => }/power_coefficient_curves.csv | 0 example/{data => }/power_curves.csv | 0 example/{data => }/turbine_data.csv | 0 tests/data/power_coefficient_curves.csv | 3 +++ tests/data/power_curves.csv | 3 +++ tests/data/turbine_data.csv | 5 +++++ tests/test_wind_turbine.py | 2 +- windpowerlib/wind_turbine.py | 4 ++-- 10 files changed, 16 insertions(+), 6 deletions(-) rename example/{data => }/power_coefficient_curves.csv (100%) rename example/{data => }/power_curves.csv (100%) rename example/{data => }/turbine_data.csv (100%) create mode 100755 tests/data/power_coefficient_curves.csv create mode 100755 tests/data/power_curves.csv create mode 100644 tests/data/turbine_data.csv 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 7a73a222..b1d68c7b 100644 --- a/example/modelchain_example.py +++ b/example/modelchain_example.py @@ -144,12 +144,11 @@ def initialize_wind_turbines(): # ************************************************************************ # **** Specification of wind turbine with data in own 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, + "path": os.path.dirname(__file__), } dummy_turbine = WindTurbine(**dummy_turbine) 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/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/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_wind_turbine.py b/tests/test_wind_turbine.py index 4140911f..fb23f084 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 = { diff --git a/windpowerlib/wind_turbine.py b/windpowerlib/wind_turbine.py index 6ab1c52a..0b4fb2fb 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, @@ -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]) From d643f48590a57ab21a1c801f3e8176dee2f21d17 Mon Sep 17 00:00:00 2001 From: uvchik Date: Thu, 13 Feb 2020 20:24:43 +0100 Subject: [PATCH 04/33] Fix pylint issues --- windpowerlib/__init__.py | 12 ++++++------ windpowerlib/power_curves.py | 2 +- windpowerlib/wind_farm.py | 1 - 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/windpowerlib/__init__.py b/windpowerlib/__init__.py index a206ff5a..445ddaae 100644 --- a/windpowerlib/__init__.py +++ b/windpowerlib/__init__.py @@ -2,9 +2,9 @@ __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 +from .wind_farm import WindFarm +from .wind_turbine_cluster import WindTurbineCluster +from .modelchain import ModelChain +from .turbine_cluster_modelchain import TurbineClusterModelChain +from .wind_turbine import get_turbine_types diff --git a/windpowerlib/power_curves.py b/windpowerlib/power_curves.py index ef9eb138..c9f36728 100644 --- a/windpowerlib/power_curves.py +++ b/windpowerlib/power_curves.py @@ -159,7 +159,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/wind_farm.py b/windpowerlib/wind_farm.py index e7deb42d..af31ca43 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 From c058db50ff489fb49b16b055649b2d8a3b0e6d4c Mon Sep 17 00:00:00 2001 From: uvchik Date: Thu, 13 Feb 2020 20:29:39 +0100 Subject: [PATCH 05/33] Revert import changes --- windpowerlib/__init__.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/windpowerlib/__init__.py b/windpowerlib/__init__.py index 445ddaae..a206ff5a 100644 --- a/windpowerlib/__init__.py +++ b/windpowerlib/__init__.py @@ -2,9 +2,9 @@ __license__ = "MIT" __version__ = "0.2.1dev" -from .wind_turbine import WindTurbine -from .wind_farm import WindFarm -from .wind_turbine_cluster import WindTurbineCluster -from .modelchain import ModelChain -from .turbine_cluster_modelchain import TurbineClusterModelChain -from .wind_turbine import get_turbine_types +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 e19d52b5d662a02c6aba6f264c8020b247498da5 Mon Sep 17 00:00:00 2001 From: uvchik Date: Thu, 13 Feb 2020 20:40:26 +0100 Subject: [PATCH 06/33] Add badge --- README.rst | 3 +++ doc/getting_started.rst | 3 +++ 2 files changed, 6 insertions(+) diff --git a/README.rst b/README.rst index 37f0bb75..11ae0ca0 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 ============= diff --git a/doc/getting_started.rst b/doc/getting_started.rst index c4373330..c7a40c1d 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 ============= From d5614d5586566ee78413b8f00ef4f890cdc33b96 Mon Sep 17 00:00:00 2001 From: uvchik Date: Thu, 13 Feb 2020 20:43:33 +0100 Subject: [PATCH 07/33] Fixe example --- example/modelchain_example.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/example/modelchain_example.py b/example/modelchain_example.py index b1d68c7b..e35684d0 100644 --- a/example/modelchain_example.py +++ b/example/modelchain_example.py @@ -291,9 +291,9 @@ def run_example(): logging.getLogger().setLevel(logging.DEBUG) weather = get_weather_data("weather.csv") - my_turbine, e126 = initialize_wind_turbines() - calculate_power_output(weather, my_turbine, e126) - plot_or_print(my_turbine, e126) + 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) if __name__ == "__main__": From 239ed62c8bb1dcb975ea59fd1cd983f321abd3a5 Mon Sep 17 00:00:00 2001 From: uvchik Date: Mon, 24 Feb 2020 16:20:08 +0100 Subject: [PATCH 08/33] Add create power curve function --- windpowerlib/wind_turbine.py | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/windpowerlib/wind_turbine.py b/windpowerlib/wind_turbine.py index 0b4fb2fb..3b43aca5 100644 --- a/windpowerlib/wind_turbine.py +++ b/windpowerlib/wind_turbine.py @@ -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) @@ -409,6 +409,29 @@ 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). From 085f90b6e17b33dc84526600e4dea49d01660dad Mon Sep 17 00:00:00 2001 From: uvchik Date: Mon, 24 Feb 2020 16:20:51 +0100 Subject: [PATCH 09/33] Use another variant of my_turbine instead of dummy_turbine --- example/modelchain_example.py | 101 +++++++++++++++++++++------------- windpowerlib/__init__.py | 4 +- 2 files changed, 65 insertions(+), 40 deletions(-) diff --git a/example/modelchain_example.py b/example/modelchain_example.py index e35684d0..028f94fe 100644 --- a/example/modelchain_example.py +++ b/example/modelchain_example.py @@ -24,7 +24,7 @@ import pandas as pd import requests import logging -from windpowerlib import ModelChain, WindTurbine +from windpowerlib import ModelChain, WindTurbine, create_power_curve try: from matplotlib import pyplot as plt @@ -32,7 +32,7 @@ plt = None -def get_weather_data(filename='weather.csv', **kwargs): +def get_weather_data(filename="weather.csv", **kwargs): r""" Imports weather data from a file. @@ -127,6 +127,7 @@ def initialize_wind_turbines(): # ************************************************************************ # **** 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 @@ -144,18 +145,31 @@ def initialize_wind_turbines(): # ************************************************************************ # **** Specification of wind turbine with data in own file *************** - dummy_turbine = { - "turbine_type": "DUMMY 1", - "hub_height": 100, # in m - "rotor_diameter": 70, # in m - "path": os.path.dirname(__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 + ), } - 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`. @@ -176,7 +190,7 @@ 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. """ @@ -215,14 +229,14 @@ def calculate_power_output(weather, my_turbine, e126, dummy_turbine): # **** 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. @@ -233,44 +247,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="dummyTurbine") + 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: @@ -291,9 +316,9 @@ def run_example(): 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/windpowerlib/__init__.py b/windpowerlib/__init__.py index a206ff5a..eaba869f 100644 --- a/windpowerlib/__init__.py +++ b/windpowerlib/__init__.py @@ -2,9 +2,9 @@ __license__ = "MIT" __version__ = "0.2.1dev" -from windpowerlib.wind_turbine import WindTurbine +from windpowerlib.wind_turbine import (WindTurbine, get_turbine_types, + create_power_curve) 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 a8b43f4dc7ddc3a30284a46e4fc7cc13fb159a2c Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Mon, 24 Feb 2020 15:21:08 +0000 Subject: [PATCH 10/33] Fixing style errors. --- example/modelchain_example.py | 3 ++- windpowerlib/__init__.py | 7 +++++-- windpowerlib/wind_turbine.py | 4 +--- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/example/modelchain_example.py b/example/modelchain_example.py index 028f94fe..1f9aaf62 100644 --- a/example/modelchain_example.py +++ b/example/modelchain_example.py @@ -154,7 +154,8 @@ def initialize_wind_turbines(): # >>> my_wind_speed = my_data["my_wind_speed"] my_power = pd.Series( - [0.0, 39000.0, 270000.0, 2250000.0, 4500000.0, 4500000.0]) + [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 = { diff --git a/windpowerlib/__init__.py b/windpowerlib/__init__.py index eaba869f..51c03086 100644 --- a/windpowerlib/__init__.py +++ b/windpowerlib/__init__.py @@ -2,8 +2,11 @@ __license__ = "MIT" __version__ = "0.2.1dev" -from windpowerlib.wind_turbine import (WindTurbine, get_turbine_types, - create_power_curve) +from windpowerlib.wind_turbine import ( + WindTurbine, + get_turbine_types, + create_power_curve, +) from windpowerlib.wind_farm import WindFarm from windpowerlib.wind_turbine_cluster import WindTurbineCluster from windpowerlib.modelchain import ModelChain diff --git a/windpowerlib/wind_turbine.py b/windpowerlib/wind_turbine.py index 3b43aca5..0e213342 100644 --- a/windpowerlib/wind_turbine.py +++ b/windpowerlib/wind_turbine.py @@ -427,9 +427,7 @@ def create_power_curve(wind_speed, power): ------- pandas.DataFrame """ - return pd.DataFrame( - data={"value": power, "wind_speed": wind_speed, } - ) + return pd.DataFrame(data={"value": power, "wind_speed": wind_speed,}) def load_turbine_data_from_oedb(schema="supply", table="wind_turbine_library"): From 08c3b61fd5af5b6e74b700dbb262f2dbcf7ff35a Mon Sep 17 00:00:00 2001 From: uvchik Date: Mon, 24 Feb 2020 16:30:30 +0100 Subject: [PATCH 11/33] Fix lint errors --- windpowerlib/__init__.py | 8 +++----- windpowerlib/wind_turbine.py | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/windpowerlib/__init__.py b/windpowerlib/__init__.py index 51c03086..83f82ab7 100644 --- a/windpowerlib/__init__.py +++ b/windpowerlib/__init__.py @@ -2,11 +2,9 @@ __license__ = "MIT" __version__ = "0.2.1dev" -from windpowerlib.wind_turbine import ( - WindTurbine, - get_turbine_types, - create_power_curve, -) +from windpowerlib.wind_turbine import WindTurbine +from windpowerlib.wind_turbine import get_turbine_types +from windpowerlib.wind_turbine import create_power_curve from windpowerlib.wind_farm import WindFarm from windpowerlib.wind_turbine_cluster import WindTurbineCluster from windpowerlib.modelchain import ModelChain diff --git a/windpowerlib/wind_turbine.py b/windpowerlib/wind_turbine.py index 0e213342..2e7dfad4 100644 --- a/windpowerlib/wind_turbine.py +++ b/windpowerlib/wind_turbine.py @@ -427,7 +427,7 @@ def create_power_curve(wind_speed, power): ------- pandas.DataFrame """ - return pd.DataFrame(data={"value": power, "wind_speed": wind_speed,}) + return pd.DataFrame(data={"value": power, "wind_speed": wind_speed}) def load_turbine_data_from_oedb(schema="supply", table="wind_turbine_library"): From d6216cf52503ade30db3beb54ba2ebfb3b94312f Mon Sep 17 00:00:00 2001 From: uvchik Date: Mon, 24 Feb 2020 16:36:46 +0100 Subject: [PATCH 12/33] Change config file to ignore unused imports in __init__.py --- .stickler.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.stickler.yml b/.stickler.yml index 49b2bdd8..93f746f9 100644 --- a/.stickler.yml +++ b/.stickler.yml @@ -4,6 +4,7 @@ linters: max-line-length: 79 select: C,E,F,W,B,B950 ignore: E203, E501, W503 + per-file-ignores: __init__.py:F401 black: config: ./pyproject.toml fixer: true From 4dcb7216533331fc2c5e0da7fea832225c8fb38f Mon Sep 17 00:00:00 2001 From: uvchik Date: Mon, 24 Feb 2020 16:37:39 +0100 Subject: [PATCH 13/33] Merge imports --- windpowerlib/__init__.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/windpowerlib/__init__.py b/windpowerlib/__init__.py index 83f82ab7..72db1a50 100644 --- a/windpowerlib/__init__.py +++ b/windpowerlib/__init__.py @@ -2,8 +2,7 @@ __license__ = "MIT" __version__ = "0.2.1dev" -from windpowerlib.wind_turbine import WindTurbine -from windpowerlib.wind_turbine import get_turbine_types +from windpowerlib.wind_turbine import WindTurbine, get_turbine_types from windpowerlib.wind_turbine import create_power_curve from windpowerlib.wind_farm import WindFarm from windpowerlib.wind_turbine_cluster import WindTurbineCluster From 221506adb88a403fa094b1839e63f3d84f9ff564 Mon Sep 17 00:00:00 2001 From: uvchik Date: Mon, 24 Feb 2020 16:42:53 +0100 Subject: [PATCH 14/33] Test another option --- .stickler.yml | 2 +- windpowerlib/__init__.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.stickler.yml b/.stickler.yml index 93f746f9..ccb7cfa9 100644 --- a/.stickler.yml +++ b/.stickler.yml @@ -4,7 +4,7 @@ linters: max-line-length: 79 select: C,E,F,W,B,B950 ignore: E203, E501, W503 - per-file-ignores: __init__.py:F401 + per-file-ignores: "__init__.py: F401" black: config: ./pyproject.toml fixer: true diff --git a/windpowerlib/__init__.py b/windpowerlib/__init__.py index 72db1a50..eaba869f 100644 --- a/windpowerlib/__init__.py +++ b/windpowerlib/__init__.py @@ -2,8 +2,8 @@ __license__ = "MIT" __version__ = "0.2.1dev" -from windpowerlib.wind_turbine import WindTurbine, get_turbine_types -from windpowerlib.wind_turbine import create_power_curve +from windpowerlib.wind_turbine import (WindTurbine, get_turbine_types, + create_power_curve) from windpowerlib.wind_farm import WindFarm from windpowerlib.wind_turbine_cluster import WindTurbineCluster from windpowerlib.modelchain import ModelChain From e9e421f1c58bf425c64215430f6f5e9a93af3666 Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Mon, 24 Feb 2020 15:43:09 +0000 Subject: [PATCH 15/33] Fixing style errors. --- windpowerlib/__init__.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/windpowerlib/__init__.py b/windpowerlib/__init__.py index eaba869f..51c03086 100644 --- a/windpowerlib/__init__.py +++ b/windpowerlib/__init__.py @@ -2,8 +2,11 @@ __license__ = "MIT" __version__ = "0.2.1dev" -from windpowerlib.wind_turbine import (WindTurbine, get_turbine_types, - create_power_curve) +from windpowerlib.wind_turbine import ( + WindTurbine, + get_turbine_types, + create_power_curve, +) from windpowerlib.wind_farm import WindFarm from windpowerlib.wind_turbine_cluster import WindTurbineCluster from windpowerlib.modelchain import ModelChain From 12bf952be1266128bc78188b60e961689c7904f8 Mon Sep 17 00:00:00 2001 From: uvchik Date: Mon, 24 Feb 2020 16:47:13 +0100 Subject: [PATCH 16/33] Add another variant --- .stickler.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stickler.yml b/.stickler.yml index ccb7cfa9..fa55bd48 100644 --- a/.stickler.yml +++ b/.stickler.yml @@ -3,8 +3,8 @@ linters: python: 3 max-line-length: 79 select: C,E,F,W,B,B950 - ignore: E203, E501, W503 - per-file-ignores: "__init__.py: F401" + ignore: E203, E501, W503, F401 + per-file-ignores: windpowerlib/__init__.py:F401 black: config: ./pyproject.toml fixer: true From 8c3fb3a2de549d7d72631f13a9e3a9c9ab3a5c32 Mon Sep 17 00:00:00 2001 From: uvchik Date: Mon, 24 Feb 2020 16:47:54 +0100 Subject: [PATCH 17/33] Change order --- windpowerlib/__init__.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/windpowerlib/__init__.py b/windpowerlib/__init__.py index 51c03086..ee58df84 100644 --- a/windpowerlib/__init__.py +++ b/windpowerlib/__init__.py @@ -5,8 +5,7 @@ from windpowerlib.wind_turbine import ( WindTurbine, get_turbine_types, - create_power_curve, -) + create_power_curve) from windpowerlib.wind_farm import WindFarm from windpowerlib.wind_turbine_cluster import WindTurbineCluster from windpowerlib.modelchain import ModelChain From 86f24395a623727d0db86997db92ce99c42edc23 Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Mon, 24 Feb 2020 15:48:12 +0000 Subject: [PATCH 18/33] Fixing style errors. --- windpowerlib/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/windpowerlib/__init__.py b/windpowerlib/__init__.py index ee58df84..51c03086 100644 --- a/windpowerlib/__init__.py +++ b/windpowerlib/__init__.py @@ -5,7 +5,8 @@ from windpowerlib.wind_turbine import ( WindTurbine, get_turbine_types, - create_power_curve) + create_power_curve, +) from windpowerlib.wind_farm import WindFarm from windpowerlib.wind_turbine_cluster import WindTurbineCluster from windpowerlib.modelchain import ModelChain From c671a97d5ae3c0f40e9a659da6a0a9f3fb25f2a8 Mon Sep 17 00:00:00 2001 From: uvchik Date: Mon, 24 Feb 2020 16:49:33 +0100 Subject: [PATCH 19/33] Check another variant --- .stickler.yml | 2 +- windpowerlib/__init__.py | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.stickler.yml b/.stickler.yml index fa55bd48..fe5b954f 100644 --- a/.stickler.yml +++ b/.stickler.yml @@ -3,7 +3,7 @@ linters: python: 3 max-line-length: 79 select: C,E,F,W,B,B950 - ignore: E203, E501, W503, F401 + ignore: E203, E501, W503 per-file-ignores: windpowerlib/__init__.py:F401 black: config: ./pyproject.toml diff --git a/windpowerlib/__init__.py b/windpowerlib/__init__.py index ee58df84..be806500 100644 --- a/windpowerlib/__init__.py +++ b/windpowerlib/__init__.py @@ -4,8 +4,7 @@ from windpowerlib.wind_turbine import ( WindTurbine, - get_turbine_types, - create_power_curve) + get_turbine_types, create_power_curve) from windpowerlib.wind_farm import WindFarm from windpowerlib.wind_turbine_cluster import WindTurbineCluster from windpowerlib.modelchain import ModelChain From 31ef550c8177242015e541bcc47fca5b243653d4 Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Mon, 24 Feb 2020 15:50:36 +0000 Subject: [PATCH 20/33] Fixing style errors. --- windpowerlib/__init__.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/windpowerlib/__init__.py b/windpowerlib/__init__.py index be806500..51c03086 100644 --- a/windpowerlib/__init__.py +++ b/windpowerlib/__init__.py @@ -4,7 +4,9 @@ from windpowerlib.wind_turbine import ( WindTurbine, - get_turbine_types, create_power_curve) + get_turbine_types, + create_power_curve, +) from windpowerlib.wind_farm import WindFarm from windpowerlib.wind_turbine_cluster import WindTurbineCluster from windpowerlib.modelchain import ModelChain From db1fbc2390c286ee388844bdc32f2b646b7584e0 Mon Sep 17 00:00:00 2001 From: uvchik Date: Mon, 24 Feb 2020 16:57:59 +0100 Subject: [PATCH 21/33] Add final soultion --- .stickler.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.stickler.yml b/.stickler.yml index fe5b954f..e1dd40b4 100644 --- a/.stickler.yml +++ b/.stickler.yml @@ -3,8 +3,7 @@ linters: python: 3 max-line-length: 79 select: C,E,F,W,B,B950 - ignore: E203, E501, W503 - per-file-ignores: windpowerlib/__init__.py:F401 + ignore: E203, E501, W503, F401 black: config: ./pyproject.toml fixer: true From d71217116553116c528701485a23a86d927f86c5 Mon Sep 17 00:00:00 2001 From: uvchik Date: Wed, 26 Feb 2020 18:23:27 +0100 Subject: [PATCH 22/33] Fix names in example --- example/modelchain_example.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/example/modelchain_example.py b/example/modelchain_example.py index 1f9aaf62..5619a668 100644 --- a/example/modelchain_example.py +++ b/example/modelchain_example.py @@ -102,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 ` @@ -180,7 +180,7 @@ def calculate_power_output(weather, my_turbine, e126, my_turbine2): 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 ---------- @@ -257,7 +257,7 @@ def plot_or_print(my_turbine, e126, my_turbine2): if plt: 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="dummyTurbine") + my_turbine2.power_output.plot(legend=True, label="myTurbine2") plt.xlabel("Time") plt.ylabel("Power in W") plt.show() From 7cc5a8e4d2750d7ccd6295e878fa5244d2a71836 Mon Sep 17 00:00:00 2001 From: uvchik Date: Wed, 26 Feb 2020 18:28:24 +0100 Subject: [PATCH 23/33] Add basic usage "how to define a turbine" to getting started --- doc/getting_started.rst | 59 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/doc/getting_started.rst b/doc/getting_started.rst index c7a40c1d..e883612a 100644 --- a/doc/getting_started.rst +++ b/doc/getting_started.rst @@ -87,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. @@ -99,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 ============== From 8147e5ce2bce54c12dc4cb8101d42abf917d1f31 Mon Sep 17 00:00:00 2001 From: uvchik Date: Wed, 26 Feb 2020 18:33:09 +0100 Subject: [PATCH 24/33] Add basic turbine definition to README --- README.rst | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 11ae0ca0..0207382e 100644 --- a/README.rst +++ b/README.rst @@ -85,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). @@ -97,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 ============== From ea3764c6287a9fd416ba58b7de165ab7a2a3463f Mon Sep 17 00:00:00 2001 From: uvchik Date: Tue, 10 Mar 2020 11:59:52 +0100 Subject: [PATCH 25/33] Ignore "imported but not used" error in __init__.py --- windpowerlib/__init__.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/windpowerlib/__init__.py b/windpowerlib/__init__.py index 51c03086..0c8f69a8 100644 --- a/windpowerlib/__init__.py +++ b/windpowerlib/__init__.py @@ -2,12 +2,12 @@ __license__ = "MIT" __version__ = "0.2.1dev" -from windpowerlib.wind_turbine import ( +from .wind_turbine import ( WindTurbine, get_turbine_types, create_power_curve, -) -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 +) # noq +from .wind_farm import WindFarm # noq +from .wind_turbine_cluster import WindTurbineCluster # noq +from .modelchain import ModelChain # noq +from .turbine_cluster_modelchain import TurbineClusterModelChain # noq From 103880fdc91c4de514dec7f056ca59ce9c251cfd Mon Sep 17 00:00:00 2001 From: uvchik Date: Tue, 10 Mar 2020 12:00:14 +0100 Subject: [PATCH 26/33] Blackify the code --- example/turbine_cluster_modelchain_example.py | 9 ++-- setup.py | 49 ++++++++++++------- tests/test_turbine_cluster_modelchain.py | 17 ++++--- tests/test_wind_turbine.py | 8 +-- windpowerlib/density.py | 16 ++++-- windpowerlib/power_curves.py | 13 +++-- windpowerlib/power_output.py | 10 ++-- windpowerlib/tools.py | 11 +++-- windpowerlib/wake_losses.py | 2 +- windpowerlib/wind_speed.py | 9 +++- 10 files changed, 94 insertions(+), 50 deletions(-) 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/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/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 fb23f084..12af8763 100644 --- a/tests/test_wind_turbine.py +++ b/tests/test_wind_turbine.py @@ -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/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/power_curves.py b/windpowerlib/power_curves.py index c9f36728..25e7131a 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. 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/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_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. From 41c8eeafa6c34a8aefd14996980df4496feaaec8 Mon Sep 17 00:00:00 2001 From: uvchik Date: Tue, 10 Mar 2020 13:34:41 +0100 Subject: [PATCH 27/33] Shorten line to make it clearer --- windpowerlib/wind_turbine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/windpowerlib/wind_turbine.py b/windpowerlib/wind_turbine.py index 2e7dfad4..9b25af67 100644 --- a/windpowerlib/wind_turbine.py +++ b/windpowerlib/wind_turbine.py @@ -523,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 From e864dbbc0796059da33fa7ea2adefb33fab29f7f Mon Sep 17 00:00:00 2001 From: uvchik Date: Tue, 10 Mar 2020 14:09:23 +0100 Subject: [PATCH 28/33] Specify ignored error --- windpowerlib/__init__.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/windpowerlib/__init__.py b/windpowerlib/__init__.py index 0c8f69a8..bc798760 100644 --- a/windpowerlib/__init__.py +++ b/windpowerlib/__init__.py @@ -6,8 +6,8 @@ WindTurbine, get_turbine_types, create_power_curve, -) # noq -from .wind_farm import WindFarm # noq -from .wind_turbine_cluster import WindTurbineCluster # noq -from .modelchain import ModelChain # noq -from .turbine_cluster_modelchain import TurbineClusterModelChain # noq +) # noq: F401 +from .wind_farm import WindFarm # noq: F401 +from .wind_turbine_cluster import WindTurbineCluster # noq: F401 +from .modelchain import ModelChain # noq: F401 +from .turbine_cluster_modelchain import TurbineClusterModelChain # noq: F401 From 26e739fe2220676f51a6a6d912d8c61353f290d8 Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Tue, 10 Mar 2020 13:11:45 +0000 Subject: [PATCH 29/33] Fixing style errors. --- windpowerlib/power_curves.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/windpowerlib/power_curves.py b/windpowerlib/power_curves.py index 25e7131a..00549a01 100644 --- a/windpowerlib/power_curves.py +++ b/windpowerlib/power_curves.py @@ -18,7 +18,7 @@ def smooth_power_curve( wind_speed_range=15.0, standard_deviation_method="turbulence_intensity", mean_gauss=0, - **kwargs + **kwargs, ): r""" Smoothes a power curve by using a Gauss distribution. From f130bb0e2673bc23763fef3cb89f6aaa19951fe7 Mon Sep 17 00:00:00 2001 From: uvchik Date: Tue, 10 Mar 2020 14:13:22 +0100 Subject: [PATCH 30/33] Blackify code --- windpowerlib/modelchain.py | 2 +- windpowerlib/power_curves.py | 2 +- windpowerlib/turbine_cluster_modelchain.py | 2 +- windpowerlib/wind_farm.py | 2 +- windpowerlib/wind_turbine.py | 2 +- windpowerlib/wind_turbine_cluster.py | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) 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 25e7131a..00549a01 100644 --- a/windpowerlib/power_curves.py +++ b/windpowerlib/power_curves.py @@ -18,7 +18,7 @@ def smooth_power_curve( wind_speed_range=15.0, standard_deviation_method="turbulence_intensity", mean_gauss=0, - **kwargs + **kwargs, ): r""" Smoothes a power curve by using a Gauss distribution. 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/wind_farm.py b/windpowerlib/wind_farm.py index af31ca43..aa806aa1 100644 --- a/windpowerlib/wind_farm.py +++ b/windpowerlib/wind_farm.py @@ -307,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_turbine.py b/windpowerlib/wind_turbine.py index 9b25af67..1c71aab9 100644 --- a/windpowerlib/wind_turbine.py +++ b/windpowerlib/wind_turbine.py @@ -123,7 +123,7 @@ def __init__( power_coefficient_curve=None, rotor_diameter=None, turbine_type=None, - **kwargs + **kwargs, ): self.hub_height = hub_height 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. From 9c040696fa4bb4cc29666ab9c974b9abd798ff15 Mon Sep 17 00:00:00 2001 From: uvchik Date: Tue, 10 Mar 2020 14:13:38 +0100 Subject: [PATCH 31/33] Do not ignore F401 in general --- .stickler.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stickler.yml b/.stickler.yml index e1dd40b4..49b2bdd8 100644 --- a/.stickler.yml +++ b/.stickler.yml @@ -3,7 +3,7 @@ linters: python: 3 max-line-length: 79 select: C,E,F,W,B,B950 - ignore: E203, E501, W503, F401 + ignore: E203, E501, W503 black: config: ./pyproject.toml fixer: true From 9c5901a8f0e8e00be99a24ce897d5b91325cc6b1 Mon Sep 17 00:00:00 2001 From: uvchik Date: Tue, 10 Mar 2020 14:18:06 +0100 Subject: [PATCH 32/33] Fix typo in comment --- windpowerlib/__init__.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/windpowerlib/__init__.py b/windpowerlib/__init__.py index bc798760..92a41d09 100644 --- a/windpowerlib/__init__.py +++ b/windpowerlib/__init__.py @@ -6,8 +6,8 @@ WindTurbine, get_turbine_types, create_power_curve, -) # noq: F401 -from .wind_farm import WindFarm # noq: F401 -from .wind_turbine_cluster import WindTurbineCluster # noq: F401 -from .modelchain import ModelChain # noq: F401 -from .turbine_cluster_modelchain import TurbineClusterModelChain # noq: F401 +) # 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 From 362827987bb6587e1440f5f3fa804635e426eb5f Mon Sep 17 00:00:00 2001 From: uvchik Date: Tue, 10 Mar 2020 14:19:57 +0100 Subject: [PATCH 33/33] Use one line per import --- windpowerlib/__init__.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/windpowerlib/__init__.py b/windpowerlib/__init__.py index 92a41d09..86aa5125 100644 --- a/windpowerlib/__init__.py +++ b/windpowerlib/__init__.py @@ -2,11 +2,9 @@ __license__ = "MIT" __version__ = "0.2.1dev" -from .wind_turbine import ( - WindTurbine, - get_turbine_types, - create_power_curve, -) # noqa: F401 +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