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

Add and rearange initial example #322

Merged
merged 42 commits into from
Feb 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
77ff47c
Add streamlit example
paulf81 Feb 10, 2022
2f08df4
clear comments
paulf81 Feb 10, 2022
0e1d486
clear comments
paulf81 Feb 10, 2022
81a6d60
Merge branch 'feature/add_streamlit' of github.com:paulf81/floris int…
paulf81 Feb 10, 2022
2cdd543
add example 00
paulf81 Feb 10, 2022
fc3fcb2
Add markers to the plot
rafmudaf Feb 11, 2022
f858f0d
Merge branch 'v3' into feature/add_streamlit
paulf81 Feb 14, 2022
b9ec583
split example
paulf81 Feb 15, 2022
746877e
Merge branch 'v3' into feature/add_streamlit
paulf81 Feb 15, 2022
4af4db5
Merge branch 'v3' into feature/add_new_initial_example
paulf81 Feb 16, 2022
db02d6e
Merge branch 'feature/add_streamlit' into feature/add_new_initial_exa…
paulf81 Feb 16, 2022
5e04a54
Add getting started notebook
paulf81 Feb 16, 2022
8fe54a2
Merge branch 'v3' into feature/add_new_initial_example
paulf81 Feb 18, 2022
f19baa5
adding grid visualization to notebook
paulf81 Feb 18, 2022
1b516c5
Merge branch 'v3' into feature/add_new_initial_example
paulf81 Feb 21, 2022
e0a976d
Update examples to new visualization standards
paulf81 Feb 21, 2022
66fc975
update notebook
paulf81 Feb 22, 2022
48c66a3
Remove references to json
paulf81 Feb 22, 2022
5490fe7
add yaw optimization example
paulf81 Feb 22, 2022
49ec561
changes to the getting_started notebook
bayc Feb 22, 2022
e7ee5e4
remove commented code
paulf81 Feb 23, 2022
121af48
Remove commented code
paulf81 Feb 23, 2022
c6c9fec
small edits
paulf81 Feb 23, 2022
4096a3a
Merge branch 'v3' into feature/add_new_initial_example
paulf81 Feb 23, 2022
5db45d8
avoid calculating 0 m/s
paulf81 Feb 23, 2022
3d366a4
copy dataframes
paulf81 Feb 23, 2022
9bc0f52
update getting started
paulf81 Feb 23, 2022
043bbeb
Merge branch 'v3' into feature/add_new_initial_example
paulf81 Feb 23, 2022
f832d8b
Update notebook
paulf81 Feb 23, 2022
bbbff41
modify example 2
paulf81 Feb 23, 2022
6e3463d
Merge branch 'v3' into pr/paulf81/322
rafmudaf Feb 24, 2022
a5d056e
Merge branch 'main' into pr/paulf81/322
rafmudaf Feb 27, 2022
4938258
Update overview
rafmudaf Feb 27, 2022
cd8d471
Merge branch 'main' into pr/paulf81/322
rafmudaf Feb 28, 2022
30c8034
Merge branch 'main' into pr/paulf81/322
rafmudaf Feb 28, 2022
553b187
Rename examples in sequence
rafmudaf Feb 28, 2022
1c8694e
Update overview notebook
rafmudaf Feb 28, 2022
2be0c8e
Merge branch 'main' into pr/paulf81/322
rafmudaf Feb 28, 2022
f0ff597
correct cp
paulf81 Feb 28, 2022
70e9f2b
updating the examples for the latest code changes
bayc Feb 28, 2022
79603d6
adding missing crossstream_dist
bayc Feb 28, 2022
70a365c
ignore slsqp outputs
paulf81 Feb 28, 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: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ pip-wheel-metadata
examples/cp_ct_cq_lut.p
_site/
.jekyll-cache/
examples/hist.hist
examples/SLSQP.out

# Log files
*.log
*.log
1,008 changes: 1,008 additions & 0 deletions examples/00_getting_started.ipynb

Large diffs are not rendered by default.

78 changes: 78 additions & 0 deletions examples/01_opening_floris_computing_power.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Copyright 2021 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 matplotlib.pyplot as plt
import numpy as np

from floris.tools import FlorisInterface

"""
This example creates a FLORIS instance
1) Makes a two-turbine layout
2) Demonstrates single ws/wd simulations
3) Demonstrates mulitple ws/wd simulations

Main concept is introduce FLORIS and illustrate essential structure of most-used FLORIS calls
"""

# Initialize FLORIS with the given input file via FlorisInterface.
# For basic usage, FlorisInterface provides a simplified and expressive
# entry point to the simulation routines.
fi = FlorisInterface("inputs/gch.yaml")

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

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

# Get the turbine powers assuming 1 wind speed and 1 wind direction
fi.reinitialize(wind_directions=[270.], wind_speeds=[8.0])

# Set the yaw angles to 0
yaw_angles = np.zeros([1,1,2]) # 1 wind direction, 1 wind speed, 2 turbines
fi.calculate_wake(yaw_angles=yaw_angles)

# Get the turbine powers
turbine_powers = fi.get_turbine_powers()/1000.
print('The turbine power matrix should be of dimensions 1 WD X 1 WS X 2 Turbines')
print(turbine_powers)
print("Shape: ",turbine_powers.shape)

# Single wind speed and wind direction
print('\n============================= Single Wind Direction and Multiple Wind Speeds =============================')


wind_speeds = np.array([8.0, 9.0, 10.0])
fi.reinitialize(wind_speeds=wind_speeds)
yaw_angles = np.zeros([1,3,2]) # 1 wind direction, 3 wind speeds, 2 turbines
fi.calculate_wake(yaw_angles=yaw_angles)
turbine_powers = fi.get_turbine_powers()/1000.
print('The turbine power matrix should be of dimensions 1 WD X 3 WS X 2 Turbines')
print(turbine_powers)
print("Shape: ",turbine_powers.shape)

# Single wind speed and wind direction
print('\n============================= Multiple Wind Directions and Multiple Wind Speeds =============================')

wind_directions = np.array([260., 270., 280.])
wind_speeds = np.array([8.0, 9.0, 10.0])
fi.reinitialize(wind_directions=wind_directions, wind_speeds=wind_speeds)
yaw_angles = np.zeros([1,3,2]) # 1 wind direction, 3 wind speeds, 2 turbines
fi.calculate_wake(yaw_angles=yaw_angles)
turbine_powers = fi.get_turbine_powers()/1000.
print('The turbine power matrix should be of dimensions 3 WD X 3 WS X 2 Turbines')
print(turbine_powers)
print("Shape: ",turbine_powers.shape)
61 changes: 37 additions & 24 deletions examples/01_plot_wakes.py → examples/02_visualizations.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,47 +33,60 @@
# entry point to the simulation routines.
fi = FlorisInterface("inputs/gch.yaml")

# FLORIS supports multiple types of grids for capturing wind speed
# information. The current input file is configured with a square grid
# placed on each rotor plane with 9 points in a 3x3 layout. This can
# be plotted to show the wind conditions that each turbine is experiencing.
# However, 9 points is very coarse for visualization so let's first
# increase the rotor grid to 10x10 points.

# Create a solver settings dictionary with the new number of points
solver_settings = {
"type": "turbine_grid",
"turbine_grid_points": 10
}

# Since we already have a FlorisInterface (fi), simply reinitialize it
# with the new configuration
fi.reinitialize(solver_settings=solver_settings)

# Run the wake calculation to get the turbine-turbine interfactions
# on the turbine grids
fi.calculate_wake()

# Plot the values at each rotor
plot_rotor_values(fi.floris.flow_field.u, wd_index=0, ws_index=0, n_rows=1, n_cols=3)

# The rotor plots show what is happening at each turbine, but we do not
# see what is happening between each turbine. For this, we use a
# grid that has points regularly distributed throughout the fluid domain.
# The FlorisInterface contains functions for configuring the new grid,
# running the simulation, and generating plots of 2D slices of the
# flow field.

# Note this visualization grid created within the calculate_horizontal_plane function will be reset
# to what existed previously at the end of the function

# Using the FlorisInterface functions, get 2D slices.
horizontal_plane = fi.calculate_horizontal_plane(x_resolution=200, y_resolution=100, height=90.0)
y_plane = fi.calculate_y_plane(x_resolution=200, z_resolution=100, crossstream_dist=630.0)
cross_plane = fi.calculate_cross_plane(y_resolution=100, z_resolution=100, downstream_dist=630.0)


# Create the plots
fig, ax_list = plt.subplots(3, 1, figsize=(10, 8))
ax_list = ax_list.flatten()
visualize_cut_plane(horizontal_plane, ax=ax_list[0], title="Horizontal")
visualize_cut_plane(y_plane, ax=ax_list[1], title="Streamwise profile")
visualize_cut_plane(cross_plane, ax=ax_list[2], title="Spanwise profile")

# FLORIS further includes visualization methods for visualing the rotor plane of each
# Turbine in the simulation

# Run the wake calculation to get the turbine-turbine interfactions
# on the turbine grids
fi.calculate_wake()

# Plot the values at each rotor
fig, axes, _ , _ = plot_rotor_values(fi.floris.flow_field.u, wd_index=0, ws_index=0, n_rows=1, n_cols=3, return_fig_objects=True)
fig.suptitle("Rotor Plane Visualization, Original Resolution")

# FLORIS supports multiple types of grids for capturing wind speed
# information. The current input file is configured with a square grid
# placed on each rotor plane with 9 points in a 3x3 layout. For visualization,
# this resolution can be increased. Note this operation, unlike the
# calc_x_plane above operations does not automatically reset the grid to
# the initial status as definied by the input file

# Increase the resolution of points on each turbien plane
solver_settings = {
"type": "turbine_grid",
"turbine_grid_points": 10
}
fi.reinitialize(solver_settings=solver_settings)

# Run the wake calculation to get the turbine-turbine interfactions
# on the turbine grids
fi.calculate_wake()

# Plot the values at each rotor
fig, axes, _ , _ = plot_rotor_values(fi.floris.flow_field.u, wd_index=0, ws_index=0, n_rows=1, n_cols=3, return_fig_objects=True)
fig.suptitle("Rotor Plane Visualization, 10x10 Resolution")

plt.show()
57 changes: 0 additions & 57 deletions examples/03_compare_models.py

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@

# Change the wind shear, reset the wind speed, and plot a vertical slice
fi.reinitialize( wind_shear=0.2, wind_speeds=[8.0] )
y_plane = fi.calculate_y_plane()
y_plane = fi.calculate_y_plane(crossstream_dist=0.0)
visualize_cut_plane(y_plane, ax=axarr[2], title="Wind shear at 0.2", minSpeed=MIN_WS, maxSpeed=MAX_WS)


Expand All @@ -61,7 +61,6 @@
fi.reinitialize( layout=( X.flatten(), 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)
# plot_turbines_with_fi(axarr[7], fi)


# Change the yaw angles and configure the plot differently
Expand All @@ -88,10 +87,4 @@
axarr[5].invert_xaxis()


plt.show()


# # Change the veer
# fi.reinitialize(wind_veer=5.0)
# fi.floris.solve_for_viz()
# plot_slice_shortcut(fi, axarr[5], "Veer=5")
plt.show()
2 changes: 1 addition & 1 deletion examples/04_sweep_wind_directions.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,4 @@
ax.legend()
ax.set_xlabel('Wind Direction (deg)')
ax.set_ylabel('Power (kW)')
plt.show()
plt.show()
2 changes: 1 addition & 1 deletion examples/05_sweep_wind_speeds.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,4 @@
ax.legend()
ax.set_xlabel('Wind Speed (m/s)')
ax.set_ylabel('Power (kW)')
plt.show()
plt.show()
4 changes: 0 additions & 4 deletions examples/06_sweep_wind_conditions.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@
layout_y = [0, 0, 0, 0, 0]
fi.reinitialize(layout = [layout_x, layout_y])


# Define a ws and wd to sweep
# Note that all combinations will be computed
ws_array = np.arange(6, 9, 1.)
Expand All @@ -65,7 +64,6 @@
# Collect the turbine powers
turbine_powers = fi.get_turbine_powers() / 1E3 # In kW


# Show results by ws and wd
fig, axarr = plt.subplots(num_ws, 1, sharex=True,sharey=True,figsize=(6,10))
for ws_idx, ws in enumerate(ws_array):
Expand All @@ -78,12 +76,10 @@
ax.set_ylabel('Power (kW)')
ax.set_xlabel('Wind Direction (deg)')


# Sum across wind speeds and directions to show energy produced by turbine as bar plot
energy_by_turbine = np.sum(turbine_powers, axis=(0,1)) # Sum over wind direction (0-axis) and wind speed (1-axis)
fig, ax = plt.subplots()
ax.bar(['T%d' % t for t in range(num_turbine)],energy_by_turbine)
ax.set_title('Energy Produced by Turbine')

plt.show()

34 changes: 24 additions & 10 deletions examples/07_calc_aep_from_rose.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

# See https://floris.readthedocs.io for documentation


import numpy as np
import pandas as pd
from scipy.interpolate import NearestNDInterpolator
Expand All @@ -29,11 +30,19 @@
# Read the windrose information file & normalize wind rose frequencies
fn = "inputs/wind_rose.csv"
df_wr = pd.read_csv(fn)
df_wr["freq_val"] = df_wr["freq_val"] / df_wr["freq_val"].sum()

# Normalize the frequencies
df_wr["freq_val"] = df_wr["freq_val"].copy() / df_wr["freq_val"].sum()

# Split the wind rose into wind speeds above (df_wr_op)
# and below cut-in (df_wr_below_cut_in) as below cut-in winds are 0 power and
# 0 ambient wind speed generates warnings and nans in some of the wake models
df_wr_below_cut_in = df_wr[df_wr.ws < 3.0].copy()
df_wr_op = df_wr[df_wr.ws >= 3.0].copy()

# Derive the wind directions and speeds we need to evaluate in FLORIS
wd_array = np.array(df_wr["wd"].unique(), dtype=float)
ws_array = np.array(df_wr["ws"].unique(), dtype=float)
wd_array = np.array(df_wr_op["wd"].unique(), dtype=float)
ws_array = np.array(df_wr_op["ws"].unique(), dtype=float)

# Load the default example FLORIS object
fi = FlorisInterface("inputs/gch.yaml") # GCH model matched to the default "legacy_gauss" of V2
Expand All @@ -54,18 +63,23 @@
farm_power_array = fi.get_farm_power()

# Now map the FLORIS solutions to the wind rose dataframe
X, Y = np.meshgrid(wd_array, ws_array, indexing='ij')
wd_grid, ws_grid = np.meshgrid(wd_array, ws_array, indexing='ij')
interpolant = NearestNDInterpolator(
np.vstack([X.flatten(), Y.flatten()]).T,
np.vstack([wd_grid.flatten(), ws_grid.flatten()]).T,
farm_power_array.flatten()
)
df_wr["farm_power"] = interpolant(df_wr[["wd", "ws"]])
df_wr["farm_power"] = df_wr["farm_power"].fillna(0.0)

print("Farm solutions:")
print(df_wr)
# Use an interpolant to map the results back to the wind rose dataframe
# Technically this could be done directly but an interpolant is safer
# in the event the wind rose is irregular and/or ordered differently
# than floris
df_wr_op["farm_power"] = interpolant(df_wr_op[["wd", "ws"]])

# Recombine with the below cut-in data
df_wr_below_cut_in["farm_power"] = 0.
df_wr = df_wr_below_cut_in.append(df_wr_op).sort_values(["wd","ws"])

# Finally, calculate AEP in GWh
aep = np.dot(df_wr["freq_val"], df_wr["farm_power"]) * 365 * 24

print("Farm AEP: {:.2f} GWh".format(aep / 1.0e9))
print("Farm AEP: {:.3f} GWh".format(aep / 1.0e9))
1 change: 1 addition & 0 deletions examples/08_opt_yaw_single_ws.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
wind_directions=np.arange(0.0, 360.0, 3.0),
wind_speeds=[8.0],
)
print(fi.floris.farm.rotor_diameters)

# Initialize optimizer object and run optimization using the Serial-Refine method
yaw_opt = YawOptimizationSR(fi)#, exploit_layout_symmetry=False)
Expand Down
6 changes: 3 additions & 3 deletions examples/09_optimize_yaw.py → examples/10_optimize_yaw.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ def load_floris():
# Specify wind farm layout and update in the floris object
N = 5 # number of turbines per row and per column
X, Y = np.meshgrid(
5.0 * fi.floris.grid.reference_turbine_diameter * np.arange(0, N, 1),
5.0 * fi.floris.grid.reference_turbine_diameter * np.arange(0, N, 1),
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()))

Expand Down Expand Up @@ -134,7 +134,7 @@ def calculate_aep(fi, df_windrose, column_name="farm_power"):
exploit_layout_symmetry=True,
)

df_opt = yaw_opt._optimize()
df_opt = yaw_opt.optimize()
end_time = timerpc()
t_tot = end_time - start_time
t_fi = yaw_opt.time_spent_in_floris
Expand Down
File renamed without changes.
Loading