Skip to content
Snippets Groups Projects
Commit dd2f150a authored by Jennifer Rinker's avatar Jennifer Rinker
Browse files

adding example 2

parent 2d85e7e2
No related branches found
No related tags found
1 merge request!59adding example 2
Pipeline #4879 passed
.. Example 2
Example 2: Optimization with Different Wake Models
===================================================
This example demonstrates the optimization of a 3-turbine farm with
the N. O. Jensen (NOJ) and G. C. Larsen (GCL) wake models implemented in
FUSED-Wake.
Specifications
--------------
- The farm is offshore.
- The wind resource is defined by arrays of the frequency and Weibull
A and k parameters taken from a Horns Rev calculation.
- There is a boundary beyond which the turbines cannot go.
- The turbines cannot be closer than 2D.
Results
-------
The optimization results are visualized in the figure below, and the
script also outputs the following information on the resultings costs::
Comparison of cost models vs. optimized locations:
Cost | GCL_aep NOJ_aep
---------------------------------
GCL_loc | -2704.40 -2688.57 (0.59%)
NOJ_loc | -2703.90 -2688.59 (0.57%)
(0.02%) (-0.00%)
The subscript ``_aep`` indicates the AEP calculated using the specified wake
model. The subscript ``_loc`` indicates the optimal locations determined when
optimizing with the specified wake model. For example, the cost corresponding
to the ``GCL_aep`` column and the ``NOJ_loc`` column is the AEP calculated
using the GCL wake model for the optimal location results when the N. O.
Jensen wake model was used in the optimization. The percentages in parentheses
are the percent differences for the column or row.
Important observations:
- The upper and lower turbines are pushed away from each other, towards
the corners.
- There is little difference in the AEP value when calculated using either of
the optimal locations, since the optimal locations themselves are quite
close.
- The N. O. Jensen wake model has an AEP that is approximately 0.6% lower than
the AEP with the G. C. Larsen wake model for this farm.
.. figure:: /../../examples/example_2_wake_comparison.png
Code
----
.. literalinclude:: /../../examples/example_2_wake_comparison.py
......@@ -16,3 +16,4 @@ Welcome to TOPFARM, the wind-farm optimizer
:maxdepth: 2
examples/example_1_constrained_layout_optimization
examples/example_2_wake_comparison
examples/example_2_wake_comparison.png

8.37 KiB

"""Example: optimization with different wake models
This example uses a dummy cost function to optimize a simple wind turbine
layout that is subject to constraints. The optimization pushes the wind turbine
locations to specified locations in the farm.
"""
import os
import warnings
from matplotlib.patches import Polygon
import matplotlib.pyplot as plt
import numpy as np
from topfarm.plotting import PlotComp
from topfarm import TopFarm
from topfarm.cost_models.utils.wind_resource import WindResource
from topfarm.cost_models.cost_model_wrappers import AEPCostModelComponent
from topfarm.cost_models.fused_wake_wrappers import FusedWakeGCLWakeModel, \
FusedWakeNOJWakeModel
from topfarm.cost_models.utils.aep_calculator import AEPCalculator
# ------------------------ INPUTS ------------------------
# paths to input files
test_files_dir = os.path.join(os.path.dirname(__file__), '..', 'topfarm',
'tests', 'test_files') # file locations
wf_path = os.path.join(test_files_dir, 'wind_farms',
'3tb.yml') # path to wind farm
f = [3.597152, 3.948682, 5.167395, 7.000154, 8.364547, 6.43485, 8.643194,
11.77051, 15.15757, 14.73792, 10.01205, 5.165975] # horns rev
a = [9.176929, 9.782334, 9.531809, 9.909545, 10.04269, 9.593921, 9.584007,
10.51499, 11.39895, 11.68746, 11.63732, 10.08803] # horns rev
k = [2.392578, 2.447266, 2.412109, 2.591797, 2.755859, 2.595703, 2.583984,
2.548828, 2.470703, 2.607422, 2.626953, 2.326172] # horns rev
rot_diam = 80.0 # rotor diameter [m]
bnd_size = 2 * rot_diam + 10 # boundary size
init_pos = np.array([(0, 2 * rot_diam), (0, 0),
(0, -2 * rot_diam)]) # initial turbine positions
boundary = [(-bnd_size, bnd_size), (bnd_size, bnd_size),
(bnd_size, -bnd_size), (-bnd_size, -bnd_size),
(-bnd_size, bnd_size)] # wind farm boundary
min_spacing = 2.0 * rot_diam # minimum spacing between turbines [m]
# ------------------------ DEFINE WIND RESOURCE ------------------------
wind_res = WindResource(f, a, k, np.zeros_like(k))
# ------------------------ OPTIMIZATION ------------------------
warnings.filterwarnings('ignore') # temporarily disable fusedwake warnings
# GCL: define the wake model, aep calculator, and optimization problem
wake_mod_gcl = FusedWakeGCLWakeModel(wf_path)
aep_calc_gcl = AEPCalculator(wind_res, wake_mod_gcl)
tf_gcl = TopFarm(init_pos, aep_calc_gcl.get_TopFarm_cost_component(),
min_spacing, boundary=boundary)
# NOJ: define the wake model, aep calculator, and optimization problem
wake_mod_noj = FusedWakeNOJWakeModel(wf_path)
aep_calc_noj = AEPCalculator(wind_res, wake_mod_noj)
tf_noj = TopFarm(init_pos, aep_calc_noj.get_TopFarm_cost_component(),
min_spacing, boundary=boundary)
# run the optimization
cost_gcl, state_gcl, recorder_gcl = tf_gcl.optimize()
cost_noj, state_noj, recorder_noj = tf_noj.optimize()
# ------------------------ POST-PROCESS ------------------------
# get the optimized locations
opt_gcl = tf_gcl.turbine_positions
opt_noj = tf_noj.turbine_positions
# create the array of costs for easier printing
costs = np.diag([cost_gcl, cost_noj])
costs[0, 1] = TopFarm(opt_gcl, aep_calc_noj.get_TopFarm_cost_component(),
min_spacing,
boundary=boundary).evaluate()[0] # noj cost, gcl locs
costs[1, 0] = TopFarm(opt_noj, aep_calc_gcl.get_TopFarm_cost_component(),
min_spacing,
boundary=boundary).evaluate()[0] # gcl cost, noj locs
warnings.filterwarnings('default') # re-enable warnings warnings
# ------------------------ PRINT STATS ------------------------
aep_diffs = 200 * (costs[:, 0] - costs[:, 1]) / (costs[:, 0] + costs[:, 1])
loc_diffs = 200 * (costs[0, :] - costs[1, :]) / (costs[0, :] + costs[1, :])
print('\nComparison of cost models vs. optimized locations:')
print('\nCost | GCL_aep NOJ_aep')
print('---------------------------------')
print(f'GCL_loc |{costs[0,0]:11.2f} {costs[0,1]:11.2f}' +
f' ({aep_diffs[0]:.2f}%)')
print(f'NOJ_loc |{costs[1,0]:11.2f} {costs[1,1]:11.2f}' +
f' ({aep_diffs[1]:.2f}%)')
print(f' ({loc_diffs[0]:.2f}%) ({loc_diffs[1]:.2f}%)')
# ------------------------ PLOT (if possible) ------------------------
try:
# initialize the figure and axes
fig = plt.figure(1, figsize=(7, 5))
plt.clf()
ax = plt.axes()
# plot the boundary and desired locations
ax.add_patch(Polygon(boundary, fill=False,
label='Boundary')) # boundary
ax.plot(init_pos[:, 0], init_pos[:, 1], 'xk',
label='Initial')
ax.plot(opt_gcl[:, 0], opt_gcl[:, 1], 'o',
label='GCL')
ax.plot(opt_noj[:, 0], opt_noj[:, 1], '^',
label='NOJ')
# make a few adjustments to the plot
ax.autoscale_view() # autoscale the boundary
plt.legend(bbox_to_anchor=(0., 1.02, 1., .102), loc=3,
ncol=4, mode='expand', borderaxespad=0.) # add a legend
plt.tight_layout() # zoom the plot in
plt.axis('off') # remove the axis
# save the png
fig.savefig(os.path.basename(__file__).replace('.py', '.png'))
except RuntimeError:
pass
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment