Skip to content

Commit 0c2adf3

Browse files
authored
Merge pull request #498 from NREL/develop
v3.2
2 parents c2006b0 + 11eece0 commit 0c2adf3

File tree

98 files changed

+3020
-1166
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

98 files changed

+3020
-1166
lines changed

.github/workflows/check-working-examples.yaml

+2-2
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,10 @@ jobs:
3636
for i in *.py; do
3737
3838
# Skip these examples since they have additional dependencies
39-
if [[ $i == *11* ]]; then
39+
if [[ $i == *15* ]]; then
4040
continue
4141
fi
42-
if [[ $i == *16* ]]; then
42+
if [[ $i == *19* ]]; then
4343
continue
4444
fi
4545

.pre-commit-config.yaml

+3-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ repos:
77
stages: [commit]
88

99
- repo: https://github.com/psf/black
10-
rev: 21.9b0
10+
rev: 22.6.0
1111
hooks:
1212
- id: black
1313
name: black
@@ -23,7 +23,7 @@ repos:
2323
# args: [--no-strict-optional, --ignore-missing-imports]
2424

2525
- repo: https://github.com/pre-commit/pre-commit-hooks
26-
rev: v4.0.1
26+
rev: v4.3.0
2727
hooks:
2828
- id: trailing-whitespace
2929
- id: end-of-file-fixer
@@ -40,3 +40,4 @@ repos:
4040
rev: '4.0.1'
4141
hooks:
4242
- id: flake8
43+
args: [--max-line-length=120]

README.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
FLORIS is a controls-focused wind farm simulation software incorporating
44
steady-state engineering wake models into a performance-focused Python
55
framework. It has been in active development at NREL since 2013 and the latest
6-
release is [FLORIS v3.1.1](https://github.com/NREL/floris/releases/latest)
6+
release is [FLORIS v3.2](https://github.com/NREL/floris/releases/latest)
77
in March 2022.
88

99
The software is in active development and engagement with the development team
@@ -76,11 +76,11 @@ and importing FLORIS:
7676

7777
DATA
7878
ROOT = PosixPath('/Users/rmudafor/Development/floris')
79-
VERSION = '3.1.1'
79+
VERSION = '3.2'
8080
version_file = <_io.TextIOWrapper name='/Users/rmudafor/Development/fl...
8181

8282
VERSION
83-
3.1.1
83+
3.2
8484

8585
FILE
8686
~/floris/floris/__init__.py

docs/_tutorials/index.md

+5-5
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ initial 3x1 layout to a 2x2 rectangular layout.
6969
```python
7070
x_2x2 = [0, 0, 800, 800]
7171
y_2x2 = [0, 400, 0, 400]
72-
fi.reinitialize( layout=(x_2x2, y_2x2) )
72+
fi.reinitialize( layout_x=x_2x2, layout_y=y_2x2 )
7373

7474
x, y = fi.get_turbine_layout()
7575

@@ -483,9 +483,9 @@ fi_gch = FlorisInterface("inputs/gch.yaml")
483483
fi_cc = FlorisInterface("inputs/cc.yaml")
484484

485485
# Assign the layouts, wind speeds and directions
486-
fi_jensen.reinitialize(layout=(X, Y), wind_directions=wind_directions, wind_speeds=wind_speeds)
487-
fi_gch.reinitialize(layout=(X, Y), wind_directions=wind_directions, wind_speeds=wind_speeds)
488-
fi_cc.reinitialize(layout=(X, Y), wind_directions=wind_directions, wind_speeds=wind_speeds)
486+
fi_jensen.reinitialize(layout_x=X, layout_y=Y, wind_directions=wind_directions, wind_speeds=wind_speeds)
487+
fi_gch.reinitialize(layout_x=X, layout_y=Y, wind_directions=wind_directions, wind_speeds=wind_speeds)
488+
fi_cc.reinitialize(layout_x=X, layout_y=Y, wind_directions=wind_directions, wind_speeds=wind_speeds)
489489

490490
def time_model_calculation(model_fi: FlorisInterface) -> Tuple[float, float]:
491491
"""
@@ -535,7 +535,7 @@ X = np.linspace(0, 6*7*D, 7)
535535
Y = np.zeros_like(X)
536536
wind_speeds = [8.]
537537
wind_directions = np.arange(0., 360., 2.)
538-
fi_gch.reinitialize(layout=(X, Y), wind_directions=wind_directions, wind_speeds=wind_speeds)
538+
fi_gch.reinitialize(layout_x=X, layout_y=Y, wind_directions=wind_directions, wind_speeds=wind_speeds)
539539
```
540540

541541
```python

docs/index.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ permalink: /
1212
FLORIS is a controls-focused wind farm simulation software incorporating
1313
steady-state engineering wake models into a performance-focused Python
1414
framework. It has been in active development at NREL since 2013 and the latest
15-
release is [FLORIS v3.1.1](https://github.com/NREL/floris/releases/latest)
15+
release is [FLORIS v3.2](https://github.com/NREL/floris/releases/latest)
1616
in March 2022.
1717

1818
The software is in active development and engagement with the development team
@@ -85,11 +85,11 @@ and importing FLORIS:
8585

8686
DATA
8787
ROOT = PosixPath('/Users/rmudafor/Development/floris')
88-
VERSION = '3.1.1'
88+
VERSION = '3.2'
8989
version_file = <_io.TextIOWrapper name='/Users/rmudafor/Development/fl...
9090

9191
VERSION
92-
3.1.1
92+
3.2
9393

9494
FILE
9595
~/floris/floris/__init__.py

examples/00_getting_started.ipynb

+31-28
Large diffs are not rendered by default.

examples/01_opening_floris_computing_power.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
fi = FlorisInterface("inputs/gch.yaml")
3434

3535
# Convert to a simple two turbine layout
36-
fi.reinitialize( layout=( [0, 500.], [0., 0.] ) )
36+
fi.reinitialize(layout_x=[0, 500.], layout_y=[0., 0.])
3737

3838
# Single wind speed and wind direction
3939
print('\n============================= Single Wind Direction and Wind Speed =============================')

examples/03_making_adjustments.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858
5.0 * fi.floris.farm.rotor_diameters[0][0][0] * np.arange(0, N, 1),
5959
5.0 * fi.floris.farm.rotor_diameters[0][0][0] * np.arange(0, N, 1),
6060
)
61-
fi.reinitialize( layout=( X.flatten(), Y.flatten() ) )
61+
fi.reinitialize(layout_x=X.flatten(), layout_y=Y.flatten())
6262
horizontal_plane = fi.calculate_horizontal_plane(height=90.0)
6363
visualize_cut_plane(horizontal_plane, ax=axarr[3], title="3x3 Farm", minSpeed=MIN_WS, maxSpeed=MAX_WS)
6464

examples/04_sweep_wind_directions.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
D = 126.
4141
layout_x = np.array([0, D*6])
4242
layout_y = [0, 0]
43-
fi.reinitialize(layout = [layout_x, layout_y])
43+
fi.reinitialize(layout_x=layout_x, layout_y=layout_y)
4444

4545
# Sweep wind speeds but keep wind direction fixed
4646
wd_array = np.arange(250,291,1.)

examples/05_sweep_wind_speeds.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
D = 126.
4141
layout_x = np.array([0, D*6])
4242
layout_y = [0, 0]
43-
fi.reinitialize(layout = [layout_x, layout_y])
43+
fi.reinitialize(layout_x=layout_x, layout_y=layout_y)
4444

4545
# Sweep wind speeds but keep wind direction fixed
4646
ws_array = np.arange(5,25,0.5)

examples/06_sweep_wind_conditions.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
D = 126.
4343
layout_x = np.array([0, D*6, D*12, D*18,D*24])
4444
layout_y = [0, 0, 0, 0, 0]
45-
fi.reinitialize(layout = [layout_x, layout_y])
45+
fi.reinitialize(layout_x=layout_x, layout_y=layout_y)
4646

4747
# Define a ws and wd to sweep
4848
# Note that all combinations will be computed

examples/07_calc_aep_from_rose.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@
5656
# floris object and assign the layout, wind speed and wind direction arrays.
5757
D = fi.floris.farm.rotor_diameters[0] # Rotor diameter for the NREL 5 MW
5858
fi.reinitialize(
59-
layout=[[0.0, 5* D, 10 * D], [0.0, 0.0, 0.0]],
59+
layout_x=[0.0, 5 * D, 10 * D],
60+
layout_y=[0.0, 0.0, 0.0],
6061
wind_directions=wd_array,
6162
wind_speeds=ws_array,
6263
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# Copyright 2022 NREL
2+
3+
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
4+
# use this file except in compliance with the License. You may obtain a copy of
5+
# the License at http://www.apache.org/licenses/LICENSE-2.0
6+
7+
# Unless required by applicable law or agreed to in writing, software
8+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10+
# License for the specific language governing permissions and limitations under
11+
# the License.
12+
13+
# See https://floris.readthedocs.io for documentation
14+
15+
16+
import numpy as np
17+
import pandas as pd
18+
import matplotlib.pyplot as plt
19+
from scipy.interpolate import NearestNDInterpolator
20+
from floris.tools import FlorisInterface, WindRose, wind_rose
21+
22+
"""
23+
This example demonstrates how to calculate the Annual Energy Production (AEP)
24+
of a wind farm using wind rose information stored in a .csv file.
25+
26+
The wind rose information is first loaded, after which we initialize our Floris
27+
Interface. A 3 turbine farm is generated, and then the turbine wakes and powers
28+
are calculated across all the wind directions. Finally, the farm power is
29+
converted to AEP and reported out.
30+
"""
31+
32+
# Read in the wind rose using the class
33+
wind_rose = WindRose()
34+
wind_rose.read_wind_rose_csv("inputs/wind_rose.csv")
35+
36+
# Show the wind rose
37+
wind_rose.plot_wind_rose()
38+
39+
# Load the FLORIS object
40+
fi = FlorisInterface("inputs/gch.yaml") # GCH model
41+
# fi = FlorisInterface("inputs/cc.yaml") # CumulativeCurl model
42+
43+
# Assume a three-turbine wind farm with 5D spacing. We reinitialize the
44+
# floris object and assign the layout, wind speed and wind direction arrays.
45+
D = 126.0 # Rotor diameter for the NREL 5 MW
46+
fi.reinitialize(
47+
layout=[[0.0, 5* D, 10 * D], [0.0, 0.0, 0.0]]
48+
)
49+
50+
# Compute the AEP using the default settings
51+
aep = fi.get_farm_AEP_wind_rose_class(wind_rose=wind_rose)
52+
print("Farm AEP (default options): {:.3f} GWh".format(aep / 1.0e9))
53+
54+
# Compute the AEP again while specifying a cut-in and cut-out wind speed.
55+
# The wake calculations are skipped for any wind speed below respectively
56+
# above the cut-in and cut-out wind speed. This can speed up computation and
57+
# prevent unexpected behavior for zero/negative and very high wind speeds.
58+
# In this example, the results should not change between this and the default
59+
# call to 'get_farm_AEP()'.
60+
aep = fi.get_farm_AEP_wind_rose_class(
61+
wind_rose=wind_rose,
62+
cut_in_wind_speed=3.0, # Wakes are not evaluated below this wind speed
63+
cut_out_wind_speed=25.0, # Wakes are not evaluated above this wind speed
64+
)
65+
print("Farm AEP (with cut_in/out specified): {:.3f} GWh".format(aep / 1.0e9))
66+
67+
# Finally, we can also compute the AEP while ignoring all wake calculations.
68+
# This can be useful to quantity the annual wake losses in the farm. Such
69+
# calculations can be facilitated by enabling the 'no_wake' handle.
70+
aep_no_wake = fi.get_farm_AEP_wind_rose_class(wind_rose=wind_rose, no_wake=True)
71+
print("Farm AEP (no_wake=True): {:.3f} GWh".format(aep_no_wake / 1.0e9))
72+
73+
74+
plt.show()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# Copyright 2022 NREL
2+
3+
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
4+
# use this file except in compliance with the License. You may obtain a copy of
5+
# the License at http://www.apache.org/licenses/LICENSE-2.0
6+
7+
# Unless required by applicable law or agreed to in writing, software
8+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10+
# License for the specific language governing permissions and limitations under
11+
# the License.
12+
13+
# See https://floris.readthedocs.io for documentation
14+
15+
16+
import numpy as np
17+
import pandas as pd
18+
from floris.tools import FlorisInterface
19+
import matplotlib.pyplot as plt
20+
21+
"""
22+
This example demonstrates how to use turbine_wieghts to define a set of turbines belonging to a neighboring farm which
23+
impacts the power production of the farm under consideration via wake losses, but whose own power production is not
24+
considered in farm power / aep production
25+
26+
The use of neighboring farms in the context of wake steering design is considered in example examples/10_optimize_yaw_with_neighboring_farm.py
27+
"""
28+
29+
30+
# Instantiate FLORIS using either the GCH or CC model
31+
fi = FlorisInterface("inputs/gch.yaml") # GCH model matched to the default "legacy_gauss" of V2
32+
33+
# Define a 4 turbine farm turbine farm
34+
D = 126.
35+
layout_x = np.array([0, D*6, 0, D*6])
36+
layout_y = [0, 0, D*3, D*3]
37+
fi.reinitialize(layout_x = layout_x, layout_y = layout_y)
38+
39+
# Define a simple wind rose with just 1 wind speed
40+
wd_array = np.arange(0,360,4.)
41+
fi.reinitialize(wind_directions=wd_array, wind_speeds=[8.])
42+
43+
44+
# Calculate
45+
fi.calculate_wake()
46+
47+
# Collect the farm power
48+
farm_power_base = fi.get_farm_power() / 1E3 # In kW
49+
50+
# Add a neighbor to the east
51+
layout_x = np.array([0, D*6, 0, D*6, D*12, D*15, D*12, D*15])
52+
layout_y = np.array([0, 0, D*3, D*3, 0, 0, D*3, D*3])
53+
fi.reinitialize(layout_x = layout_x, layout_y = layout_y)
54+
55+
# Define the weights to exclude the neighboring farm from calcuations of power
56+
turbine_weights = np.zeros(len(layout_x), dtype=int)
57+
turbine_weights[0:4] = 1.0
58+
59+
# Calculate
60+
fi.calculate_wake()
61+
62+
# Collect the farm power with the neightbor
63+
farm_power_neighbor = fi.get_farm_power(turbine_weights=turbine_weights) / 1E3 # In kW
64+
65+
# Show the farms
66+
fig, ax = plt.subplots()
67+
ax.scatter(layout_x[turbine_weights==1],layout_y[turbine_weights==1], color='k',label='Base Farm')
68+
ax.scatter(layout_x[turbine_weights==0],layout_y[turbine_weights==0], color='r',label='Neighboring Farm')
69+
ax.legend()
70+
71+
# Plot the power difference
72+
fig, ax = plt.subplots()
73+
ax.plot(wd_array,farm_power_base,color='k',label='Farm Power (no neighbor)')
74+
ax.plot(wd_array,farm_power_neighbor,color='r',label='Farm Power (neighboring farm due east)')
75+
ax.grid(True)
76+
ax.legend()
77+
ax.set_xlabel('Wind Direction (deg)')
78+
ax.set_ylabel('Power (kW)')
79+
plt.show()

examples/08_opt_yaw_single_ws.py examples/10_opt_yaw_single_ws.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@
3232
# Reinitialize as a 3-turbine farm with range of WDs and 1 WS
3333
D = 126.0 # Rotor diameter for the NREL 5 MW
3434
fi.reinitialize(
35-
layout=[[0.0, 5 * D, 10 * D], [0.0, 0.0, 0.0]],
35+
layout_x=[0.0, 5 * D, 10 * D],
36+
layout_y=[0.0, 0.0, 0.0],
3637
wind_directions=np.arange(0.0, 360.0, 3.0),
3738
wind_speeds=[8.0],
3839
)

examples/09_opt_yaw_multiple_ws.py examples/11_opt_yaw_multiple_ws.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@
3232
# Reinitialize as a 3-turbine farm with range of WDs and 1 WS
3333
D = 126.0 # Rotor diameter for the NREL 5 MW
3434
fi.reinitialize(
35-
layout=[[0.0, 5 * D, 10 * D], [0.0, 0.0, 0.0]],
35+
layout_x=[0.0, 5 * D, 10 * D],
36+
layout_y=[0.0, 0.0, 0.0],
3637
wind_directions=np.arange(0.0, 360.0, 3.0),
3738
wind_speeds=np.arange(2.0, 18.0, 1.0),
3839
)

examples/10_optimize_yaw.py examples/12_optimize_yaw.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ def load_floris():
4545
5.0 * fi.floris.farm.rotor_diameters_sorted[0][0][0] * np.arange(0, N, 1),
4646
5.0 * fi.floris.farm.rotor_diameters_sorted[0][0][0] * np.arange(0, N, 1),
4747
)
48-
fi.reinitialize(layout=(X.flatten(), Y.flatten()))
48+
fi.reinitialize(layout_x=X.flatten(), layout_y=Y.flatten())
4949

5050
return fi
5151

0 commit comments

Comments
 (0)