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

Enhancement: Add a Dimension Validator for 5-D and 3-D Array Structures #763

Open
wants to merge 17 commits into
base: develop
Choose a base branch
from
Open
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 examples/01_opening_floris_computing_power.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@
wind_directions = np.array([260., 270., 280.])
wind_speeds = np.array([8.0, 9.0, 10.0])
fi.reinitialize(wind_directions=wind_directions, wind_speeds=wind_speeds)
yaw_angles = np.zeros([1,3,2]) # 1 wind direction, 3 wind speeds, 2 turbines
yaw_angles = np.zeros([3,3,2]) # 1 wind direction, 3 wind speeds, 2 turbines
fi.calculate_wake(yaw_angles=yaw_angles)
turbine_powers = fi.get_turbine_powers()/1000.
print('The turbine power matrix should be of dimensions 3 WD X 3 WS X 2 Turbines')
Expand Down
2 changes: 1 addition & 1 deletion examples/30_multi_dimensional_cp_ct.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@
wind_directions = np.array([260., 270., 280.])
wind_speeds = np.array([8.0, 9.0, 10.0])
fi.reinitialize(wind_directions=wind_directions, wind_speeds=wind_speeds)
yaw_angles = np.zeros([1,3,2]) # 1 wind direction, 3 wind speeds, 2 turbines
yaw_angles = np.zeros([3,3,2]) # 1 wind direction, 3 wind speeds, 2 turbines
fi.calculate_wake(yaw_angles=yaw_angles)
turbine_powers = fi.get_turbine_powers_multidim()/1000.
print('The turbine power matrix should be of dimensions 3 WD X 3 WS X 2 Turbines')
Expand Down
4 changes: 2 additions & 2 deletions floris/simulation/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
)

from floris.logging_manager import LoggingManager
from floris.type_dec import FromDictMixin
from floris.type_dec import FromDictMixin, ValidateMixin


class State(Enum):
Expand All @@ -43,7 +43,7 @@ class State(Enum):


@define
class BaseClass(FromDictMixin):
class BaseClass(FromDictMixin, ValidateMixin):
"""
BaseClass object class. This class does the logging and MixIn class inheritance.
"""
Expand Down
55 changes: 31 additions & 24 deletions floris/simulation/farm.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
)
from floris.simulation.turbine import compute_tilt_angles_for_floating_turbines
from floris.type_dec import (
array_3D_field,
convert_to_path,
floris_array_converter,
iter_validator,
Expand Down Expand Up @@ -79,50 +80,53 @@ class Farm(BaseClass):
default=default_turbine_library_path, converter=convert_to_path
)

n_wind_directions: int = field(init=False)
n_wind_speeds: int = field(init=False)

turbine_definitions: list = field(init=False, validator=iter_validator(list, dict))

turbine_fCts: Dict[str, interp1d] | List[interp1d] = field(init=False, factory=list)
turbine_fCts_sorted: NDArrayFloat = field(init=False, factory=list)
turbine_fCts_sorted: NDArrayFloat = array_3D_field

turbine_fTilts: list = field(init=False, factory=list)

yaw_angles: NDArrayFloat = field(init=False)
yaw_angles_sorted: NDArrayFloat = field(init=False)
yaw_angles: NDArrayFloat = array_3D_field
yaw_angles_sorted: NDArrayFloat = array_3D_field

tilt_angles: NDArrayFloat = field(init=False)
tilt_angles_sorted: NDArrayFloat = field(init=False)
tilt_angles: NDArrayFloat = array_3D_field
tilt_angles_sorted: NDArrayFloat = array_3D_field

hub_heights: NDArrayFloat = field(init=False)
hub_heights_sorted: NDArrayFloat = field(init=False, factory=list)
hub_heights: NDArrayFloat = array_3D_field
hub_heights_sorted: NDArrayFloat = array_3D_field

turbine_map: List[Turbine | TurbineMultiDimensional] = field(init=False, factory=list)

turbine_type_map: NDArrayObject = field(init=False, factory=list)
turbine_type_map_sorted: NDArrayObject = field(init=False, factory=list)
turbine_type_map: NDArrayObject = array_3D_field
turbine_type_map_sorted: NDArrayObject = array_3D_field

turbine_power_interps: Dict[str, interp1d] | List[interp1d] = field(init=False, factory=list)
turbine_power_interps_sorted: NDArrayFloat = field(init=False, factory=list)
turbine_power_interps_sorted: NDArrayFloat = array_3D_field

rotor_diameters: NDArrayFloat = field(init=False, factory=list)
rotor_diameters_sorted: NDArrayFloat = field(init=False, factory=list)
rotor_diameters: NDArrayFloat = array_3D_field
rotor_diameters_sorted: NDArrayFloat = array_3D_field

TSRs: NDArrayFloat = field(init=False, factory=list)
TSRs_sorted: NDArrayFloat = field(init=False, factory=list)
TSRs: NDArrayFloat = array_3D_field
TSRs_sorted: NDArrayFloat = array_3D_field

pPs: NDArrayFloat = field(init=False, factory=list)
pPs_sorted: NDArrayFloat = field(init=False, factory=list)
pPs: NDArrayFloat = array_3D_field
pPs_sorted: NDArrayFloat = array_3D_field

pTs: NDArrayFloat = field(init=False, factory=list)
pTs_sorted: NDArrayFloat = field(init=False, factory=list)
pTs: NDArrayFloat = array_3D_field
pTs_sorted: NDArrayFloat = array_3D_field

ref_density_cp_cts: NDArrayFloat = field(init=False, factory=list)
ref_density_cp_cts_sorted: NDArrayFloat = field(init=False, factory=list)
ref_density_cp_cts: NDArrayFloat = array_3D_field
ref_density_cp_cts_sorted: NDArrayFloat = array_3D_field

ref_tilt_cp_cts: NDArrayFloat = field(init=False, factory=list)
ref_tilt_cp_cts_sorted: NDArrayFloat = field(init=False, factory=list)
ref_tilt_cp_cts: NDArrayFloat = array_3D_field
ref_tilt_cp_cts_sorted: NDArrayFloat = array_3D_field

correct_cp_ct_for_tilt: NDArrayFloat = field(init=False, factory=list)
correct_cp_ct_for_tilt_sorted: NDArrayFloat = field(init=False, factory=list)
correct_cp_ct_for_tilt: NDArrayFloat = array_3D_field
correct_cp_ct_for_tilt_sorted: NDArrayFloat = array_3D_field

internal_turbine_library: Path = field(init=False, default=default_turbine_library_path)

Expand Down Expand Up @@ -405,6 +409,9 @@ def expand_farm_properties(
)

def set_yaw_angles(self, n_wind_directions: int, n_wind_speeds: int):
self.n_wind_directions = n_wind_directions
self.n_wind_speeds = n_wind_speeds

# TODO Is this just for initializing yaw angles to zero?
self.yaw_angles = np.zeros((n_wind_directions, n_wind_speeds, self.n_turbines))
self.yaw_angles_sorted = np.zeros((n_wind_directions, n_wind_speeds, self.n_turbines))
Expand Down
51 changes: 33 additions & 18 deletions floris/simulation/flow_field.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
Grid,
)
from floris.type_dec import (
array_5D_field,
array_mixed_dim_field,
floris_array_converter,
NDArrayFloat,
)
Expand All @@ -47,26 +49,24 @@ class FlowField(BaseClass):

n_wind_speeds: int = field(init=False)
n_wind_directions: int = field(init=False)

u_initial_sorted: NDArrayFloat = field(init=False, factory=lambda: np.array([]))
v_initial_sorted: NDArrayFloat = field(init=False, factory=lambda: np.array([]))
w_initial_sorted: NDArrayFloat = field(init=False, factory=lambda: np.array([]))
u_sorted: NDArrayFloat = field(init=False, factory=lambda: np.array([]))
v_sorted: NDArrayFloat = field(init=False, factory=lambda: np.array([]))
w_sorted: NDArrayFloat = field(init=False, factory=lambda: np.array([]))
u: NDArrayFloat = field(init=False, factory=lambda: np.array([]))
v: NDArrayFloat = field(init=False, factory=lambda: np.array([]))
w: NDArrayFloat = field(init=False, factory=lambda: np.array([]))
n_turbines: int = field(init=False, default=0)
grid_shape: tuple[int, int, int, int, int] = field(init=False, default=(0, 0, 0, 0, 0))

u_initial_sorted: NDArrayFloat = array_5D_field
v_initial_sorted: NDArrayFloat = array_5D_field
w_initial_sorted: NDArrayFloat = array_5D_field
u_sorted: NDArrayFloat = array_5D_field
v_sorted: NDArrayFloat = array_5D_field
w_sorted: NDArrayFloat = array_5D_field
u: NDArrayFloat = array_5D_field
v: NDArrayFloat = array_5D_field
w: NDArrayFloat = array_5D_field
het_map: list = field(init=False, default=None)
dudz_initial_sorted: NDArrayFloat = field(init=False, factory=lambda: np.array([]))
dudz_initial_sorted: NDArrayFloat = array_5D_field

turbulence_intensity_field: NDArrayFloat = field(init=False, factory=lambda: np.array([]))
turbulence_intensity_field_sorted: NDArrayFloat = field(
init=False, factory=lambda: np.array([])
)
turbulence_intensity_field_sorted_avg: NDArrayFloat = field(
init=False, factory=lambda: np.array([])
)
turbulence_intensity_field: NDArrayFloat = array_mixed_dim_field
turbulence_intensity_field_sorted: NDArrayFloat = array_5D_field
turbulence_intensity_field_sorted_avg: NDArrayFloat = array_mixed_dim_field

@wind_speeds.validator
def wind_speeds_validator(self, instance: attrs.Attribute, value: NDArrayFloat) -> None:
Expand Down Expand Up @@ -113,6 +113,18 @@ def het_map_validator(self, instance: attrs.Attribute, value: list | None) -> No
"The het_map's wind direction dimension not equal to number of wind directions."
)

@grid_shape.validator
def grid_shape_validator(self, attribute: attrs.Attribute, value: tuple) -> None:
"""Validates that ``grid_shape`` is length-5 tuple of integers.

Args:
attribute (attrs.Attribute): The attrs Attribute data.
value (tuple): A length-5 tuple of integers.
"""
if len(value) != 5:
raise ValueError("`grid_shape` must be a tuple of 5 integer values.")
if not all(isinstance(v, int) for v in value):
raise TypeError("`grid_shape` must be a tuple of 5 integer values.")

def __attrs_post_init__(self) -> None:
if self.heterogenous_inflow_config is not None:
Expand All @@ -131,6 +143,9 @@ def initialize_velocity_field(self, grid: Grid) -> None:
# determined by this line. Since the right-most dimension on grid.z is storing the values
# for height, using it here to apply the shear law makes that dimension store the vertical
# wind profile.
self.n_turbines = grid.n_turbines
self.grid_shape = grid.grid_shape

wind_profile_plane = (grid.z_sorted / self.reference_wind_height) ** self.wind_shear
dwind_profile_plane = (
self.wind_shear
Expand Down
Loading