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

Bug fix: Scipy layout optimization boundary constraints are violated #576

Merged
merged 3 commits into from
Feb 22, 2023

Conversation

bayc
Copy link
Collaborator

@bayc bayc commented Feb 14, 2023

Feature or improvement description
This PR fixes the issue of boundary constraints not being respected with the Scipy layout optimization tool.

Related issue, if one exists
Closes #575

Impacted areas of the software
layout_optimization_scipy.py

Additional supporting information
This problem was originally identified in discussion #557 by @Rodrig03.

Test results, if applicable
Using the below script, all turbine optimized locations are within the defined boundary.

import os
import numpy as np

from floris.tools import FlorisInterface

from floris.tools.optimization.layout_optimization.layout_optimization_scipy import LayoutOptimizationScipy

# Initialize the FLORIS interface fi
file_dir = os.path.dirname(os.path.abspath(__file__))
fi = FlorisInterface('inputs/gch.yaml')

# Setup 72 wind directions with a random wind speed and frequency distribution
wind_directions = np.arange(0, 360.0, 5.0)
np.random.seed(1)
wind_speeds = 8.0 + np.random.randn(1) * 0.5
# Shape frequency distribution to match number of wind directions and wind speeds
freq = np.abs(np.sort(np.random.randn(len(wind_directions)))).reshape((len(wind_directions), len(wind_speeds)))
freq = freq / freq.sum()

fi.reinitialize(wind_directions=wind_directions, wind_speeds=wind_speeds)

# The boundaries for the turbines, specified as vertices
boundaries = [(0, 0), (0, 1600), (1000, 1600), (1600, 1200), (1600, 0), (0, 0)]

# Set turbine locations to 4 turbines in a rectangle
D = 126.0 # rotor diameter for the NREL 5MW
layout_x = [0, 0, 6 * D, 6 * D]
layout_y = [0, 4 * D, 0, 4 * D]
fi.reinitialize(layout_x=layout_x, layout_y=layout_y)

# Setup the optimization problem
layout_opt = LayoutOptimizationScipy(fi, boundaries, freq=freq)

# Run the optimization
sol = layout_opt.optimize()

# Get the resulting improvement in AEP
print('... calcuating improvement in AEP')
fi.calculate_wake()
base_aep = fi.get_farm_AEP(freq=freq) / 1e6
fi.reinitialize(layout_x=sol[0], layout_y=sol[1])
fi.calculate_wake()
opt_aep = fi.get_farm_AEP(freq=freq) / 1e6
percent_gain = 100 * (opt_aep - base_aep) / base_aep

# Print and plot the results
print('Optimal layout: ', sol)
print('Optimal layout improves AEP by %.1f%% from %.1f MWh to %.1f MWh' % (percent_gain, base_aep, opt_aep))
layout_opt.plot_layout_opt_results()

image

@bayc bayc self-assigned this Feb 14, 2023
@bayc bayc added bug Something isn't working floris.tools labels Feb 14, 2023
@rafmudaf
Copy link
Collaborator

Well done documenting this so well @bayc!

Copy link
Collaborator

@paulf81 paulf81 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to be me too, thanks @bayc !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working floris.tools
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Setting non-rectangular boundaries for layout optimization
3 participants