Skip to main content
Version: 0.1.0

OpenAeroStruct VLM Analysis

This tutorial demonstrates how to wrap an entire OpenMDAO Group -- the OpenAeroStruct (OAS) vortex-lattice method (VLM) aerodynamic solver -- as a single Philote discipline using the OpenMdaoSubProblem class. Unlike the NACA/XFOIL example, which wraps individual tools as ExplicitDiscipline subclasses, this approach packages a complete analysis pipeline (geometry + aerodynamics) into one gRPC-servable discipline.

By the end of this tutorial you will be able to:

  • Wrap an OpenMDAO Group as a Philote discipline using OpenMdaoSubProblem.
  • Serve the OAS VLM solver over gRPC.
  • Run a VLM aerodynamic analysis from an OpenMDAO client.
  • Customize the wing geometry and surface properties.

Prerequisites

Install the package

From the repository root:

pip install -e .

This installs philote-mdo, openmdao, openaerostruct, and numpy as dependencies.

Architecture Overview

The example wraps two OAS components inside a single Philote discipline:

┌─────────────────────────────────────────────────────┐
│ OasDiscipline (Philote gRPC server, port 50051) │
│ │
│ ┌──────────────┐ ┌────────────────────────┐ │
│ │ Geometry │──mesh──▶ AeroPoint (VLM) │ │
│ │ (wing shape) │ │ (vortex-lattice solve)│ │
│ └──────────────┘ └────────────────────────┘ │
│ │
│ Inputs: Outputs: │
│ v (m/s) CL (scalar) │
│ alpha (deg) CD (scalar) │
│ Mach_number CM (3-vector) │
│ re (1/m) │
│ rho (kg/m^3) │
│ cg (3-vector, m) │
└─────────────────────────────────────────────────────┘

Geometry applies design variables (twist, chord, shear) to a baseline mesh.

AeroPoint runs the VLM aerodynamic analysis on the deformed mesh at the specified flight condition and computes lift, drag, and moment coefficients.

The OasDiscipline class inherits from OpenMdaoSubProblem, which wraps an entire om.Problem as a Philote explicit discipline. Variable mappings translate between the Philote interface (flat inputs/outputs) and the internal OpenMDAO problem paths.

Running the Analysis

All-in-one script

The quickest way to run the example starts the server in-process, connects via gRPC, runs the analysis, and prints the results:

cd examples/oas_vlm
python run_analysis.py

This evaluates a rectangular wing (10 m span, 1 m chord, 7 spanwise panels) at the following flight conditions: v = 248.136 m/s, alpha = 5 deg, M = 0.84, Re = 1e6/m, rho = 0.38 kg/m^3. Expected output:

OAS VLM analysis: v=248.136 m/s, alpha=5.0 deg, M=0.84, Re=1e+06/m, rho=0.38 kg/m^3
CL = ...
CD = ...
CM = [...]

Standalone server

To run the discipline as a standalone gRPC server for integration into larger workflows:

Terminal 1 -- Start the server:

python server.py

Output:

OAS VLM server started. Listening on port 50051.

Terminal 2 -- Connect from a client:

from run_analysis import run

cl, cd, cm = run(start_server=False)

Customizing the Wing

Mesh configuration

Pass a mesh_dict to OasDiscipline to change the wing planform:

from philote_examples import OasDiscipline

# CRM wing with 13 spanwise panels
discipline = OasDiscipline(
mesh_dict={
"num_y": 13,
"num_x": 3,
"wing_type": "CRM",
"symmetry": True,
"num_twist_cp": 5,
}
)

Surface properties

Use surface_options to override defaults like viscous drag or baseline CD:

discipline = OasDiscipline(
surface_options={
"with_viscous": True,
"CD0": 0.015,
"with_wave": True,
}
)

Understanding the Code

The OpenMdaoSubProblem pattern

Where the NACA/XFOIL example wraps external executables using ExplicitDiscipline, this example takes advantage of the fact that OAS is already an OpenMDAO Group. The OpenMdaoSubProblem class handles the wrapping automatically:

  1. Create an om.Group (OasAeroGroup) that contains the solver components and their internal connections.
  2. Subclass OpenMdaoSubProblem (OasDiscipline) and in the constructor:
    • Generate the mesh and build the surface dictionary.
    • Call self.add_group(group) to embed the Group in an internal om.Problem.
    • Call self.add_mapped_input() and self.add_mapped_output() to define the Philote-level interface.

At runtime, compute() copies inputs into the internal problem, calls run_model(), and copies outputs back -- all handled by the base class.

Key variable mappings

Philote nameOpenMDAO pathShapeUnits
vv(1,)m/s
alphaalpha(1,)deg
Mach_numberMach_number(1,)--
rere(1,)1/m
rhorho(1,)kg/m^3
cgcg(3,)m
CLaero_point_0.wing_perf.CL(1,)--
CDaero_point_0.wing_perf.CD(1,)--
CMaero_point_0.CM(3,)--

Troubleshooting

Port already in use The default port is 50051. If another process is using it, stop it or change the PORT constant in the scripts.

OpenAeroStruct not installed Run pip install -e . from the repository root to install all dependencies including openaerostruct.