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

[BUGFIX] Track FLORIS v4 changes #178

Merged
merged 19 commits into from
Apr 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -16,41 +16,41 @@
if __name__ == "__main__":
# Set up FLORIS interface
print("Initializing the FLORIS object for our demo wind farm")
fi, _ = load_floris()
fm, _ = load_floris()

# Defines alternative names for each turbine with 1-index
turbine_names = ["Turbine-%d" % (t + 1) for t in range(len(fi.layout_x))]
turbine_names = ["Turbine-%d" % (t + 1) for t in range(len(fm.layout_x))]

# Plot using default 0-indexed labels (includes power/thrust curve)
plot_floris_layout(fi, plot_terrain=False)
plot_floris_layout(fm, plot_terrain=False)

# Plot using default given 1-indexed labels (includes power/thrust curve)
plot_floris_layout(fi, plot_terrain=False, turbine_names=turbine_names)
plot_floris_layout(fm, plot_terrain=False, turbine_names=turbine_names)

# Plot only the layout with default options
plot_layout_only(fi)
plot_layout_only(fm)

# Plot only the layout with custom options
plot_layout_only(fi, {"turbine_names": turbine_names, "color": "g"})
plot_layout_only(fm, {"turbine_names": turbine_names, "color": "g"})

# Plot layout with wake directions and inter-turbine distances labeled
plot_layout_with_waking_directions(fi)
plot_layout_with_waking_directions(fm)

# Plot layout with wake directions and inter-turbine distances labeled
# (using custom options)
plot_layout_with_waking_directions(
fi,
fm,
limit_num=3, # limit to 3 lines per turbine
layout_plotting_dict={
"turbine_names": turbine_names,
"turbine_indices": range(2, len(fi.layout_x)),
"turbine_indices": range(2, len(fm.layout_x)),
},
wake_plotting_dict={"color": "r"},
)

# Demonstrate shading of an arbitrary region
points_for_demo = np.array([[600, 0], [1400, 0], [1200, 1000]])
ax = plot_layout_only(fi)
ax = plot_layout_only(fm)
shade_region(
points_for_demo,
show_points=True,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Copyright 2022 NREL & Shell
import matplotlib.pyplot as plt
from floris.tools.visualization import visualize_cut_plane
from floris.flow_visualization import visualize_cut_plane

from flasc.utilities.utilities_examples import load_floris_artificial as load_floris
from flasc.visualization import plot_floris_layout
Expand All @@ -20,19 +20,19 @@
)

# Load FLORIS
fi, _ = load_floris()
fi.reinitialize(
fm, _ = load_floris()
fm.set(
wind_directions=[wind_direction],
wind_speeds=[wind_speed],
turbulence_intensities=[turbulence_intensity],
)
plot_floris_layout(fi, plot_terrain=False)
plot_floris_layout(fm, plot_terrain=False)

# Generate baseline flowfield
print("Calculating flowfield...")
fi.calculate_wake()
farm_power = fi.get_farm_power().flatten()
horizontal_plane = fi.calculate_horizontal_plane(
fm.run()
farm_power = fm.get_farm_power().flatten()
horizontal_plane = fm.calculate_horizontal_plane(
x_resolution=x_resolution, y_resolution=y_resolution, height=plot_height
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,26 +13,26 @@

root_path = os.path.dirname(os.path.abspath(__file__))
for wake_model in wake_models:
fn = os.path.join(root_path, "df_fi_approx_{:s}.ftr".format(wake_model))
fn = os.path.join(root_path, "df_fm_approx_{:s}.ftr".format(wake_model))
if os.path.exists(fn):
print("FLORIS table for '{:s}' model exists. Skipping...".format(wake_model))
continue

start_time = timerpc()
print("Precalculating FLORIS table for '{:s}' model...".format(wake_model))
fi, turbine_weights = load_floris(wake_model=wake_model)
fm, turbine_weights = load_floris(wake_model=wake_model)
# fi_pci = ParallelComputingInterface(
# fi=fi,
# max_workers=max_workers,
# n_wind_direction_splits=max_workers,
# print_timings=True,
# )
df_fi_approx = ftools.calc_floris_approx_table(
fi=fi, # fi=fi_pci,
df_fm_approx = ftools.calc_floris_approx_table(
fm=fm, # fi=fi_pci,
wd_array=np.arange(0.0, 360.01, 3.0),
ws_array=np.arange(1.0, 30.01, 1.0),
ti_array=[0.03, 0.06, 0.09, 0.12, 0.15],
)
end_time = timerpc()
print("Computation time: {:.2f} s".format(end_time - start_time))
df_fi_approx.to_feather(fn)
df_fm_approx.to_feather(fn)
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,20 @@

# Set up FLORIS interface
print("Initializing the FLORIS object for our demo wind farm")
fi, _ = load_floris()
fm, _ = load_floris()

# Plot the layout of the farm for reference
fsaviz.plot_layout_only(fi)
fsaviz.plot_layout_only(fm)

# Get the dependencies of turbine 2
check_directions = np.arange(0, 360.0, 2.0)
depend_on_2 = fsatools.get_dependent_turbines_by_wd(fi, 2, check_directions)
depend_on_2 = fsatools.get_dependent_turbines_by_wd(fm, 2, check_directions)

print("Turbines that depend on T002 at 226 degrees:", depend_on_2[round(226 / 2)])

# Can also return all influences as a matrix for other use (not ordered)
depend_on_2, influence_magnitudes = fsatools.get_dependent_turbines_by_wd(
fi, 2, check_directions, return_influence_magnitudes=True
fm, 2, check_directions, return_influence_magnitudes=True
)
print(
"\nArray of all influences of T002 has shape (num_wds x num_turbs): ",
Expand All @@ -41,25 +41,25 @@
)
)

df_dependencies = fsatools.get_all_dependent_turbines(fi, check_directions)
df_dependencies = fsatools.get_all_dependent_turbines(fm, check_directions)
print("\nAll turbine dependencies using default threshold " + "(first 5 wind directions printed):")
print(df_dependencies.head())

df_dependencies = fsatools.get_all_dependent_turbines(fi, check_directions, limit_number=2)
df_dependencies = fsatools.get_all_dependent_turbines(fm, check_directions, limit_number=2)
print(
"\nTwo most significant turbine dependencies using default threshold "
+ "(first 5 wind directions printed):"
)
print(df_dependencies.head())

df_dependencies = fsatools.get_all_dependent_turbines(fi, check_directions, change_threshold=0.01)
df_dependencies = fsatools.get_all_dependent_turbines(fm, check_directions, change_threshold=0.01)
print("\nAll turbine dependencies using higher threshold " + "(first 5 wind directions printed):")
print(df_dependencies.head())

print(
"\nAll upstream turbine impacts using default threshold " + "(first 5 wind directions printed):"
)
df_impacting = fsatools.get_all_impacting_turbines(fi, check_directions)
df_impacting = fsatools.get_all_impacting_turbines(fm, check_directions)
print(df_impacting.head())
# Inclusion of T005 here as an impact on T000 is surprising; try increasing
# the threshold or reducing the limit_number (see next).
Expand All @@ -68,21 +68,21 @@
"\nMost significant upstream turbine impact using default threshold "
+ "(first 5 wind directions printed):"
)
df_impacting = fsatools.get_all_impacting_turbines(fi, check_directions, limit_number=1)
df_impacting = fsatools.get_all_impacting_turbines(fm, check_directions, limit_number=1)
print(df_impacting.head())

print(
"\nAll upstream turbine impacts using higher threshold " + "(first 5 wind directions printed):"
)
df_impacting = fsatools.get_all_impacting_turbines(fi, check_directions, change_threshold=0.01)
df_impacting = fsatools.get_all_impacting_turbines(fm, check_directions, change_threshold=0.01)
print(df_impacting.head())

# Note that there is no individual turbine version for the "impacting"
# function; instead, compute all impacting turbines and extract desired
# turbine from the output dataframe.

# (compute using defaults again, for example)
df_impacting = fsatools.get_all_impacting_turbines(fi, check_directions)
df_impacting = fsatools.get_all_impacting_turbines(fm, check_directions)
print("\nTurbines that T006 depends on at 226 degrees:", df_impacting.loc[226, 6])


Expand Down
Original file line number Diff line number Diff line change
@@ -1,41 +1,41 @@
import matplotlib.pyplot as plt
import numpy as np
from floris.tools import FlorisInterface
from floris import FlorisModel

from flasc.utilities.floris_tools import get_all_impacting_turbines_geometrical

# Demonstrate the get_all_impacting_turbines_geometrical
# function in floris_tools

# Load a large FLORIS object
fi = FlorisInterface("../floris_input_artificial/gch.yaml")
fm = FlorisModel("../floris_input_artificial/gch.yaml")
D = 126.0
X, Y = np.meshgrid(7.0 * D * np.arange(20), 5.0 * D * np.arange(20))
fi.reinitialize(layout_x=X.flatten(), layout_y=Y.flatten())
fm.set(layout_x=X.flatten(), layout_y=Y.flatten())

# Specify which turbines are of interest
turbine_weights = np.zeros(len(X.flatten()), dtype=float)
turbine_weights[np.hstack([a + range(10) for a in np.arange(50, 231, 20)])] = 1.0

# Get all impacting turbines for each wind direction using simple geometry rules
df_impacting = get_all_impacting_turbines_geometrical(
fi=fi, turbine_weights=turbine_weights, wd_array=np.arange(0.0, 360.0, 30.0)
fm=fm, turbine_weights=turbine_weights, wd_array=np.arange(0.0, 360.0, 30.0)
)

# Produce plots showcasing which turbines are estimated to be impacting
for ii in range(df_impacting.shape[0]):
wd = df_impacting.loc[ii, "wd"]

fig, ax = plt.subplots()
ax.plot(fi.layout_x, fi.layout_y, "o", color="lightgray", label="All turbines")
ax.plot(fm.layout_x, fm.layout_y, "o", color="lightgray", label="All turbines")

ids = df_impacting.loc[ii, "impacting_turbines"]
no_turbines_total = len(fi.layout_x)
no_turbines_total = len(fm.layout_x)
no_turbines_reduced = len(ids)
ax.plot(fi.layout_x[ids], fi.layout_y[ids], "o", color="black", label="Impacting turbines")
ax.plot(fm.layout_x[ids], fm.layout_y[ids], "o", color="black", label="Impacting turbines")

ids = np.where(turbine_weights > 0.001)[0]
ax.plot(fi.layout_x[ids], fi.layout_y[ids], "o", color="red", label="Turbines of interest")
ax.plot(fm.layout_x[ids], fm.layout_y[ids], "o", color="red", label="Turbines of interest")

ax.set_xlabel("X location (m)")
ax.set_ylabel("Y location (m)")
Expand Down

Large diffs are not rendered by default.

2,451 changes: 1,235 additions & 1,216 deletions examples_artificial_data/01_raw_data_processing/01_northing_calibration.ipynb

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@

if __name__ == "__main__":
# Load FLORIS model and plot layout (and additional information)
fi, _ = load_floris()
plot_floris_layout(fi)
plot_layout_with_waking_directions(fi, limit_dist_D=5, limit_num=3)
fm, _ = load_floris()
plot_floris_layout(fm)
plot_layout_with_waking_directions(fm, limit_dist_D=5, limit_num=3)

# Compare optimizing over all wind speeds vs. optimizing over a single wind speed
AEP_baseline_array = []
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,19 @@
# Compare optimizing over different pPs and evaluating over different pPs
for pP_opt in pP_list:
# Optimize yaw angles
fi, _ = load_floris(pP=pP_opt)
fm, _ = load_floris(cosine_exponent=pP_opt)
df_opt = optimize_yaw_angles(
fi=fi,
fm=fm,
)

# Make an interpolant
yaw_angle_interpolant = get_yaw_angles_interpolant(df_opt) # Create yaw angle interpolant

# Calculate AEP uplift
for pP_eval in pP_list:
fi, _ = load_floris(pP=pP_eval)
fm, _ = load_floris(cosine_exponent=pP_eval)
AEP_baseline, AEP_opt, _ = evaluate_optimal_yaw_angles(
fi=fi,
fm=fm,
yaw_angle_interpolant=yaw_angle_interpolant,
)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,18 @@
import pandas as pd
import seaborn as sns
from _local_helper_functions import evaluate_optimal_yaw_angles, optimize_yaw_angles
from floris.tools.uncertainty_interface import UncertaintyInterface
from floris.uncertain_floris_model import UncertainFlorisModel
from matplotlib import pyplot as plt

from flasc.utilities.lookup_table_tools import get_yaw_angles_interpolant
from flasc.utilities.utilities_examples import load_floris_artificial as load_floris


def load_floris_with_uncertainty(std_wd=0.0):
fi, _ = load_floris() # Load nominal floris object
fm, _ = load_floris() # Load nominal floris object
if std_wd > 0.001:
unc_options = {
"std_wd": std_wd, # Standard deviation for inflow wind direction (deg)
"pmf_res": 1.0, # Resolution over which to calculate angles (deg)
"pdf_cutoff": 0.995, # Probability density function cut-off (-)
}
fi = UncertaintyInterface(fi, unc_options=unc_options) # Load uncertainty object
return fi
fm = UncertainFlorisModel(fm.core.as_dict(), wd_std=std_wd) # Load uncertainty object
return fm


if __name__ == "__main__":
Expand All @@ -30,7 +25,7 @@ def load_floris_with_uncertainty(std_wd=0.0):
print("Optimizing yaw angles with std_wd={:.2f}".format(std_wd_opt))
# Optimize yaw angles
df_opt = optimize_yaw_angles(
fi=load_floris_with_uncertainty(std_wd=std_wd_opt),
fm=load_floris_with_uncertainty(std_wd=std_wd_opt),
)

# Make an interpolant
Expand All @@ -40,7 +35,7 @@ def load_floris_with_uncertainty(std_wd=0.0):
for std_wd_eval in std_wd_list:
print("Evalating AEP uplift with std_wd={:.2f}".format(std_wd_eval))
AEP_baseline, AEP_opt, _ = evaluate_optimal_yaw_angles(
fi=load_floris_with_uncertainty(std_wd=std_wd_eval),
fm=load_floris_with_uncertainty(std_wd=std_wd_eval),
yaw_angle_interpolant=yaw_angle_interpolant,
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@
result_list = []

# Compare optimizing and evaluating over different turbulence intensities
for ti_opt in ti_list:
for ti_opt in ti_list: # TODO: with Floris v4, could optimize all at once
print("Optimizing yaw angles with turbulence_intensity={:.2f}".format(ti_opt))
# Optimize yaw angles
df_opt = optimize_yaw_angles(opt_turbulence_intensity=ti_opt)
df_opt = optimize_yaw_angles(opt_turbulence_intensities=ti_opt)

# Make an interpolant
yaw_angle_interpolant = get_yaw_angles_interpolant(df_opt) # Create yaw angle interpolant
Expand Down
Loading
Loading