Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Raise informative errors if v3 input files passed in #829

Merged
merged 8 commits into from
Mar 4, 2024
Merged
39 changes: 39 additions & 0 deletions floris/simulation/farm.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,10 @@ def __attrs_post_init__(self) -> None:
if len(_turbine_types) == 1:
_turbine_types *= self.n_turbines

# Check that turbine definitions contain any v3 keys
for t in _turbine_types:
check_turbine_definition_for_v3_keys(turbine_definition_cache[t])

# Map each turbine definition to its index in this list
self.turbine_definitions = [
copy.deepcopy(turbine_definition_cache[t]) for t in _turbine_types
Expand Down Expand Up @@ -404,3 +408,38 @@ def coordinates(self):
@property
def n_turbines(self):
return len(self.layout_x)

def check_turbine_definition_for_v3_keys(turbine_definition: dict):
"""Check that the turbine definition does not contain any v3 keys."""
v3_deprecation_msg = (
"Consider using the convert_turbine_v3_to_v4.py utility in floris/tools "
+ "to convert from a FLORIS v3 turbine definition to FLORIS v4. "
+ "See https://nrel.github.io/floris/upgrade_guides/v3_to_v4.html for more information."
)
if "generator_efficiency" in turbine_definition:
raise ValueError(
"generator_efficiency is no longer supported as power is specified in absolute terms "
+ "in FLORIS v4. "
+ v3_deprecation_msg
)

v3_renamed_keys = ["pP", "pT", "ref_density_cp_ct", "ref_tilt_cp_ct"]
if any(k in turbine_definition for k in v3_renamed_keys):
v3_list_keys = ", ".join(map(str,v3_renamed_keys[:-1]))+", and "+v3_renamed_keys[-1]
v4_versions = (
"cosine_loss_exponent_yaw, cosine_loss_exponent_tilt, ref_air_density, and ref_tilt"
)
raise ValueError(
v3_list_keys
+ " have been renamed to "
+ v4_versions
+ ", respectively, and placed under the power_thrust_table field in FLORIS v4. "
+ v3_deprecation_msg
)

if "thrust" in turbine_definition["power_thrust_table"]:
raise ValueError(
"thrust has been renamed thrust_coefficient in FLORIS v4 (and power is now specified "
"in absolute terms with units kW, rather than as a coefficient). "
+ v3_deprecation_msg
)
34 changes: 34 additions & 0 deletions floris/simulation/floris.py
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,7 @@ def from_file(cls, input_file_path: str | Path) -> Floris:
Floris: The class object instance.
"""
input_dict = load_yaml(Path(input_file_path).resolve())
check_input_file_for_v3_keys(input_dict)
return Floris.from_dict(input_dict)

def to_file(self, output_file_path: str) -> None:
Expand All @@ -362,3 +363,36 @@ def to_file(self, output_file_path: str) -> None:
sort_keys=False,
default_flow_style=False
)

def check_input_file_for_v3_keys(input_dict) -> None:
"""
Checks if any FLORIS v3 keys are present in the input file and raises special errors if
the extra keys belong to a v3 definition of the input_dct.
and raises special errors if the extra arguments belong to a v3 definition of the class.

Args:
input_dict (dict): The input dictionary to be checked for v3 keys.
"""
v3_deprecation_msg = (
"Consider using the convert_floris_input_v3_to_v4.py utility in floris/tools "
+ "to convert from a FLORIS v3 input file to FLORIS v4. "
"See https://nrel.github.io/floris/upgrade_guides/v3_to_v4.html for more information."
)
if "turbulence_intensity" in input_dict["flow_field"]:
raise AttributeError(
"turbulence_intensity has been updated to turbulence_intensities in FLORIS v4. "
+ v3_deprecation_msg
)
elif not hasattr(input_dict["flow_field"]["turbulence_intensities"], "__len__"):
raise AttributeError(
"turbulence_intensities must be a list of floats in FLORIS v4. "
+ v3_deprecation_msg
)

if input_dict["wake"]["model_strings"]["velocity_model"] == "multidim_cp_ct":
raise AttributeError(
"Dedicated 'multidim_cp_ct' velocity model has been removed in FLORIS v4 in favor of "
+ "supporting all available wake models. To recover previous operation, set "
+ "velocity_model to gauss. "
+ v3_deprecation_msg
)
70 changes: 70 additions & 0 deletions floris/tools/convert_floris_input_v3_to_v4.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@

import sys
from pathlib import Path

import yaml

from floris.utilities import load_yaml


"""
This script is intended to be called with an argument and converts a floris input
yaml file specified for FLORIS v3 to one specified for FLORIS v4.

Usage:
python convert_floris_input_v3_to_v4.py <path/to/floris_input>.yaml

The resulting floris input file is placed in the same directory as the original yaml,
and is appended _v4.
"""


if __name__ == "__main__":
if len(sys.argv) != 2:
raise Exception(
"Usage: python convert_floris_input_v3_to_v4.py <path/to/floris_input>.yaml"
)

input_yaml = sys.argv[1]

# Handling the path and new filename
input_path = Path(input_yaml)
split_input = input_path.parts
[filename_v3, extension] = split_input[-1].split(".")
filename_v4 = filename_v3 + "_v4"
split_output = list(split_input[:-1]) + [filename_v4+"."+extension]
output_path = Path(*split_output)

# Load existing v3 model
v3_floris_input_dict = load_yaml(input_yaml)
v4_floris_input_dict = v3_floris_input_dict.copy()

# Change turbulence_intensity field to turbulence_intensities as list
if "turbulence_intensities" in v3_floris_input_dict["flow_field"]:
if "turbulence_intensity" in v3_floris_input_dict["flow_field"]:
del v4_floris_input_dict["flow_field"]["turbulence_intensity"]
elif "turbulence_intensity" in v3_floris_input_dict["flow_field"]:
v4_floris_input_dict["flow_field"]["turbulence_intensities"] = (
[v3_floris_input_dict["flow_field"]["turbulence_intensity"]]
)
del v4_floris_input_dict["flow_field"]["turbulence_intensity"]

# Change multidim_cp_ct velocity model to gauss
if v3_floris_input_dict["wake"]["model_strings"]["velocity_model"] == "multidim_cp_ct":
print(
"multidim_cp_ct velocity model specified. Changing to gauss, "
+ "but note that other velocity models are also compatible with multidimensional "
+ "turbines in FLORIS v4. "
+ "You will also need to convert your multidimensional turbine yaml files and their "
+ "corresponding power/thrust csv files to be compatible with FLORIS v4 and to reflect "
+ " the absolute power curve, rather than the power coefficient curve."
)
v4_floris_input_dict["wake"]["model_strings"]["velocity_model"] = "gauss"

yaml.dump(
v4_floris_input_dict,
open(output_path, "w"),
sort_keys=False
)

print(output_path, "created.")
11 changes: 9 additions & 2 deletions floris/tools/convert_turbine_v3_to_v4.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
yaml file specified for FLORIS v3 to one specified for FLORIS v4.

Usage:
python convert_turbine_yaml_v3_to_v4.py <path/to/turbine>.yaml
python convert_turbine_v3_to_v4.py <path/to/turbine>.yaml

The resulting turbine is placed in the same directory as the original yaml,
and is appended _v4.
Expand All @@ -20,7 +20,7 @@

if __name__ == "__main__":
if len(sys.argv) != 2:
raise Exception("Usage: python convert_turbine_yaml_v3_to_v4.py <path/to/turbine>.yaml")
raise Exception("Usage: python convert_turbine_v3_to_v4.py <path/to/turbine>.yaml")

input_yaml = sys.argv[1]

Expand All @@ -37,6 +37,13 @@

# Split into components expected by build_turbine_dict
power_thrust_table = v3_turbine_dict["power_thrust_table"]
if "power_thrust_data_file" in power_thrust_table:
raise ValueError(
"Cannot convert multidimensional turbine model. Please manually update your "
+ "turbine yaml. Note that the power_thrust_data_file csv needs to be updated to "
+ "reflect the absolute power curve, rather than the power coefficient curve,"
+ "and that `thrust` has been replaced by `thrust_coefficient`."
)
power_thrust_table["power_coefficient"] = power_thrust_table["power"]
power_thrust_table["thrust_coefficient"] = power_thrust_table["thrust"]
power_thrust_table.pop("power")
Expand Down
Loading
Loading