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

Feature: add FLOWERS wake model to FLORIS #627

Draft
wants to merge 39 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
3263e31
Add function to read in wind rose as csv
paulf81 Mar 15, 2022
8505a68
add aep function which accepts wind rose object
paulf81 Mar 15, 2022
3a07bd7
add an example using wind rose object aep
paulf81 Mar 15, 2022
96671d8
Merge branch 'develop' into feature/wind_rose
paulf81 Apr 7, 2022
1f04082
update how no_wake is passed
paulf81 Apr 7, 2022
0409475
Merge branch 'develop' into feature/wind_rose
paulf81 Apr 27, 2022
15f30d5
preventing negative sqrts that produce NANs in the cumulative model
bayc Apr 27, 2022
34c8475
Merge branch 'feature/wind_rose' of github.com:paulf81/floris into fe…
bayc Apr 27, 2022
8f69053
add the base layout optimization class
bayc Apr 29, 2022
ff66aba
add the scipy layout optimzation class
bayc Apr 29, 2022
21e73c2
add the pyoptsparse layout optimization class
bayc Apr 29, 2022
582d12b
Add label option
paulf81 May 2, 2022
3b36d6a
add x_20 turbine option
paulf81 May 2, 2022
8493320
Add boundary grid functions for layout optimization
bayc May 10, 2022
02b425d
removing print statements
bayc May 12, 2022
c7004a8
adding check for second turbine
bayc May 13, 2022
19d3e31
Merge branch 'feature/optimization_refactor' into feature/wind_rose
paulf81 May 13, 2022
95cdf54
add time limit and storeHistory options
May 26, 2022
18f746b
add hotStart option
paulf81 May 31, 2022
b113df0
call get_farm_aep from within the wind rose ver
paulf81 Jun 1, 2022
104c13c
Merge branch 'feature/wind_rose' of github.com:paulf81/floris into fe…
paulf81 Jun 1, 2022
3622739
add deflection to the turbopark model
bayc Jun 3, 2022
048cc12
Merge branch 'feature/turbo_park_deflection' into feature/wind_rose
bayc Jun 3, 2022
60a5ffc
Add a simplified spreading optimization
paulf81 Jun 4, 2022
48fbb42
Merge remote-tracking branch 'origin/develop' into feature/wind_rose
Jun 22, 2022
54b04e0
Merge branch 'develop' into wind_rose
Jun 29, 2022
894ca22
changes to layout optimization with flowers
Jul 29, 2022
1d94a3a
testing new branch
Jul 29, 2022
44f5a5f
Merge branch 'feature/layout_opt' of https://github.com/locascio-m/fl…
Jul 29, 2022
13730cd
testing changes
Jul 29, 2022
1e3dc32
remote branch testing
Jul 29, 2022
49af1b6
test again
Jul 29, 2022
1e8cf24
snopt finite difference
Aug 1, 2022
6b61549
change to layout optimization
Aug 8, 2022
5d8f78f
Merge branch 'feature/layout_opt' of https://github.com/locascio-m/fl…
Aug 8, 2022
7da56ae
turbine model with constant coefficients
locascio-m Mar 16, 2023
2183858
layout optimization changes
Mar 17, 2023
fe29f84
Merge remote-tracking branch 'origin/develop' into feature/flowers
bayc Apr 18, 2023
f57000b
Merge remote-tracking branch 'origin/develop' into feature/flowers
bayc Jul 12, 2023
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
74 changes: 74 additions & 0 deletions examples/07b_calc_aep_from_rose_use_class.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Copyright 2022 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
import pandas as pd
import matplotlib.pyplot as plt
from scipy.interpolate import NearestNDInterpolator
from floris.tools import FlorisInterface, WindRose, wind_rose

"""
This example demonstrates how to calculate the Annual Energy Production (AEP)
of a wind farm using wind rose information stored in a .csv file.

The wind rose information is first loaded, after which we initialize our Floris
Interface. A 3 turbine farm is generated, and then the turbine wakes and powers
are calculated across all the wind directions. Finally, the farm power is
converted to AEP and reported out.
"""

# Read in the wind rose using the class
wind_rose = WindRose()
wind_rose.read_wind_rose_csv("inputs/wind_rose.csv")

# Show the wind rose
wind_rose.plot_wind_rose()

# Load the FLORIS object
fi = FlorisInterface("inputs/gch.yaml") # GCH model
# fi = FlorisInterface("inputs/cc.yaml") # CumulativeCurl model

# Assume a three-turbine wind farm with 5D spacing. We reinitialize the
# floris object and assign the layout, wind speed and wind direction arrays.
D = 126.0 # Rotor diameter for the NREL 5 MW
fi.reinitialize(
layout=[[0.0, 5* D, 10 * D], [0.0, 0.0, 0.0]]
)

# Compute the AEP using the default settings
aep = fi.get_farm_AEP_wind_rose_class(wind_rose=wind_rose)
print("Farm AEP (default options): {:.3f} GWh".format(aep / 1.0e9))

# Compute the AEP again while specifying a cut-in and cut-out wind speed.
# The wake calculations are skipped for any wind speed below respectively
# above the cut-in and cut-out wind speed. This can speed up computation and
# prevent unexpected behavior for zero/negative and very high wind speeds.
# In this example, the results should not change between this and the default
# call to 'get_farm_AEP()'.
aep = fi.get_farm_AEP_wind_rose_class(
wind_rose=wind_rose,
cut_in_wind_speed=3.0, # Wakes are not evaluated below this wind speed
cut_out_wind_speed=25.0, # Wakes are not evaluated above this wind speed
)
print("Farm AEP (with cut_in/out specified): {:.3f} GWh".format(aep / 1.0e9))

# Finally, we can also compute the AEP while ignoring all wake calculations.
# This can be useful to quantity the annual wake losses in the farm. Such
# calculations can be facilitated by enabling the 'no_wake' handle.
aep_no_wake = fi.get_farm_AEP_wind_rose_class(wind_rose=wind_rose, no_wake=True)
print("Farm AEP (no_wake=True): {:.3f} GWh".format(aep_no_wake / 1.0e9))


plt.show()
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ def __init__(
boundary_spacing=None,
):
self.fi = fi

self.boundary_x = np.array([val[0] for val in boundaries])
self.boundary_y = np.array([val[1] for val in boundaries])
boundary = np.zeros((len(self.boundary_x), 2))
Expand Down Expand Up @@ -224,7 +223,6 @@ def _discrete_grid(
d = np.array([i for x in xlocs for i in row_number])
layout_x = np.array([x for x in xlocs for y in ylocs]) + d*y_spacing*np.tan(shear)
layout_y = np.array([y for x in xlocs for y in ylocs])

# rotate
rotate_x = np.cos(rotation)*layout_x - np.sin(rotation)*layout_y
rotate_y = np.sin(rotation)*layout_x + np.cos(rotation)*layout_y
Expand All @@ -243,7 +241,6 @@ def _discrete_grid(
# arrange final x,y points
return_x = rotate_x[meets_constraints]
return_y = rotate_y[meets_constraints]

return return_x, return_y

def find_lengths(self, x, y, npoints):
Expand Down Expand Up @@ -327,7 +324,6 @@ def _place_boundary_turbines(self, start, boundary_poly, nturbs=None, spacing=No
nBounds = len(xBounds)
lenBound = self.find_lengths(xBounds, yBounds, len(xBounds) - 1)
circumference = sum(lenBound)

if nturbs is not None and spacing is None:
# When the number of boundary turbines is specified
nturbs = int(nturbs)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -226,5 +226,4 @@ def plot_layout_opt_results(self):
plt.plot(
[verts[i][0], verts[i + 1][0]], [verts[i][1], verts[i + 1][1]], "b"
)

plt.show()
30 changes: 24 additions & 6 deletions floris/tools/optimization/legacy/pyoptsparse/optimization.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,14 @@ class Optimization(LoggerBase):
Optimization: An instantiated Optimization object.
"""

def __init__(self, model, solver=None):
def __init__(
self,
model,
solver=None,
storeHistory='hist.hist',
optOptions=None,
timeLimit=None
):
"""
Instantiate Optimization object and its parameters.
"""
Expand All @@ -51,7 +58,11 @@ def __init__(self, model, solver=None):
+ str(self.solver_choices)
)

self.reinitialize(solver=solver)
self.optOptions = optOptions
self.reinitialize(solver=solver, optOptions=optOptions)
self.storeHistory = storeHistory
self.timeLimit = timeLimit


# Private methods

Expand Down Expand Up @@ -85,20 +96,27 @@ def _reinitialize(self, solver=None, optOptions=None):
if self.solver == "SNOPT":
self.optOptions = {"Major optimality tolerance": 1e-7}
else:
self.optOptions = {}
self.optOptions = {"IPRINT": 0}

exec("self.opt = pyoptsparse." + self.solver + "(options=self.optOptions)")

def _optimize(self):
if hasattr(self.model, "_sens"):
self.sol = self.opt(self.optProb, sens=self.model._sens)
else:
self.sol = self.opt(self.optProb, sens="CDR", storeHistory='hist.hist')
if self.timeLimit is not None: #sens="CDR"
self.sol = self.opt(
self.optProb,
storeHistory=self.storeHistory,
timeLimit=self.timeLimit
)
else:
self.sol = self.opt(self.optProb, storeHistory=self.storeHistory)

# Public methods

def reinitialize(self, solver=None):
self._reinitialize(solver=solver)
def reinitialize(self, solver=None, optOptions=None):
self._reinitialize(solver=solver, optOptions=optOptions)

def optimize(self):
self._optimize()
Expand Down
1 change: 1 addition & 0 deletions floris/tools/wind_rose.py
Original file line number Diff line number Diff line change
Expand Up @@ -701,6 +701,7 @@ def make_wind_rose_from_user_data(

return self.df


def read_wind_rose_csv(
self,
filename
Expand Down
164 changes: 164 additions & 0 deletions floris/turbine_library/nrel_5MW_cc.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
turbine_type: 'nrel_5MW'
generator_efficiency: 1.0
hub_height: 90.0
pP: 1.88
pT: 1.88
rotor_diameter: 126.0
TSR: 8.0
power_thrust_table:
power:
- 0.0
- 0.000000
- 0.000000
- 0.43
- 0.43
- 0.43
- 0.43
- 0.43
- 0.43
- 0.43
- 0.43
- 0.43
- 0.43
- 0.43
- 0.43
- 0.43
- 0.43
- 0.43
- 0.43
- 0.43
- 0.43
- 0.43
- 0.43
- 0.43
- 0.43
- 0.43
- 0.43
- 0.43
- 0.43
- 0.43
- 0.43
- 0.43
- 0.43
- 0.43
- 0.43
- 0.43
- 0.43
- 0.43
- 0.43
- 0.43
- 0.43
- 0.43
- 0.43
- 0.43
- 0.43
- 0.43
- 0.43
- 0.43
- 0.43
- 0.0
- 0.0
thrust:
- 0.0
- 0.0
- 0.0
- 0.75
- 0.75
- 0.75
- 0.75
- 0.75
- 0.75
- 0.75
- 0.75
- 0.75
- 0.75
- 0.75
- 0.75
- 0.75
- 0.75
- 0.75
- 0.75
- 0.75
- 0.75
- 0.75
- 0.75
- 0.75
- 0.75
- 0.75
- 0.75
- 0.75
- 0.75
- 0.75
- 0.75
- 0.75
- 0.75
- 0.75
- 0.75
- 0.75
- 0.75
- 0.75
- 0.75
- 0.75
- 0.75
- 0.75
- 0.75
- 0.75
- 0.75
- 0.75
- 0.75
- 0.75
- 0.75
- 0.0
- 0.0
wind_speed:
- 0.0
- 2.0
- 2.5
- 3.0
- 3.5
- 4.0
- 4.5
- 5.0
- 5.5
- 6.0
- 6.5
- 7.0
- 7.5
- 8.0
- 8.5
- 9.0
- 9.5
- 10.0
- 10.5
- 11.0
- 11.5
- 12.0
- 12.5
- 13.0
- 13.5
- 14.0
- 14.5
- 15.0
- 15.5
- 16.0
- 16.5
- 17.0
- 17.5
- 18.0
- 18.5
- 19.0
- 19.5
- 20.0
- 20.5
- 21.0
- 21.5
- 22.0
- 22.5
- 23.0
- 23.5
- 24.0
- 24.5
- 25.0
- 25.01
- 25.02
- 50.0