Commit bb02eddc authored by Mikkel Friis-Møller's avatar Mikkel Friis-Møller
Browse files

added bathymetry.ipynb

parent 4a7886d4
Pipeline #25358 canceled with stages
in 21 seconds
......@@ -8,6 +8,7 @@ test_topfarm: # name the job what we like
stage: # build, test, deploy defined by default [2]
test
script:
- pip install --upgrade git+https://gitlab.windenergy.dtu.dk/TOPFARM/PyWake.git
- pip install -e .
- py.test
tags: # only runners with this tag can do the job [3]
......@@ -31,9 +32,11 @@ test_topfarm_windows: # name the job what we like
stage: # build, test, deploy defined by default [2]
test
script: # runs on windows machine due to tag below
- source activate py36_openmdao26
- conda init powershell
- "if (test-path $PROFILE.CurrentUserAllHosts) { & $PROFILE.CurrentUserAllHosts}"
- conda activate py36_openmdao26
- pip install --upgrade git+https://gitlab.windenergy.dtu.dk/TOPFARM/PyWake.git
- pip install -e .
- pip install --upgrade py_wake
- python -m pytest --cov-report term-missing:skip-covered --cov=topfarm --cov-config .coveragerc --ignore=topfarm/cost_models/fuga/Colonel
tags: # tag for shared runner on windows machine
- ANMH_old
......
[![pipeline status](https://gitlab.windenergy.dtu.dk/TOPFARM/TopFarm2/badges/master/pipeline.svg)](https://gitlab.windenergy.dtu.dk/TOPFARM/TopFarm2/commits/master)
[![coverage report](https://gitlab.windenergy.dtu.dk/TOPFARM/TopFarm2/badges/master/coverage.svg)](https://gitlab.windenergy.dtu.dk/TOPFARM/TopFarm2/commits/master)
[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/git/https%3A%2F%2Fgitlab.windenergy.dtu.dk%2FTOPFARM%2FTopFarm2.git/HEAD)
Welcome to TOPFARM
------------------
......
This diff is collapsed.
......@@ -61,11 +61,10 @@ def make_doc_notebooks(notebooks):
t = '[Try this yourself](https://colab.research.google.com/github/DTUWindEnergy/TopFarm2/blob/master/docs/notebooks/%s.ipynb) (requires google account)'
nb.insert_markdown_cell(1, t % name)
code = """%%capture
# Install Topfarm if needed
try:
import topfarm
except ModuleNotFoundError:
!pip install topfarm"""
import importlib
if not importlib.util.find_spec("topfarm"):
!pip install topfarm
# Install Topfarm if needed"""
if not name in ['loads', 'wake_steering_and_loads', 'layout_and_loads']:
nb.insert_code_cell(2, code)
nb.save(dst_path + name + ".ipynb")
......@@ -92,8 +91,9 @@ def check_notebooks(notebooks=None):
if __name__ == '__main__':
notebooks = ['constraints', 'cost_models', 'drivers', 'loads', 'problems',
'roads_and_cables', 'wake_steering_and_loads', 'layout_and_loads']
# notebooks.remove('roads_and_cables')
'roads_and_cables', 'wake_steering_and_loads', 'layout_and_loads',
'bathymetry',]
notebooks.remove('wake_steering_and_loads')
notebooks.remove('loads')
check_notebooks(notebooks)
make_doc_notebooks(notebooks)
......
This diff is collapsed.
%% Cell type:markdown id: tags:
# Constraints
%% Cell type:markdown id: tags:
[Try this yourself](https://colab.research.google.com/github/DTUWindEnergy/TopFarm2/blob/master/docs/notebooks/constraints.ipynb) (requires google account)
%% Cell type:code id: tags:
``` python
%%capture\n# Install Topfarm if needed\ntry:\n import topfarm\nexcept ModuleNotFoundError:\n !pip install topfarm
%%capture\nimport importlib\nif not importlib.util.find_spec("topfarm"):\n !pip install topfarm\n# Install Topfarm if needed
```
%% Cell type:markdown id: tags:
Constraints are the second key element of a an optimization problem formulation. They ensure that the optimization results conforms to feasible / realistic solutions. There are three types of constraints in optimization:
* Variable bounds - upper and lower boundary values for design variables
* inequality constraints - constraint function values must be less or more than a given threshold
* equality constraints - constraint function must be exactly equal to a value (not as commonly used)
This notebook walks through a process to set up typical constraints in Topfarm for wind farm design problems including:
* boundary constraints - these tell Topfarm within a region where the perimeter of the site is that turbines must be sited within and also any exclusion zones that must be avoided
* spacing constraints - these tell Topfarm the minimum allowable inter-turbine spacing in the farm
%% Cell type:markdown id: tags:
**First we import supporting libraries in Python numpy and matplotlib**
%% Cell type:code id: tags:
``` python
# Import numpy and matplotlib files
import numpy as np
%matplotlib inline
import matplotlib.pyplot as plt
```
%% Cell type:markdown id: tags:
**Next we import and initialize several functions and classes from Topfarm to set up the problem including:**
* **TopFarmProblem - overall topfarm problem class to which the objectives, design variables, and constraints are added**
* **XYBoundaryConstraint - for a boundary specified as a series of connected perimeter vertices**
* **CircleBoundaryConstraint - for a circular boundary with a central location and a radius**
* **SpacingConstraint - for the inter-turbine spacing distance constraints**
* **CostModelComponent - a generic class for setting up a problem objective function**
**We also import a helper function to plot**
**For documentation on Topfarm see:**
https://topfarm.pages.windenergy.dtu.dk/TopFarm2/user_guide.html#
%% Cell type:code id: tags:
``` python
# Import topfarm problem, plotting support, constraint classes and generic cost model component
from topfarm import TopFarmProblem
from topfarm.plotting import XYPlotComp
from topfarm.constraint_components.boundary import XYBoundaryConstraint, CircleBoundaryConstraint
from topfarm.constraint_components.spacing import SpacingConstraint
from topfarm.cost_models.cost_model_wrappers import CostModelComponent
```
%% Cell type:markdown id: tags:
## Boundary constraints
**Next we are going to demonstrate the use of the XYBoundaryConstraint to set up site boundaries of a variety of types including square, rectangle and an arbitrary polygon. Additionally, a "convex hull" example is provided which is a commonly used boundary type for wind farm design optimization problems.**
**(From wikipedia) In mathematics, the convex hull or convex envelope or convex closure of a set X of points in the Euclidean plane or in a Euclidean space (or, more generally, in an affine space over the reals) is the smallest convex set that contains X. For instance, when X is a bounded subset of the plane, the convex hull may be visualized as the shape enclosed by a rubber band stretched around X.**
%% Cell type:code id: tags:
``` python
# set up a "boundary" arry with arbitrary points for use in the example
boundary = np.array([(0, 0), (1, 1), (3, 0), (3, 2), (0, 2)])
# set up dummy design variables and cost model component.
# This example includes 2 turbines (n_wt=2) located at x,y=0.5,0.5 and 1.5,1.5 respectively
x = [0.5,1.5]
y = [.5,1.5]
dummy_cost = CostModelComponent(input_keys=[],
n_wt=2,
cost_function=lambda : 1)
# We introduce a simple plotting function so we can quickly plot different types of site boundaries
def plot_boundary(name, constraint_comp):
tf = TopFarmProblem(
design_vars={'x':x, 'y':y}, # setting up our two turbines as design variables
cost_comp=dummy_cost, # using dummy cost model
constraints=[constraint_comp], # constraint set up for the boundary type provided
plot_comp=XYPlotComp()) # support plotting function
plt.figure()
plt.title(name)
tf.plot_comp.plot_constraints() # plot constraints is a helper function in topfarm to plot constraints
plt.plot(boundary[:,0], boundary[:,1],'.r', label='Boundary points') # plot the boundary points
plt.axis('equal')
plt.legend() # add the legend
```
%% Cell type:markdown id: tags:
**Now that we have set up our dummy problem, we can illustrate how different boundary types can be created from our boundary vertices**
**First we show a convex hull type as described above. Note that for the convex hull, all boundary points are contained within a convex perimeter but one of the boundary points on the interior is not used.**
%% Cell type:code id: tags:
``` python
# Now we use our boundary defined above to plot different types of boundary constraints on the problem
plot_boundary('convex_hull', XYBoundaryConstraint(boundary, 'convex_hull'))
```
%% Output
%% Cell type:markdown id: tags:
**Next we show a square type of boundary. In this case the maximum distance between the x and y elements of the vertices is used to establish the perimeter.**
%% Cell type:code id: tags:
``` python
plot_boundary('square', XYBoundaryConstraint(boundary, 'square'))
```
%% Output
%% Cell type:markdown id: tags:
**Now a rectangle boundary. Here we use the maximum distance on both x and y axes of the boundary coordinates to establish the perimeter.**
%% Cell type:code id: tags:
``` python
plot_boundary('rectangle', XYBoundaryConstraint(boundary, 'rectangle'))
```
%% Output
%% Cell type:markdown id: tags:
**Now a polygon boundary. This connects all the points in sequence. Note that this results in a nonconvex boundary. Nonconvex functions in optimization problems introduce complexity that can be challenging to handle and often require more sophisticated algorithms and higher computational expense.**
%% Cell type:code id: tags:
``` python
plot_boundary('polygon', XYBoundaryConstraint(boundary, 'polygon'))
```
%% Output
%% Cell type:markdown id: tags:
**Finally a circular boundary. For this we have to specify the midpoint of the circle and the radius.**
%% Cell type:code id: tags:
``` python
plot_boundary('Circle',CircleBoundaryConstraint((1.5,1),1))
```
%% Output
%% Cell type:markdown id: tags:
**You can also quickly plot all boundary types using some quick python tricks**
%% Cell type:code id: tags:
``` python
# plot all boundary types using our dummy problem and boundaries
for boundary_type in ['convex_hull','square','rectangle','polygon']:
plot_boundary(boundary_type, XYBoundaryConstraint(boundary, boundary_type))
```
%% Output
%% Cell type:markdown id: tags:
### Exercise!!
**Now play around with a new set of boundary vertices and construct different perimeters to explore the functionality. See if you can make even more complex polygon shapes.**
%% Cell type:code id: tags:
``` python
# Make your own set of vertices - anything you would like!
boundary = np.array([(0, 0), (2, 1), (4, 7), (1, 1), (0, 2)])
# Then see what types of perimeters they generate
for boundary_type in ['convex_hull','square','rectangle','polygon']:
plot_boundary(boundary_type, XYBoundaryConstraint(boundary, boundary_type))
```
%% Output
%% Cell type:markdown id: tags:
## Spacing constraints
The next most common constraint in a wind farm design optimization problem is on the allowable inter-turbine spacing in the farm. Losses due to wakes should ensure that turbines do spread out but a minimum constraint can also help to ensure that turbines do not get placed too close together.
The following provides a simple example of implementation of a minimum spacing constraint.
%% Cell type:markdown id: tags:
**Implement a minimum spacing constraint example**
%% Cell type:code id: tags:
``` python
# set up dummy design variables and cost model component.
# This example includes 2 turbines (n_wt=2) located at x,y=0.5,0.5 and 1.5,1.5 respectively
x = [0.5,1.5]
y = [.5,1.5]
dummy_cost = CostModelComponent(input_keys=[],
n_wt=2,
cost_function=lambda : 1)
# a function to plot a spacing constraint for a Topfarm problem
def plot_spacing(name, constraint_comp):
tf = TopFarmProblem(
design_vars={'x':x, 'y':y}, # setting up our two turbines as design variables
cost_comp=dummy_cost, # using dummy cost model
constraints=[constraint_comp], # constraint set up for the boundary type provided
plot_comp=XYPlotComp()) # support plotting function
tf.evaluate()
plt.figure()
plt.title(name)
tf.plot_comp.plot_constraints() # plot constraints is a helper function in topfarm to plot constraints
plt.plot(x,y,'.b', label='Wind turbines') # plot the turbine locations
plt.axis('equal')
plt.legend() # add the legend
plt.ylim([0,2])
plot_spacing('spacing', SpacingConstraint(1))
```
%% Output
%% Cell type:markdown id: tags:
### Exercise!!
**Play around with the spacing constraint size**
%% Cell type:code id: tags:
``` python
plot_spacing('spacing', SpacingConstraint(3))
```
%% Output
%% Cell type:code id: tags:
``` python
```
......
%% Cell type:markdown id: tags:
## Cost Models
Topfarm now comes with two built-in cost models. Additional user-defined cost models can easily be integrated as well. In this example, the ability to switch from using each of the two models is demonstrated.
%% Cell type:markdown id: tags:
[Try this yourself](https://colab.research.google.com/github/DTUWindEnergy/TopFarm2/blob/master/docs/notebooks/cost_models.ipynb) (requires google account)
%% Cell type:code id: tags:
``` python
%%capture\n# Install Topfarm if needed\ntry:\n import topfarm\nexcept ModuleNotFoundError:\n !pip install topfarm
%%capture\nimport importlib\nif not importlib.util.find_spec("topfarm"):\n !pip install topfarm\n# Install Topfarm if needed
```
%% Cell type:markdown id: tags:
### Cost Model 1: DTU implementation of the NREL Cost and Scaling Model
The first cost model in Topfarm is a python implementation of the National Renewable Energy Laboratory (NREL) Cost and Scaling Model. The report on which the model is based can be found here:
https://www.nrel.gov/docs/fy07osti/40566.pdf
The model was developed from the early to mid-2000s as part of the Wind Partnership for Advanced Component Technology (WindPACT) which explored innovative turbine design (at that time) as well as innovations on the balance of plant and operations. Several detailed design studies on the turbine and plant design can cost were made. For publications associated with the WindPACT program, see: [WindPACT publication list](http://nrel-primo.hosted.exlibrisgroup.com/primo_library/libweb/action/search.do;jsessionid=00F1EA4B14428BED000D0D1E7C0E2C46?fn=search&ct=search&initialSearch=true&mode=Basic&tab=default_tab&indx=1&dum=true&srt=rank&vid=Pubs&frbg=&vl%28freeText0%29=windpact&scp.scps=scope%3A%28PUBS%29%2Cscope%3A%28NREL_INTERNAL%29&vl%28870446075UI1%29=all_items)
From the WindPACT studies, the NREL cost and scaling model was developed as a set of curve-fits to the underlying detailed design data and includes:
* Turbine component masses and costs
* Balance of system costs
* Operational expenditures
* Financing and other costs
Over time, changes in turbine and plant technology have rendered the NREL cost and scaling model obselete, but it is still useful as a publicly available, full levelized cost of energy (LCOE) model for wind energy.
%% Cell type:markdown id: tags:
**Import Topfarm models to set up an LCOE workflow including the cost model**
%% Cell type:code id: tags:
``` python
# Import numerical python
import numpy as np
# Import pywake models including the IEA Wind Task 37 case study site, the Gaussian wake model and the AEP calculator
from py_wake.examples.data.iea37._iea37 import IEA37_WindTurbines, IEA37Site
from py_wake.deficit_models.gaussian import IEA37SimpleBastankhahGaussian
# Import Topfarm implementation of NREL Cost and Scaling model
from topfarm.cost_models.economic_models.turbine_cost import economic_evaluation as ee_1
# Import Topfarm constraints for site boundary and spacing
from topfarm.drivers.random_search_driver import RandomizeTurbinePosition_Circle
from topfarm.constraint_components.boundary import CircleBoundaryConstraint
from topfarm.constraint_components.spacing import SpacingConstraint
# Import Topfarm support classes for setting up problem and workflow
from topfarm.cost_models.cost_model_wrappers import CostModelComponent, AEPCostModelComponent
from topfarm.cost_models.py_wake_wrapper import PyWakeAEPCostModelComponent
from topfarm import TopFarmGroup, TopFarmProblem
from topfarm.plotting import XYPlotComp, NoPlot
# Import Topfarm implementation of Random Search or Scipy drivers
from topfarm.easy_drivers import EasyRandomSearchDriver
from topfarm.easy_drivers import EasyScipyOptimizeDriver
from topfarm.easy_drivers import EasySimpleGADriver
```
%% Cell type:markdown id: tags:
**Set up plotting capability**
%% Cell type:code id: tags:
``` python
try:
import matplotlib.pyplot as plt
plt.gcf()
plot_comp = XYPlotComp()
plot = True
except RuntimeError:
plot_comp = NoPlot()
plot = False
```
%% Output
%% Cell type:markdown id: tags:
**Set up IEA Wind Task 37 case study site with 16 turbines.**
%% Cell type:code id: tags:
``` python
# site set up
n_wt = 16 # number of wind turbines
site = IEA37Site(n_wt) # site is the IEA Wind Task 37 site with a circle boundary
windTurbines = IEA37_WindTurbines() # wind turbines are the IEA Wind Task 37 3.4 MW reference turbine
wake_model = IEA37SimpleBastankhahGaussian(site, windTurbines) # select the Gaussian wake model
# vectors for turbine properties: diameter, rated power and hub height
# these are inputs to the cost model
Drotor_vector = [windTurbines.diameter()] * n_wt
power_rated_vector = [float(windTurbines.power(20)/1000)] * n_wt
hub_height_vector = [windTurbines.hub_height()] * n_wt
```
%% Cell type:markdown id: tags:
**Set up functions for the AEP and cost calculations. Here we are using the internal rate of return (IRR) as our financial metric of interest.**
%% Cell type:code id: tags:
``` python
# function for calculating aep as a function of x,y positions of the wind turbiens
def aep_func(x, y, **kwargs):
return wake_model(x, y).aep().sum(['wd','ws']).values*10**6
# function for calculating overall internal rate of return (IRR)
def irr_func(aep, **kwargs):
my_irr = ee_1(Drotor_vector, power_rated_vector, hub_height_vector, aep).calculate_irr()
print(my_irr)
return my_irr
```
%% Cell type:markdown id: tags:
**Now set up a problem to run an optimization using IRR as the objective function. Note that the turbines are fixed so the main driver changing the IRR will be the AEP as the turbine positions change.**
%% Cell type:code id: tags:
``` python
# create an openmdao component for aep and irr to add to the problem
aep_comp = CostModelComponent(input_keys=['x','y'], n_wt=n_wt, cost_function=aep_func, output_key="aep", output_unit="GWh", objective=False, output_val=np.zeros(n_wt))
irr_comp = CostModelComponent(input_keys=['aep'], n_wt=n_wt, cost_function=irr_func, output_key="irr", output_unit="%", objective=True, income_model=True)
# create a group for the aep and irr components that links their common input/output (aep)
irr_group = TopFarmGroup([aep_comp, irr_comp])
# add the group to an optimization problem and specify the design variables (turbine positions),
# cost function (irr_group), driver (random search), and constraints (circular boundary and spacing)
problem = TopFarmProblem(
design_vars=dict(zip('xy', site.initial_position.T)),
cost_comp=irr_group,
driver=EasyRandomSearchDriver(randomize_func=RandomizeTurbinePosition_Circle(), max_iter=50),
#driver=EasyScipyOptimizeDriver(optimizer='COBYLA', maxiter=200, tol=1e-6, disp=False),
#driver=EasySimpleGADriver(max_gen=100, pop_size=5, Pm=None, Pc=.5, elitism=True, bits={}),
constraints=[SpacingConstraint(200),
CircleBoundaryConstraint([0, 0], 1300.1)],
plot_comp=plot_comp)
# assign data from optimizationn to a set of accessible variables and run the optimization
cost, state, recorder = problem.optimize()
```
%% Output
59.15317035889765
59.15317035889765
59.15317035889765
59.14310441797548
59.15317035889765
59.15317035889765
59.15317035889765
59.15317035889765
59.15317035889765
58.29211938020884
59.15317035889765
59.15317035889765
58.306611078551015
59.15317035889765
58.65177988998911
59.15317035889765
59.15317035889765
59.15317035889765
59.15317035889765
59.15317035889765
58.59176040816389
59.15317035889765
59.31620110565699
59.31620110565699
59.31620110565699
59.31620110565699
59.31620110565699
58.66292698793363
59.31620110565699
59.31620110565699
59.31620110565699
59.31620110565699
59.31620110565699
59.31620110565699
59.31620110565699
59.303257188319215
59.31620110565699
59.31620110565699
57.47298599965627
59.31620110565699
59.31620110565699
59.31620110565699
59.31620110565699
59.31620110565699
57.6380941604278
59.31620110565699
59.31620110565699
59.31620110565699
59.31620110565699
58.43798216603633
59.31620110565699
57.50524264369579
59.31620110565699
58.82976209996185
59.31620110565699
59.31620110565699
59.31620110565699
59.31620110565699
59.31620110565699
59.31620110565699
59.31620110565699
59.31620110565699
59.31620110565699
59.31620110565699
57.70824040792708
59.31620110565699
59.31620110565699
58.590114202784505
59.31620110565699
59.31620110565699
59.31620110565699
59.31620110565699
59.726153083156255
59.726153083156255
59.726153083156255
59.726153083156255
59.726153083156255
59.726153083156255
59.726153083156255
59.726153083156255
59.726153083156255
58.406299153034944
59.726153083156255
59.726153083156255
59.726153083156255
59.726153083156255
59.726153083156255
58.37976410053296
59.726153083156255
59.552670809081754
59.726153083156255
59.726153083156255
59.32561802599095
59.726153083156255
59.726153083156255
59.27489893145545
59.726153083156255
59.726153083156255
59.726153083156255
59.726153083156255
59.726153083156255
59.726153083156255
59.726153083156255
58.95636326531617
59.726153083156255
58.578302590782606
59.726153083156255
59.726153083156255
59.726153083156255
58.6548498707578
59.726153083156255
59.726153083156255
59.726153083156255
59.726153083156255
59.726153083156255
59.726153083156255
58.64491622007393
59.726153083156255
59.726153083156255
58.087380184410264
59.726153083156255
59.726153083156255
59.726153083156255
59.726153083156255
59.726153083156255
59.726153083156255
58.89200916787394
59.726153083156255
59.726153083156255
59.726153083156255
59.726153083156255
59.726153083156255
59.726153083156255
58.465669464734574
59.726153083156255
59.726153083156255
59.726153083156255
59.726153083156255
59.726153083156255
59.726153083156255
58.64173080326604
59.726153083156255
59.726153083156255
59.726153083156255
59.726153083156255
59.726153083156255
59.726153083156255
59.82344544880953
59.82344544880953
59.82344544880953
59.82344544880953
59.82344544880953
59.82344544880953
59.82344544880953
58.90464363372247
59.82344544880953
58.88967957072477
59.82344544880953
59.82344544880953
59.832213357205674
59.832213357205674
59.832213357205674
59.832213357205674
59.832213357205674
59.37873069716875
59.832213357205674
59.832213357205674
59.832213357205674
59.832213357205674
59.15816420672304
59.832213357205674
59.832213357205674
59.832213357205674
59.832213357205674
59.832213357205674
59.832213357205674
59.641800244598016
59.832213357205674
59.832213357205674
59.832213357205674
59.832213357205674
59.832213357205674
58.47211418414566
59.832213357205674
59.89894655634669
59.89894655634669
59.89894655634669
59.12846366971658
59.89894655634669
59.89894655634669
59.32547979740623
59.89894655634669
59.89894655634669
59.48567409483194
59.89894655634669
58.77730766731513
59.89894655634669
59.89894655634669
59.89894655634669
59.89894655634669
59.89894655634669
57.81442561305228
59.89894655634669
59.89894655634669
59.89894655634669
59.89894655634669
59.89894655634669
59.89894655634669
59.89894655634669
59.89894655634669
59.89894655634669
59.89894655634669
59.89894655634669
58.89618064107394
59.89894655634669
59.89894655634669
59.89894655634669
59.89894655634669
58.98923004229027
59.89894655634669
59.89894655634669
59.89894655634669
59.20273938936526
59.89894655634669
59.89894655634669
59.885485187420294
59.89894655634669
59.89894655634669
59.89894655634669
59.89894655634669
59.89894655634669
59.89894655634669
59.89894655634669
59.89894655634669
58.82856639362857
59.89894655634669
59.06568394785339
59.89894655634669
59.87507845753805
59.89894655634669
%% Cell type:markdown id: tags:
### Exercise!!
**Play with the driver above to see if an improved objective function can be obtained.**
%% Cell type:markdown id: tags:
### DTU Cost Model
The DTU Cost Model is based on more recent industry data. It has a similar structure to the NREL cost and scaling model and contains the major elements to calculate LCOE, IRR etc. One key innovation of the DTU Cost model compared to the NREL cost and scaling model is the use of a detailed financial cash flow analysis. This is not yet implemented but will be implemented in a future version.
For more information on the DTU Cost model see its background here:
https://topfarm.pages.windenergy.dtu.dk/TopFarm2/user_guide.html#dtu-cost-model
and the source code documentation here:
https://topfarm.pages.windenergy.dtu.dk/TopFarm2/api_reference/dtucost.html
%% Cell type:markdown id: tags:
**Import the new DTU Cost model**
%% Cell type:code id: tags:
``` python
#import the DTU cost model
from topfarm.cost_models.economic_models.dtu_wind_cm_main import economic_evaluation as ee_2
```
%% Cell type:markdown id: tags:
**Set up the site and inputs as before but with additional cost variables.**
%% Cell type:code id: tags:
``` python
# site set up
n_wt = 16 # number of wind turbines
site = IEA37Site(n_wt) # site is the IEA Wind Task 37 site with a circle boundary
windTurbines = IEA37_WindTurbines() # wind turbines are the IEA Wind Task 37 3.4 MW reference turbine
wake_model = IEA37SimpleBastankhahGaussian(site, windTurbines) # select the Gaussian wake model
AEPComp = PyWakeAEPCostModelComponent(wake_model, n_wt) # set up AEP caculator to use Gaussiann model
# vectors for turbine properties: diameter, rated power and hub height
# these are inputs to the cost model
Drotor_vector = [windTurbines.diameter()] * n_wt
power_rated_vector = [float(windTurbines.power(20))*1e-6] * n_wt
hub_height_vector = [windTurbines.hub_height()] * n_wt
# add additional cost model inputs for shore distance, energy price, project lifetime, rated rotor speed and water depth
distance_from_shore = 30 # [km]
energy_price = 0.1 # [Euro/kWh] What we get per kWh
project_duration = 20 # [years]
rated_rpm_array = [12] * n_wt # [rpm]
water_depth_array = [15] * n_wt # [m]
```
%% Cell type:markdown id: tags:
**Set up the cost function to use the new DTU cost model.**
%% Cell type:code id: tags:
``` python
# set up function for new cost model with initial inputs as set above
eco_eval = ee_2(distance_from_shore, energy_price, project_duration)
# function for calculating aep as a function of x,y positions of the wind turbiens
def aep_func(x, y, **kwargs):
return wake_model(x, y).aep().sum(['wd','ws']).values*10**6
# function for calculating overall internal rate of return (IRR)
def irr_func(aep, **kwargs):
eco_eval.calculate_irr(rated_rpm_array, Drotor_vector, power_rated_vector, hub_height_vector, water_depth_array, aep)
print(eco_eval.IRR)
return eco_eval.IRR
```
%% Cell type:markdown id: tags:
**Set up rest of problem just as in prior example and run optimization with new model.**
%% Cell type:code id: tags:
``` python
# create an openmdao component for aep and irr to add to the problem
aep_comp = CostModelComponent(input_keys=['x','y'], n_wt=n_wt, cost_function=aep_func, output_key="aep", output_unit="kWh", objective=False, output_val=np.zeros(n_wt))
irr_comp = CostModelComponent(input_keys=['aep'], n_wt=n_wt, cost_function=irr_func, output_key="irr", output_unit="%", objective=True, income_model=True)
# create a group for the aep and irr components that links their common input/output (aep)
irr_group = TopFarmGroup([aep_comp, irr_comp])
# add the group to an optimization problem and specify the design variables (turbine positions),
# cost function (irr_group), driver (random search), and constraints (circular boundary and spacing)
problem = TopFarmProblem(
design_vars=dict(zip('xy', site.initial_position.T)),
cost_comp=irr_group,
driver=EasyRandomSearchDriver(randomize_func=RandomizeTurbinePosition_Circle(), max_iter=50),
constraints=[SpacingConstraint(200),
CircleBoundaryConstraint([0, 0], 1300.1)],
plot_comp=plot_comp)
# assign data from optimizationn to a set of accessible variables and run the optimization
cost, state, recorder = problem.optimize()
```
%% Output
21.446512022323127
21.446512022323127
21.446512022323127
21.17893667262343
21.446512022323127
21.446512022323127
21.446512022323127
21.446512022323127
21.446512022323127
21.446512022323127
21.446512022323127
21.446512022323127
21.446512022323127
21.446512022323127
21.437270403804053
21.446512022323127
21.446512022323127
21.446512022323127
21.03553821343114
21.446512022323127
21.446512022323127
21.446512022323127
21.446512022323127
21.446512022323127
21.446512022323127
21.446512022323127
21.446512022323127
21.446512022323127
21.446512022323127
21.446512022323127
21.446512022323127
21.446512022323127
21.446512022323127
20.992255096835912
21.446512022323127
21.446512022323127
21.446512022323127
21.446512022323127
21.446512022323127
21.446512022323127
21.446512022323127
21.446512022323127
21.363733476893998
21.446512022323127
21.446512022323127
21.446512022323127
21.446512022323127
21.446512022323127
21.446512022323127
21.446512022323127
21.446512022323127
21.48852558866341
21.48852558866341
21.48852558866341
21.48852558866341
21.281585607342723
21.48852558866341
21.48852558866341
21.48852558866341
21.48852558866341
21.25922672347491
21.48852558866341
21.48852558866341
21.48852558866341
21.00257651418671
21.48852558866341
21.48852558866341
21.263403230547297
21.48852558866341
21.48852558866341
21.48852558866341
21.456301805729705
21.48852558866341
21.277472110151873
21.48852558866341
21.577302623117035
21.577302623117035
21.577302623117035
20.992957850395257
21.577302623117035
21.290930849806333
21.577302623117035
21.577302623117035
21.462797679778454
21.577302623117035
21.577302623117035
21.577302623117035
21.43515397737461
21.577302623117035
21.577302623117035
21.577302623117035
21.577302623117035
21.57196544375224
21.577302623117035
21.577302623117035
21.577302623117035
21.577302623117035
21.577302623117035
21.577302623117035
21.538581645219246
21.577302623117035
21.100004439465756
21.577302623117035
21.466435149229703
21.577302623117035
21.577302623117035
21.577302623117035
21.06296472635949
21.577302623117035
21.55833401755942
21.577302623117035
21.577302623117035
21.470572287468848
21.577302623117035
21.577302623117035
21.577302623117035
21.577302623117035
21.50161511285176
21.577302623117035
21.577302623117035
21.577302623117035
21.570150836228173
21.577302623117035
21.577302623117035
21.577302623117035
21.577302623117035
21.577302623117035
21.577302623117035
21.35153427253387
21.577302623117035
21.501613537685117
21.577302623117035
21.577302623117035
21.130918497068162
21.577302623117035
21.57438356618886
21.577302623117035
21.577302623117035
21.577302623117035
21.577302623117035
21.577302623117035
21.577302623117035
21.558036556377314
21.577302623117035
21.577302623117035
21.577302623117035
21.577302623117035
21.577302623117035
21.577302623117035
21.577302623117035
21.577302623117035
21.577302623117035
21.45434911494344
21.577302623117035
21.577302623117035
21.577302623117035
21.577302623117035
21.577302623117035
21.577302623117035
21.577302623117035
21.22252856494111
21.577302623117035
21.577302623117035
21.577302623117035
21.577302623117035
21.577302623117035
21.37875444182682
21.577302623117035
21.577302623117035
21.577302623117035
21.577302623117035
21.577302623117035
21.577302623117035
21.577302623117035
21.502203177340306
21.577302623117035
21.577302623117035
21.577302623117035
21.652427276781584
21.652427276781584
21.652427276781584
21.652427276781584
21.652427276781584
21.652427276781584
21.652427276781584
21.652427276781584
21.652427276781584
21.500772093175048
21.652427276781584
21.652427276781584
21.652427276781584
21.652427276781584
21.565941646924557
21.652427276781584
21.652427276781584
21.652427276781584
21.652427276781584
21.652427276781584
21.652427276781584
21.652427276781584
21.652427276781584
21.652427276781584
21.652427276781584
21.652427276781584
21.652427276781584
21.58873526794094
21.652427276781584
21.313762796093584
21.652427276781584
21.652427276781584
21.652427276781584
21.652427276781584
21.652427276781584
21.652427276781584
21.191123490112407
21.652427276781584
21.652427276781584
21.652427276781584
21.652427276781584
21.652427276781584
21.652427276781584
21.45933698990017
21.652427276781584
21.652427276781584
21.652427276781584
21.652427276781584
21.172905361146952
21.652427276781584
21.52339463106443
21.652427276781584
21.652427276781584
21.257246752291238
21.652427276781584
21.50614430327602
21.652427276781584
21.652427276781584
21.652427276781584
21.391320185168716
21.652427276781584
21.647446945777894
21.652427276781584
21.43411865417406
21.652427276781584
21.652427276781584
21.652427276781584
21.144746997831287
21.652427276781584
%% Cell type:markdown id: tags:
Note how the IRR results with the new cost model are quite different (lower) than the old NREL cost and scaling model.
### Exercise!!
Manipulate the cost inputs to the DTU cost model to see the impact on IRR.
%% Cell type:code id: tags:
``` python
```
......
%% Cell type:markdown id: tags:
# Drivers
The word "driver" is an OpenMDAO specific term that refers to something that operates on a workflow. The most simple driver is something that simply executes an entire workflow once. For optimization, a driver is usually an optimization algorithm that iterates over the workflow until (ideally) an optimal solution is found. In a very complex workflow and problem formulation, there may be multiple drivers acting on sub-groups of a workflow. For instance, in an optimization under uncertainty (OUU) problem, there is usually an uncertainty quantification / analysis driver operating on a workflow nested within a larger optimization workflow.
In this tutorial, a basic introduction to drivers is provided that focuses on some of the most commonly used drivers in Topfarm. These include examples of four types of drivers:
* Design of Experiments (DoE) - these drivers sample across a set of input parameters and execute the workflow for each input set. Such drivers can be parallelized easily since each workflow execution is independent from the next.
* Gradient-based or local search optimizers - these drivers use information about the gradients of the objective function for the problem with respect to the design variables in order to move through the design space systematically to find an improved design. This class of optimization algorithms are efficient but are challenged problems that contain significant nonconvexity, objective functions that are relatively insensitive to the design variables, and other issues.
* Gradient-free metaheuristic optimizers - these drivers typically use "nature-inspired" algorithms to search the design space more globally. They use multiple instances of designs at once and compare performance to make decisions about how to generate new designs that hopefully improve the objective function performance. A clasic example of this type of optimizer is a genetic algorithm.
* Gradient-free heuristic optimizers - these drivers use some sort of heuristic to search through the design space that is informed by domain knowledge and experience with some element of randomness as well. Random search algorithms fall into this category and are widely used in commercial wind farm optimization.
We will introduce a specific example of each of the above driver types applied to a Topfarm problem in the next sequence of examples.
%% Cell type:markdown id: tags:
[Try this yourself](https://colab.research.google.com/github/DTUWindEnergy/TopFarm2/blob/master/docs/notebooks/drivers.ipynb) (requires google account)
%% Cell type:code id: tags:
``` python
%%capture\n# Install Topfarm if needed\ntry:\n import topfarm\nexcept ModuleNotFoundError:\n !pip install topfarm
%%capture\nimport importlib\nif not importlib.util.find_spec("topfarm"):\n !pip install topfarm\n# Install Topfarm if needed
```
%% Cell type:markdown id: tags:
**First we import supporting libraries in Python numpy and matplotlib**
%% Cell type:code id: tags:
``` python
from topfarm.easy_drivers import EasyDriverBase
EasyDriverBase.max_iter = 1
```
%% Cell type:code id: tags:
``` python
import numpy as np
%matplotlib inline
# uncomment to update plot during optimization
# %matplotlib qt
import matplotlib.pyplot as plt
```
%% Cell type:markdown id: tags:
**Next we import and initialize several functions and classes from Topfarm to set up the problem including:**
* **TopFarmProblem - overall topfarm problem class to which the objectives, design variables, and constraints are added**
* **XYBoundaryConstraint - for a boundary specified as a series of connected perimeter vertices**
* **CircleBoundaryConstraint - for a circular boundary with a central location and a radius**
* **SpacingConstraint - for the inter-turbine spacing distance constraints**
**We also import some dummy models (DummyCost, NoPlot, DummyCostPlotComp) as stand-ins for what would be the actual models used in a real wind farm design problem. The dummy cost model takes user defined input for an initial and optimal state and computes the sum of squared error between the two.**
**For documentation on Topfarm see:**
https://topfarm.pages.windenergy.dtu.dk/TopFarm2/user_guide.html#
%% Cell type:code id: tags:
``` python
from topfarm.cost_models.dummy import DummyCost
from topfarm.plotting import NoPlot
from topfarm.constraint_components.spacing import SpacingConstraint
from topfarm.constraint_components.boundary import XYBoundaryConstraint
from topfarm._topfarm import TopFarmProblem
from topfarm.cost_models.dummy import DummyCostPlotComp
```
%% Cell type:markdown id: tags:
**Next we do some problem set up to provide an initial and optimal turbine layout as well as the overall turbine location boundary.**
**We also configure initalize the plotting component for use in the optimization.**
%% Cell type:code id: tags:
``` python
initial = np.array([[6, 0, 0], [6, -8, 0], [1, 1, 0]]) # user-defined initial turbine layouts
boundary = np.array([(0, 0), (6, 0), (6, -10), (0, -10)]) # user-defined site boundary vertices
optimal = np.array([[3, -3, 1], [7, -7, 2], [4, -3, 4]]) # user-defined optimal turbine layouts
plot_comp = DummyCostPlotComp(optimal, delay=0.1, plot_improvements_only=True)
```
%% Cell type:markdown id: tags:
**A function is introduced below that will allow us to quickly reconfigure the example for the different drivers.**
%% Cell type:code id: tags:
``` python
def optimize(driver):
tf = TopFarmProblem(
dict(zip('xy', (initial[:, :2]).T)), # setting up the turbines as design variables
DummyCost(optimal[:, :2]), # using dummy cost model
constraints=[SpacingConstraint(2), # spacing constraint set up for minimum inter-turbine spacing
XYBoundaryConstraint(boundary)], # constraint set up for the boundary type provided
driver=driver, # driver is specified for the example
plot_comp=plot_comp) # support plotting function
tf.optimize() # run the DoE analysis or optimization
```
%% Cell type:markdown id: tags:
## DOE (Design Of Experiment) Driver
The first driver example executes a design of experiments looking at how different sets of inputs for the turbine positions affect the cost function. In the first case, a user-defined set of inputs is provided, while in the second a "full-factorial" sampling approach is used.
(Wikipedia) "In statistics, a full factorial experiment is an experiment whose design consists of two or more factors, each with discrete possible values or "levels", and whose experimental units take on all possible combinations of these levels across all such factors. A full factorial design may also be called a fully crossed design. Such an experiment allows the investigator to study the effect of each factor on the response variable, as well as the effects of interactions between factors on the response variable."
%% Cell type:markdown id: tags:
**Set up a DoE experiment example using a user-defined set up input combinations of the 3 turbine positions**
%% Cell type:code id: tags:
``` python
from openmdao.drivers.doe_generators import ListGenerator
from openmdao.drivers.doe_driver import DOEDriver
optimize(DOEDriver(ListGenerator([[('x', [0., 3., 6.]), ('y', [-10., -10., -10.])],
[('x', [0., 3., 6.]), ('y', [-5., -5., -5.])],
[('x', [0., 3., 6.]), ('y', [-0., -0., -0.])],
])))
```
%% Output
%% Cell type:markdown id: tags:
**Run a full factorial experiment for two inputs using OpenMDAO's built-in FullFactorialGenerator class. The input value of 2 is "the number of evenly spaced levels between each design variable lower and upper bound."**
**See: http://openmdao.org/twodocs/versions/latest/_srcdocs/packages/drivers/doe_generators.html**
**for more information on the various built-in DoE drivers for OpenMDAO.**
%% Cell type:code id: tags:
``` python
from openmdao.drivers.doe_generators import FullFactorialGenerator, ListGenerator
from openmdao.drivers.doe_driver import DOEDriver
optimize(DOEDriver(FullFactorialGenerator(3))) # full factorial sampling with 2 levels (2 is the default)
```
%% Output
%% Cell type:markdown id: tags:
### Exercise
**Update the number of levels of the full factorial to see how it affects the sampling of the design space.**
%% Cell type:code id: tags:
``` python
optimize(DOEDriver(FullFactorialGenerator(2)))
```
%% Output