OpenAeroStruct v1 to v2 Conversion

There are quite a few differences between OpenAeroStruct v1 and v2, though the underlying analyses remain largely the same. In this document, we’ll example code in each subsection using v1 on the top and the corresponding code to perform the same computations in v2 on the bottom. This can serve as a Rosetta Stone to translate older v1 scripts to run in v2.

In general, much more of the code is exposed to the user in v2. This was done to make the settings more explicit and to make it clear what values the user needs to supply. For example, in v1 there was a default surface dictionary that contained some nominal values, but in v2 there are no defaults for any values in the surface dictionaries so the user must supply everything necessary.

We’ll first go through individual sets of commands then present a full example script that performs the same analyses in both versions.

Instantiate the problem

v1 Script

from __future__ import division, print_function
from time import time
import numpy as np

from OpenAeroStruct import OASProblem


# Set problem type
prob_dict = {'type' : 'aero',
              'optimize' : True}

# Instantiate problem and add default surface
OAS_prob = OASProblem(prob_dict)

v2 Script

import numpy as np

from openaerostruct.geometry.utils import generate_mesh
from openaerostruct.geometry.geometry_group import Geometry
from openaerostruct.aerodynamics.aero_groups import AeroPoint

import openmdao.api as om

# Instantiate the problem and the model group
prob = om.Problem()

indep_var_comp = om.IndepVarComp()
indep_var_comp.add_output("v", val=248.136, units="m/s")
indep_var_comp.add_output("alpha", val=5.0, units="deg")
indep_var_comp.add_output("Mach_number", val=0.84)
indep_var_comp.add_output("re", val=1.0e6, units="1/m")
indep_var_comp.add_output("rho", val=0.38, units="kg/m**3")
indep_var_comp.add_output("cg", val=np.zeros((3)), units="m")

prob.model.add_subsystem("prob_vars", indep_var_comp, promotes=["*"])

Create the surface and add it to the problem

v1 Script

# Create a dictionary to store options about the surface
surf_dict = {'num_y' : 5,
              'num_x' : 3,
              'wing_type' : 'rect',
              'symmetry' : True,
              'num_twist_cp' : 2}

# Add the specified wing surface to the problem
OAS_prob.add_surface(surf_dict)

v2 Script

# Create a dictionary to store options about the surface
mesh_dict = {
    "num_y": 5,
    "num_x": 3,
    "wing_type": "rect",
    "symmetry": True,
    "span": 10.0,
    "chord": 1,
    "span_cos_spacing": 1.0,
}

mesh = generate_mesh(mesh_dict)

surface = {
    # Wing definition
    "name": "wing",  # name of the surface
    "symmetry": True,  # if true, model one half of wing
    # reflected across the plane y = 0
    "S_ref_type": "wetted",  # how we compute the wing area,
    # can be 'wetted' or 'projected'
    "twist_cp": np.zeros(2),
    "mesh": mesh,
    # Aerodynamic performance of the lifting surface at
    # an angle of attack of 0 (alpha=0).
    # These CL0 and CD0 values are added to the CL and CD
    # obtained from aerodynamic analysis of the surface to get
    # the total CL and CD.
    # These CL0 and CD0 values do not vary wrt alpha.
    "CL0": 0.0,  # CL of the surface at alpha=0
    "CD0": 0.0,  # CD of the surface at alpha=0
    # Airfoil properties for viscous drag calculation
    "k_lam": 0.05,  # percentage of chord with laminar
    # flow, used for viscous drag
    "t_over_c_cp": np.array([0.12]),  # thickness over chord ratio (NACA0015)
    "c_max_t": 0.303,  # chordwise location of maximum (NACA0015)
    # thickness
    "with_viscous": False,  # if true, compute viscous drag,
    "with_wave": False,  # if true, compute wave drag
    "sweep": 0.0,
    "dihedral": 0.0,
    "taper": 1.0,
}  # end of surface dictionary

Set up the problem, add design variables, and run the optimization

v1 Script

# Setup problem and add design variables, constraint, and objective
OAS_prob.add_desvar('wing.twist_cp', lower=-10., upper=15.)
OAS_prob.add_desvar('wing.sweep', lower=10., upper=30.)
OAS_prob.add_desvar('wing.dihedral', lower=-10., upper=20.)
OAS_prob.add_constraint('wing_perf.CL', equals=0.5)
OAS_prob.add_objective('wing_perf.CD', scaler=1e4)
OAS_prob.setup()

# Actually run the problem
OAS_prob.run()

v2 Script

geom_group = Geometry(surface=surface)

# Add tmp_group to the problem as the name of the surface.
# Note that is a group and performance group for each
# individual surface.
prob.model.add_subsystem(surface["name"], geom_group)

# Create the aero point group and add it to the model
aero_group = AeroPoint(surfaces=[surface])
point_name = "aero_point_0"
prob.model.add_subsystem(point_name, aero_group)

# Connect flow properties to the analysis point
prob.model.connect("v", point_name + ".v")
prob.model.connect("alpha", point_name + ".alpha")
prob.model.connect("Mach_number", point_name + ".Mach_number")
prob.model.connect("re", point_name + ".re")
prob.model.connect("rho", point_name + ".rho")
prob.model.connect("cg", point_name + ".cg")

name = "wing"

# Connect the mesh from the geometry component to the analysis point
prob.model.connect(name + ".mesh", point_name + "." + name + ".def_mesh")

# Perform the connections with the modified names within the
# 'aero_states' group.
prob.model.connect(name + ".mesh", point_name + ".aero_states." + name + "_def_mesh")

prob.model.connect(name + ".t_over_c", point_name + "." + name + "_perf." + "t_over_c")

prob.driver = om.ScipyOptimizeDriver()

# # Setup problem and add design variables, constraint, and objective
prob.model.add_design_var("wing.twist_cp", lower=-10.0, upper=15.0)
prob.model.add_design_var("wing.sweep", lower=-10.0, upper=30.0)
prob.model.add_design_var("wing.dihedral", lower=-10.0, upper=15.0)
prob.model.add_constraint(point_name + ".wing_perf.CL", equals=0.5)
prob.model.add_objective(point_name + ".wing_perf.CD", scaler=1e4)

# Set up the problem
prob.setup()

prob.run_driver()

Full run scripts

v1 Script

from __future__ import division, print_function
from time import time
import numpy as np

from OpenAeroStruct import OASProblem


# Set problem type
prob_dict = {'type' : 'aero',
              'optimize' : True}

# Instantiate problem and add default surface
OAS_prob = OASProblem(prob_dict)

# Create a dictionary to store options about the surface
surf_dict = {'num_y' : 5,
              'num_x' : 3,
              'wing_type' : 'rect',
              'symmetry' : True,
              'num_twist_cp' : 2}

# Add the specified wing surface to the problem
OAS_prob.add_surface(surf_dict)

# Setup problem and add design variables, constraint, and objective
OAS_prob.add_desvar('wing.twist_cp', lower=-10., upper=15.)
OAS_prob.add_desvar('wing.sweep', lower=10., upper=30.)
OAS_prob.add_desvar('wing.dihedral', lower=-10., upper=20.)
OAS_prob.add_constraint('wing_perf.CL', equals=0.5)
OAS_prob.add_objective('wing_perf.CD', scaler=1e4)
OAS_prob.setup()

# Actually run the problem
OAS_prob.run()

v2 Script

import numpy as np

from openaerostruct.geometry.utils import generate_mesh
from openaerostruct.geometry.geometry_group import Geometry
from openaerostruct.aerodynamics.aero_groups import AeroPoint

import openmdao.api as om

# Instantiate the problem and the model group
prob = om.Problem()

indep_var_comp = om.IndepVarComp()
indep_var_comp.add_output("v", val=248.136, units="m/s")
indep_var_comp.add_output("alpha", val=5.0, units="deg")
indep_var_comp.add_output("Mach_number", val=0.84)
indep_var_comp.add_output("re", val=1.0e6, units="1/m")
indep_var_comp.add_output("rho", val=0.38, units="kg/m**3")
indep_var_comp.add_output("cg", val=np.zeros((3)), units="m")

prob.model.add_subsystem("prob_vars", indep_var_comp, promotes=["*"])
# docs checkpoint 1

# docs checkpoint 2
# Create a dictionary to store options about the surface
mesh_dict = {
    "num_y": 5,
    "num_x": 3,
    "wing_type": "rect",
    "symmetry": True,
    "span": 10.0,
    "chord": 1,
    "span_cos_spacing": 1.0,
}

mesh = generate_mesh(mesh_dict)

surface = {
    # Wing definition
    "name": "wing",  # name of the surface
    "symmetry": True,  # if true, model one half of wing
    # reflected across the plane y = 0
    "S_ref_type": "wetted",  # how we compute the wing area,
    # can be 'wetted' or 'projected'
    "twist_cp": np.zeros(2),
    "mesh": mesh,
    # Aerodynamic performance of the lifting surface at
    # an angle of attack of 0 (alpha=0).
    # These CL0 and CD0 values are added to the CL and CD
    # obtained from aerodynamic analysis of the surface to get
    # the total CL and CD.
    # These CL0 and CD0 values do not vary wrt alpha.
    "CL0": 0.0,  # CL of the surface at alpha=0
    "CD0": 0.0,  # CD of the surface at alpha=0
    # Airfoil properties for viscous drag calculation
    "k_lam": 0.05,  # percentage of chord with laminar
    # flow, used for viscous drag
    "t_over_c_cp": np.array([0.12]),  # thickness over chord ratio (NACA0015)
    "c_max_t": 0.303,  # chordwise location of maximum (NACA0015)
    # thickness
    "with_viscous": False,  # if true, compute viscous drag,
    "with_wave": False,  # if true, compute wave drag
    "sweep": 0.0,
    "dihedral": 0.0,
    "taper": 1.0,
}  # end of surface dictionary
# docs checkpoint 3

# docks checkpoint 4
geom_group = Geometry(surface=surface)

# Add tmp_group to the problem as the name of the surface.
# Note that is a group and performance group for each
# individual surface.
prob.model.add_subsystem(surface["name"], geom_group)

# Create the aero point group and add it to the model
aero_group = AeroPoint(surfaces=[surface])
point_name = "aero_point_0"
prob.model.add_subsystem(point_name, aero_group)

# Connect flow properties to the analysis point
prob.model.connect("v", point_name + ".v")
prob.model.connect("alpha", point_name + ".alpha")
prob.model.connect("Mach_number", point_name + ".Mach_number")
prob.model.connect("re", point_name + ".re")
prob.model.connect("rho", point_name + ".rho")
prob.model.connect("cg", point_name + ".cg")

name = "wing"

# Connect the mesh from the geometry component to the analysis point
prob.model.connect(name + ".mesh", point_name + "." + name + ".def_mesh")

# Perform the connections with the modified names within the
# 'aero_states' group.
prob.model.connect(name + ".mesh", point_name + ".aero_states." + name + "_def_mesh")

prob.model.connect(name + ".t_over_c", point_name + "." + name + "_perf." + "t_over_c")

prob.driver = om.ScipyOptimizeDriver()

# # Setup problem and add design variables, constraint, and objective
prob.model.add_design_var("wing.twist_cp", lower=-10.0, upper=15.0)
prob.model.add_design_var("wing.sweep", lower=-10.0, upper=30.0)
prob.model.add_design_var("wing.dihedral", lower=-10.0, upper=15.0)
prob.model.add_constraint(point_name + ".wing_perf.CL", equals=0.5)
prob.model.add_objective(point_name + ".wing_perf.CD", scaler=1e4)

# Set up the problem
prob.setup()

prob.run_driver()