From abaf3b8d5aad50a8db9e38ff383e679c6fcbe0b4 Mon Sep 17 00:00:00 2001 From: uvchik Date: Mon, 13 Jan 2020 16:46:21 +0100 Subject: [PATCH 1/7] Raise a warning if there are nan values in the weather data set --- windpowerlib/modelchain.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/windpowerlib/modelchain.py b/windpowerlib/modelchain.py index 6726541a..df5fe20d 100644 --- a/windpowerlib/modelchain.py +++ b/windpowerlib/modelchain.py @@ -7,6 +7,7 @@ SPDX-License-Identifier: MIT """ import logging +import warnings import pandas as pd from windpowerlib import (wind_speed, density, temperature, power_output, tools) @@ -516,6 +517,13 @@ def run_model(self, weather_df): weather_df.columns.get_level_values(0), pd.to_numeric(weather_df.columns.get_level_values(1))]) + if weather_df.isnull().any().any(): + nan_columns = list(weather_df.columns[weather_df.isnull().any()]) + msg = ("The following columns of the weather data contain invalid " + "values like 'nan': {0}") + warnings.warn(msg.format(nan_columns), + tools.WindpowerlibUserWarning) + wind_speed_hub = self.wind_speed_hub(weather_df) density_hub = ( None From 2ea5a81b373ab696503fa594d0a8830c72358638 Mon Sep 17 00:00:00 2001 From: uvchik Date: Mon, 13 Jan 2020 16:55:35 +0100 Subject: [PATCH 2/7] Move the checks of the weather file to tools --- windpowerlib/modelchain.py | 12 +---------- windpowerlib/tools.py | 23 ++++++++++++++++++++++ windpowerlib/turbine_cluster_modelchain.py | 7 ++----- 3 files changed, 26 insertions(+), 16 deletions(-) diff --git a/windpowerlib/modelchain.py b/windpowerlib/modelchain.py index df5fe20d..326446f9 100644 --- a/windpowerlib/modelchain.py +++ b/windpowerlib/modelchain.py @@ -512,17 +512,7 @@ def run_model(self, weather_df): 'wind_speed' """ - # Convert data heights to integer. In some case they are strings. - weather_df.columns = pd.MultiIndex.from_arrays([ - weather_df.columns.get_level_values(0), - pd.to_numeric(weather_df.columns.get_level_values(1))]) - - if weather_df.isnull().any().any(): - nan_columns = list(weather_df.columns[weather_df.isnull().any()]) - msg = ("The following columns of the weather data contain invalid " - "values like 'nan': {0}") - warnings.warn(msg.format(nan_columns), - tools.WindpowerlibUserWarning) + weather_df = tools.check_weather_data(weather_df) wind_speed_hub = self.wind_speed_hub(weather_df) density_hub = ( diff --git a/windpowerlib/tools.py b/windpowerlib/tools.py index faab0202..143214e8 100644 --- a/windpowerlib/tools.py +++ b/windpowerlib/tools.py @@ -7,6 +7,7 @@ """ import numpy as np import warnings +import pandas as pd class WindpowerlibUserWarning(UserWarning): @@ -221,3 +222,25 @@ def estimate_turbulence_intensity(height, roughness_length): """ return 1 / (np.log(height / roughness_length)) + + +def check_weather_data(weather_df): + """ + Check weather Data Frame. + + - Raise warning if there are nan values. + - Convert columns if heights are string and not numeric. + + """ + # Convert data heights to integer. In some case they are strings. + weather_df.columns = pd.MultiIndex.from_arrays([ + weather_df.columns.get_level_values(0), + pd.to_numeric(weather_df.columns.get_level_values(1))]) + + # check for nan values + if weather_df.isnull().any().any(): + nan_columns = list(weather_df.columns[weather_df.isnull().any()]) + msg = ("The following columns of the weather data contain invalid " + "values like 'nan': {0}") + warnings.warn(msg.format(nan_columns), WindpowerlibUserWarning) + return weather_df diff --git a/windpowerlib/turbine_cluster_modelchain.py b/windpowerlib/turbine_cluster_modelchain.py index a72ae52a..b6309ac2 100644 --- a/windpowerlib/turbine_cluster_modelchain.py +++ b/windpowerlib/turbine_cluster_modelchain.py @@ -10,7 +10,7 @@ import logging import pandas as pd from windpowerlib import wake_losses -from windpowerlib.modelchain import ModelChain +from windpowerlib.modelchain import ModelChain, tools class TurbineClusterModelChain(ModelChain): @@ -289,10 +289,7 @@ def run_model(self, weather_df): 'wind_speed' """ - # Convert data heights to integer. In some case they are strings. - weather_df.columns = pd.MultiIndex.from_arrays([ - weather_df.columns.get_level_values(0), - pd.to_numeric(weather_df.columns.get_level_values(1))]) + weather_df = tools.check_weather_data(weather_df) self.assign_power_curve(weather_df) self.power_plant.mean_hub_height() From 423d01f3d0f895b4573055a62b2cd4d225ff1792 Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Mon, 13 Jan 2020 15:57:45 +0000 Subject: [PATCH 3/7] Fixing style errors. --- windpowerlib/tools.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/windpowerlib/tools.py b/windpowerlib/tools.py index 143214e8..07ec376f 100644 --- a/windpowerlib/tools.py +++ b/windpowerlib/tools.py @@ -233,14 +233,19 @@ def check_weather_data(weather_df): """ # Convert data heights to integer. In some case they are strings. - weather_df.columns = pd.MultiIndex.from_arrays([ - weather_df.columns.get_level_values(0), - pd.to_numeric(weather_df.columns.get_level_values(1))]) + weather_df.columns = pd.MultiIndex.from_arrays( + [ + weather_df.columns.get_level_values(0), + pd.to_numeric(weather_df.columns.get_level_values(1)), + ] + ) # check for nan values if weather_df.isnull().any().any(): nan_columns = list(weather_df.columns[weather_df.isnull().any()]) - msg = ("The following columns of the weather data contain invalid " - "values like 'nan': {0}") + msg = ( + "The following columns of the weather data contain invalid " + "values like 'nan': {0}" + ) warnings.warn(msg.format(nan_columns), WindpowerlibUserWarning) return weather_df From e98020bc039571b32c56aa51c8b5f69c7af7bc82 Mon Sep 17 00:00:00 2001 From: uvchik Date: Mon, 13 Jan 2020 16:58:59 +0100 Subject: [PATCH 4/7] Fix imports --- windpowerlib/modelchain.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/windpowerlib/modelchain.py b/windpowerlib/modelchain.py index 326446f9..57d9dfd4 100644 --- a/windpowerlib/modelchain.py +++ b/windpowerlib/modelchain.py @@ -7,10 +7,8 @@ SPDX-License-Identifier: MIT """ import logging -import warnings import pandas as pd -from windpowerlib import (wind_speed, density, temperature, power_output, - tools) +from windpowerlib import wind_speed, density, temperature, power_output, tools class ModelChain(object): From eaab5f6decd2d22fceeb1a1dbd709be21a9db2ad Mon Sep 17 00:00:00 2001 From: uvchik Date: Wed, 12 Feb 2020 14:26:53 +0100 Subject: [PATCH 5/7] Add test with and without Warning --- tests/test_modelchain.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/test_modelchain.py b/tests/test_modelchain.py index 04bf19e5..7144f27d 100644 --- a/tests/test_modelchain.py +++ b/tests/test_modelchain.py @@ -11,6 +11,7 @@ import windpowerlib.wind_turbine as wt import windpowerlib.modelchain as mc +from windpowerlib.tools import WindpowerlibUserWarning class TestModelChain: @@ -454,3 +455,20 @@ def test_heigths_as_string(self): test_mc = mc.ModelChain(wt.WindTurbine(**test_turbine), **test_modelchain) test_mc.run_model(string_weather) + + def test_weather_with_nan_values(self, recwarn): + """Test warning if weather data contain nan values.""" + test_turbine = {'hub_height': 100, + 'rotor_diameter': 80, + 'turbine_type': 'E-126/4200'} + nan_weather = self.weather_df.copy() + nan_weather.loc[1, ("temperature", 10)] = np.nan + test_modelchain = {'power_output_model': 'power_curve', + 'density_corr': True} + test_mc = mc.ModelChain(wt.WindTurbine(**test_turbine), + **test_modelchain) + msg = "'temperature', 10" + with pytest.warns(WindpowerlibUserWarning, match=msg): + test_mc.run_model(nan_weather) + test_mc.run_model(self.weather_df) + assert len(recwarn) == 0 From 879342d8e5c0dd7fd36271969c6e5a70c6aa8c2b Mon Sep 17 00:00:00 2001 From: uvchik Date: Wed, 12 Feb 2020 14:27:01 +0100 Subject: [PATCH 6/7] Make pylint happy --- tests/test_modelchain.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_modelchain.py b/tests/test_modelchain.py index 7144f27d..e5b0bf94 100644 --- a/tests/test_modelchain.py +++ b/tests/test_modelchain.py @@ -16,9 +16,9 @@ class TestModelChain: @classmethod - def setup_class(self): + def setup_class(cls): """Setup default values""" - self.test_turbine = { + cls.test_turbine = { "hub_height": 100, "turbine_type": "E-126/4200", "power_curve": pd.DataFrame( @@ -32,7 +32,7 @@ def setup_class(self): wind_speed_8m = np.array([[4.0], [5.0]]) wind_speed_10m = np.array([[5.0], [6.5]]) roughness_length = np.array([[0.15], [0.15]]) - self.weather_df = pd.DataFrame( + cls.weather_df = pd.DataFrame( np.hstack( ( temperature_2m, From 5c7b7c646775bd41b0c8e914e8033faa489aa2fd Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Wed, 12 Feb 2020 13:29:11 +0000 Subject: [PATCH 7/7] Fixing style errors. --- tests/test_modelchain.py | 52 +++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/tests/test_modelchain.py b/tests/test_modelchain.py index e5b0bf94..5b2c8b2f 100644 --- a/tests/test_modelchain.py +++ b/tests/test_modelchain.py @@ -435,38 +435,52 @@ def test_modelchain_with_power_coefficient_curve_as_dict(self): def test_heigths_as_string(self): """Test run_model if data heights are of type string.""" - test_turbine = {'hub_height': 100, - 'rotor_diameter': 80, - 'turbine_type': 'E-126/4200'} + test_turbine = { + "hub_height": 100, + "rotor_diameter": 80, + "turbine_type": "E-126/4200", + } # 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_modelchain = {'power_output_model': 'power_curve', - 'density_corr': True} - test_mc = mc.ModelChain(wt.WindTurbine(**test_turbine), - **test_modelchain) + test_modelchain = { + "power_output_model": "power_curve", + "density_corr": True, + } + test_mc = mc.ModelChain( + wt.WindTurbine(**test_turbine), **test_modelchain + ) test_mc.run_model(string_weather) def test_weather_with_nan_values(self, recwarn): """Test warning if weather data contain nan values.""" - test_turbine = {'hub_height': 100, - 'rotor_diameter': 80, - 'turbine_type': 'E-126/4200'} + test_turbine = { + "hub_height": 100, + "rotor_diameter": 80, + "turbine_type": "E-126/4200", + } nan_weather = self.weather_df.copy() nan_weather.loc[1, ("temperature", 10)] = np.nan - test_modelchain = {'power_output_model': 'power_curve', - 'density_corr': True} - test_mc = mc.ModelChain(wt.WindTurbine(**test_turbine), - **test_modelchain) + test_modelchain = { + "power_output_model": "power_curve", + "density_corr": True, + } + test_mc = mc.ModelChain( + wt.WindTurbine(**test_turbine), **test_modelchain + ) msg = "'temperature', 10" with pytest.warns(WindpowerlibUserWarning, match=msg): test_mc.run_model(nan_weather)