Aero-elastic Turbine Example

This example shows the basics of how to connect a parameterized geometric definition of a wind turbine blade planform to the inputs of an aeroelastic solver. The example is located in src/fusedwind/examples/turbine/aeroelastic_turbine.py.

The overall turbine geometry and beam properties are defined in the fusedwind.turbine.turbine_vt.AeroelasticHAWTVT variable tree. This variable tree needs to be an input to an aeroelastic solver wrapper, and is currently the only requirement. For optimization contexts you will need some parameterization of the blade geometry and if you choose to use the one supplied in FUSED-Wind, hooking up the solver with this geometric definition is easy.

The first step is to write a wrapper for an aeroelastic code. In the example we have made a dummy component that implements the AeroElasticSolverBase interface and otherwise does nothing.

from openmdao.main.api import Assembly, Component
from openmdao.lib.datatypes.api import VarTree

from fusedwind.interface import implement_base
from fusedwind.turbine.aeroelastic_solver import AeroElasticSolverBase
from fusedwind.turbine.turbine_vt import configure_turbine, AeroelasticHAWTVT
from fusedwind.turbine.geometry import SplinedBladePlanform, read_blade_planform


@implement_base(AeroElasticSolverBase)
class AEsolver(Component):

    wt = VarTree(AeroelasticHAWTVT(), iotype='in')

    def execute(self):

        print 'run some analysis here'

Then we instantiate the assembly we want to run our analysis in and add an instance of the fusedwind.turbine.geometry.SplinedBladePlanform class which adds an FFD spline to each of the planform curves. Secondly, we add our new aeroelastic solver.

top = Assembly()

# add splined planform description
top.add('pf_splines', SplinedBladePlanform())
top.driver.workflow.add('pf_splines')

top.pf_splines.blade_length = 86.366
top.pf_splines.pfIn = read_blade_planform('data/DTU_10MW_RWT_blade_axis_prebend.dat')

# add aeroelastic solver
top.add('ae', AEsolver())
top.driver.workflow.add('ae')

In the next step we then configure this turbine. The fusedwind.turbine.turbine_vt.configure_turbine method configures the AeroelasticHAWTVT variable tree as a standard three bladed turbine with a tower, tower top, shaft, hub and blades. Each of these are a MainBody variable tree, which defines the body’s geometric and structural properties. The overall dimensions of the turbine are then specified, which in this case corresponds to the DTU 10MW RWT.

# configure the turbine with standard sub-components
configure_turbine(top.ae.wt)

# define overall dimensions
wt = top.ae.wt
wt.turbine_name = 'DTU 10MW RWT'
wt.doc = 'FUSED-Wind definition of the DTU 10MW RWT'
wt.tower_height = 115.63
wt.hub_height = 119.0
wt.towertop_height = 2.75
wt.shaft_length = 7.1
wt.tilt_angle = 5.0
wt.cone_angle = -2.5
wt.hub_radius = 2.8
wt.blade_length = 86.366
wt.rotor_diameter = 178.332
c = wt.set_machine_type('VarSpeedVarPitch')
c.vIn = 3.
c.vOut = 25.
c.minOmega = 6.
c.maxOmega = 9.6
c.minPitch = 0.

The final configuration step is to link the splined geometry to the blade geometry of the turbine definition in the aeroelastic solver.

# connect the splined planform to the blade geometry vartree
# in the aeroelastic solver
top.connect('pf_splines.pfOut', 'ae.wt.blade1.geom')

And all that remains is to run the assembly which in this case is not so eventful.

Coupled Structural Aero-elastic Turbine Example

In this example, we extend the above example to also interface to to a structural model capable of computing the mass and stiffness beam properties of the blade, that is a required input to most aeroelastic solvers, e.g. FAST and HAWC2. The aim with this is to have the capability of simultaneously optimize the structural and aerodynamic design of a blade.

The example combines the example explaining the blade structural parameterization with the above example of interfacing an aeroelastic solver. The example is located in src/fusedwind/examples/turbine/aerostructural_turbine.py.

The first step is to define our solvers, which is now both an aeroelastic solver and a cross-sectional structure solver capable of computing the beam properties of a blade.

import numpy as np

from openmdao.main.api import Assembly, Component
from openmdao.lib.datatypes.api import List, VarTree

from fusedwind.interface import implement_base
from fusedwind.turbine.geometry import read_blade_planform
from fusedwind.turbine.configurations import configure_bladestructure
from fusedwind.turbine.blade_structure import SplinedBladeStructure
from fusedwind.turbine.structure_vt import BladeStructureVT3D, BeamStructureVT
from fusedwind.turbine.turbine_vt import AeroelasticHAWTVT, configure_turbine

from fusedwind.turbine.aeroelastic_solver import AeroElasticSolverBase
from fusedwind.turbine.structural_props_solver import StructuralCSPropsSolver


@implement_base(AeroElasticSolverBase)
class AEsolver(Component):

    wt = VarTree(AeroelasticHAWTVT(), iotype='in')

    def execute(self):

        print ''
        print 'running aeroelastic analysis ...'


@implement_base(StructuralCSPropsSolver)
class CS2Dsolver(Component):

    cs2d = List(iotype='in')
    beam_structure = VarTree(BeamStructureVT(), iotype='out')

    def execute(self):

        print ''
        for i, cs in enumerate(self.cs2d):
            print 'processing cross section %i' % i

Next, we define our blade geometry, both in terms of planform and lofted shape.

top = Assembly()

configure_bladestructure(top, 'data/DTU10MW', planform_nC=6, structure_nC=5)

top.st_writer.filebase = 'st_test'

top.blade_length = 86.366

top.pf_splines.pfIn = read_blade_planform('data/DTU_10MW_RWT_blade_axis_prebend.dat')
top.blade_surface.chord_ni = 300

for f in ['data/ffaw3241.dat',
          'data/ffaw3301.dat',
          'data/ffaw3360.dat',
          'data/ffaw3480.dat',
          'data/tc72.dat',
          'data/cylinder.dat']:

    top.blade_surface.base_airfoils.append(np.loadtxt(f))

top.blade_surface.blend_var = np.array([0.241, 0.301, 0.36, 0.48, 0.72, 1.])

# spanwise distribution of planform spline DVs
top.pf_splines.Cx = [0, 0.2, 0.4, 0.6, 0.8, 1.]

# spanwise distribution of sptructural spline DVs
top.st_splines.Cx = [0, 0.2, 0.4, 0.75, 1.]

# spanwise distribution of points where
# cross-sectional structure vartrees will be created
top.st_splines.x = np.linspace(0, 1, 12)

Then we add our two solvers:

# add structural solver
top.add('st', CS2Dsolver())
top.driver.workflow.add('st')


# add aeroelastic solver
top.add('ae', AEsolver())
top.driver.workflow.add('ae')

And configure the turbine:

# configure the turbine with standard sub-components
configure_turbine(top.ae.wt)

# define overall dimensions
wt = top.ae.wt
wt.turbine_name = 'DTU 10MW RWT'
wt.doc = 'FUSED-Wind definition of the DTU 10MW RWT'
wt.tower_height = 115.63
wt.hub_height = 119.0
wt.towertop_height = 2.75
wt.shaft_length = 7.1
wt.tilt_angle = 5.0
wt.cone_angle = -2.5
wt.hub_radius = 2.8
wt.blade_length = 86.366
wt.rotor_diameter = 178.332
c = wt.set_machine_type('VarSpeedVarPitch')
c.vIn = 3.
c.vOut = 25.
c.minOmega = 6.
c.maxOmega = 9.6
c.minPitch = 0.

And finally make the necessary connections between, firstly, the structural geometry and the cross-sectional solver, secondly, the planform splines and the aeroelastic solver, and finally the beam structural properties computed by the structural solver with the blade beam properties used by the aeroelastic solver.

# connect the parameterized structure vartrees to the 
# structural solver
top.connect('st_builder.cs2d', 'st.cs2d')

# connect the splined planform to the blade geometry vartree
# in the aeroelastic solver
top.connect('pf_splines.pfOut', 'ae.wt.blade1.geom')

# connect computed beam structure to input vartree in the
# aeroelastic solver
top.connect('st.beam_structure', 'ae.wt.blade1.beam_structure')

And lastly, we run the aero-structural analysis.

# run it
top.run()