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 12 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
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
41 changes: 22 additions & 19 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 @@ -45,28 +47,26 @@ class FlowField(BaseClass):
heterogenous_inflow_config: dict = field(default=None)
multidim_conditions: dict = field(default=None)

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_wind_speeds: int = field(init=False)
n_turbines: int = field(init=False)
grid_resolution: int = field(init=False)

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 @@ -131,6 +131,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_resolution = grid.grid_resolution

wind_profile_plane = (grid.z_sorted / self.reference_wind_height) ** self.wind_shear
dwind_profile_plane = (
self.wind_shear
Expand Down
74 changes: 48 additions & 26 deletions floris/simulation/grid.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
floris_float_type,
NDArrayFloat,
NDArrayInt,
validate_3DArray_shape,
validate_5DArray_shape,
)
from floris.utilities import (
reverse_rotate_coordinates_rel_west,
Expand Down Expand Up @@ -74,15 +76,15 @@ class Grid(ABC, BaseClass):
time_series: bool = field()
grid_resolution: int | Iterable = field()

n_turbines: int = field(init=False)
n_wind_speeds: int = field(init=False)
n_wind_directions: int = field(init=False)
x_sorted: NDArrayFloat = field(init=False)
y_sorted: NDArrayFloat = field(init=False)
z_sorted: NDArrayFloat = field(init=False)
x_sorted_inertial_frame: NDArrayFloat = field(init=False)
y_sorted_inertial_frame: NDArrayFloat = field(init=False)
z_sorted_inertial_frame: NDArrayFloat = field(init=False)
n_wind_speeds: int = field(init=False)
n_turbines: int = field(init=False)
x_sorted: NDArrayFloat = field(init=False, validator=validate_5DArray_shape)
y_sorted: NDArrayFloat = field(init=False, validator=validate_5DArray_shape)
z_sorted: NDArrayFloat = field(init=False, validator=validate_5DArray_shape)
x_sorted_inertial_frame: NDArrayFloat = field(init=False, validator=validate_5DArray_shape)
y_sorted_inertial_frame: NDArrayFloat = field(init=False, validator=validate_5DArray_shape)
z_sorted_inertial_frame: NDArrayFloat = field(init=False, validator=validate_5DArray_shape)
cubature_weights: NDArrayFloat = field(init=False, default=None)

@turbine_coordinates.validator
Expand Down Expand Up @@ -151,11 +153,15 @@ class TurbineGrid(Grid):
creates a 3x3 grid within the rotor swept area.
"""
# TODO: describe these and the differences between `sorted_indices` and `sorted_coord_indices`
sorted_indices: NDArrayInt = field(init=False)
sorted_coord_indices: NDArrayInt = field(init=False)
unsorted_indices: NDArrayInt = field(init=False)
x_center_of_rotation: NDArrayFloat = field(init=False)
y_center_of_rotation: NDArrayFloat = field(init=False)
sorted_indices: NDArrayInt = field(init=False, validator=validate_5DArray_shape)
sorted_coord_indices: NDArrayInt = field(init=False, validator=validate_3DArray_shape)
unsorted_indices: NDArrayInt = field(init=False, validator=validate_5DArray_shape)
x_center_of_rotation: floris_float_type = field(
init=False, validator=attrs.validators.instance_of(floris_float_type)
)
y_center_of_rotation: floris_float_type = field(
init=False, validator=attrs.validators.instance_of(floris_float_type)
)
average_method = "cubic-mean"

def __attrs_post_init__(self) -> None:
Expand Down Expand Up @@ -311,11 +317,15 @@ class TurbineCubatureGrid(Grid):
include in the cubature method. This value must be in the range [1, 10], and the
corresponding cubature weights are set automatically.
"""
sorted_indices: NDArrayInt = field(init=False)
sorted_coord_indices: NDArrayInt = field(init=False)
unsorted_indices: NDArrayInt = field(init=False)
x_center_of_rotation: NDArrayFloat = field(init=False)
y_center_of_rotation: NDArrayFloat = field(init=False)
sorted_indices: NDArrayInt = field(init=False, validator=validate_5DArray_shape)
sorted_coord_indices: NDArrayInt = field(init=False, validator=validate_3DArray_shape)
unsorted_indices: NDArrayInt = field(init=False, validator=validate_5DArray_shape)
x_center_of_rotation: floris_float_type = field(
init=False, validator=attrs.validators.instance_of(floris_float_type)
)
y_center_of_rotation: floris_float_type = field(
init=False, validator=attrs.validators.instance_of(floris_float_type)
)
average_method = "simple-cubature"

def __attrs_post_init__(self) -> None:
Expand Down Expand Up @@ -475,8 +485,12 @@ class FlowFieldGrid(Grid):
grid_resolution (:py:obj:`Iterable(int,)`): The number of grid points to create in each
planar direction. Must be 3 components for resolution in the x, y, and z directions.
"""
x_center_of_rotation: NDArrayFloat = field(init=False)
y_center_of_rotation: NDArrayFloat = field(init=False)
x_center_of_rotation: floris_float_type = field(
init=False, validator=attrs.validators.instance_of(floris_float_type)
)
y_center_of_rotation: floris_float_type = field(
init=False, validator=attrs.validators.instance_of(floris_float_type)
)

def __attrs_post_init__(self) -> None:
self.set_grid()
Expand Down Expand Up @@ -553,10 +567,14 @@ class FlowFieldPlanarGrid(Grid):
planar_coordinate: float = field()
x1_bounds: tuple = field(default=None)
x2_bounds: tuple = field(default=None)
x_center_of_rotation: NDArrayFloat = field(init=False)
y_center_of_rotation: NDArrayFloat = field(init=False)
sorted_indices: NDArrayInt = field(init=False)
unsorted_indices: NDArrayInt = field(init=False)
x_center_of_rotation: floris_float_type = field(
init=False, validator=attrs.validators.instance_of(floris_float_type)
)
y_center_of_rotation: floris_float_type = field(
init=False, validator=attrs.validators.instance_of(floris_float_type)
)
sorted_indices: NDArrayInt = field(init=False, validator=validate_3DArray_shape)
unsorted_indices: NDArrayInt = field(init=False, validator=validate_3DArray_shape)

def __attrs_post_init__(self) -> None:
self.set_grid()
Expand Down Expand Up @@ -681,8 +699,12 @@ class PointsGrid(Grid):
points_x: NDArrayFloat = field(converter=floris_array_converter)
points_y: NDArrayFloat = field(converter=floris_array_converter)
points_z: NDArrayFloat = field(converter=floris_array_converter)
x_center_of_rotation: float | None = field(default=None)
y_center_of_rotation: float | None = field(default=None)
x_center_of_rotation: floris_float_type | None = field(
default=None, validator=attrs.validators.instance_of(floris_float_type)
)
y_center_of_rotation: floris_float_type | None = field(
default=None, validator=attrs.validators.instance_of(floris_float_type)
)

def __attrs_post_init__(self) -> None:
self.set_grid()
Expand Down
Loading
Loading