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

Enable heterogeneous inflows in yaw optimization routines #678

Merged
merged 6 commits into from Jul 11, 2023

Conversation

misi9170
Copy link
Collaborator

@misi9170 misi9170 commented Jul 6, 2023

Neither Serial Refine nor the scipy minimize routine for yaw angle optimization currently work with a heterogeneous inflow (the issue for Serial Refine is identified in #673). This pull request addresses that.

Additionally, turbine.py is updated to allow power to be extrapolated outside of the specified range in the turbine input file. Sampling with a wind speed outside of the interpolation range returns a power of 0. Finally, a minor update is made to turbine.py to warn the user if the rotor_effective_velocities contains any negative entries, which can happen in situations where turbines are very close together.

To reproduce the existing error with heterogeneous inflows and yaw optimizations, run

# Copyright 2021 NREL

# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.

# See https://floris.readthedocs.io for documentation

import numpy as np

from floris.tools import FlorisInterface
from floris.tools.optimization.yaw_optimization.yaw_optimizer_scipy import YawOptimizationScipy
from floris.tools.optimization.yaw_optimization.yaw_optimizer_sr import YawOptimizationSR


"""
This example showcases the heterogeneous inflow capabilities of FLORIS
when multiple wind speeds and direction are considered.
"""


# Define the speed ups of the heterogeneous inflow, and their locations.
# For the 2-dimensional case, this requires x and y locations.
# The speed ups are multipliers of the ambient wind speed.
x_locs = [-300.0, -300.0, 2600.0, 2600.0]
y_locs = [ -300.0, 300.0, -300.0, 300.0]

# Initialize FLORIS with the given input file via FlorisInterface.
# Note the heterogeneous inflow is defined in the input file.
#fi = FlorisInterface("inputs/gch_heterogeneous_inflow.yaml")
fi = FlorisInterface("inputs/gch.yaml")

# Set shear to 0.0 to highlight the heterogeneous inflow
fi.reinitialize(
    wind_shear=0.0,
    wind_speeds=[8.0],
    wind_directions=[270.],
    layout_x=[0, 0],
    layout_y=[-250., 250.],
)

# To change the number of wind directions however it is necessary to make a matching
# change to the dimensions of the het map
speed_multipliers = [[2.0, 1.0, 2.0, 1.0], [2.0, 1.0, 2.0, 1.0]] # Expand to two wind directions
heterogenous_inflow_config = {
    'speed_multipliers': speed_multipliers,
    'x': x_locs,
    'y': y_locs,
}
fi.reinitialize(
    wind_directions=[270.0, 180.0],
    wind_speeds=[8.0],
    heterogenous_inflow_config=heterogenous_inflow_config # Or, None
)
fi.calculate_wake()
turbine_powers = np.round(fi.get_turbine_powers() / 1000.)
print('With wind directions now set to 270 and 180 deg')
print(f'T0: {turbine_powers[:, :, 0].flatten()} kW')
print(f'T1: {turbine_powers[:, :, 1].flatten()} kW')

print("Serial refine:")
yaw_opt = YawOptimizationSR(
    fi=fi,
    minimum_yaw_angle=0.0,  # Allowable yaw angles lower bound
    maximum_yaw_angle=20.0,  # Allowable yaw angles upper bound
    Ny_passes=[5, 4],
    exclude_downstream_turbines=True,
    exploit_layout_symmetry=True,
)

df_opt = yaw_opt.optimize()
print(df_opt)


print("\nScipy optimize:")
yaw_opt = YawOptimizationScipy(
    fi=fi,
    minimum_yaw_angle=0.0,  # Allowable yaw angles lower bound
    maximum_yaw_angle=20.0,  # Allowable yaw angles upper bound
)

df_opt = yaw_opt.optimize()
print(df_opt)

As an example of a negative wind speed raising a power interpolation error, run

import numpy as np

from floris.tools import FlorisInterface

fi = FlorisInterface("inputs/emgauss.yaml")

fi.reinitialize(layout_x = [0, 5*126, 10*126], layout_y = [0, 0, 0], wind_speeds=[3])

# Alter initial wake width to something unreasonably low
fi_dict = fi.floris.as_dict()
fi_dict['wake']['wake_velocity_parameters']['empirical_gauss']\
    ['sigma_0_D'] = 0.01
fi = FlorisInterface(fi_dict)

fi.calculate_wake()

print(fi.get_turbine_powers()/1000)

Closes #673

Ready for review/merge.

@misi9170 misi9170 requested review from paulf81 and rafmudaf July 6, 2023 20:08
@rafmudaf rafmudaf added this to the v3.5 milestone Jul 6, 2023
@rafmudaf rafmudaf added bug Something isn't working enhancement An improvement of an existing feature labels Jul 6, 2023
@misi9170
Copy link
Collaborator Author

Also addresses #457 (earlier version of #673)

@misi9170
Copy link
Collaborator Author

Also addresses discussion #658

@rafmudaf
Copy link
Collaborator

@paulf81 Just checking in whether you want to review this one

@paulf81
Copy link
Collaborator

paulf81 commented Jul 10, 2023

@misi9170 are going to review it together at 1130, thanks for checking!

@rafmudaf rafmudaf merged commit 063d8b5 into NREL:develop Jul 11, 2023
5 checks passed
@rafmudaf rafmudaf mentioned this pull request Oct 26, 2023
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working enhancement An improvement of an existing feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants