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

v3.2 #498

Merged
merged 25 commits into from
Sep 16, 2022
Merged

v3.2 #498

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
0697c37
Expand functionalities of UncertaintyInterface and fix no_wake compat…
May 26, 2022
1d094cd
Remove commented and legacy code in floris_interface.py (#397)
May 26, 2022
e825493
Remove BaseModel.model_string attribute
rafmudaf May 27, 2022
5dea659
Remove unused code and clean up imports
rafmudaf May 27, 2022
f30abbc
Merge pull request #437 from rafmudaf/develop
rafmudaf Jun 1, 2022
ec7483d
Merge branch 'main' into develop
bayc Jun 2, 2022
4feaea3
Enabling vectorized time series calculation of wind conditions (#400)
bayc Jun 3, 2022
ce5245e
Add method for returning turbine turbulence intensities (#452)
bayc Jun 29, 2022
a34c6c8
Add example of getting wind speeds at turbines (#423)
paulf81 Jul 18, 2022
a9d024f
bugfix: pass in het map when copying fi (#456)
paulf81 Jul 27, 2022
cb1f54f
Bugfix: Convert `layout` to `layout_x` and `layout_y` in `FlorisInter…
RHammond2 Jul 27, 2022
3cca335
Issue alert if calc wake needs to be run (#432)
paulf81 Jul 27, 2022
27e7691
Bugfix: update plot_turbines_with_fi API (#445)
pjireland Jul 27, 2022
1d73401
Add wake deflection to the TurbOPark wake deficit model (#439)
bayc Jul 27, 2022
58fe45d
Add a forced max of 3 to turbine grid points (#472)
paulf81 Jul 28, 2022
c3bf314
Update profiling script API and problem size
rafmudaf Aug 9, 2022
5f1ab65
calculate dudz_initial analytically to support using only 1 rotor gri…
bayc Aug 12, 2022
35899f2
Add turbine_weights option in get_farm_power and get_farm_aep (#435)
Aug 12, 2022
3e2d0d2
Layout optimization tools refactoring (#429)
bayc Aug 13, 2022
9fa6c38
Feature/add ref density (#398)
paulf81 Sep 8, 2022
647ed14
Update wind rose and power rose (#392)
paulf81 Sep 8, 2022
d75333e
Merge branch 'main' into develop
rafmudaf Sep 9, 2022
a7cf49c
add ref density to reader (#497)
paulf81 Sep 12, 2022
ab65590
Update version to v3.2
rafmudaf Sep 12, 2022
11eece0
adding missing time_series flag to cc flow field solver call (#493)
bayc Sep 16, 2022
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
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