diff --git a/floris/core/farm.py b/floris/core/farm.py index 5c009c253..c92078be6 100644 --- a/floris/core/farm.py +++ b/floris/core/farm.py @@ -209,7 +209,8 @@ def check_turbine_type(self, attribute: attrs.Attribute, value: Any) -> None: if len(value) != 1 and len(value) != self.n_turbines: raise ValueError( "turbine_type must have the same number of entries as layout_x/layout_y or have " - "a single turbine_type value." + "a single turbine_type value. This error can arise if you set the turbine_type or " + "alter the operation model before setting the layout." ) @turbine_library_path.validator diff --git a/floris/floris_model.py b/floris/floris_model.py index 157c99ac2..9ad56b41e 100644 --- a/floris/floris_model.py +++ b/floris/floris_model.py @@ -1309,13 +1309,23 @@ def set_operation_model(self, operation_model: str | List[str]): operation_model (str): The operation model to set. """ if isinstance(operation_model, str): - operation_model = [operation_model]*self.core.farm.n_turbines - elif len(operation_model) != self.core.farm.n_turbines: + if len(self.core.farm.turbine_type) == 1: + # Set a single one here, then, and return + turbine_type = self.core.farm.turbine_definitions[0] + turbine_type["operation_model"] = operation_model + self.set(turbine_type=[turbine_type]) + return + else: + operation_model = [operation_model]*self.core.farm.n_turbines + + if len(operation_model) != self.core.farm.n_turbines: raise ValueError( - "The length of the operation_model list must be equal to the number of turbines." - ) + "The length of the operation_model list must be " + "equal to the number of turbines." + ) turbine_type_list = self.core.farm.turbine_definitions + for tindex in range(self.core.farm.n_turbines): turbine_type_list[tindex]["turbine_type"] = ( turbine_type_list[tindex]["turbine_type"]+"_"+operation_model[tindex] diff --git a/tests/floris_model_integration_test.py b/tests/floris_model_integration_test.py index 7d4fcbc12..9947d6ef8 100644 --- a/tests/floris_model_integration_test.py +++ b/tests/floris_model_integration_test.py @@ -591,3 +591,38 @@ def test_set_operation_model(): fmodel.set(layout_x=[0, 0], layout_y=[0, 1000]) fmodel.set_operation_model(["simple-derating", "cosine-loss"]) assert fmodel.get_operation_model() == ["simple-derating", "cosine-loss"] + + # Check that setting a single turbine type, and then altering the operation model works + fmodel.set(layout_x=[0, 0], layout_y=[0, 1000]) + fmodel.set(turbine_type=["nrel_5MW"]) + fmodel.set_operation_model("simple-derating") + assert fmodel.get_operation_model() == "simple-derating" + + # Check that setting over mutliple turbine types works + fmodel.set(turbine_type=["nrel_5MW", "iea_15MW"]) + fmodel.set_operation_model("simple-derating") + assert fmodel.get_operation_model() == "simple-derating" + fmodel.set_operation_model(["simple-derating", "cosine-loss"]) + assert fmodel.get_operation_model() == ["simple-derating", "cosine-loss"] + + # Check setting over single turbine type; then updating layout works + fmodel.set(turbine_type=["nrel_5MW"]) + fmodel.set_operation_model("simple-derating") + fmodel.set(layout_x=[0, 0, 0], layout_y=[0, 1000, 2000]) + assert fmodel.get_operation_model() == "simple-derating" + + # Check that setting for multiple turbine types and then updating layout breaks + fmodel.set(layout_x=[0, 0], layout_y=[0, 1000]) + fmodel.set(turbine_type=["nrel_5MW"]) + fmodel.set_operation_model(["simple-derating", "cosine-loss"]) + assert fmodel.get_operation_model() == ["simple-derating", "cosine-loss"] + with pytest.raises(ValueError): + fmodel.set(layout_x=[0, 0, 0], layout_y=[0, 1000, 2000]) + + # Check one more variation + fmodel.set(layout_x=[0, 0], layout_y=[0, 1000]) + fmodel.set(turbine_type=["nrel_5MW", "iea_15MW"]) + fmodel.set_operation_model("simple-derating") + fmodel.set(layout_x=[0, 0], layout_y=[0, 1000]) + with pytest.raises(ValueError): + fmodel.set(layout_x=[0, 0, 0], layout_y=[0, 1000, 2000])