diff --git a/LICENSE.txt b/LICENSE.txt index 4389e867..957ad99f 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,6 +1,6 @@ BSD 3-Clause License -Copyright (c) 2025 Alliance for Sustainable Energy, LLC and Colorado School of Mines. +Copyright (c) 2025 Alliance for Energy Innovation, LLC and Colorado School of Mines. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/tests/battery_test.py b/tests/battery_test.py index 74ccf4f7..b874193d 100644 --- a/tests/battery_test.py +++ b/tests/battery_test.py @@ -3,25 +3,8 @@ ) from hycon.interfaces import HerculesInterface -test_hercules_dict = { - "dt": 1, - "time": 0, - "plant": {"interconnect_limit": 10}, - "battery": { - "size": 100.0, - "energy_capacity": 400.0, - "power": 100.0, - "soc": 0.5, - "charge_rate": 50.0 * 1e3, - "discharge_rate": 100.0 * 1e3, - }, - "external_signals": { - "RT_LMP": 10.0, - }, -} - - -def test_BatteryPriceSOCController_init(): + +def test_BatteryPriceSOCController_init(test_hercules_dict): test_interface = HerculesInterface(test_hercules_dict) # Initialize controller @@ -34,7 +17,7 @@ def test_BatteryPriceSOCController_init(): ) -def test_BatteryPriceSOCController_compute_controls(): +def test_BatteryPriceSOCController_compute_controls(test_hercules_dict): test_interface = HerculesInterface(test_hercules_dict) # Initialize controller diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 00000000..13d8d109 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,206 @@ +import pytest +from hycon.interfaces import HerculesADInterface, HerculesHybridADInterface, HerculesInterface +from hycon.interfaces.interface_base import InterfaceBase + + +@pytest.fixture +def test_hercules_v1_dict(): + return { + "dt": 1, + "time": 0, + "controller": { + "num_turbines": 2, + "initial_conditions": {"yaw": [270.0, 270.0]}, + "nominal_plant_power_kW": 10000, + "nominal_hydrogen_rate_kgps": 0.1, + "hydrogen_controller_gain": 1.0, + }, + "hercules_comms": { + "amr_wind": { + "test_farm": { + "turbine_wind_directions": [271.0, 272.5], + "turbine_powers": [4000.0, 4001.0], + "wind_speed": 10.0, + } + } + }, + "py_sims": { + "test_battery": { + "outputs": {"power": 10.0, "soc": 0.3}, + "charge_rate": 20, + "discharge_rate": 20, + }, + "test_solar": {"outputs": {"power_mw": 1.0, "dni": 1000.0, "aoi": 30.0}}, + "test_hydrogen": {"outputs": {"H2_mfr": 0.03}}, + "inputs": {}, + }, + "external_signals": { + "wind_power_reference": 1000.0, + "plant_power_reference": 1000.0, + "hydrogen_reference": 0.02, + }, + } + + +@pytest.fixture +def test_hercules_dict(): + return { + "dt": 1, + "time": 0, + "plant": {"interconnect_limit": None}, + "controller": { + "test_controller_parameter": 1.0, + }, + "wind_farm": { + "n_turbines": 2, + "capacity": 10000.0, + "wind_direction_mean": 271.0, + "turbine_powers": [4000.0, 4001.0], + "wind_speed": 10.0, + }, + "solar_farm": { + "capacity": 1000.0, + "power": 1000.0, # kW + "dni": 1000.0, + "aoi": 30.0, + }, + "battery": { + "size": 10.0e3, + "energy_capacity": 40.0e3, + "power": 10.0e3, + "soc": 0.3, + "charge_rate": 20e3, + "discharge_rate": 15e3, + }, + "electrolyzer": { + "H2_mfr": 0.03, + }, + "external_signals": { + "wind_power_reference": 1000.0, + "solar_power_reference": 800.0, + "battery_power_reference": 0.0, + "plant_power_reference": 1000.0, + "forecast_ws_mean_0": 8.0, + "forecast_ws_mean_1": 8.1, + "ws_median_0": 8.1, + "hydrogen_reference": 0.02, + }, + } + + +class StandinInterface(InterfaceBase): + """ + Empty class to test controllers. + """ + + def __init__(self): + super().__init__() + self.dt = 1.0 + # Set up stand-in plant parameters and controller parameters + self.plant_parameters = {"n_turbines": 2} + self.controller_parameters = {} + + def get_measurements(self): + pass + + def check_controls(self): + pass + + def send_controls(self): + pass + + +@pytest.fixture +def test_interface_standin(): + return StandinInterface() + + +@pytest.fixture +def test_interface_hercules(test_hercules_dict): + """ + Fixture to create a Hercules v2 dictionary for testing. + """ + return HerculesInterface(test_hercules_dict) + + +@pytest.fixture +def test_interface_hercules_ad(test_hercules_v1_dict): + """ + Fixture to create a HerculesADInterface for testing. + """ + return HerculesADInterface(test_hercules_v1_dict) + + +@pytest.fixture +def test_interface_hercules_hybrid_ad(test_hercules_v1_dict): + """ + Fixture to create a HerculesHybridADInterface for testing. + """ + test_hercules_v1_dict["controller"]["num_batteries"] = 1 + test_hercules_v1_dict["controller"]["num_solar"] = 1 + return HerculesHybridADInterface(test_hercules_v1_dict) + + +@pytest.fixture +def floris_dict(): + """ + Fixture to create a FLORIS dictionary for testing. + """ + return { + "name": "test_input", + "description": "Two-turbine farm for testing", + "floris_version": "v4", + "logging": { + "console": {"enable": False, "level": "WARNING"}, + "file": {"enable": False, "level": "WARNING"}, + }, + "solver": {"type": "turbine_grid", "turbine_grid_points": 3}, + "farm": { + "layout_x": [0.0, 500.0], + "layout_y": [0.0, 0.0], + "turbine_type": ["nrel_5MW"], + }, + "flow_field": { + "air_density": 1.225, + "reference_wind_height": 90.0, + "turbulence_intensities": [0.06], + "wind_directions": [270.0], + "wind_shear": 0.12, + "wind_speeds": [8.0], + "wind_veer": 0.0, + }, + "wake": { + "model_strings": { + "combination_model": "sosfs", + "deflection_model": "gauss", + "turbulence_model": "crespo_hernandez", + "velocity_model": "gauss", + }, + "enable_secondary_steering": True, + "enable_yaw_added_recovery": True, + "enable_active_wake_mixing": True, + "enable_transverse_velocities": True, + "wake_deflection_parameters": { + "gauss": { + "ad": 0.0, + "alpha": 0.58, + "bd": 0.0, + "beta": 0.077, + "dm": 1.0, + "ka": 0.38, + "kb": 0.004, + }, + }, + "wake_velocity_parameters": { + "gauss": {"alpha": 0.58, "beta": 0.077, "ka": 0.38, "kb": 0.004}, + }, + "wake_turbulence_parameters": { + "crespo_hernandez": { + "initial": 0.01, + "constant": 0.9, + "ai": 0.83, + "downstream": -0.25, + } + }, + }, + } diff --git a/tests/controller_base_test.py b/tests/controller_base_test.py index cafb14aa..d11c15bb 100644 --- a/tests/controller_base_test.py +++ b/tests/controller_base_test.py @@ -1,24 +1,5 @@ import pytest from hycon.controllers.controller_base import ControllerBase -from hycon.interfaces.interface_base import InterfaceBase - - -class StandinInterface(InterfaceBase): - """ - Empty class to test controllers. - """ - - def __init__(self): - super().__init__() - - def get_measurements(self): - pass - - def check_controls(self): - pass - - def send_controls(self): - pass class InheritanceTestClassBad(ControllerBase): @@ -42,26 +23,22 @@ def compute_controls(self): pass -def test_ControllerBase_methods(): +def test_ControllerBase_methods(test_interface_standin): """ Check that the base interface class establishes the correct methods. """ - test_interface = StandinInterface() - - controller_base = InheritanceTestClassGood(test_interface) + controller_base = InheritanceTestClassGood(test_interface_standin) assert hasattr(controller_base, "_receive_measurements") assert hasattr(controller_base, "_send_controls") assert hasattr(controller_base, "step") assert hasattr(controller_base, "compute_controls") -def test_inherited_methods(): +def test_inherited_methods(test_interface_standin): """ Check that a subclass of InterfaceBase inherits methods correctly. """ - test_interface = StandinInterface() - with pytest.raises(TypeError): - _ = InheritanceTestClassBad(test_interface) + _ = InheritanceTestClassBad(test_interface_standin) - _ = InheritanceTestClassGood(test_interface) + _ = InheritanceTestClassGood(test_interface_standin) diff --git a/tests/controller_library_test.py b/tests/controller_library_test.py index c4a97efa..444995a8 100644 --- a/tests/controller_library_test.py +++ b/tests/controller_library_test.py @@ -1,5 +1,3 @@ -import copy - import numpy as np import pandas as pd import pytest @@ -18,154 +16,52 @@ ) from hycon.controllers.wind_farm_power_tracking_controller import POWER_SETPOINT_DEFAULT from hycon.interfaces import ( - HerculesADInterface, HerculesBatteryInterface, - HerculesHybridADInterface, - HerculesInterface, ) -from hycon.interfaces.interface_base import InterfaceBase -class StandinInterface(InterfaceBase): - """ - Empty class to test controllers. - """ - - def __init__(self): - super().__init__() - self.dt = 1.0 - # Set up stand-in plant parameters - self.plant_parameters = {"n_turbines": 2} - - def get_measurements(self): - pass - - def check_controls(self): - pass - - def send_controls(self): - pass - - -# TODO: make these fixtures, use across interfaces and controller tests -test_hercules_dict = { - "dt": 1, - "time": 0, - "controller": { - "num_turbines": 2, - "initial_conditions": {"yaw": [270.0, 270.0]}, - "nominal_plant_power_kW": 10000, - "nominal_hydrogen_rate_kgps": 0.1, - "hydrogen_controller_gain": 1.0, - }, - "hercules_comms": { - "amr_wind": { - "test_farm": { - "turbine_wind_directions": [271.0, 272.5], - "turbine_powers": [4000.0, 4001.0], - "wind_speed": 10.0, - } - } - }, - "py_sims": { - "test_battery": { - "outputs": {"power": 10.0, "soc": 0.3}, - "charge_rate": 20, - "discharge_rate": 20, - }, - "test_solar": {"outputs": {"power_mw": 1.0, "dni": 1000.0, "aoi": 30.0}}, - "test_hydrogen": {"outputs": {"H2_mfr": 0.03}}, - "inputs": {}, - }, - "external_signals": { - "wind_power_reference": 1000.0, - "plant_power_reference": 1000.0, - "hydrogen_reference": 0.02, - }, -} - -test_hercules_v2_dict = { - "dt": 1, - "time": 0, - "plant": { - "interconnect_limit": 10000.0, - }, - "controller": { - "test_controller_parameter": 1.0, - }, - "wind_farm": { - "n_turbines": 2, - "capacity": 10000.0, - "wind_direction_mean": 271.0, - "turbine_powers": [4000.0, 4001.0], - "wind_speed": 10.0, - }, - "solar_farm": { - "capacity": 1000.0, - "power": 1000.0, # kW - "dni": 1000.0, - "aoi": 30.0, - }, - "battery": { - "size": 10.0e3, - "energy_capacity": 40.0e3, - "power": 10.0e3, - "soc": 0.3, - "charge_rate": 20e3, - "discharge_rate": 15e3, - }, - "electrolyzer": { - "H2_mfr": 0.03, - }, - "external_signals": { - "wind_power_reference": 1000.0, - "solar_power_reference": 800.0, - "battery_power_reference": 0.0, - "plant_power_reference": 1000.0, - "forecast_ws_mean_0": 8.0, - "forecast_ws_mean_1": 8.1, - "ws_median_0": 8.1, - "hydrogen_reference": 0.02, - }, -} - - -def test_controller_instantiation(): +def test_controller_instantiation(test_interface_standin, test_hercules_v1_dict): """ Tests whether all controllers can be imported correctly and that they each implement the required methods specified by ControllerBase. """ - test_interface = StandinInterface() - - _ = LookupBasedWakeSteeringController(interface=test_interface, input_dict=test_hercules_dict) - _ = WindFarmPowerDistributingController(interface=test_interface, input_dict=test_hercules_dict) - _ = WindFarmPowerTrackingController(interface=test_interface, input_dict=test_hercules_dict) + _ = LookupBasedWakeSteeringController( + interface=test_interface_standin, input_dict=test_hercules_v1_dict + ) + _ = WindFarmPowerDistributingController( + interface=test_interface_standin, input_dict=test_hercules_v1_dict + ) + _ = WindFarmPowerTrackingController( + interface=test_interface_standin, input_dict=test_hercules_v1_dict + ) _ = HybridSupervisoryControllerBaseline( - interface=test_interface, - input_dict=test_hercules_dict, + interface=test_interface_standin, + input_dict=test_hercules_v1_dict, wind_controller=1, # Override error raised for empty controllers ) - _ = SolarPassthroughController(interface=test_interface, input_dict=test_hercules_dict) - _ = BatteryPassthroughController(interface=test_interface, input_dict=test_hercules_dict) - _ = BatteryController(interface=test_interface, input_dict=test_hercules_dict) - + _ = SolarPassthroughController( + interface=test_interface_standin, input_dict=test_hercules_v1_dict + ) + _ = BatteryPassthroughController( + interface=test_interface_standin, input_dict=test_hercules_v1_dict + ) + _ = BatteryController(interface=test_interface_standin, input_dict=test_hercules_v1_dict) -def test_LookupBasedWakeSteeringController(): - test_interface = HerculesADInterface(test_hercules_dict) +def test_LookupBasedWakeSteeringController(test_hercules_v1_dict, test_interface_hercules_ad): # No lookup table passed; simply passes through wind direction to yaw angles test_controller = LookupBasedWakeSteeringController( - interface=test_interface, input_dict=test_hercules_dict + interface=test_interface_hercules_ad, input_dict=test_hercules_v1_dict ) # Check that the controller can be stepped - test_hercules_dict["time"] = 20 - test_hercules_dict_out = test_controller.step(input_dict=test_hercules_dict) + test_hercules_v1_dict["time"] = 20 + test_dict_out = test_controller.step(input_dict=test_hercules_v1_dict) test_angles = np.array( - test_hercules_dict_out["hercules_comms"]["amr_wind"]["test_farm"]["turbine_yaw_angles"] + test_dict_out["hercules_comms"]["amr_wind"]["test_farm"]["turbine_yaw_angles"] ) wind_directions = np.array( - test_hercules_dict["hercules_comms"]["amr_wind"]["test_farm"]["turbine_wind_directions"] + test_hercules_v1_dict["hercules_comms"]["amr_wind"]["test_farm"]["turbine_wind_directions"] ) assert np.allclose(test_angles, wind_directions) @@ -181,107 +77,111 @@ def test_LookupBasedWakeSteeringController(): } ) test_controller = LookupBasedWakeSteeringController( - interface=test_interface, input_dict=test_hercules_dict, df_yaw=df_opt_test + interface=test_interface_hercules_ad, input_dict=test_hercules_v1_dict, df_yaw=df_opt_test ) - test_hercules_dict["time"] = 20 - test_hercules_dict_out = test_controller.step(input_dict=test_hercules_dict) + test_hercules_v1_dict["time"] = 20 + test_dict_out = test_controller.step(input_dict=test_hercules_v1_dict) test_angles = np.array( - test_hercules_dict_out["hercules_comms"]["amr_wind"]["test_farm"]["turbine_yaw_angles"] + test_dict_out["hercules_comms"]["amr_wind"]["test_farm"]["turbine_yaw_angles"] ) wind_directions = np.array( - test_hercules_dict["hercules_comms"]["amr_wind"]["test_farm"]["turbine_wind_directions"] + test_hercules_v1_dict["hercules_comms"]["amr_wind"]["test_farm"]["turbine_wind_directions"] ) assert np.allclose(test_angles, wind_directions - test_offsets) -def test_WindFarmPowerDistributingController(): - test_interface = HerculesADInterface(test_hercules_dict) +def test_WindFarmPowerDistributingController(test_hercules_v1_dict, test_interface_hercules_ad): test_controller = WindFarmPowerDistributingController( - interface=test_interface, input_dict=test_hercules_dict + interface=test_interface_hercules_ad, input_dict=test_hercules_v1_dict ) # Default behavior when no power reference is given - test_hercules_dict["time"] = 20 - test_hercules_dict["external_signals"] = {} - test_hercules_dict_out = test_controller.step(input_dict=test_hercules_dict) + test_hercules_v1_dict["time"] = 20 + test_hercules_v1_dict["external_signals"] = {} + test_dict_out = test_controller.step(input_dict=test_hercules_v1_dict) test_power_setpoints = np.array( - test_hercules_dict_out["hercules_comms"]["amr_wind"]["test_farm"]["turbine_power_setpoints"] + test_dict_out["hercules_comms"]["amr_wind"]["test_farm"]["turbine_power_setpoints"] ) assert np.allclose( test_power_setpoints, - POWER_SETPOINT_DEFAULT / test_hercules_dict["controller"]["num_turbines"], + POWER_SETPOINT_DEFAULT / test_hercules_v1_dict["controller"]["num_turbines"], ) # Test with power reference - test_hercules_dict["external_signals"]["wind_power_reference"] = 1000 - test_hercules_dict_out = test_controller.step(input_dict=test_hercules_dict) + test_hercules_v1_dict["external_signals"]["wind_power_reference"] = 1000 + test_dict_out = test_controller.step(input_dict=test_hercules_v1_dict) test_power_setpoints = np.array( - test_hercules_dict_out["hercules_comms"]["amr_wind"]["test_farm"]["turbine_power_setpoints"] + test_dict_out["hercules_comms"]["amr_wind"]["test_farm"]["turbine_power_setpoints"] ) assert np.allclose(test_power_setpoints, 500) -def test_WindFarmPowerTrackingController(): - test_interface = HerculesADInterface(test_hercules_dict) +def test_WindFarmPowerTrackingController(test_hercules_v1_dict, test_interface_hercules_ad): test_controller = WindFarmPowerTrackingController( - interface=test_interface, input_dict=test_hercules_dict + interface=test_interface_hercules_ad, input_dict=test_hercules_v1_dict ) # Test no change to power setpoints if producing desired power - test_hercules_dict["external_signals"]["wind_power_reference"] = 1000 - test_hercules_dict["hercules_comms"]["amr_wind"]["test_farm"]["turbine_powers"] = [500, 500] - test_hercules_dict_out = test_controller.step(input_dict=test_hercules_dict) + test_hercules_v1_dict["external_signals"]["wind_power_reference"] = 1000 + test_hercules_v1_dict["hercules_comms"]["amr_wind"]["test_farm"]["turbine_powers"] = [500, 500] + test_dict_out = test_controller.step(input_dict=test_hercules_v1_dict) test_power_setpoints = np.array( - test_hercules_dict_out["hercules_comms"]["amr_wind"]["test_farm"]["turbine_power_setpoints"] + test_dict_out["hercules_comms"]["amr_wind"]["test_farm"]["turbine_power_setpoints"] ) assert np.allclose(test_power_setpoints, 500) # Test if power exceeds farm reference, power setpoints are reduced - test_hercules_dict["hercules_comms"]["amr_wind"]["test_farm"]["turbine_powers"] = [600, 600] - test_hercules_dict_out = test_controller.step(input_dict=test_hercules_dict) + test_hercules_v1_dict["hercules_comms"]["amr_wind"]["test_farm"]["turbine_powers"] = [600, 600] + test_dict_out = test_controller.step(input_dict=test_hercules_v1_dict) test_power_setpoints = np.array( - test_hercules_dict_out["hercules_comms"]["amr_wind"]["test_farm"]["turbine_power_setpoints"] + test_dict_out["hercules_comms"]["amr_wind"]["test_farm"]["turbine_power_setpoints"] ) assert ( test_power_setpoints - <= test_hercules_dict["hercules_comms"]["amr_wind"]["test_farm"]["turbine_powers"] + <= test_hercules_v1_dict["hercules_comms"]["amr_wind"]["test_farm"]["turbine_powers"] ).all() # Test if power is less than farm reference, power setpoints are increased - test_hercules_dict["hercules_comms"]["amr_wind"]["test_farm"]["turbine_powers"] = [550, 400] - test_hercules_dict_out = test_controller.step(input_dict=test_hercules_dict) + test_hercules_v1_dict["hercules_comms"]["amr_wind"]["test_farm"]["turbine_powers"] = [550, 400] + test_dict_out = test_controller.step(input_dict=test_hercules_v1_dict) test_power_setpoints = np.array( - test_hercules_dict_out["hercules_comms"]["amr_wind"]["test_farm"]["turbine_power_setpoints"] + test_dict_out["hercules_comms"]["amr_wind"]["test_farm"]["turbine_power_setpoints"] ) assert ( test_power_setpoints - >= test_hercules_dict["hercules_comms"]["amr_wind"]["test_farm"]["turbine_powers"] + >= test_hercules_v1_dict["hercules_comms"]["amr_wind"]["test_farm"]["turbine_powers"] ).all() # Test that more aggressive control leads to faster response test_controller = WindFarmPowerTrackingController( - interface=test_interface, input_dict=test_hercules_dict, proportional_gain=2 + interface=test_interface_hercules_ad, input_dict=test_hercules_v1_dict, proportional_gain=2 ) - test_hercules_dict["hercules_comms"]["amr_wind"]["test_farm"]["turbine_powers"] = [600, 600] - test_hercules_dict_out = test_controller.step(input_dict=test_hercules_dict) + test_hercules_v1_dict["hercules_comms"]["amr_wind"]["test_farm"]["turbine_powers"] = [600, 600] + test_dict_out = test_controller.step(input_dict=test_hercules_v1_dict) test_power_setpoints_a = np.array( - test_hercules_dict_out["hercules_comms"]["amr_wind"]["test_farm"]["turbine_power_setpoints"] + test_dict_out["hercules_comms"]["amr_wind"]["test_farm"]["turbine_power_setpoints"] ) assert (test_power_setpoints_a < test_power_setpoints).all() -def test_HybridSupervisoryControllerBaseline(): - test_interface = HerculesHybridADInterface(test_hercules_dict) - +def test_HybridSupervisoryControllerBaseline( + test_hercules_v1_dict, test_interface_hercules_hybrid_ad +): # Establish lower controllers - wind_controller = WindFarmPowerTrackingController(test_interface, test_hercules_dict) - solar_controller = SolarPassthroughController(test_interface, test_hercules_dict) - battery_controller = BatteryPassthroughController(test_interface, test_hercules_dict) + wind_controller = WindFarmPowerTrackingController( + test_interface_hercules_hybrid_ad, test_hercules_v1_dict + ) + solar_controller = SolarPassthroughController( + test_interface_hercules_hybrid_ad, test_hercules_v1_dict + ) + battery_controller = BatteryPassthroughController( + test_interface_hercules_hybrid_ad, test_hercules_v1_dict + ) test_controller = HybridSupervisoryControllerBaseline( - interface=test_interface, - input_dict=test_hercules_dict, + interface=test_interface_hercules_hybrid_ad, + input_dict=test_hercules_v1_dict, wind_controller=wind_controller, solar_controller=solar_controller, battery_controller=battery_controller, @@ -292,13 +192,15 @@ def test_HybridSupervisoryControllerBaseline(): power_ref = 1000 # Simply test the supervisory_control method, for the time being - test_hercules_dict["external_signals"]["plant_power_reference"] = power_ref - test_hercules_dict["hercules_comms"]["amr_wind"]["test_farm"]["turbine_powers"] = wind_current - test_hercules_dict["py_sims"]["test_solar"]["outputs"]["power_mw"] = solar_current / 1e3 + test_hercules_v1_dict["external_signals"]["plant_power_reference"] = power_ref + test_hercules_v1_dict["hercules_comms"]["amr_wind"]["test_farm"]["turbine_powers"] = ( + wind_current + ) + test_hercules_v1_dict["py_sims"]["test_solar"]["outputs"]["power_mw"] = solar_current / 1e3 test_controller.prev_solar_power = solar_current # To override filtering test_controller.prev_wind_power = sum(wind_current) # To override filtering - test_controller.step(test_hercules_dict) # Run the controller once to update measurements + test_controller.step(test_hercules_v1_dict) # Run the controller once to update measurements supervisory_control_output = test_controller.supervisory_control( test_controller._measurements_dict ) @@ -314,22 +216,30 @@ def test_HybridSupervisoryControllerBaseline(): ) # To charge battery -def test_HybridSupervisoryControllerBaseline_subsets(): +def test_HybridSupervisoryControllerBaseline_subsets( + test_hercules_v1_dict, test_interface_hercules_hybrid_ad +): """ Tests that the HybridSupervisoryControllerBaseline can be run with only some of the wind, solar, and battery controllers. """ - test_interface = HerculesHybridADInterface(test_hercules_dict) + test_interface = test_interface_hercules_hybrid_ad # Establish lower controllers - wind_controller = WindFarmPowerTrackingController(test_interface, test_hercules_dict) - solar_controller = SolarPassthroughController(test_interface, test_hercules_dict) - battery_controller = BatteryPassthroughController(test_interface, test_hercules_dict) + wind_controller = WindFarmPowerTrackingController( + test_interface_hercules_hybrid_ad, test_hercules_v1_dict + ) + solar_controller = SolarPassthroughController( + test_interface_hercules_hybrid_ad, test_hercules_v1_dict + ) + battery_controller = BatteryPassthroughController( + test_interface_hercules_hybrid_ad, test_hercules_v1_dict + ) ## First, try with wind and solar only test_controller = HybridSupervisoryControllerBaseline( - interface=test_interface, - input_dict=test_hercules_dict, + interface=test_interface_hercules_hybrid_ad, + input_dict=test_hercules_v1_dict, wind_controller=wind_controller, solar_controller=solar_controller, battery_controller=None, @@ -340,13 +250,15 @@ def test_HybridSupervisoryControllerBaseline_subsets(): power_ref = 1000 # Simply test the supervisory_control method, for the time being - test_hercules_dict["external_signals"]["plant_power_reference"] = power_ref - test_hercules_dict["hercules_comms"]["amr_wind"]["test_farm"]["turbine_powers"] = wind_current - test_hercules_dict["py_sims"]["test_solar"]["outputs"]["power_mw"] = solar_current / 1e3 + test_hercules_v1_dict["external_signals"]["plant_power_reference"] = power_ref + test_hercules_v1_dict["hercules_comms"]["amr_wind"]["test_farm"]["turbine_powers"] = ( + wind_current + ) + test_hercules_v1_dict["py_sims"]["test_solar"]["outputs"]["power_mw"] = solar_current / 1e3 test_controller.prev_solar_power = solar_current # To override filtering test_controller.prev_wind_power = sum(wind_current) # To override filtering - test_controller.step(test_hercules_dict) # Run the controller once to update measurements + test_controller.step(test_hercules_v1_dict) # Run the controller once to update measurements supervisory_control_output = test_controller.supervisory_control( test_controller._measurements_dict ) @@ -363,7 +275,7 @@ def test_HybridSupervisoryControllerBaseline_subsets(): ## Next, wind and battery only test_controller = HybridSupervisoryControllerBaseline( interface=test_interface, - input_dict=test_hercules_dict, + input_dict=test_hercules_v1_dict, wind_controller=wind_controller, solar_controller=None, battery_controller=battery_controller, @@ -371,7 +283,7 @@ def test_HybridSupervisoryControllerBaseline_subsets(): test_controller.prev_solar_power = 0 test_controller.prev_wind_power = sum(wind_current) # To override filtering - test_controller.step(test_hercules_dict) # Run the controller once to update measurements + test_controller.step(test_hercules_v1_dict) # Run the controller once to update measurements supervisory_control_output = test_controller.supervisory_control( test_controller._measurements_dict ) @@ -387,7 +299,7 @@ def test_HybridSupervisoryControllerBaseline_subsets(): ## Finally, solar and battery only test_controller = HybridSupervisoryControllerBaseline( interface=test_interface, - input_dict=test_hercules_dict, + input_dict=test_hercules_v1_dict, wind_controller=None, solar_controller=solar_controller, battery_controller=battery_controller, @@ -395,7 +307,7 @@ def test_HybridSupervisoryControllerBaseline_subsets(): test_controller.prev_solar_power = solar_current # To override filtering test_controller.prev_wind_power = 0 - test_controller.step(test_hercules_dict) # Run the controller once to update measurements + test_controller.step(test_hercules_v1_dict) # Run the controller once to update measurements supervisory_control_output = test_controller.supervisory_control( test_controller._measurements_dict ) @@ -412,7 +324,7 @@ def test_HybridSupervisoryControllerBaseline_subsets(): with pytest.raises(ValueError): _ = HybridSupervisoryControllerBaseline( interface=test_interface, - input_dict=test_hercules_dict, + input_dict=test_hercules_v1_dict, wind_controller=None, solar_controller=None, battery_controller=battery_controller, @@ -421,7 +333,7 @@ def test_HybridSupervisoryControllerBaseline_subsets(): ## Only wind controller test_controller = HybridSupervisoryControllerBaseline( interface=test_interface, - input_dict=test_hercules_dict, + input_dict=test_hercules_v1_dict, wind_controller=wind_controller, solar_controller=None, battery_controller=None, @@ -429,7 +341,7 @@ def test_HybridSupervisoryControllerBaseline_subsets(): test_controller.prev_solar_power = 0 test_controller.prev_wind_power = sum(wind_current) # To override filtering - test_controller.step(test_hercules_dict) # Run the controller once to update measurements + test_controller.step(test_hercules_v1_dict) # Run the controller once to update measurements supervisory_control_output = test_controller.supervisory_control( test_controller._measurements_dict ) @@ -445,7 +357,7 @@ def test_HybridSupervisoryControllerBaseline_subsets(): ## Only solar controller test_controller = HybridSupervisoryControllerBaseline( interface=test_interface, - input_dict=test_hercules_dict, + input_dict=test_hercules_v1_dict, wind_controller=None, solar_controller=solar_controller, battery_controller=None, @@ -453,7 +365,7 @@ def test_HybridSupervisoryControllerBaseline_subsets(): test_controller.prev_solar_power = solar_current # To override filtering test_controller.prev_wind_power = 0 - test_controller.step(test_hercules_dict) # Run the controller once to update measurements + test_controller.step(test_hercules_v1_dict) # Run the controller once to update measurements supervisory_control_output = test_controller.supervisory_control( test_controller._measurements_dict ) @@ -467,36 +379,36 @@ def test_HybridSupervisoryControllerBaseline_subsets(): ) -def test_HybridSupervisoryControllerMultiRef_requirements(): +def test_HybridSupervisoryControllerMultiRef_requirements( + test_hercules_dict, test_interface_hercules +): + test_interface = test_interface_hercules # Check that errors are correctly raised if interconnect_limit is not set correctly - test_hercules_v2_dict_temp = copy.deepcopy(test_hercules_v2_dict) - del test_hercules_v2_dict_temp["plant"]["interconnect_limit"] - interface = HerculesInterface(test_hercules_v2_dict_temp) + del test_interface.plant_parameters["interconnect_limit"] with pytest.raises(KeyError): - HybridSupervisoryControllerMultiRef(interface, test_hercules_v2_dict_temp) + HybridSupervisoryControllerMultiRef(test_interface, test_hercules_dict) - test_hercules_v2_dict_temp["plant"]["interconnect_limit"] = "1" + test_interface.plant_parameters["interconnect_limit"] = "1" with pytest.raises(ValueError): - interface = HerculesInterface(test_hercules_v2_dict_temp) - HybridSupervisoryControllerMultiRef(interface, test_hercules_v2_dict_temp) + HybridSupervisoryControllerMultiRef(test_interface, test_hercules_dict) - test_hercules_v2_dict_temp["plant"]["interconnect_limit"] = -1 + test_interface.plant_parameters["interconnect_limit"] = -1 with pytest.raises(ValueError): - interface = HerculesInterface(test_hercules_v2_dict_temp) - HybridSupervisoryControllerMultiRef(interface, test_hercules_v2_dict_temp) + HybridSupervisoryControllerMultiRef(test_interface, test_hercules_dict) -def test_HybridSupervisoryControllerMultiRef(): - test_interface = HerculesInterface(test_hercules_v2_dict) +def test_HybridSupervisoryControllerMultiRef(test_hercules_dict, test_interface_hercules): + test_interface = test_interface_hercules + test_interface.plant_parameters["interconnect_limit"] = 10000.0 # Establish lower controllers - wind_controller = WindFarmPowerTrackingController(test_interface, test_hercules_v2_dict) - solar_controller = SolarPassthroughController(test_interface, test_hercules_v2_dict) - battery_controller = BatteryPassthroughController(test_interface, test_hercules_v2_dict) + wind_controller = WindFarmPowerTrackingController(test_interface, test_hercules_dict) + solar_controller = SolarPassthroughController(test_interface, test_hercules_dict) + battery_controller = BatteryPassthroughController(test_interface, test_hercules_dict) test_controller = HybridSupervisoryControllerMultiRef( interface=test_interface, - input_dict=test_hercules_v2_dict, + input_dict=test_hercules_dict, wind_controller=wind_controller, solar_controller=solar_controller, battery_controller=battery_controller, @@ -506,11 +418,11 @@ def test_HybridSupervisoryControllerMultiRef(): wind_current = [600, 300] # Simply test the supervisory_control method, for the time being - test_hercules_v2_dict["wind_farm"]["turbine_powers"] = wind_current - test_hercules_v2_dict["solar_farm"]["power"] = solar_current + test_hercules_dict["wind_farm"]["turbine_powers"] = wind_current + test_hercules_dict["solar_farm"]["power"] = solar_current test_controller.prev_solar_power = solar_current # To override filtering test_controller.prev_wind_power = sum(wind_current) # To override filtering - test_controller.step(test_hercules_v2_dict) # Run the controller once to update measurements + test_controller.step(test_hercules_dict) # Run the controller once to update measurements supervisory_control_output = test_controller.supervisory_control( test_controller._measurements_dict @@ -520,16 +432,17 @@ def test_HybridSupervisoryControllerMultiRef(): assert np.allclose( supervisory_control_output, [ - test_hercules_v2_dict["external_signals"]["wind_power_reference"], - test_hercules_v2_dict["external_signals"]["solar_power_reference"], - test_hercules_v2_dict["external_signals"]["battery_power_reference"], + test_hercules_dict["external_signals"]["wind_power_reference"], + test_hercules_dict["external_signals"]["solar_power_reference"], + test_hercules_dict["external_signals"]["battery_power_reference"], ], ) # Check individual components producing according to their references -def test_BatteryPassthroughController(): - test_interface = HerculesHybridADInterface(test_hercules_dict) - test_controller = BatteryPassthroughController(test_interface, test_hercules_dict) +def test_BatteryPassthroughController(test_hercules_v1_dict, test_interface_hercules_hybrid_ad): + test_controller = BatteryPassthroughController( + test_interface_hercules_hybrid_ad, test_hercules_v1_dict + ) power_ref = 1000 measurements_dict = {"battery": {"power_reference": power_ref}} @@ -537,9 +450,10 @@ def test_BatteryPassthroughController(): assert controls_dict["power_setpoint"] == power_ref -def test_SolarPassthroughController(): - test_interface = HerculesHybridADInterface(test_hercules_dict) - test_controller = SolarPassthroughController(test_interface, test_hercules_dict) +def test_SolarPassthroughController(test_hercules_v1_dict, test_interface_hercules_hybrid_ad): + test_controller = SolarPassthroughController( + test_interface_hercules_hybrid_ad, test_hercules_v1_dict + ) power_ref = 1000 measurements_dict = {"solar_farm": {"power_reference": power_ref}} @@ -547,41 +461,41 @@ def test_SolarPassthroughController(): assert controls_dict["power_setpoint"] == power_ref -def test_BatteryController(): - test_interface = HerculesBatteryInterface(test_hercules_dict) - test_controller = BatteryController(test_interface, test_hercules_dict, {"k_batt": 0.1}) +def test_BatteryController(test_hercules_v1_dict): + test_interface = HerculesBatteryInterface(test_hercules_v1_dict) + test_controller = BatteryController(test_interface, test_hercules_v1_dict, {"k_batt": 0.1}) # Test when starting with 0 power output power_ref = 1000 - test_hercules_dict["py_sims"]["test_battery"]["outputs"] = {"power": 0, "soc": 0.3} - test_hercules_dict["external_signals"]["plant_power_reference"] = power_ref - test_controller.step(test_hercules_dict) + test_hercules_v1_dict["py_sims"]["test_battery"]["outputs"] = {"power": 0, "soc": 0.3} + test_hercules_v1_dict["external_signals"]["plant_power_reference"] = power_ref + test_controller.step(test_hercules_v1_dict) out_0 = test_controller._controls_dict["power_setpoint"] assert 0 < out_0 < power_ref # Test that increasing the gain increases the control response - test_controller = BatteryController(test_interface, test_hercules_dict, {"k_batt": 0.5}) - test_controller.step(test_hercules_dict) + test_controller = BatteryController(test_interface, test_hercules_v1_dict, {"k_batt": 0.5}) + test_controller.step(test_hercules_v1_dict) out_1 = test_controller._controls_dict["power_setpoint"] assert out_0 < out_1 < power_ref # Decreasing the gain slows the response - test_controller = BatteryController(test_interface, test_hercules_dict, {"k_batt": 0.01}) - test_controller.step(test_hercules_dict) + test_controller = BatteryController(test_interface, test_hercules_v1_dict, {"k_batt": 0.01}) + test_controller.step(test_hercules_v1_dict) out_2 = test_controller._controls_dict["power_setpoint"] assert 0 < out_2 < out_0 # More complex test for smoothing capabilities (mid-low gain) power_refs_in = np.tile(np.array([1000.0, -1000.0]), 5) power_refs_out = np.zeros_like(power_refs_in) - test_controller = BatteryController(test_interface, test_hercules_dict, {"k_batt": 0.1}) + test_controller = BatteryController(test_interface, test_hercules_v1_dict, {"k_batt": 0.1}) battery_power = 0 for i, pr_in in enumerate(power_refs_in): - test_hercules_dict["external_signals"]["plant_power_reference"] = pr_in - test_hercules_dict["py_sims"]["test_battery"]["outputs"]["power"] = -battery_power - test_hercules_dict["time"] += 1 - out = test_controller.step(test_hercules_dict) + test_hercules_v1_dict["external_signals"]["plant_power_reference"] = pr_in + test_hercules_v1_dict["py_sims"]["test_battery"]["outputs"]["power"] = -battery_power + test_hercules_v1_dict["time"] += 1 + out = test_controller.step(test_hercules_v1_dict) battery_power = out["py_sims"]["inputs"]["battery_signal"] power_refs_out[i] = battery_power @@ -594,24 +508,24 @@ def test_BatteryController(): clipping_threshold_2 = [0.0, 0.5, 0.5, 1.0] # Clipping throughout # at 30% SOC, all should match if power reference is small - test_hercules_dict["py_sims"]["test_battery"]["outputs"] = {"power": 0, "soc": 0.3} - test_hercules_dict["external_signals"]["plant_power_reference"] = power_ref + test_hercules_v1_dict["py_sims"]["test_battery"]["outputs"] = {"power": 0, "soc": 0.3} + test_hercules_v1_dict["external_signals"]["plant_power_reference"] = power_ref test_controller_0 = BatteryController( - test_interface, test_hercules_dict, {"clipping_thresholds": clipping_threshold_0} + test_interface, test_hercules_v1_dict, {"clipping_thresholds": clipping_threshold_0} ) - test_controller_0.step(test_hercules_dict) + test_controller_0.step(test_hercules_v1_dict) out_0 = test_controller_0._controls_dict["power_setpoint"] test_controller_1 = BatteryController( - test_interface, test_hercules_dict, {"clipping_thresholds": clipping_threshold_1} + test_interface, test_hercules_v1_dict, {"clipping_thresholds": clipping_threshold_1} ) - test_controller_1.step(test_hercules_dict) + test_controller_1.step(test_hercules_v1_dict) out_1 = test_controller_1._controls_dict["power_setpoint"] test_controller_2 = BatteryController( - test_interface, test_hercules_dict, {"clipping_thresholds": clipping_threshold_2} + test_interface, test_hercules_v1_dict, {"clipping_thresholds": clipping_threshold_2} ) - test_controller_2.step(test_hercules_dict) + test_controller_2.step(test_hercules_v1_dict) out_2 = test_controller_2._controls_dict["power_setpoint"] assert out_0 == out_1 @@ -621,69 +535,71 @@ def test_BatteryController(): test_controller_0.x = 0 test_controller_1.x = 0 test_controller_2.x = 0 - test_hercules_dict["external_signals"]["plant_power_reference"] = 20000 - test_controller_0.step(test_hercules_dict) + test_hercules_v1_dict["external_signals"]["plant_power_reference"] = 20000 + test_controller_0.step(test_hercules_v1_dict) out_0 = test_controller_0._controls_dict["power_setpoint"] - test_controller_1.step(test_hercules_dict) + test_controller_1.step(test_hercules_v1_dict) out_1 = test_controller_1._controls_dict["power_setpoint"] - test_controller_2.step(test_hercules_dict) + test_controller_2.step(test_hercules_v1_dict) out_2 = test_controller_2._controls_dict["power_setpoint"] assert out_0 == out_1 assert out_0 > out_2 # at 85% SOC and large reference, 1 should be clipped - test_hercules_dict["py_sims"]["test_battery"]["outputs"] = {"power": 0, "soc": 0.85} + test_hercules_v1_dict["py_sims"]["test_battery"]["outputs"] = {"power": 0, "soc": 0.85} test_controller_0.x = 0 test_controller_1.x = 0 - test_controller_0.step(test_hercules_dict) + test_controller_0.step(test_hercules_v1_dict) out_0 = test_controller_0._controls_dict["power_setpoint"] - test_controller_1.step(test_hercules_dict) + test_controller_1.step(test_hercules_v1_dict) out_1 = test_controller_1._controls_dict["power_setpoint"] assert out_0 > out_1 -def test_HydrogenPlantController(): +def test_HydrogenPlantController(test_hercules_v1_dict, test_interface_hercules_hybrid_ad): """ Tests that the HydrogenPlantController outputs a reasonable signal """ - test_interface = HerculesHybridADInterface(test_hercules_dict) - ## Test with only wind providing generation - wind_controller = WindFarmPowerTrackingController(test_interface, test_hercules_dict) + wind_controller = WindFarmPowerTrackingController( + test_interface_hercules_hybrid_ad, test_hercules_v1_dict + ) test_controller = HydrogenPlantController( - interface=test_interface, - input_dict=test_hercules_dict, + interface=test_interface_hercules_hybrid_ad, + input_dict=test_hercules_v1_dict, generator_controller=wind_controller, ) wind_current = [600, 300] hyrogen_ref = 0.03 - hydrogen_output = test_hercules_dict["py_sims"]["test_hydrogen"]["outputs"]["H2_mfr"] + hydrogen_output = test_hercules_v1_dict["py_sims"]["test_hydrogen"]["outputs"]["H2_mfr"] hydrogen_error = hyrogen_ref - hydrogen_output # Simply test the supervisory_control method, for the time being - test_hercules_dict["external_signals"]["hydrogen_reference"] = hyrogen_ref - test_hercules_dict["hercules_comms"]["amr_wind"]["test_farm"]["turbine_powers"] = wind_current - test_hercules_dict["py_sims"]["test_battery"]["outputs"]["power"] = 0.0 - test_hercules_dict["py_sims"]["test_solar"]["outputs"]["power_mw"] = 0.0 + test_hercules_v1_dict["external_signals"]["hydrogen_reference"] = hyrogen_ref + test_hercules_v1_dict["hercules_comms"]["amr_wind"]["test_farm"]["turbine_powers"] = ( + wind_current + ) + test_hercules_v1_dict["py_sims"]["test_battery"]["outputs"]["power"] = 0.0 + test_hercules_v1_dict["py_sims"]["test_solar"]["outputs"]["power_mw"] = 0.0 test_controller.filtered_power_prev = sum(wind_current) # To override filtering # Without removing wind power reference, wind controller can't reconcile its setpoint with pytest.raises(KeyError): - test_controller.step(test_hercules_dict) + test_controller.step(test_hercules_v1_dict) # Remove wind power reference to allow wind controller to operate freely - del test_hercules_dict["external_signals"]["wind_power_reference"] - test_controller.step(test_hercules_dict) # Run the controller once to update measurements + del test_hercules_v1_dict["external_signals"]["wind_power_reference"] + test_controller.step(test_hercules_v1_dict) # Run the controller once to update measurements supervisory_control_output = test_controller.supervisory_control( test_controller._measurements_dict ) controller_gain = ( - test_hercules_dict["controller"]["nominal_plant_power_kW"] - / test_hercules_dict["controller"]["nominal_hydrogen_rate_kgps"] - * test_hercules_dict["controller"]["hydrogen_controller_gain"] + test_hercules_v1_dict["controller"]["nominal_plant_power_kW"] + / test_hercules_v1_dict["controller"]["nominal_hydrogen_rate_kgps"] + * test_hercules_v1_dict["controller"]["hydrogen_controller_gain"] ) assert controller_gain == test_controller.K @@ -693,16 +609,20 @@ def test_HydrogenPlantController(): # Test with a full wind/solar/battery plant hybrid_controller = HybridSupervisoryControllerBaseline( - interface=test_interface, - input_dict=test_hercules_dict, + interface=test_interface_hercules_hybrid_ad, + input_dict=test_hercules_v1_dict, wind_controller=wind_controller, - solar_controller=SolarPassthroughController(test_interface, test_hercules_dict), - battery_controller=BatteryPassthroughController(test_interface, test_hercules_dict), + solar_controller=SolarPassthroughController( + test_interface_hercules_hybrid_ad, test_hercules_v1_dict + ), + battery_controller=BatteryPassthroughController( + test_interface_hercules_hybrid_ad, test_hercules_v1_dict + ), ) test_controller = HydrogenPlantController( - interface=test_interface, - input_dict=test_hercules_dict, + interface=test_interface_hercules_hybrid_ad, + input_dict=test_hercules_v1_dict, generator_controller=hybrid_controller, ) @@ -710,12 +630,14 @@ def test_HydrogenPlantController(): solar_current = 1000 battery_current = 500 total_current_power = sum(wind_current) + solar_current - battery_current - test_hercules_dict["hercules_comms"]["amr_wind"]["test_farm"]["turbine_powers"] = wind_current - test_hercules_dict["py_sims"]["test_battery"]["outputs"]["power"] = battery_current - test_hercules_dict["py_sims"]["test_solar"]["outputs"]["power_mw"] = solar_current / 1e3 + test_hercules_v1_dict["hercules_comms"]["amr_wind"]["test_farm"]["turbine_powers"] = ( + wind_current + ) + test_hercules_v1_dict["py_sims"]["test_battery"]["outputs"]["power"] = battery_current + test_hercules_v1_dict["py_sims"]["test_solar"]["outputs"]["power_mw"] = solar_current / 1e3 test_controller.filtered_power_prev = total_current_power # To override filtering - test_controller.step(test_hercules_dict) # Run the controller once to update measurements + test_controller.step(test_hercules_v1_dict) # Run the controller once to update measurements supervisory_control_output = test_controller.supervisory_control( test_controller._measurements_dict ) @@ -734,29 +656,29 @@ def test_HydrogenPlantController(): # Test an error is raised if controller_parameters is passed while also specified on input_dict with pytest.raises(KeyError): HydrogenPlantController( - interface=test_interface, - input_dict=test_hercules_dict, + interface=test_interface_hercules_hybrid_ad, + input_dict=test_hercules_v1_dict, generator_controller=hybrid_controller, controller_parameters=external_controller_parameters, ) # Check instantiation fails if a required parameter is missing from both controller_parameters # and input_dict["controller"] - del test_hercules_dict["controller"]["nominal_plant_power_kW"] + del test_hercules_v1_dict["controller"]["nominal_plant_power_kW"] with pytest.raises(TypeError): HydrogenPlantController( - interface=test_interface, - input_dict=test_hercules_dict, + interface=test_interface_hercules_hybrid_ad, + input_dict=test_hercules_v1_dict, generator_controller=hybrid_controller, ) # Check instantiation proceeds correctly if doubly-specified parameters are avoided - del test_hercules_dict["controller"]["nominal_hydrogen_rate_kgps"] - del test_hercules_dict["controller"]["hydrogen_controller_gain"] + del test_hercules_v1_dict["controller"]["nominal_hydrogen_rate_kgps"] + del test_hercules_v1_dict["controller"]["hydrogen_controller_gain"] test_controller = HydrogenPlantController( - interface=test_interface, - input_dict=test_hercules_dict, + interface=test_interface_hercules_hybrid_ad, + input_dict=test_hercules_v1_dict, generator_controller=hybrid_controller, controller_parameters=external_controller_parameters, ) diff --git a/tests/floris_input.yaml b/tests/floris_input.yaml deleted file mode 100644 index 34ab3675..00000000 --- a/tests/floris_input.yaml +++ /dev/null @@ -1,92 +0,0 @@ - -name: test_input -description: Two-turbine farm for testing -floris_version: v4 - -logging: - console: - enable: false - level: WARNING - file: - enable: false - level: WARNING - -solver: - type: turbine_grid - turbine_grid_points: 3 - -farm: - layout_x: - - 0.0 - - 500.0 - layout_y: - - 0.0 - - 0.0 - turbine_type: - - nrel_5MW - -flow_field: - air_density: 1.225 - reference_wind_height: 90.0 - turbulence_intensities: - - 0.06 - wind_directions: - - 270.0 - wind_shear: 0.12 - wind_speeds: - - 8.0 - wind_veer: 0.0 - -wake: - model_strings: - combination_model: sosfs - deflection_model: gauss - turbulence_model: crespo_hernandez - velocity_model: gauss - - enable_secondary_steering: true - enable_yaw_added_recovery: true - enable_active_wake_mixing: true - enable_transverse_velocities: true - - wake_deflection_parameters: - gauss: - ad: 0.0 - alpha: 0.58 - bd: 0.0 - beta: 0.077 - dm: 1.0 - ka: 0.38 - kb: 0.004 - jimenez: - ad: 0.0 - bd: 0.0 - kd: 0.05 - - wake_velocity_parameters: - cc: - a_s: 0.179367259 - b_s: 0.0118889215 - c_s1: 0.0563691592 - c_s2: 0.13290157 - a_f: 3.11 - b_f: -0.68 - c_f: 2.41 - alpha_mod: 1.0 - gauss: - alpha: 0.58 - beta: 0.077 - ka: 0.38 - kb: 0.004 - jensen: - we: 0.05 - turboparkgauss: - A: 0.04 - include_mirror_wake: True - - wake_turbulence_parameters: - crespo_hernandez: - initial: 0.01 - constant: 0.9 - ai: 0.83 - downstream: -0.25 diff --git a/tests/hercules_interface_test.py b/tests/hercules_interface_test.py index 1f0f9995..738b12bb 100644 --- a/tests/hercules_interface_test.py +++ b/tests/hercules_interface_test.py @@ -1,49 +1,8 @@ import pytest from hycon.interfaces import HerculesInterface -test_hercules_dict = { - "dt": 1, - "time": 0, - "plant": {"interconnect_limit": None}, - "controller": { - "test_controller_parameter": 1.0, - }, - "wind_farm": { - "n_turbines": 2, - "capacity": 10000.0, - "wind_direction_mean": 271.0, - "turbine_powers": [4000.0, 4001.0], - "wind_speed": 10.0, - }, - "solar_farm": { - "capacity": 1000.0, - "power": 1000.0, # kW - "dni": 1000.0, - "aoi": 30.0, - }, - "battery": { - "size": 10.0e3, - "energy_capacity": 40.0e3, - "power": 10.0e3, - "soc": 0.3, - "charge_rate": 20e3, - "discharge_rate": 15e3, - }, - "electrolyzer": { - "H2_mfr": 0.03, - }, - "external_signals": { # Is this OK like this? - "wind_power_reference": 1000.0, - "plant_power_reference": 1000.0, - "forecast_ws_mean_0": 8.0, - "forecast_ws_mean_1": 8.1, - "ws_median_0": 8.1, - "hydrogen_reference": 0.02, - }, -} - - -def test_interface_instantiation(): + +def test_interface_instantiation(test_hercules_dict): """ Tests whether all interfaces can be imported correctly and that they each implement the required methods specified by InterfaceBase. @@ -52,7 +11,7 @@ def test_interface_instantiation(): _ = HerculesInterface(h_dict=test_hercules_dict) -def test_HerculesInterface_windonly(): +def test_HerculesInterface_windonly(test_hercules_dict): # Test instantiation interface = HerculesInterface(h_dict=test_hercules_dict) assert interface.dt == test_hercules_dict["dt"] @@ -107,7 +66,7 @@ def test_HerculesInterface_windonly(): interface.send_controls(test_hercules_dict, **bad_controls_dict1) -def test_HerculesInterface_hybrid(): +def test_HerculesInterface_hybrid(test_hercules_dict): # Test instantiation interface = HerculesInterface(h_dict=test_hercules_dict) assert interface.dt == test_hercules_dict["dt"] diff --git a/tests/hercules_v1_interfaces_test.py b/tests/hercules_v1_interfaces_test.py index c4bb821b..b6b644e7 100644 --- a/tests/hercules_v1_interfaces_test.py +++ b/tests/hercules_v1_interfaces_test.py @@ -5,68 +5,37 @@ HerculesV1HybridADInterface, ) -test_hercules_dict = { - "dt": 1, - "time": 0, - "controller": {"num_turbines": 2, "wind_capacity_MW": 10}, - "hercules_comms": { - "amr_wind": { - "test_farm": { - "turbine_wind_directions": [271.0, 272.5], - "turbine_powers": [4000.0, 4001.0], - "wind_speed": 10.0, - } - } - }, - "py_sims": { - "test_battery": { - "outputs": {"power": 10.0, "soc": 0.3}, - "charge_rate": 20, - "discharge_rate": 20, - }, - "test_solar": {"outputs": {"power_mw": 1.0, "dni": 1000.0, "aoi": 30.0}}, - "test_hydrogen": {"outputs": {"H2_mfr": 0.03}}, - "inputs": {}, - }, - "external_signals": { - "wind_power_reference": 1000.0, - "plant_power_reference": 1000.0, - "forecast_ws_mean_0": 8.0, - "forecast_ws_mean_1": 8.1, - "ws_median_0": 8.1, - "hydrogen_reference": 0.02, - }, -} - -def test_interface_instantiation(): +def test_interface_instantiation(test_hercules_v1_dict): """ Tests whether all interfaces can be imported correctly and that they each implement the required methods specified by InterfaceBase. """ - _ = HerculesV1ADInterface(hercules_dict=test_hercules_dict) - _ = HerculesV1HybridADInterface(hercules_dict=test_hercules_dict) - _ = HerculesV1BatteryInterface(hercules_dict=test_hercules_dict) + _ = HerculesV1ADInterface(hercules_dict=test_hercules_v1_dict) + _ = HerculesV1HybridADInterface(hercules_dict=test_hercules_v1_dict) + _ = HerculesV1BatteryInterface(hercules_dict=test_hercules_v1_dict) -def test_HerculesADInterface(): - interface = HerculesV1ADInterface(hercules_dict=test_hercules_dict) +def test_HerculesADInterface(test_hercules_v1_dict): + interface = HerculesV1ADInterface(hercules_dict=test_hercules_v1_dict) # Test get_measurements() - measurements = interface.get_measurements(hercules_dict=test_hercules_dict) + measurements = interface.get_measurements(hercules_dict=test_hercules_v1_dict) - assert measurements["time"] == test_hercules_dict["time"] + assert measurements["time"] == test_hercules_v1_dict["time"] assert ( measurements["wind_farm"]["wind_directions"] - == test_hercules_dict["hercules_comms"]["amr_wind"]["test_farm"]["turbine_wind_directions"] + == test_hercules_v1_dict["hercules_comms"]["amr_wind"]["test_farm"][ + "turbine_wind_directions" + ] ) assert ( measurements["wind_farm"]["turbine_powers"] - == test_hercules_dict["hercules_comms"]["amr_wind"]["test_farm"]["turbine_powers"] + == test_hercules_v1_dict["hercules_comms"]["amr_wind"]["test_farm"]["turbine_powers"] ) test_forecast = { - k: v for k, v in test_hercules_dict["external_signals"].items() if "forecast" in k + k: v for k, v in test_hercules_v1_dict["external_signals"].items() if "forecast" in k } assert measurements["forecast"] == test_forecast @@ -96,7 +65,7 @@ def test_HerculesADInterface(): # test send_controls() test_hercules_dict_out = interface.send_controls( - hercules_dict=test_hercules_dict, **controls_dict + hercules_dict=test_hercules_v1_dict, **controls_dict ) assert ( controls_dict["yaw_angles"] @@ -104,60 +73,64 @@ def test_HerculesADInterface(): ) with pytest.raises(TypeError): # Bad kwarg - interface.send_controls(test_hercules_dict, **bad_controls_dict1) + interface.send_controls(test_hercules_v1_dict, **bad_controls_dict1) with pytest.raises(TypeError): # Bad kwarg - interface.send_controls(test_hercules_dict, **bad_controls_dict2) + interface.send_controls(test_hercules_v1_dict, **bad_controls_dict2) # bad_controls_dict3 would pass, but faile the check_controls step. # test that both wind_power_reference and plant_power_reference work, and that # wind_power_reference takes precedence - test_hercules_dict["external_signals"]["wind_power_reference"] = 500.0 - test_hercules_dict["external_signals"]["plant_power_reference"] = 400.0 - assert interface.get_measurements(test_hercules_dict)["wind_farm"]["power_reference"] == 500.0 - del test_hercules_dict["external_signals"]["wind_power_reference"] - assert interface.get_measurements(test_hercules_dict)["wind_farm"]["power_reference"] == 400.0 + test_hercules_v1_dict["external_signals"]["wind_power_reference"] = 500.0 + test_hercules_v1_dict["external_signals"]["plant_power_reference"] = 400.0 + assert ( + interface.get_measurements(test_hercules_v1_dict)["wind_farm"]["power_reference"] == 500.0 + ) + del test_hercules_v1_dict["external_signals"]["wind_power_reference"] + assert ( + interface.get_measurements(test_hercules_v1_dict)["wind_farm"]["power_reference"] == 400.0 + ) # Reinstate original values for future tests - test_hercules_dict["external_signals"]["wind_power_reference"] = 1000.0 - test_hercules_dict["external_signals"]["plant_power_reference"] = 1000.0 + test_hercules_v1_dict["external_signals"]["wind_power_reference"] = 1000.0 + test_hercules_v1_dict["external_signals"]["plant_power_reference"] = 1000.0 -def test_HerculesHybridADInterface(): - interface = HerculesV1HybridADInterface(hercules_dict=test_hercules_dict) +def test_HerculesHybridADInterface(test_hercules_v1_dict): + interface = HerculesV1HybridADInterface(hercules_dict=test_hercules_v1_dict) # Test get_measurements() - measurements = interface.get_measurements(hercules_dict=test_hercules_dict) + measurements = interface.get_measurements(hercules_dict=test_hercules_v1_dict) - assert measurements["time"] == test_hercules_dict["time"] + assert measurements["time"] == test_hercules_v1_dict["time"] assert ( measurements["wind_farm"]["turbine_powers"] - == test_hercules_dict["hercules_comms"]["amr_wind"]["test_farm"]["turbine_powers"] + == test_hercules_v1_dict["hercules_comms"]["amr_wind"]["test_farm"]["turbine_powers"] ) assert ( measurements["wind_farm"]["wind_speed"] - == test_hercules_dict["hercules_comms"]["amr_wind"]["test_farm"]["wind_speed"] + == test_hercules_v1_dict["hercules_comms"]["amr_wind"]["test_farm"]["wind_speed"] ) assert ( measurements["wind_farm"]["power_reference"] - == test_hercules_dict["external_signals"]["wind_power_reference"] + == test_hercules_v1_dict["external_signals"]["wind_power_reference"] ) assert ( measurements["battery"]["power"] - == -test_hercules_dict["py_sims"]["test_battery"]["outputs"]["power"] + == -test_hercules_v1_dict["py_sims"]["test_battery"]["outputs"]["power"] ) assert ( measurements["solar_farm"]["power"] - == test_hercules_dict["py_sims"]["test_solar"]["outputs"]["power_mw"] * 1000 + == test_hercules_v1_dict["py_sims"]["test_solar"]["outputs"]["power_mw"] * 1000 ) assert ( measurements["solar_farm"]["direct_normal_irradiance"] - == test_hercules_dict["py_sims"]["test_solar"]["outputs"]["dni"] + == test_hercules_v1_dict["py_sims"]["test_solar"]["outputs"]["dni"] ) assert ( measurements["solar_farm"]["angle_of_incidence"] - == test_hercules_dict["py_sims"]["test_solar"]["outputs"]["aoi"] + == test_hercules_v1_dict["py_sims"]["test_solar"]["outputs"]["aoi"] ) test_forecast = { - k: v for k, v in test_hercules_dict["external_signals"].items() if "forecast" in k + k: v for k, v in test_hercules_v1_dict["external_signals"].items() if "forecast" in k } assert measurements["forecast"] == test_forecast @@ -181,7 +154,7 @@ def test_HerculesHybridADInterface(): # Test send_controls() test_hercules_dict_out = interface.send_controls( - hercules_dict=test_hercules_dict, **controls_dict + hercules_dict=test_hercules_v1_dict, **controls_dict ) assert ( @@ -198,44 +171,44 @@ def test_HerculesHybridADInterface(): ) assert ( measurements["hydrogen"]["power_reference"] - == test_hercules_dict["external_signals"]["hydrogen_reference"] + == test_hercules_v1_dict["external_signals"]["hydrogen_reference"] ) assert ( measurements["hydrogen"]["production_rate"] - == test_hercules_dict["py_sims"]["test_hydrogen"]["outputs"]["H2_mfr"] + == test_hercules_v1_dict["py_sims"]["test_hydrogen"]["outputs"]["H2_mfr"] ) with pytest.raises(TypeError): # Bad kwarg - interface.send_controls(test_hercules_dict, **bad_controls_dict) + interface.send_controls(test_hercules_v1_dict, **bad_controls_dict) -def test_HerculesBatteryInterface(): - interface = HerculesV1BatteryInterface(hercules_dict=test_hercules_dict) +def test_HerculesBatteryInterface(test_hercules_v1_dict): + interface = HerculesV1BatteryInterface(hercules_dict=test_hercules_v1_dict) # Check instantiation with no battery raises and error - temp = test_hercules_dict["py_sims"].pop("test_battery") + temp = test_hercules_v1_dict["py_sims"].pop("test_battery") with pytest.raises(ValueError): - _ = HerculesV1BatteryInterface(hercules_dict=test_hercules_dict) + _ = HerculesV1BatteryInterface(hercules_dict=test_hercules_v1_dict) # Reinstate and add second battery; test that 2 batteries causes error - test_hercules_dict["py_sims"]["test_battery"] = temp - test_hercules_dict["py_sims"]["test_battery_2"] = temp + test_hercules_v1_dict["py_sims"]["test_battery"] = temp + test_hercules_v1_dict["py_sims"]["test_battery_2"] = temp with pytest.raises(ValueError): - _ = HerculesV1BatteryInterface(hercules_dict=test_hercules_dict) - test_hercules_dict["py_sims"].pop("test_battery_2") + _ = HerculesV1BatteryInterface(hercules_dict=test_hercules_v1_dict) + test_hercules_v1_dict["py_sims"].pop("test_battery_2") # Test get_measurements() - measurements = interface.get_measurements(hercules_dict=test_hercules_dict) + measurements = interface.get_measurements(hercules_dict=test_hercules_v1_dict) assert ( measurements["battery"]["power"] - == -test_hercules_dict["py_sims"]["test_battery"]["outputs"]["power"] + == -test_hercules_v1_dict["py_sims"]["test_battery"]["outputs"]["power"] ) assert ( measurements["battery"]["state_of_charge"] - == test_hercules_dict["py_sims"]["test_battery"]["outputs"]["soc"] + == test_hercules_v1_dict["py_sims"]["test_battery"]["outputs"]["soc"] ) assert ( measurements["battery"]["power_reference"] - == test_hercules_dict["external_signals"]["plant_power_reference"] + == test_hercules_v1_dict["external_signals"]["plant_power_reference"] ) # Test check_controls() @@ -252,12 +225,12 @@ def test_HerculesBatteryInterface(): # Test send_controls() test_hercules_dict_out = interface.send_controls( - hercules_dict=test_hercules_dict, **controls_dict + hercules_dict=test_hercules_v1_dict, **controls_dict ) assert ( test_hercules_dict_out["py_sims"]["inputs"]["battery_signal"] == -controls_dict["power_setpoint"] ) # defaults to zero - test_hercules_dict_out = interface.send_controls(hercules_dict=test_hercules_dict) + test_hercules_dict_out = interface.send_controls(hercules_dict=test_hercules_v1_dict) assert test_hercules_dict_out["py_sims"]["inputs"]["battery_signal"] == 0 diff --git a/tests/wake_steering_design_test.py b/tests/wake_steering_design_test.py index 279acc0d..592b2bd0 100644 --- a/tests/wake_steering_design_test.py +++ b/tests/wake_steering_design_test.py @@ -1,5 +1,3 @@ -from pathlib import Path - import numpy as np import pytest from floris import FlorisModel @@ -15,11 +13,9 @@ get_yaw_angles_interpolant, ) -TEST_DATA = Path(__file__).resolve().parent -YAML_INPUT = TEST_DATA / "floris_input.yaml" - def generic_df_opt( + floris_dictionary, wd_resolution=4.0, wd_min=220.0, wd_max=310.0, @@ -34,7 +30,7 @@ def generic_df_opt( wd_std=None, kwargs_UncertainFlorisModel={}, ): - fmodel_test = FlorisModel(YAML_INPUT) + fmodel_test = FlorisModel(floris_dictionary) if wd_std is None: return build_simple_wake_steering_lookup_table( @@ -68,7 +64,7 @@ def generic_df_opt( ) -def test_build_simple_wake_steering_lookup_table(): +def test_build_simple_wake_steering_lookup_table(floris_dict): # Start with the simple case wd_resolution = 4.0 wd_min = 220.0 @@ -82,6 +78,7 @@ def test_build_simple_wake_steering_lookup_table(): minimum_yaw_angle = -20 maximum_yaw_angle = 20 df_opt = generic_df_opt( + floris_dict, wd_resolution=wd_resolution, wd_min=wd_min, wd_max=wd_max, @@ -93,7 +90,7 @@ def test_build_simple_wake_steering_lookup_table(): ti_max=ti_max, ) - df_opt = generic_df_opt() + df_opt = generic_df_opt(floris_dict) opt_yaw_angles = np.vstack(df_opt["yaw_angles_opt"]) @@ -112,6 +109,7 @@ def test_build_simple_wake_steering_lookup_table(): wd_max = 360.0 minimum_yaw_angle = -5 # Positive numbers DO NOT WORK. FLORIS bug? df_opt = generic_df_opt( + floris_dict, wd_resolution=wd_resolution, wd_min=wd_min, wd_max=wd_max, @@ -141,6 +139,7 @@ def test_build_simple_wake_steering_lookup_table(): wd_min = 2.0 wd_max = 360.0 # Shouldn't appear in output; max should be 358.0 df_opt = generic_df_opt( + floris_dict, wd_resolution=wd_resolution, wd_min=wd_min, wd_max=wd_max, @@ -149,11 +148,11 @@ def test_build_simple_wake_steering_lookup_table(): assert df_opt.wind_direction.max() == 358.0 -def test_build_uncertain_wake_steering_lookup_table(): +def test_build_uncertain_wake_steering_lookup_table(floris_dict): max_yaw_angle = 35 # To force split between basic and uncertain - df_opt_simple = generic_df_opt(wd_std=None, maximum_yaw_angle=max_yaw_angle) - df_opt_uncertain = generic_df_opt(wd_std=3.0, maximum_yaw_angle=max_yaw_angle) + df_opt_simple = generic_df_opt(floris_dict, wd_std=None, maximum_yaw_angle=max_yaw_angle) + df_opt_uncertain = generic_df_opt(floris_dict, wd_std=3.0, maximum_yaw_angle=max_yaw_angle) max_offset_simple = df_opt_simple.yaw_angles_opt.apply(lambda x: np.max(x)).max() max_offset_uncertain = df_opt_uncertain.yaw_angles_opt.apply(lambda x: np.max(x)).max() @@ -161,6 +160,7 @@ def test_build_uncertain_wake_steering_lookup_table(): # Check that kwargs are passed correctly (results not identical) df_opt_uncertain_fixed = generic_df_opt( + floris_dict, wd_std=3.0, maximum_yaw_angle=max_yaw_angle, kwargs_UncertainFlorisModel={"fix_yaw_to_nominal_direction": True}, @@ -168,14 +168,17 @@ def test_build_uncertain_wake_steering_lookup_table(): assert not np.allclose(df_opt_uncertain.farm_power_opt, df_opt_uncertain_fixed.farm_power_opt) -def test_apply_static_rate_limits(): +def test_apply_static_rate_limits(floris_dict): eps = 1e-4 wd_resolution = 4 ws_resolution = 0.5 ti_resolution = 0.01 df_opt = generic_df_opt( - wd_resolution=wd_resolution, ws_resolution=ws_resolution, ti_resolution=ti_resolution + floris_dict, + wd_resolution=wd_resolution, + ws_resolution=ws_resolution, + ti_resolution=ti_resolution, ) wd_rate_limit = 4 @@ -208,11 +211,11 @@ def test_apply_static_rate_limits(): assert not (np.abs(np.diff(offsets_unlimited, axis=2)) <= ti_rate_limit * ti_resolution).all() -def test_apply_wind_speed_ramps(): +def test_apply_wind_speed_ramps(floris_dict): ws_specified = 8.0 ws_wake_steering_cut_out = 13.0 ws_wake_steering_fully_engaged_high = 10.0 - df_opt_single_ws = generic_df_opt(ws_min=ws_specified, ws_max=ws_specified) + df_opt_single_ws = generic_df_opt(floris_dict, ws_min=ws_specified, ws_max=ws_specified) df_opt_ramps = apply_wind_speed_ramps( df_opt_single_ws, @@ -255,8 +258,8 @@ def test_apply_wind_speed_ramps(): ) -def test_wake_steering_interpolant(): - df_opt = generic_df_opt() +def test_wake_steering_interpolant(floris_dict): + df_opt = generic_df_opt(floris_dict) yaw_interpolant = get_yaw_angles_interpolant(df_opt) @@ -288,8 +291,8 @@ def test_wake_steering_interpolant(): with pytest.raises(ValueError): _ = yaw_interpolant(200.0, 8.0, 0.06) # min specified wd is 220 - # Check wrapping works - df_0_270 = generic_df_opt(wd_min=0.0, wd_max=270.0, wd_resolution=10.0) # Includes 0 degree WD + # Check wrapping works (includes 0 degree wind direction) + df_0_270 = generic_df_opt(floris_dict, wd_min=0.0, wd_max=270.0, wd_resolution=10.0) yaw_interpolant = get_yaw_angles_interpolant(df_0_270) _ = yaw_interpolant(0.0, 8.0, 0.06) _ = yaw_interpolant(355.0, 8.0, 0.06) @@ -300,8 +303,8 @@ def test_wake_steering_interpolant(): _ = yaw_interpolant(361.0, 8.0, 0.06) -def test_hysteresis_zones(): - df_opt = generic_df_opt() +def test_hysteresis_zones(floris_dict): + df_opt = generic_df_opt(floris_dict) min_zone_width = 4.0 hysteresis_dict_base = {"T000": [(270 - min_zone_width / 2, 270 + min_zone_width / 2)]} @@ -311,12 +314,12 @@ def test_hysteresis_zones(): assert hysteresis_dict_test == hysteresis_dict_base # Check angle wrapping works (runs through) - df_opt = generic_df_opt(wd_min=0.0, wd_max=360.0) + df_opt = generic_df_opt(floris_dict, wd_min=0.0, wd_max=360.0) hysteresis_dict_test = compute_hysteresis_zones(df_opt, min_zone_width=min_zone_width) assert hysteresis_dict_test["T000"] == hysteresis_dict_base["T000"] # Limited wind directions that span 360/0 \ - df_opt_2 = generic_df_opt() + df_opt_2 = generic_df_opt(floris_dict) df_opt_2.wind_direction = (df_opt_2.wind_direction + 90.0) % 360.0 df_opt_2 = df_opt_2.sort_values(by=["wind_direction", "wind_speed", "turbulence_intensity"]) hysteresis_dict_test = compute_hysteresis_zones(df_opt_2, min_zone_width=min_zone_width) @@ -326,21 +329,21 @@ def test_hysteresis_zones(): ).all() # Check 0 low end, less than 360 upper end - df_opt = generic_df_opt(wd_min=0.0, wd_max=300.0) + df_opt = generic_df_opt(floris_dict, wd_min=0.0, wd_max=300.0) hysteresis_dict_test = compute_hysteresis_zones(df_opt, min_zone_width=min_zone_width) assert hysteresis_dict_test["T000"] == hysteresis_dict_base["T000"] # Check nonzero low end, 360 upper end - df_opt = generic_df_opt(wd_min=200.0, wd_max=360.0) + df_opt = generic_df_opt(floris_dict, wd_min=200.0, wd_max=360.0) hysteresis_dict_test = compute_hysteresis_zones(df_opt, min_zone_width=min_zone_width) assert hysteresis_dict_test["T000"] == hysteresis_dict_base["T000"] # Close to zero low end, 360 upper end - df_opt = generic_df_opt(wd_min=2.0, wd_max=360.0) + df_opt = generic_df_opt(floris_dict, wd_min=2.0, wd_max=360.0) _ = compute_hysteresis_zones(df_opt) # Check grouping of regions by reducing yaw rate threshold - df_opt = generic_df_opt() + df_opt = generic_df_opt(floris_dict) hysteresis_dict_test = compute_hysteresis_zones( df_opt, min_zone_width=3 * min_zone_width, # Force regions to be grouped @@ -451,9 +454,9 @@ def test_create_uniform_wind_rose(): assert (frequencies == frequencies[0]).all() -def test_check_df_opt_ordering(): +def test_check_df_opt_ordering(floris_dict): # Pass tests - df_opt = generic_df_opt() + df_opt = generic_df_opt(floris_dict) check_df_opt_ordering(df_opt) # Remove a row so that not all data is present