# coding: utf-8 # Importing a few things # In[1]: # OpenMDAO imports from openmdao.main.datatypes.array import Array from openmdao.main.datatypes.float import Float from openmdao.main.datatypes.list import List from openmdao.main.component import Component # FUSED-Wind imports from fusedwind.plant_flow.asym import AEPMultipleWindRoses, AEPSingleWindRose, BaseAEPModel from fusedwind.interface import InterfaceSlot, implement_base from fusedwind.plant_flow.comp import GenericWindFarm # GCLarsen import #from gclarsen.fused import FGCLarsen from topfarm.tlib import TopfarmComponent # Other import numpy as np from scipy.interpolate import interp1d # In[2]: # OpenMDAO imports #from openmdao.main.api import Assembly #from openmdao.lib.datatypes.api import VarTree, Float, Slot, Array, List, Int, Str, Dict, Enum # FUSEDWind imports #from fusedwind.interface import implement_base, InterfaceSlot #from fusedwind.plant_flow.comp import GenericWindFarm from fusedwind.plant_flow.vt import GenericWindFarmTurbineLayout, WTPC, WeibullWindRoseVT, GenericWindRoseVT # Topfarm lib imports from topfarm.aep import AEP from topfarm.layout_distribution import spiral, DistributeSpiral, DistributeXY, DistributeFilledPolygon from topfarm.plot import OffshorePlot, PrintOutputs from topfarm.tlib import DistFromTurbines, PolyFill, document, DistFromBorders #from topfarm.tlib import ConverHullArea, from topfarm.foundation import FoundationLength from topfarm.elnet import ElNetLength, elnet from topfarm.optimizers import * from topfarm.topfarm import Topfarm #GCL imports from gclarsen.fusedwasp import PlantFromWWH, WTDescFromWTG from gclarsen.fused import FGCLarsen from numpy import * import numpy as np # For plotting import pylab as plt # ### Loading all the input data # In[3]: dat = loadtxt('WaterDepth1.dat') X, Y = meshgrid(linspace(0., 1000., 50), linspace(0., 1000., 50)) depth = array(zip(X.flatten(), Y.flatten(), dat.flatten())) borders = array([[200, 200], [150, 500], [200, 800], [600, 900], [700, 700], [900, 500], [800, 200], [500, 100], [200, 200]]) baseline = array([[587.5, 223.07692308], [525., 346.15384615], [837.5, 530.76923077], [525., 530.76923077], [525., 838.46153846], [837.5, 469.23076923]]) wt_desc = WTDescFromWTG('V80-2MW-offshore.wtg').wt_desc wt_layout = GenericWindFarmTurbineLayout([WTPC(wt_desc=wt_desc, position=pos) for pos in baseline]) # The wind rose weibull_array = np.array([[ 0.00000000e+00, 3.59673400e-02, 9.22422800e+00, 2.38867200e+00], [ 3.00000000e+01, 3.94977300e-02, 9.86435600e+00, 2.44726600e+00], [ 6.00000000e+01, 5.17838000e-02, 9.65220200e+00, 2.41992200e+00], [ 9.00000000e+01, 6.99794900e-02, 9.98217800e+00, 2.58789100e+00], [ 1.20000000e+02, 8.36383000e-02, 1.00946000e+01, 2.74804700e+00], [ 1.50000000e+02, 6.43412500e-02, 9.64369000e+00, 2.59179700e+00], [ 1.80000000e+02, 8.64220000e-02, 9.63377500e+00, 2.58007800e+00], [ 2.10000000e+02, 1.17690000e-01, 1.05678600e+01, 2.54492200e+00], [ 2.40000000e+02, 1.51555100e-01, 1.14525200e+01, 2.46679700e+00], [ 2.70000000e+02, 1.47361100e-01, 1.17423700e+01, 2.60351600e+00], [ 3.00000000e+02, 1.00109800e-01, 1.16923200e+01, 2.62304700e+00], [ 3.30000000e+02, 5.16542400e-02, 1.01385800e+01, 2.32226600e+00]]) wind_rose = WeibullWindRoseVT() wind_rose.wind_directions = weibull_array[:,0] wind_rose.frequency = weibull_array[:,1] wind_rose.k = weibull_array[:,3] wind_rose.A = weibull_array[:,2] # Minimum distance between turbines dist_WT_D = 3.0 # #### Plotting the depth # Some matplotlib options # In[4]: #get_ipython().magic(u'matplotlib inline') import pylab as plt plt.rcParams['axes.labelsize'] = 14 plt.rcParams['legend.fontsize'] = 14 plt.rcParams['axes.titleweight'] = 'bold' plt.rcParams['axes.titlesize'] = 14 # To see all the options: #plt.rcParams.keys() plt.draw() # In[7]: N = 100 X, Y = plt.meshgrid(plt.linspace(depth[:,0].min(), depth[:,0].max(), N), plt.linspace(depth[:,1].min(), depth[:,1].max(), N)) Z = plt.griddata(depth[:,0],depth[:,1],depth[:,2],X,Y, interp='linear') fig = plt.figure(figsize=(6,6), dpi=2000) fs = 14 ax = plt.subplot(111) plt.contourf(X,Y,Z, label='depth [m]') #ax.plot(wt_layout.wt_positions[:,0], wt_layout.wt_positions[:,1], 'or', label='baseline position') ax.scatter(wt_layout.wt_positions[:,0], wt_layout.wt_positions[:,1], wt_layout._wt_list('rotor_diameter'), label='baseline position') ax.plot(borders[:,0], borders[:,1], 'r--', label='border') ax.set_xlabel('x [m]'); ax.set_ylabel('y [m]') ax.axis('equal'); ax.legend(loc='lower left') plt.colorbar().set_label('water depth [m]') plt.draw() # The red points indicate the position of the baseline turbines, the contour plot illustrate the water depth in meters and the red line illustrates the position of the borders limiting the domain of exploration of the optimization. # #### Plot the wind rose # In[8]: fig = plt.figure(figsize=(12,5), dpi=1000) # Plotting the wind statistics ax1 = plt.subplot(121, polar=True) w = 2.*np.pi/len(wind_rose.frequency) b = ax1.bar(pi/2.0-np.array(wind_rose.wind_directions)/180.*np.pi - w/2.0, np.array(wind_rose.frequency)*100, width=w) # Trick to set the right axes (by default it's not oriented as we are used to in the WE community) mirror = lambda d: 90.0 - d if d < 90.0 else 360.0 + (90.0 - d) ax1.set_xticklabels([u'%d\xb0'%(mirror(d)) for d in linspace(0.0, 360.0,9)[:-1]]); ax1.set_title('Wind direction frequency'); # Plotting the Weibull A parameter ax2 = plt.subplot(122, polar=True) b = ax2.bar(pi/2.0-np.array(wind_rose.wind_directions)/180.*np.pi - w/2.0, np.array(wind_rose.A), width=w) ax2.set_xticklabels([u'%d\xb0'%(mirror(d)) for d in linspace(0.0, 360.0,9)[:-1]]); ax2.set_title('Weibull A parameter per wind direction sectors'); plt.draw() # ### Setting up TOPFARM # #### Calculating the wind farm AEP # In[9]: ws = linspace(4, 25, 21) wd = linspace(0, 360, 37)[:-1] # In[11]: aep = AEP(wt_layout=wt_layout, wind_rose=wind_rose, wf=FGCLarsen(), wind_speeds=ws, wind_directions=wd, scaling=1.0, wt_positions=baseline) aep.run() print 'Net AEP=',aep.net_aep/1e6, 'MWh' # Getting the inputs and outputs of the OpenMDAO components # In[15]: document(CONMINdriver) # Optimize only the foundation length # In[22]: components = { 'foundation': FoundationLength(borders=borders, scaling=0.0, depth=depth), 'distribute': DistributeXY(wt_layout=wt_layout, borders=borders), 'elnet': ElNetLength(scaling=0.0), 'wt_dist': DistFromTurbines(scaling=wt_desc.rotor_diameter * dist_WT_D), 'dist_from_borders': DistFromBorders(wt_layout=wt_layout, borders=borders, scaling=0.0), 'plotting': OffshorePlot(baseline=baseline, borders=borders, depth=depth, distribution='xy', add_inputs=['elnet_length', 'foundation_length', 'min_dist' ], title='foundation_length'), 'driver': CONMINOpt()} #COBYLAOpt(rhobeg=1e-2)} workflows = {'driver': ['distribute', 'foundation','wt_dist', 'elnet', 'dist_from_borders', 'plotting']} #objectives = {'driver': 'foundation.foundation_length'} objectives = {'driver': '0.5 * foundation.foundation_length + 0.5*elnet.elnet_length'} constraints = {'driver': ['wt_dist.min_dist>0.8', 'elnet.elnet_length<1.1', 'dist_from_borders' ]} design_variables = {'driver': 'distribute'} connections = {'distribute.wt_positions': ['foundation.wt_positions', 'wt_dist.wt_positions', 'plotting.wt_positions', 'elnet.wt_positions', 'dist_from_borders.wt_positions'], 'foundation.foundation_length': 'plotting.foundation_length', 'foundation.foundations': 'plotting.foundations', 'elnet.elnet_layout': 'plotting.elnet_layout', 'elnet.elnet_length': 'plotting.elnet_length', 'wt_dist.min_dist': 'plotting.min_dist'} input_parameters = {} top = Topfarm(components, workflows, objectives, constraints, design_variables, connections, input_parameters) top.run() # #### Optimization using the AEP # In[24]: components = { 'elnet': ElNetLength(scaling=0.0), 'foundation': FoundationLength(borders=borders, scaling=0.0, depth=depth), 'aep': AEP(wt_layout=wt_layout, wind_rose=wind_rose, wf=FGCLarsen(), wind_speeds=[4, 8, 12], wind_directions=linspace(0, 360, 12)[:-1], scaling=0.0), # 'area': ConverHullArea(wt_layout=wt_layout, scaling=0.0), 'dist_from_borders': DistFromBorders(wt_layout=wt_layout, borders=borders, scaling=0.0), 'wt_dist': DistFromTurbines(scaling=wt_desc.rotor_diameter * dist_WT_D), 'distribute': DistributeFilledPolygon(wt_layout=wt_layout, borders=borders), 'plotting': OffshorePlot(baseline=baseline, borders=borders, depth=depth, distribution='xy', add_inputs=['capacity_factor', 'elnet_length', 'net_aep', 'foundation_length', 'min_dist' ], title='capacity_factor'), 'driver': COBYLAOpt(rhobeg=1e-2)} workflows = {'driver': ['distribute', 'foundation', 'elnet', 'aep', 'dist_from_borders', 'wt_dist', 'plotting']} objectives = {'driver': '-aep.net_aep'} # objectives = {'driver': '-aep.net_aep + 0.4*elnet.elnet_length'} #objectives = {'driver': '-aep.capacity_factor/area.area'} constraints = {'driver': ['wt_dist.min_dist>0.8', 'foundation.foundation_length<1.02' # 'dist_from_borders' #'foundation.foundation_length<1.02', #'elnet.elnet_length<1.02', ]} design_variables = {'driver': 'distribute'} connections = {'distribute.wt_positions': ['foundation.wt_positions', 'elnet.wt_positions', 'wt_dist.wt_positions', 'aep.wt_positions', 'plotting.wt_positions', 'dist_from_borders.wt_positions'], 'foundation.foundation_length': 'plotting.foundation_length', 'foundation.foundations': 'plotting.foundations', 'elnet.elnet_layout': 'plotting.elnet_layout', 'elnet.elnet_length': 'plotting.elnet_length', 'wt_dist.min_dist': 'plotting.min_dist', 'aep.capacity_factor': 'plotting.capacity_factor', 'aep.net_aep': 'plotting.net_aep'} input_parameters = {} top = Topfarm(components, workflows, objectives, constraints, design_variables, connections, input_parameters) top.run() # In[ ]: baseline = top.distribute.wt_positions # In[ ]: from openmdao.main.api import Assembly, Component from openmdao.lib.drivers.api import DOEdriver, COBYLAdriver from openmdao.lib.doegenerators.api import Uniform from openmdao.examples.simple.paraboloid import Paraboloid from openmdao.lib.casehandlers.api import JSONCaseRecorder, ListCaseRecorder class Optimization(Assembly): def configure(self): self.add('paraboloid', Paraboloid()) self.add('driver', COBYLAdriver()) self.driver.add_parameter('paraboloid.x', low=-50, high=50) self.driver.add_parameter('paraboloid.y', low=-50, high=50) self.driver.add_objective('paraboloid.f_xy') self.recorders = [ListCaseRecorder()] # In[ ]: class Analysis(Assembly): def configure(self): self.add('paraboloid', Paraboloid()) self.add('driver', DOEdriver()) self.driver.DOEgenerator = Uniform(1000) self.driver.add_parameter('paraboloid.x', low=-50, high=50) self.driver.add_parameter('paraboloid.y', low=-50, high=50) self.driver.add_response('paraboloid.f_xy') self.recorders = [ListCaseRecorder()] # In[ ]: #---------------------------------------------------- # Print out history of our objective for inspection #---------------------------------------------------- # In[ ]: from topfarm.tlib import listcase2df analysis = Optimization() analysis.run() df = listcase2df(analysis.recorders[0]) # In[ ]: get_ipython().magic(u'matplotlib inline') import pylab as plt import numpy as np from fusedwind.fused_helper import * # In[ ]: def contour_plot(func): rose = func() XS, YS = plt.meshgrid(np.linspace(-2, 2, 20), np.linspace(-2,2, 20)); ZS = np.array([rose(x1=x, x2=y).f_xy for x,y in zip(XS.flatten(),YS.flatten())]).reshape(XS.shape); plt.contourf(XS, YS, ZS, 50); plt.colorbar() contour_plot(Paraboloid()) df.plot(x='paraboloid.x', y='paraboloid.y', ls='', marker='.') plt.draw() # In[ ]: plt.show() # In[ ]: