-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add timeline plot for wind-up input data
Plot includes key milestones, analysis and exclusion periods. This provides a useful overview of the configuration used for an analysis.
- Loading branch information
1 parent
c16c93a
commit 2302d07
Showing
8 changed files
with
450 additions
and
39 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file added
BIN
+57 KB
tests/plots/baseline_images/test_input_data/input_data_timeline_fig_prepost.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+52.8 KB
tests/plots/baseline_images/test_input_data/input_data_timeline_fig_toggle.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
import copy | ||
import logging | ||
import re | ||
|
||
import numpy as np | ||
import pandas as pd | ||
import pytest | ||
from matplotlib.testing.decorators import image_comparison | ||
|
||
from examples.smarteole_example import SmarteoleData | ||
from wind_up.interface import AssessmentInputs | ||
from wind_up.plots.input_data import plot_input_data_timeline | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
class TestInputDataTimeline: | ||
@pytest.mark.slow | ||
@pytest.mark.filterwarnings("ignore") | ||
@pytest.mark.parametrize("exclusion_period_attribute_name", ["yaw_data_exclusions_utc", "exclusion_periods_utc"]) | ||
def test_data_is_present_within_an_exclusion_period( | ||
self, exclusion_period_attribute_name: str, smarteole_assessment_inputs: tuple[AssessmentInputs, SmarteoleData] | ||
) -> None: | ||
"""Test that a ValueError is raised if any non-NaN data is present within any exclusion period.""" | ||
|
||
assessment_inputs = copy.deepcopy(smarteole_assessment_inputs[0]) | ||
|
||
setattr( | ||
assessment_inputs.cfg, | ||
exclusion_period_attribute_name, | ||
[ | ||
("SMV1", pd.Timestamp("2020-03-01T00:00:00+0000"), pd.Timestamp("2020-03-03T00:00:00+0000")), | ||
], | ||
) | ||
|
||
with pytest.raises( | ||
ValueError, | ||
match=re.escape( | ||
"Data is not all NaN within exclusion period " | ||
f"{getattr(assessment_inputs.cfg, exclusion_period_attribute_name)[0]}" | ||
), | ||
): | ||
plot_input_data_timeline(assessment_inputs) | ||
|
||
@pytest.mark.slow | ||
@pytest.mark.filterwarnings("ignore") | ||
@image_comparison( | ||
baseline_images=["input_data_timeline_fig_toggle"], remove_text=False, extensions=["png"], style="mpl20" | ||
) | ||
def test_toggle(self, smarteole_assessment_inputs: tuple[AssessmentInputs, SmarteoleData]) -> None: | ||
"""Test plotting timeline of input data on the Smarteole wind farm.""" | ||
|
||
assessment_inputs = copy.deepcopy(smarteole_assessment_inputs[0]) | ||
|
||
assessment_inputs.cfg.yaw_data_exclusions_utc = [ | ||
("SMV1", pd.Timestamp("2020-03-01T00:00:00+0000"), pd.Timestamp("2020-03-03T00:00:00+0000")), | ||
("SMV4", pd.Timestamp("2020-04-02T00:00:00+0000"), pd.Timestamp("2020-05-20T00:00:00+0000")), | ||
] | ||
|
||
assessment_inputs.cfg.exclusion_periods_utc = [ | ||
("SMV3", pd.Timestamp("2020-04-01T00:00:00+0000"), pd.Timestamp("2020-04-10T00:00:00+0000")), | ||
("SMV6", pd.Timestamp("2020-03-10T00:00:00+0000"), pd.Timestamp("2020-03-12T00:00:00+0000")), | ||
] | ||
|
||
for exclusion in [*assessment_inputs.cfg.yaw_data_exclusions_utc, *assessment_inputs.cfg.exclusion_periods_utc]: | ||
turbine_name = exclusion[0] | ||
start, end = exclusion[1], exclusion[2] | ||
assessment_inputs.wf_df.loc[pd.IndexSlice[turbine_name, start:end], "ActivePowerMean"] = np.nan | ||
|
||
plot_input_data_timeline(assessment_inputs) | ||
|
||
@pytest.mark.slow | ||
@pytest.mark.filterwarnings("ignore") | ||
@image_comparison( | ||
baseline_images=["input_data_timeline_fig_prepost"], remove_text=False, extensions=["png"], style="mpl20" | ||
) | ||
def test_prepost(self, smarteole_assessment_inputs: tuple[AssessmentInputs, SmarteoleData]) -> None: | ||
"""Test plotting timeline of input data on the Smarteole wind farm.""" | ||
|
||
assessment_inputs = copy.deepcopy(smarteole_assessment_inputs[0]) | ||
|
||
# manual adjustments to the configuration for the test | ||
assessment_inputs.cfg.toggle = None | ||
assessment_inputs.cfg.upgrade_first_dt_utc_start = pd.Timestamp("2020-03-01T00:00:00+0000") | ||
|
||
assessment_inputs.cfg.yaw_data_exclusions_utc = [ | ||
("SMV1", pd.Timestamp("2020-03-01T00:00:00+0000"), pd.Timestamp("2020-03-03T00:00:00+0000")), | ||
("SMV4", pd.Timestamp("2020-04-02T00:00:00+0000"), pd.Timestamp("2020-05-20T00:00:00+0000")), | ||
] | ||
|
||
assessment_inputs.cfg.exclusion_periods_utc = [ | ||
("SMV3", pd.Timestamp("2020-04-01T00:00:00+0000"), pd.Timestamp("2020-04-10T00:00:00+0000")), | ||
("SMV6", pd.Timestamp("2020-03-10T00:00:00+0000"), pd.Timestamp("2020-03-12T00:00:00+0000")), | ||
] | ||
|
||
for exclusion in [*assessment_inputs.cfg.yaw_data_exclusions_utc, *assessment_inputs.cfg.exclusion_periods_utc]: | ||
turbine_name = exclusion[0] | ||
start, end = exclusion[1], exclusion[2] | ||
assessment_inputs.wf_df.loc[pd.IndexSlice[turbine_name, start:end], "ActivePowerMean"] = np.nan | ||
|
||
plot_input_data_timeline(assessment_inputs) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,45 +1,30 @@ | ||
"""Tests running the Smarteole dataset through wind-up analysis.""" | ||
|
||
import copy | ||
from pathlib import Path | ||
|
||
import pytest | ||
|
||
from examples.smarteole_example import ( | ||
SmarteoleData, | ||
main_smarteole_analysis, | ||
unpack_smarteole_metadata, | ||
unpack_smarteole_scada, | ||
unpack_smarteole_toggle_data, | ||
) | ||
from examples.smarteole_example import SmarteoleData, main_smarteole_analysis | ||
from tests.conftest import SMARTEOLE_CACHE_DIR | ||
from wind_up.interface import AssessmentInputs | ||
|
||
SMARTEOLE_DATA_DIR = Path(__file__).parents[1] / "tests/test_data/smarteole" | ||
|
||
|
||
@pytest.mark.slow | ||
@pytest.mark.filterwarnings("ignore") | ||
def test_smarteole_analysis(tmp_path: Path) -> None: | ||
def test_smarteole_analysis( | ||
smarteole_assessment_inputs: tuple[AssessmentInputs, SmarteoleData], tmp_path: Path | ||
) -> None: | ||
"""Test running the Smarteole analysis.""" | ||
|
||
timebase_s = 600 | ||
cache_subdir = tmp_path / f"timebase_{timebase_s}" | ||
cache_subdir.mkdir(parents=True, exist_ok=True) | ||
|
||
scada_df = unpack_smarteole_scada( | ||
timebase_s=timebase_s, scada_data_file=SMARTEOLE_DATA_DIR / "SMARTEOLE_WakeSteering_SCADA_1minData.csv" | ||
) | ||
metadata_df = unpack_smarteole_metadata( | ||
timebase_s=timebase_s, metadata_file=SMARTEOLE_DATA_DIR / "SMARTEOLE_WakeSteering_Coordinates_staticData.csv" | ||
) | ||
toggle_df = unpack_smarteole_toggle_data( | ||
timebase_s=timebase_s, toggle_file=SMARTEOLE_DATA_DIR / "SMARTEOLE_WakeSteering_ControlLog_1minData.csv" | ||
) | ||
smarteole_data = SmarteoleData(scada_df=scada_df, metadata_df=metadata_df, toggle_df=toggle_df) | ||
smarteole_data = copy.deepcopy(smarteole_assessment_inputs[1]) | ||
|
||
main_smarteole_analysis( | ||
smarteole_data=smarteole_data, | ||
reanalysis_file_path=SMARTEOLE_DATA_DIR / "ERA5T_50.00N_2.75E_100m_1hr_20200201_20200531.parquet", | ||
analysis_timebase_s=timebase_s, | ||
analysis_timebase_s=600, | ||
check_results=True, # asserts expected results | ||
analysis_output_dir=tmp_path, | ||
cache_sub_dir=cache_subdir, | ||
cache_sub_dir=SMARTEOLE_CACHE_DIR, | ||
) |
Oops, something went wrong.