Wing–Fuselage Configuration with OpenVSP
Level: Intermediate
This notebook demonstrates how to build a wing–fuselage aircraft configuration using the OpenVSP Python API and perform a panel aerodynamic analysis with VSPAero.
Topics covered
OpenVSP geometry creation via Python API
Wing and fuselage parametric modeling
VSPAero VLM (Vortex Lattice Method) analysis setup
Aerodynamic coefficient extraction: CL, CDi, Cm
Effect of fuselage on wing aerodynamics
Requirements
openvsppackage installed (see https://openvsp.org)If OpenVSP is not installed, this notebook will use a mock/fallback mode
References
OpenVSP Python API docs: https://openvsp.org/pyapi_docs/latest/
Raymer, D.P., Aircraft Design: A Conceptual Approach, AIAA, 2018
[ ]:
import numpy as np
import matplotlib.pyplot as plt
import sys, os
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath('.')), 'src'))
from aerodemo.openvsp_utils import (
check_openvsp, init_vsp, add_wing, add_fuselage, run_vspaero
)
from aerodemo.vlm import WingGeometry, VortexLatticeMethod
HAS_VSP = check_openvsp()
print(f"OpenVSP available: {HAS_VSP}")
if not HAS_VSP:
print("NOTE: OpenVSP not found. Using VLM fallback for aerodynamic analysis.")
print("Install OpenVSP with: pip install openvsp")
plt.rcParams.update({'figure.dpi': 100, 'axes.grid': True, 'grid.alpha': 0.3, 'font.size': 11})
1. Aircraft Configuration Parameters
We design a simple low-wing transport aircraft:
Component |
Parameter |
Value |
|---|---|---|
Wing |
Span |
28 m |
Wing |
Root chord |
4.5 m |
Wing |
Tip chord |
1.8 m |
Wing |
Sweep (c/4) |
20° |
Wing |
Dihedral |
5° |
Fuselage |
Length |
30 m |
Fuselage |
Max diameter |
3.2 m |
[ ]:
# Aircraft configuration parameters
config = {
# Wing
'wing_span': 28.0,
'wing_root_chord': 4.5,
'wing_tip_chord': 1.8,
'wing_sweep': 20.0,
'wing_dihedral': 5.0,
'wing_x_offset': 10.0,
'wing_z_offset': -1.2,
# Fuselage
'fuse_length': 30.0,
'fuse_diameter': 3.2,
}
# Derived parameters
S_ref = config['wing_span'] * (config['wing_root_chord'] + config['wing_tip_chord']) / 2
AR = config['wing_span']**2 / S_ref
lam = config['wing_tip_chord'] / config['wing_root_chord']
MAC = (2/3) * config['wing_root_chord'] * (1 + lam + lam**2) / (1 + lam)
print("Wing-Fuselage Configuration:")
print(f" Wing span: b = {config['wing_span']:.1f} m")
print(f" Reference area: S = {S_ref:.2f} m²")
print(f" Aspect ratio: AR = {AR:.2f}")
print(f" Taper ratio: λ = {lam:.3f}")
print(f" MAC: c̄ = {MAC:.3f} m")
print(f" Fuselage length: L = {config['fuse_length']:.1f} m")
print(f" Fuselage diameter: D = {config['fuse_diameter']:.1f} m")
print(f" Fineness ratio: L/D = {config['fuse_length']/config['fuse_diameter']:.2f}")
2. OpenVSP Model Creation
We create the wing and fuselage geometry in OpenVSP. If OpenVSP is installed, the geometry is built programmatically. Otherwise, we proceed with the VLM analysis.
[ ]:
if HAS_VSP:
# Initialize fresh model
init_vsp("WingFuselage")
# Add fuselage
fuse_id = add_fuselage(
length=config['fuse_length'],
max_diameter=config['fuse_diameter'],
name="Fuselage"
)
print(f"Fuselage geometry ID: {fuse_id}")
# Add wing
wing_id = add_wing(
span=config['wing_span'],
root_chord=config['wing_root_chord'],
tip_chord=config['wing_tip_chord'],
sweep_deg=config['wing_sweep'],
dihedral_deg=config['wing_dihedral'],
x_offset=config['wing_x_offset'],
z_offset=config['wing_z_offset'],
name="Wing"
)
print(f"Wing geometry ID: {wing_id}")
print("VSP model created successfully.")
else:
print("Skipping VSP model creation (OpenVSP not available).")
print("Using VLM analysis as fallback.")
3. Aerodynamic Analysis
VSPAero (if OpenVSP available)
VSPAero performs a Vortex Lattice analysis on the full 3D geometry.
VLM fallback
Our custom VLM solver provides equivalent results for isolated wing analysis.
[ ]:
alpha_range = np.linspace(-4, 14, 10)
if HAS_VSP:
print("Running VSPAero VLM sweep...")
vsp_results = run_vspaero(
alpha_start=-4.0,
alpha_end=14.0,
alpha_npts=10,
mach=0.2,
ref_area=S_ref,
ref_span=config['wing_span'],
ref_chord=MAC,
)
if vsp_results:
alpha_data = np.array(vsp_results['Alpha'])
CL_data = np.array(vsp_results['CL'])
CDi_data = np.array(vsp_results['CDi'])
Cm_data = np.array(vsp_results.get('Cm', [0]*len(alpha_data)))
analysis_label = 'VSPAero VLM'
else:
vsp_results = None
print("VSPAero returned no results. Falling back to VLM.")
HAS_VSP = False
if not HAS_VSP or vsp_results is None:
# VLM fallback
wing_geom = WingGeometry(
span=config['wing_span'],
root_chord=config['wing_root_chord'],
tip_chord=config['wing_tip_chord'],
sweep_angle=config['wing_sweep'],
dihedral=config['wing_dihedral'],
n_spanwise=14,
n_chordwise=5,
)
vlm_solver = VortexLatticeMethod(wing_geom)
sweep = vlm_solver.sweep_alpha(alpha_range)
alpha_data = sweep['alpha']
CL_data = sweep['CL']
CDi_data = sweep['CDi']
Cm_data = np.zeros_like(CL_data)
analysis_label = 'VLM (fallback)'
print(f"Analysis complete using: {analysis_label}")
print(f"\nResults at α=4°:")
idx = np.argmin(np.abs(alpha_data - 4.0))
print(f" CL = {CL_data[idx]:.4f}")
print(f" CDi = {CDi_data[idx]:.4f}")
print(f" L/D = {CL_data[idx]/max(CDi_data[idx], 1e-6):.1f}")
[ ]:
fig, axes = plt.subplots(1, 3, figsize=(15, 5))
ax = axes[0]
ax.plot(alpha_data, CL_data, 'bo-', linewidth=2, markersize=7, label=analysis_label)
ax.axhline(0, color='k', linewidth=0.5)
ax.axvline(0, color='k', linewidth=0.5)
ax.set_xlabel('α [deg]')
ax.set_ylabel('$C_L$')
ax.set_title('Lift Curve', fontweight='bold')
ax.legend()
ax = axes[1]
ax.plot(CDi_data, CL_data, 'rs-', linewidth=2, markersize=7, label=analysis_label)
ax.set_xlabel('$C_{Di}$')
ax.set_ylabel('$C_L$')
ax.set_title('Drag Polar', fontweight='bold')
ax.legend()
ax = axes[2]
LD = CL_data / np.maximum(CDi_data, 1e-8)
ax.plot(alpha_data, LD, 'gD-', linewidth=2, markersize=7)
ax.set_xlabel('α [deg]')
ax.set_ylabel('$C_L / C_{Di}$')
ax.set_title('Aerodynamic Efficiency', fontweight='bold')
plt.suptitle(f'Wing–Fuselage Configuration — {analysis_label}', fontsize=13, fontweight='bold')
plt.tight_layout()
plt.savefig('wing_fuselage_aero.png', bbox_inches='tight', dpi=100)
plt.show()
4. Summary
In this notebook we have:
Defined a wing–fuselage configuration with realistic parameters
Created the geometry in OpenVSP (when available) or used VLM fallback
Performed an angle-of-attack sweep and extracted CL, CDi
Visualized the lift curve, drag polar, and efficiency
Key takeaways
OpenVSP enables accurate 3D geometry modeling with fuselage-wing interference
The VLM provides a quick first-estimate for isolated wing aerodynamics
Fuselage presence reduces effective wing aspect ratio slightly
Next steps
Proceed to ../04_complete_aircraft/full_aircraft_openvsp.ipynb for the full aircraft configuration including horizontal and vertical tails with control surfaces.