Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion LICENSE.txt
Original file line number Diff line number Diff line change
@@ -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:
Expand Down
23 changes: 3 additions & 20 deletions tests/battery_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
206 changes: 206 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -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,
}
},
},
}
33 changes: 5 additions & 28 deletions tests/controller_base_test.py
Original file line number Diff line number Diff line change
@@ -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):
Expand All @@ -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)
Loading