Skip to content

Commit

Permalink
Use numpy array for coordinates
Browse files Browse the repository at this point in the history
Rather than a list of Vec3. This supports creating a layout from a dictionary of exported modules and classes rather than having to do the additional step of converting to Vec3.
  • Loading branch information
rafmudaf committed Dec 1, 2023
1 parent 00e8b6b commit 17cad6b
Show file tree
Hide file tree
Showing 7 changed files with 25 additions and 37 deletions.
12 changes: 6 additions & 6 deletions floris/simulation/farm.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ class Farm(BaseClass):
)

turbine_definitions: list = field(init=False, validator=iter_validator(list, dict))
coordinates: List[Vec3] = field(init=False)
turbine_fCts: tuple = field(init=False, default=[])
turbine_fTilts: list = field(init=False, default=[])

Expand Down Expand Up @@ -306,11 +305,6 @@ def construct_turbine_power_interps(self):
def construct_multidim_turbine_power_interps(self):
self.turbine_power_interps = [turb.power_interp for turb in self.turbine_map]

def construct_coordinates(self):
self.coordinates = np.array([
Vec3([x, y, z]) for x, y, z in zip(self.layout_x, self.layout_y, self.hub_heights)
])

def expand_farm_properties(
self,
n_wind_directions: int,
Expand Down Expand Up @@ -501,6 +495,12 @@ def finalize(self, unsorted_indices):
)
self.state.USED

@property
def coordinates(self):
return np.array([
np.array([x, y, z]) for x, y, z in zip(self.layout_x, self.layout_y, self.hub_heights)
])

@property
def n_turbines(self):
return len(self.layout_x)
1 change: 0 additions & 1 deletion floris/simulation/floris.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,6 @@ def __attrs_post_init__(self) -> None:
self.farm.construct_turbine_ref_tilt_cp_cts()
self.farm.construct_turbine_fTilts()
self.farm.construct_turbine_correct_cp_ct_for_tilt()
self.farm.construct_coordinates()
self.farm.set_yaw_angles(self.flow_field.n_wind_directions, self.flow_field.n_wind_speeds)
self.farm.set_tilt_to_ref_tilt(
self.flow_field.n_wind_directions,
Expand Down
26 changes: 10 additions & 16 deletions floris/simulation/grid.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class Grid(ABC):
time_series (:py:obj:`bool`): Flag to indicate whether the supplied wind data is a time
series.
"""
turbine_coordinates: list[Vec3] = field()
turbine_coordinates: NDArrayFloat = field()
turbine_diameters: NDArrayFloat = field(converter=floris_array_converter)
grid_resolution: int | Iterable = field()
wind_directions: NDArrayFloat = field(converter=floris_array_converter)
Expand All @@ -76,7 +76,6 @@ class Grid(ABC):
n_turbines: int = field(init=False)
n_wind_speeds: int = field(init=False)
n_wind_directions: int = field(init=False)
turbine_coordinates_array: NDArrayFloat = field(init=False)
x_sorted: NDArrayFloat = field(init=False)
y_sorted: NDArrayFloat = field(init=False)
z_sorted: NDArrayFloat = field(init=False)
Expand All @@ -85,18 +84,18 @@ class Grid(ABC):
z_sorted_inertial_frame: NDArrayFloat = field(init=False)
cubature_weights: NDArrayFloat = field(init=False, default=None)

def __attrs_post_init__(self) -> None:
self.turbine_coordinates_array = np.array([c.elements for c in self.turbine_coordinates])

@turbine_coordinates.validator
def check_coordinates(self, instance: attrs.Attribute, value: list[Vec3]) -> None:
"""
Ensures all elements are `Vec3` objects and keeps the `n_turbines`
attribute up to date.
"""
types = np.unique([isinstance(c, Vec3) for c in value])
types = np.unique([isinstance(c, np.ndarray) for c in value])
if not all(types):
raise TypeError("'turbine_coordinates' must be `Vec3` objects.")
raise TypeError(
"'turbine_coordinates' must be `np.array` objects "
"with three components of type `float`."
)

self.n_turbines = len(value)

Expand Down Expand Up @@ -158,7 +157,6 @@ class TurbineGrid(Grid):
average_method = "cubic-mean"

def __attrs_post_init__(self) -> None:
super().__attrs_post_init__()
self.set_grid()

def set_grid(self) -> None:
Expand Down Expand Up @@ -217,7 +215,7 @@ def set_grid(self) -> None:
# These are the rotated coordinates of the wind turbines based on the wind direction
x, y, z, self.x_center_of_rotation, self.y_center_of_rotation = rotate_coordinates_rel_west(
self.wind_directions,
self.turbine_coordinates_array,
self.turbine_coordinates,
)

# - **rloc** (*float, optional): A value, from 0 to 1, that determines
Expand Down Expand Up @@ -318,7 +316,6 @@ class TurbineCubatureGrid(Grid):
average_method = "simple-cubature"

def __attrs_post_init__(self) -> None:
super().__attrs_post_init__()
self.set_grid()

def set_grid(self) -> None:
Expand All @@ -327,7 +324,7 @@ def set_grid(self) -> None:
# These are the rotated coordinates of the wind turbines based on the wind direction
x, y, z, self.x_center_of_rotation, self.y_center_of_rotation = rotate_coordinates_rel_west(
self.wind_directions,
self.turbine_coordinates_array
self.turbine_coordinates
)

# Coefficients
Expand Down Expand Up @@ -474,7 +471,6 @@ class FlowFieldGrid(Grid):
y_center_of_rotation: NDArrayFloat = field(init=False)

def __attrs_post_init__(self) -> None:
super().__attrs_post_init__()
self.set_grid()

def set_grid(self) -> None:
Expand All @@ -496,7 +492,7 @@ def set_grid(self) -> None:
# These are the rotated coordinates of the wind turbines based on the wind direction
x, y, z, self.x_center_of_rotation, self.y_center_of_rotation = rotate_coordinates_rel_west(
self.wind_directions,
self.turbine_coordinates_array
self.turbine_coordinates
)

# Construct the arrays storing the grid points
Expand Down Expand Up @@ -549,7 +545,6 @@ class FlowFieldPlanarGrid(Grid):
unsorted_indices: NDArrayInt = field(init=False)

def __attrs_post_init__(self) -> None:
super().__attrs_post_init__()
self.set_grid()

def set_grid(self) -> None:
Expand All @@ -570,7 +565,7 @@ def set_grid(self) -> None:
# These are the rotated coordinates of the wind turbines based on the wind direction
x, y, z, self.x_center_of_rotation, self.y_center_of_rotation = rotate_coordinates_rel_west(
self.wind_directions,
self.turbine_coordinates_array
self.turbine_coordinates
)
max_diameter = np.max(self.turbine_diameters)

Expand Down Expand Up @@ -675,7 +670,6 @@ class PointsGrid(Grid):
y_center_of_rotation: float | None = field(default=None)

def __attrs_post_init__(self) -> None:
super().__attrs_post_init__()
self.set_grid()

def set_grid(self) -> None:
Expand Down
4 changes: 0 additions & 4 deletions floris/simulation/solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,6 @@ def full_flow_sequential_solver(
turbine_grid_farm.construct_turbine_ref_tilt_cp_cts()
turbine_grid_farm.construct_turbine_fTilts()
turbine_grid_farm.construct_turbine_correct_cp_ct_for_tilt()
turbine_grid_farm.construct_coordinates()
turbine_grid_farm.set_tilt_to_ref_tilt(flow_field.n_wind_directions, flow_field.n_wind_speeds)

turbine_grid = TurbineGrid(
Expand Down Expand Up @@ -690,7 +689,6 @@ def full_flow_cc_solver(
turbine_grid_farm.construct_turbine_ref_tilt_cp_cts()
turbine_grid_farm.construct_turbine_fTilts()
turbine_grid_farm.construct_turbine_correct_cp_ct_for_tilt()
turbine_grid_farm.construct_coordinates()
turbine_grid_farm.set_tilt_to_ref_tilt(flow_field.n_wind_directions, flow_field.n_wind_speeds)

turbine_grid = TurbineGrid(
Expand Down Expand Up @@ -1125,7 +1123,6 @@ def full_flow_turbopark_solver(
# turbine_grid_farm.construct_rotor_diameters()
# turbine_grid_farm.construct_turbine_TSRs()
# turbine_grid_farm.construc_turbine_pPs()
# turbine_grid_farm.construct_coordinates()

# turbine_grid = TurbineGrid(
# turbine_coordinates=turbine_grid_farm.coordinates,
Expand Down Expand Up @@ -1368,7 +1365,6 @@ def full_flow_empirical_gauss_solver(
turbine_grid_farm.construct_turbine_ref_tilt_cp_cts()
turbine_grid_farm.construct_turbine_fTilts()
turbine_grid_farm.construct_turbine_correct_cp_ct_for_tilt()
turbine_grid_farm.construct_coordinates()
turbine_grid_farm.set_tilt_to_ref_tilt(flow_field.n_wind_directions, flow_field.n_wind_speeds)

turbine_grid = TurbineGrid(
Expand Down
4 changes: 2 additions & 2 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ def flow_field_fixture(sample_inputs_fixture):

@pytest.fixture
def turbine_grid_fixture(sample_inputs_fixture) -> TurbineGrid:
turbine_coordinates = [Vec3(c) for c in list(zip(X_COORDS, Y_COORDS, Z_COORDS))]
turbine_coordinates = np.array([np.array([c]) for c in list(zip(X_COORDS, Y_COORDS, Z_COORDS))])

# TODO: The TurbineGrid requires that the rotor diameters be 1d but the
# Farm constructs them as 3d
Expand All @@ -137,7 +137,7 @@ def turbine_grid_fixture(sample_inputs_fixture) -> TurbineGrid:

@pytest.fixture
def flow_field_grid_fixture(sample_inputs_fixture) -> FlowFieldGrid:
turbine_coordinates = [Vec3(c) for c in list(zip(X_COORDS, Y_COORDS, Z_COORDS))]
turbine_coordinates = np.array([np.array([c]) for c in list(zip(X_COORDS, Y_COORDS, Z_COORDS))])
rotor_diameters = ROTOR_DIAMETER * np.ones( (N_WIND_DIRECTIONS, N_WIND_SPEEDS, N_TURBINES) )
return FlowFieldGrid(
turbine_coordinates=turbine_coordinates,
Expand Down
5 changes: 1 addition & 4 deletions tests/farm_unit_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def test_farm_init_homogenous_turbines():
layout_x = farm_data["layout_x"]
layout_y = farm_data["layout_y"]
coordinates = np.array([
Vec3([x, y, turbine_data["hub_height"]])
np.array([x, y, turbine_data["hub_height"]])
for x, y in zip(layout_x, layout_y)
])

Expand All @@ -49,7 +49,6 @@ def test_farm_init_homogenous_turbines():
# turbine_type=[turbine_data["turbine_type"]]

farm.construct_hub_heights()
farm.construct_coordinates()
farm.set_yaw_angles(N_WIND_DIRECTIONS, N_WIND_SPEEDS)

# Check initial values
Expand All @@ -61,15 +60,13 @@ def test_farm_init_homogenous_turbines():
def test_asdict(sample_inputs_fixture: SampleInputs):
farm = Farm.from_dict(sample_inputs_fixture.farm)
farm.construct_hub_heights()
farm.construct_coordinates()
farm.construct_turbine_ref_tilt_cp_cts()
farm.set_yaw_angles(N_WIND_DIRECTIONS, N_WIND_SPEEDS)
farm.set_tilt_to_ref_tilt(N_WIND_DIRECTIONS, N_WIND_SPEEDS)
dict1 = farm.as_dict()

new_farm = farm.from_dict(dict1)
new_farm.construct_hub_heights()
new_farm.construct_coordinates()
new_farm.construct_turbine_ref_tilt_cp_cts()
new_farm.set_yaw_angles(N_WIND_DIRECTIONS, N_WIND_SPEEDS)
new_farm.set_tilt_to_ref_tilt(N_WIND_DIRECTIONS, N_WIND_SPEEDS)
Expand Down
10 changes: 6 additions & 4 deletions tests/turbine_grid_unit_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,14 +83,16 @@ def test_dynamic_properties(turbine_grid_fixture):
assert turbine_grid_fixture.n_wind_speeds == N_WIND_SPEEDS
assert turbine_grid_fixture.n_wind_directions == N_WIND_DIRECTIONS

# TODO: @Rob @Chris This breaks n_turbines since the validator is not run.
# TODO: The following two lines break n_turbines since the validator is not run.
# Is this case ok? Do we enforce that turbine_coordinates must be set by =?
# turbine_grid_fixture.turbine_coordinates.append(Vec3([100.0, 200.0, 300.0]))
# assert turbine_grid_fixture.n_turbines == N_TURBINES + 1

turbine_grid_fixture.turbine_coordinates = [
*turbine_grid_fixture.turbine_coordinates, Vec3([100.0, 200.0, 300.0])
]
turbine_grid_fixture.turbine_coordinates = np.append(
turbine_grid_fixture.turbine_coordinates,
np.array([[[100.0, 200.0, 300.0]]]),
axis=0
)
assert turbine_grid_fixture.n_turbines == N_TURBINES + 1

turbine_grid_fixture.wind_speeds = [*turbine_grid_fixture.wind_speeds, 0.0]
Expand Down

0 comments on commit 17cad6b

Please sign in to comment.