SkillAgentSearch skills...

LovelacePM

Open source, python-interpretable vortex panel method design to optimize aircraft configuration studies

Install / Use

/learn @pedrosecchi67/LovelacePM
About this skill

Quality Score

0/100

Category

Design

Supported Platforms

Universal

README

LovelacePM

LovelacePM is an open source, Python-interpretable 3D vortex panel method code for optimized full aircraft configuration analysis.

It provides optimized access to three-dimentional, viscous-corrected potential flow calculations in the easy-to-access fashion preferred for optimization purposes in academia.

Named after Ada Lovelace and her fascination for flying machines!

Quick start

Defining a wing

To install LovelacePM's dependencies, use:

pip3 install numpy; pip3 install skbuild

To install LovelacePM, use:

pip3 install LovelacePM

Note that, when installing source distributions on Windows, pip might require that you install Visual C++ Compiler for Python, which is needed for compilation of Fortran modules.

From version v0.1.7 and on, LovelacePM has been converted to raw Python and can thus be installed on any platform without worries on the need for compilers.

For further installation instructions, check out the final section of this README.

To quickly analysie an ONERA M6 wing, start by importing the package and defining its dimensions. You can then run a simulation as the one below. File 'onerad.dat' should be located in the simulation's directory.

from LovelacePM import *
import numpy as np
from math import tan, radians

if multiprocess_guard():
    #this guard is highly recommended on Windows 
    
    b=1.1963; croot=0.806; taper=0.56; sweep=26.7
    alpha=5.0; Uinf=10.0

    root_sect=wing_section(afl='onerad', c=croot, xdisc=30, sweep=sweep) 
    #CA_position set to origin as default
    left_tip_sect=wing_section(afl='onerad', c=croot*taper, \
    CA_position=np.array([b*tan(radians(sweep)), -b, 0.0]), closed=True, xdisc=30, sweep=sweep)
    right_tip_sect=wing_section(afl='onerad', c=croot*taper, \
    CA_position=np.array([b*tan(radians(sweep)), b, 0.0]), closed=True, xdisc=30, sweep=sweep)

    sld=Solid()

    left_wingquad=wing_quadrant(sld, sect1=left_tip_sect, sect2=root_sect)
    right_wingquad=wing_quadrant(sld, sect1=root_sect, sect2=right_tip_sect)
    wng=wing(sld, wingquads=[left_wingquad, right_wingquad])

    acft=aircraft(sld, elems=[wng])
    acft.edit_parameters({'a':alpha, 'Uinf':Uinf, 'M':0.5})

    wng.patchcompose(ydisc=50)
    acft.plotgeometry()

    acft.addwake()
    acft.eulersolve()
    acft.forces_report()
    plot_Cls(sld, wings=[wng])

You can also run the case above without any console output using keyword argument

echo=False

in every "aircraft" class method execution. Check out

from LovelacePM import *; from LovelacePM.documentation import *
print(aircraft.__doc__)

The code above follows the steps:

  • Instantiating a Solid (class containing info about geometry and aerodynamic singularities);
  • Instantiating wing sections (with airfoil x-discretization, in number of panels, specified by kwarg "xdisc");
  • Gathering pairs of wing sections into wing quadrants (thus specifying an order);
  • Gathering wing quadrants into wings (from leftmost/highest quadrant to rightmost/lowest quadrant);
  • Gathering all wings and non-lifting bodies into an aircraft;
  • Using "patchcompose" methods to generate panel networks;
  • Adding a wake;
  • Generating an euler solution;
  • Calculate forces and stability derivatives;
  • Plot results, if desired.

Adding a non-lifting body

You can add a "standard body" (with ellipsoidal nose and conical tailcone) with code as in the following example:

fuselage=standard_body(sld, defsect=circdefsect, body_thdisc=50, \
body_width=fuselage_width, nose_loc=np.array([-fuselage_aftlen, 0.0, -0.01]))

# ... create wings wing_left, wing_right as you want them ...

#trim right wing's leftmost/highest side so that none of its points 
#penetrate the fuselage
wing_right.trim_bybody(fuselage, sectside=1)
#trim right wing's rightmost/lowest side so that none of its points 
#penetrate the fuselage
wing_left.trim_bybody(fuselage, sectside=2)

acft=aircraft(sld, elems=[wing_left, wing_right, fuselage], Sref=Sref, bref=b)

wing_right.patchcompose(ydisc=20, ystrategy=lambda x: x)
wing_left.patchcompose(ydisc=20, ystrategy=lambda x: x)

fuselage.patchcompose(leftqueue=[wing_left], rightqueue=[wing_right], xdisc=60, \
    thdisc_upleft=5, thdisc_downleft=5, thdisc_downright=5, thdisc_upright=5)

Note the arguments "leftqueue", "rightqueue", etc. in the "fuselage.patchcompose" method. They are lists identifying the lifting surfaces which are connected to the body a given side of it, ordered in x-axis's positive direction.

Arguments "thdisc_downleft", "thdisc_upright", etc. identify the angular discretization (in number of panels) specified for the body between queues "lowqueue" and "leftqueue", "upqueue" and "rightqueue", etc.

Customizing a body's geometry

You can also define a body instantiating "body" class and provide it with sections instantiated x-position by x-position, as in:

fusdefsect=smooth_angle_defsect_function(r_1x=0.5, r_2x=0.5, r_2y=0.5, r_1y=0.5, ldisc=20, thdisc=10)

sects=[
    fusdefsect(center=np.array([-spinner_length-motor_length, 0.0, motor_spinner_height]), R=0.0), \
    \
    fusdefsect(center=np.array([-motor_length, 0.0, motor_spinner_height]), \
    R=motor_width/2, z_expand=radiator_height/motor_width), \
    \
    fusdefsect(center=np.array([-screen_aft_projection, 0.0, (fuselage_height-cabin_screen_height)/2]), \
    R=(fuselage_height-cabin_screen_height)/2, \
    y_expand=motor_width/(fuselage_height-cabin_screen_height)), \
    \
    fusdefsect(center=np.array([-cabin_aft_projection, 0.0, fuselage_height/2]), \
    R=fuselage_width/2, z_expand=fuselage_height/fuselage_width), \
    \
    fusdefsect(center=np.array([cabin_length-cabin_aft_projection, 0.0, fuselage_height/2]), \
    R=fuselage_width/2, z_expand=fuselage_height/fuselage_width), \
    \
    fusdefsect(center=np.array([cabin_length-cabin_aft_projection+tailcone_length, 0.0, tailcone_height]), R=0.0)
]

fuselage=body(sld, sections=sects)

To check out the fuselage composed above, use

from LovelacePM import *; from LovelacePM.monoplane import *

Note that a function with suffix "defsect" is used in the code above. A defsect is a lambda function that defines a body section based on data simpler than its point-by-point geometry - speciffically, its maximum dimension, center position in 3D space and y and z axis scale factors (to make it easier to transform a tubular into an egg-shape fuselage, if you so desire =D). If you want further info on what is a defsect and how to customize it, check out:

from LovelacePM import *
from LovelacePM.documentation import *
print(body.__doc__)

You can also use pre-programmed defsects "circdefsect" and "squaredefsect", which can be instantiated individually as in the example above, or provided as an argument to function "standard_body", as in:

#circular section fuselage
fuselage=standard_body(sld, defsect=circdefsect, body_thdisc=50, \
body_width=fuselage_width, nose_loc=np.array([-fuselage_aftlen, 0.0, -0.01]))

#square section fuselage
fuselage=standard_body(sld, defsect=squaredefsect, body_thdisc=50, \
body_width=fuselage_width, nose_loc=np.array([-fuselage_aftlen, 0.0, -0.01]))

For further info, check:

from LovelacePM import *
from LovelacePM.documentation import *

help(body)
help(body_section)
help(circdefsect)
help(squaredefsect)
help(smooth_angle_defsect_function)

Adding viscous corrections

LovelacePM comes with an automation of Mark Drela's viscous-inviscid Xfoil panel method code to ease strip theory viscous corrections and thus make the package complete in itself in its capability of assisting aircraft design.

To get instructions on how to use this automation for viscous corrections, check out:

from LovelacePM import *
from LovelacePM.documentation import *

help(xfoil_visc)
help(polar_correction)

Or begin by following this example:

if multiprocess_guard():
    #generating xfoil corrected polars
    n4412_polar=polar_correction(name='n4412')
    #notice that n4412.dat Selig format airfoil file must be included in your script's directory

    #adding them to a wing section
    sect1=wing_section(CA_position=np.array([0.0, -b/2, 0.0]), c=croot*taper, xdisc=20, correction=n4412_polar, Re=Uinf*rho*croot*taper/mu, closed=True)

Note that, for the automation to work, Xfoil must be located within the user's PATH environment variable.

Contributing to LovelacePM

You can contribute to LovelacePM by assisting us in meeting the system requirements and code conventions listed in the sections below.

You can also check our file structure at our CONTRIBUTING.md file.

Introduction to the project

This README refers to capabilities and usage conditions referrent to version 0.1.0. Version 0.1.0 is a beta testing version and has not yet met all system requirements listed below.

This project is subject to GNU GPL v3.0.

The system requirements defined for the final product are labelled below, along with their objective, numbered as: (1) - performance optimization in highly iterative optimization problems; (2) - flexibility of configuration and calculation method definition by the user; (3) - higher accuracy and completeness of the analysis performed.

  • Performing full configuration analysis of subsonic aircraft in an amount of time that doesn't exceed 50 s per AOA for a 5000-panel mesh; (1) [completed]
  • Performing viscous effect estimations based on viscid-inviscid coupling exclusively with geometry, Mach and Reynolds specifications, accepting custom initial guesses for boundary layer thickness; (2, 3) [not yet implemented]
  • Modelling fuselages, nacelles and engines accurately in terms of Euler solution and viscous flow; (3) [completed for non-lifting bodies]
  • Approximating rotor behaviour through means of geometry and flow information, provided either by previous BEMT or LLT calculations (I. E., recieving local inflow chara

Related Skills

View on GitHub
GitHub Stars42
CategoryDesign
Updated17d ago
Forks9

Languages

Python

Security Score

90/100

Audited on Mar 13, 2026

No findings