Skip to content

Commit

Permalink
Merge pull request #498 from NREL/develop
Browse files Browse the repository at this point in the history
v3.2
  • Loading branch information
rafmudaf authored Sep 16, 2022
2 parents c2006b0 + 11eece0 commit 0c2adf3
Show file tree
Hide file tree
Showing 98 changed files with 3,020 additions and 1,166 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/check-working-examples.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,10 @@ jobs:
for i in *.py; do
# Skip these examples since they have additional dependencies
if [[ $i == *11* ]]; then
if [[ $i == *15* ]]; then
continue
fi
if [[ $i == *16* ]]; then
if [[ $i == *19* ]]; then
continue
fi
Expand Down
5 changes: 3 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ repos:
stages: [commit]

- repo: https://github.com/psf/black
rev: 21.9b0
rev: 22.6.0
hooks:
- id: black
name: black
Expand All @@ -23,7 +23,7 @@ repos:
# args: [--no-strict-optional, --ignore-missing-imports]

- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.0.1
rev: v4.3.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
Expand All @@ -40,3 +40,4 @@ repos:
rev: '4.0.1'
hooks:
- id: flake8
args: [--max-line-length=120]
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
FLORIS is a controls-focused wind farm simulation software incorporating
steady-state engineering wake models into a performance-focused Python
framework. It has been in active development at NREL since 2013 and the latest
release is [FLORIS v3.1.1](https://github.com/NREL/floris/releases/latest)
release is [FLORIS v3.2](https://github.com/NREL/floris/releases/latest)
in March 2022.

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

DATA
ROOT = PosixPath('/Users/rmudafor/Development/floris')
VERSION = '3.1.1'
VERSION = '3.2'
version_file = <_io.TextIOWrapper name='/Users/rmudafor/Development/fl...

VERSION
3.1.1
3.2

FILE
~/floris/floris/__init__.py
Expand Down
10 changes: 5 additions & 5 deletions docs/_tutorials/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ initial 3x1 layout to a 2x2 rectangular layout.
```python
x_2x2 = [0, 0, 800, 800]
y_2x2 = [0, 400, 0, 400]
fi.reinitialize( layout=(x_2x2, y_2x2) )
fi.reinitialize( layout_x=x_2x2, layout_y=y_2x2 )

x, y = fi.get_turbine_layout()

Expand Down Expand Up @@ -483,9 +483,9 @@ fi_gch = FlorisInterface("inputs/gch.yaml")
fi_cc = FlorisInterface("inputs/cc.yaml")

# Assign the layouts, wind speeds and directions
fi_jensen.reinitialize(layout=(X, Y), wind_directions=wind_directions, wind_speeds=wind_speeds)
fi_gch.reinitialize(layout=(X, Y), wind_directions=wind_directions, wind_speeds=wind_speeds)
fi_cc.reinitialize(layout=(X, Y), wind_directions=wind_directions, wind_speeds=wind_speeds)
fi_jensen.reinitialize(layout_x=X, layout_y=Y, wind_directions=wind_directions, wind_speeds=wind_speeds)
fi_gch.reinitialize(layout_x=X, layout_y=Y, wind_directions=wind_directions, wind_speeds=wind_speeds)
fi_cc.reinitialize(layout_x=X, layout_y=Y, wind_directions=wind_directions, wind_speeds=wind_speeds)

def time_model_calculation(model_fi: FlorisInterface) -> Tuple[float, float]:
"""
Expand Down Expand Up @@ -535,7 +535,7 @@ X = np.linspace(0, 6*7*D, 7)
Y = np.zeros_like(X)
wind_speeds = [8.]
wind_directions = np.arange(0., 360., 2.)
fi_gch.reinitialize(layout=(X, Y), wind_directions=wind_directions, wind_speeds=wind_speeds)
fi_gch.reinitialize(layout_x=X, layout_y=Y, wind_directions=wind_directions, wind_speeds=wind_speeds)
```

```python
Expand Down
6 changes: 3 additions & 3 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ permalink: /
FLORIS is a controls-focused wind farm simulation software incorporating
steady-state engineering wake models into a performance-focused Python
framework. It has been in active development at NREL since 2013 and the latest
release is [FLORIS v3.1.1](https://github.com/NREL/floris/releases/latest)
release is [FLORIS v3.2](https://github.com/NREL/floris/releases/latest)
in March 2022.

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

DATA
ROOT = PosixPath('/Users/rmudafor/Development/floris')
VERSION = '3.1.1'
VERSION = '3.2'
version_file = <_io.TextIOWrapper name='/Users/rmudafor/Development/fl...

VERSION
3.1.1
3.2

FILE
~/floris/floris/__init__.py
Expand Down
59 changes: 31 additions & 28 deletions examples/00_getting_started.ipynb

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion examples/01_opening_floris_computing_power.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
fi = FlorisInterface("inputs/gch.yaml")

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

# Single wind speed and wind direction
print('\n============================= Single Wind Direction and Wind Speed =============================')
Expand Down
2 changes: 1 addition & 1 deletion examples/03_making_adjustments.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
5.0 * fi.floris.farm.rotor_diameters[0][0][0] * np.arange(0, N, 1),
5.0 * fi.floris.farm.rotor_diameters[0][0][0] * np.arange(0, N, 1),
)
fi.reinitialize( layout=( X.flatten(), Y.flatten() ) )
fi.reinitialize(layout_x=X.flatten(), layout_y=Y.flatten())
horizontal_plane = fi.calculate_horizontal_plane(height=90.0)
visualize_cut_plane(horizontal_plane, ax=axarr[3], title="3x3 Farm", minSpeed=MIN_WS, maxSpeed=MAX_WS)

Expand Down
2 changes: 1 addition & 1 deletion examples/04_sweep_wind_directions.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
D = 126.
layout_x = np.array([0, D*6])
layout_y = [0, 0]
fi.reinitialize(layout = [layout_x, layout_y])
fi.reinitialize(layout_x=layout_x, layout_y=layout_y)

# Sweep wind speeds but keep wind direction fixed
wd_array = np.arange(250,291,1.)
Expand Down
2 changes: 1 addition & 1 deletion examples/05_sweep_wind_speeds.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
D = 126.
layout_x = np.array([0, D*6])
layout_y = [0, 0]
fi.reinitialize(layout = [layout_x, layout_y])
fi.reinitialize(layout_x=layout_x, layout_y=layout_y)

# Sweep wind speeds but keep wind direction fixed
ws_array = np.arange(5,25,0.5)
Expand Down
2 changes: 1 addition & 1 deletion examples/06_sweep_wind_conditions.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
D = 126.
layout_x = np.array([0, D*6, D*12, D*18,D*24])
layout_y = [0, 0, 0, 0, 0]
fi.reinitialize(layout = [layout_x, layout_y])
fi.reinitialize(layout_x=layout_x, layout_y=layout_y)

# Define a ws and wd to sweep
# Note that all combinations will be computed
Expand Down
3 changes: 2 additions & 1 deletion examples/07_calc_aep_from_rose.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@
# floris object and assign the layout, wind speed and wind direction arrays.
D = fi.floris.farm.rotor_diameters[0] # Rotor diameter for the NREL 5 MW
fi.reinitialize(
layout=[[0.0, 5* D, 10 * D], [0.0, 0.0, 0.0]],
layout_x=[0.0, 5 * D, 10 * D],
layout_y=[0.0, 0.0, 0.0],
wind_directions=wd_array,
wind_speeds=ws_array,
)
Expand Down
74 changes: 74 additions & 0 deletions examples/08_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()
79 changes: 79 additions & 0 deletions examples/09_compare_farm_power_with_neighbor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# 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
from floris.tools import FlorisInterface
import matplotlib.pyplot as plt

"""
This example demonstrates how to use turbine_wieghts to define a set of turbines belonging to a neighboring farm which
impacts the power production of the farm under consideration via wake losses, but whose own power production is not
considered in farm power / aep production
The use of neighboring farms in the context of wake steering design is considered in example examples/10_optimize_yaw_with_neighboring_farm.py
"""


# Instantiate FLORIS using either the GCH or CC model
fi = FlorisInterface("inputs/gch.yaml") # GCH model matched to the default "legacy_gauss" of V2

# Define a 4 turbine farm turbine farm
D = 126.
layout_x = np.array([0, D*6, 0, D*6])
layout_y = [0, 0, D*3, D*3]
fi.reinitialize(layout_x = layout_x, layout_y = layout_y)

# Define a simple wind rose with just 1 wind speed
wd_array = np.arange(0,360,4.)
fi.reinitialize(wind_directions=wd_array, wind_speeds=[8.])


# Calculate
fi.calculate_wake()

# Collect the farm power
farm_power_base = fi.get_farm_power() / 1E3 # In kW

# Add a neighbor to the east
layout_x = np.array([0, D*6, 0, D*6, D*12, D*15, D*12, D*15])
layout_y = np.array([0, 0, D*3, D*3, 0, 0, D*3, D*3])
fi.reinitialize(layout_x = layout_x, layout_y = layout_y)

# Define the weights to exclude the neighboring farm from calcuations of power
turbine_weights = np.zeros(len(layout_x), dtype=int)
turbine_weights[0:4] = 1.0

# Calculate
fi.calculate_wake()

# Collect the farm power with the neightbor
farm_power_neighbor = fi.get_farm_power(turbine_weights=turbine_weights) / 1E3 # In kW

# Show the farms
fig, ax = plt.subplots()
ax.scatter(layout_x[turbine_weights==1],layout_y[turbine_weights==1], color='k',label='Base Farm')
ax.scatter(layout_x[turbine_weights==0],layout_y[turbine_weights==0], color='r',label='Neighboring Farm')
ax.legend()

# Plot the power difference
fig, ax = plt.subplots()
ax.plot(wd_array,farm_power_base,color='k',label='Farm Power (no neighbor)')
ax.plot(wd_array,farm_power_neighbor,color='r',label='Farm Power (neighboring farm due east)')
ax.grid(True)
ax.legend()
ax.set_xlabel('Wind Direction (deg)')
ax.set_ylabel('Power (kW)')
plt.show()
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@
# Reinitialize as a 3-turbine farm with range of WDs and 1 WS
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]],
layout_x=[0.0, 5 * D, 10 * D],
layout_y=[0.0, 0.0, 0.0],
wind_directions=np.arange(0.0, 360.0, 3.0),
wind_speeds=[8.0],
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@
# Reinitialize as a 3-turbine farm with range of WDs and 1 WS
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]],
layout_x=[0.0, 5 * D, 10 * D],
layout_y=[0.0, 0.0, 0.0],
wind_directions=np.arange(0.0, 360.0, 3.0),
wind_speeds=np.arange(2.0, 18.0, 1.0),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def load_floris():
5.0 * fi.floris.farm.rotor_diameters_sorted[0][0][0] * np.arange(0, N, 1),
5.0 * fi.floris.farm.rotor_diameters_sorted[0][0][0] * np.arange(0, N, 1),
)
fi.reinitialize(layout=(X.flatten(), Y.flatten()))
fi.reinitialize(layout_x=X.flatten(), layout_y=Y.flatten())

return fi

Expand Down
Loading

0 comments on commit 0c2adf3

Please sign in to comment.